RowProxy and ResultProxy should implement complete standard interfaces

Issue #3463 new
Javier Domingo Cansino created an issue

I have been using sqlalchemy core and I have found that in RowProxy and ResultProxy, standard interfaces are implemented (and even recommended), but not totally, confusing users (like me).

Although these interfaces implement some of the methods to treat the results as tuples or dicts, they don't implement the ones that give the actual support for these datatypes.

The implementation of standard basetype interfaces should be done using ABCs: https://docs.python.org/3/library/collections.abc.html

In my case, .get() was the function that I expected to be supported (given the dict access they have) but wasn't working, so I switched to a getattr() call instead.

Comments (4)

  1. Mike Bayer repo owner

    The implementation of standard basetype interfaces should be done using ABCs

    unfortunately these are not standard basetypes. The RowProxy acts like a tuple in some ways and a dictionary in the other.

    Here's a simple test case:

    from sqlalchemy import create_engine
    
    e = create_engine("sqlite://")
    r = e.execute("select 1")
    row = r.first()
    
    assert row == (1, )
    

    it passes. If we apply this patch:

    diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
    index b2b78de..200db58 100644
    --- a/lib/sqlalchemy/engine/result.py
    +++ b/lib/sqlalchemy/engine/result.py
    @@ -98,7 +98,10 @@ except ImportError:
                     raise AttributeError(e.args[0])
    
    
    -class RowProxy(BaseRowProxy):
    +import collections
    +
    +
    +class RowProxy(collections.Mapping, BaseRowProxy):
         """Proxy values from a single cursor row.
    
         Mostly follows "ordered dictionary" behavior, mapping result
    

    now it fails.

  2. Mike Bayer repo owner

    also, the ABC just breaks the whole thing. Every time I've tried to do the "right" thing and use ABCs for things, even in much simpler cases than this, they never seem to work. We don't even get a real row back. Below, this fails:

    from sqlalchemy import create_engine
    
    e = create_engine("sqlite://")
    r = e.execute("select 1")
    
    row = r.first()
    assert row[0] == 1
    

    why does it fail? I have no idea. If you can look into this for me, that would be great.

  3. Javier Domingo Cansino reporter

    I would not subclass those ABCs but implement the __*__ methods, if I have some time I will try to debug it a little further.

  4. Log in to comment