I understand. I was thinking it would make the psycopg2 results more similar to what you get when using the DAL methods. But if being able to switch from postgres to some other database mid-project is important (it's not for us), you'd want to avoid using the DictCursor extension. We'll just adjust the source when we want to use DictCursor. Thanks for considering.
--David On Apr 1, 10:36 am, mdipierro <[email protected]> wrote: > I think that changing the return value of fetchall should be > considered breaking backward compatibility. Moreover it would make > postgresql behave differently than the other database backends. > > On Apr 1, 7:22 am, David Niergarth <[email protected]> wrote: > > > > Is it really backward compatible? Have you tried? > > > I tried basic integer indexing and slicing, which work as expected, as > > does the dictionary interface. I just went through all the scenarios I > > could think of and found two differences with DictCursor. > > > 1) Extended slicing fails with an exception (e.g., row[2:5:2] or > > row[::-1]). > > 2) DictCursor objects have the unfortunate list behavior that they > > can't be used directly for string interpolation, whereas tuples can. > > > --David > > > Here are the details. Starting with a simple query, > > > >>> import psycopg2 > > >>> query = ('select id, first_name, last_name, email, password, ' > > ... 'registration_key from auth_user;') > > > check the default behavior. > > > >>> conn = psycopg2.connect('') > > >>> cursor = conn.cursor() > > >>> cursor.execute(query) > > >>> rs = cursor.fetchall() > > >>> row = rs[0] > > >>> row > > (1, 'Joe', 'Demo', '[email protected]', > > '4352cd32e514b98bf6d88ccde0775bf3', '') > > > Rows are plain tuples by default. > > > >>> type(row) > > <type 'tuple'> > > >>> default_row = row # preserve the row for later > > > Now try with DictConnection. > > > >>> import psycopg2.extras > > >>> conn = psycopg2.extras.DictConnection('') > > >>> cursor = conn.cursor() > > >>> cursor.execute(query) > > >>> rs = cursor.fetchall() > > >>> row = rs[0] > > >>> type(row) > > <class 'psycopg2.extras.DictRow'> > > > Results are now DictRows instead of tuples. DictRows repr like lists. > > >>> row > > [1, 'Joe', 'Demo', '[email protected]', > > '4352cd32e514b98bf6d88ccde0775bf3', ''] > > > And they have list methods. (Tuples have no non-special methods so > > this seems ok. > > > >>> row.index('Joe') > > 1 > > > They convert nicely to other builtins. > > > >>> list(row) > > [1, 'Joe', 'Demo', '[email protected]', > > '4352cd32e514b98bf6d88ccde0775bf3', ''] > > >>> tuple(row) > > (1, 'Joe', 'Demo', '[email protected]', > > '4352cd32e514b98bf6d88ccde0775bf3', '') > > >>> dict(row) > > {'first_name': 'Joe', 'last_name': 'Demo', 'id': 1, 'password': > > '4352cd32e514b98bf6d88ccde0775bf3', 'registration_key': '', 'email': > > '[email protected]'} > > > Integer indexing and len() works. > > > >>> row[0], row[1], row[2], row[3], row[4], row[5] > > (1, 'Joe', 'Demo', '[email protected]', > > '4352cd32e514b98bf6d88ccde0775bf3', '') > > >>> len(row) > > 6 > > > They also have a dict interface. > > > >>> row.keys() > > ['first_name', 'last_name', 'email', 'password', > > 'registration_key', 'id'] > > >>> row['first_name'], row['last_name'], row['id'] > > ('Joe', 'Demo', 1) > > > Slicing works as expected. > > > >>> row[:3] > > [1, 'Joe', 'Demo'] > > >>> row[-3:] > > ['[email protected]', '4352cd32e514b98bf6d88ccde0775bf3', ''] > > >>> row[2:5] > > ['Demo', '[email protected]', '4352cd32e514b98bf6d88ccde0775bf3'] > > > Hmmm, extended slicing fails (Strike 1)... > > > >>> row[2:5:-1] > > Traceback (most recent call last): > > File "<stdin>", line 1, in <module> > > File "/usr/lib/python2.5/site-packages/psycopg2/extras.py", line > > 110, in __getitem__ > > x = self._index[x] > > TypeError: unhashable type > > >>> row[2:5:1] > > Traceback (most recent call last): > > File "<stdin>", line 1, in <module> > > File "/usr/lib/python2.5/site-packages/psycopg2/extras.py", line > > 110, in __getitem__ > > x = self._index[x] > > TypeError: unhashable type > > > but it works for regular tuples. > > > >>> default_row[2:5:1] > > ('Demo', '[email protected]', '4352cd32e514b98bf6d88ccde0775bf3') > > >>> default_row[2:5:-1] > > () > > > Another problem is the difference between tuples and lists when doing > > string interpolation. String interpolation requires a tuple and fails > > with a list. For example, > > > >>> '%s %s' % ('a', 'b') > > 'a b' > > > >>> '%s %s' % ['a', 'b'] > > Traceback (most recent call last): > > File "<stdin>", line 1, in <module> > > TypeError: not enough arguments for format string > > > The DictCursor fails with string interpolation, just like a list > > (Strike 2), > > > >>> '%s %s %s %s %s %s' % row > > Traceback (most recent call last): > > File "<stdin>", line 1, in <module> > > TypeError: not enough arguments for format string > > > but works when wrapped with tuple(). > > > >>> '%s %s %s %s %s %s' % tuple(row) > > '1 Joe Demo [email protected] 4352cd32e514b98bf6d88ccde0775bf3 ' > > > It was pretty easy to find two ways DictCursor wouldn't be completely > > backward compatible. It's probably safe to bet there are other edge > > cases that could be found. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "web2py Web Framework" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/web2py?hl=en -~----------~----~----~----~------~----~------~--~---

