RowProxy and ResultProxy should implement complete standard interfaces

Issue #3463 wontfix
JavierD
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 (5)

  1. Michael 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. Michael 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. Michael Bayer repo owner

    If a contributor would like to work on this, this can be reopened, but rebasing the entire result/rowproxy series on top of ABC as opposed to making individual use cases work as expected is a very complicated and potentially de-stabilizing change that isn't necessary to get a good result right now.

  4. Log in to comment