Re: row_factory and DictCursor

"Joel Nothman" <[email protected]>
Newsgroups gmane.comp.python.db.psycopg.devel
Message-ID <[email protected]>
On Wed, 03 Jun 2009 16:20:12 +1000, James Henstridge <[email protected]>  
wrote:
[snip]
> Here is a quick example of the sort of thing I was thinking of using  
> rownumber:
>
> class DictConnection(_connection):
>     def cursor(self, name=None):
>         cursor = super(DictConnection, self).cursor(name)
>         field_names = []
>         def row_factory(cursor, data):
>             # Update field descriptions if it is a new result set.
>             if cursor.rownumber == 0:
>                 field_names[:] = [info[0] for info in cursor.description]
>             return dict(zip(field_names, data))
>         cursor.row_factory = row_factory
>         return cursor
>
> Something similar would be possible with for a namedtuple
> implementation.  In both cases you can get by without a cursor
> subclass, which is probably a plus.
>
> James.

Looks very nice (and a very neat way of keeping field_names static to the  
cursor without requiring a distinct cursor class. Ideally, though, one  
would like to just be able to pass a cursor factory or row factory  
definition to an existing object. (We could do this with a row factory  
factory which is passed a field_names variable!)

This implementation is also a bit nuanced in terms of name binding:  
field_names cannot be bound to something else in row_factory(), and hence  
a namedtuple implementation would look something like:

class DictConnection(_connection):
     def cursor(self, name=None):
         cursor = super(DictConnection, self).cursor(name)
         tuple_cls = []
         def row_factory(cursor, data):
             # Update field descriptions if it is a new result set.
             if cursor.rownumber == 0:
                 tuple_cls[:] = [namedtuple('NamedTupleRow', (info[0] for  
info in cursor.description))]
             return tuple_cls[0](data))
         cursor.row_factory = row_factory
         return cursor

Here the list defined in 'tuple_cls = []' is used merely as a mutable  
placeholder.

I would absolutely love to have extras.py rewritten like this, and if we  
do it right, we don't have to break much.

I think passing the row data to the row_factory constructor is the Right  
Thing To Do, so anyone relying on the old functionality might just have to  
break.

Nonetheless, I'm trying to find uses in open-source:  
<http://www.google.com/codesearch?q=psycopg2+row_factory>. There is only  
one result that's not in reference to SQLite and is not the psycopg2  
source: skytools (github.com/markokr/skytools-dev.git) inherits from the  
existing DictRow: the above therefore isn't good enough for compatibility,  
but the row_factory interface can be changed.

- Joel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.