can't use RowProxy in params to execute()

Issue #935 resolved
jek created an issue
data = db1.execute(tbl.select())
db2.execute(tbl.insert(), data) # or list(data)

ought to work to copy data from one engine to another. haven't looked at the source yet, but the traceback suggests that execute *params inspection is doing an isinstance(dict) where it could be duck-typing hasattr('keys')

current workaround:

db2.execute(tbl.insert(), [for row in data](dict(row.items())))

Comments (4)

  1. Mike Bayer repo owner

    after some research, I think the full feature here is not possible without making some expensive across-the-board behavior. The resultproxy is an iterator, and peeking into it requires that it be a non-iterable. This would imply we have to convert all incoming arguments into lists/tuples/dicts in all cases just to inspect them, which 99% of the time is needless overhead.

    This fragment doesn't entirely work, but this is the idea:

    Index: lib/sqlalchemy/engine/base.py
    ===================================================================
    --- lib/sqlalchemy/engine/base.py   (revision 5546)
    +++ lib/sqlalchemy/engine/base.py   (working copy)
    @@ -834,17 +834,17 @@
                     return [        elif len(multiparams) == 1:
                 zero = multiparams[0](]
    )
    -            if isinstance(zero, (list, tuple)):
    -                if not zero or isinstance(zero[0](0), (list, tuple, dict)):
    -                    return zero
    +            if hasattr(zero, 'iteritems'):
    +                return [zero](zero)
    +            elif hasattr(zero, '__iter__'):
    +                if not zero or hasattr(zero[0](0), '__iter__'):
    +                    return tuple(zero)
                     else:
                         return [zero](zero)
    -            elif isinstance(zero, dict):
    -                return [zero](zero)
                 else:
                     return [[zero]([zero)]
             else:
    -            if isinstance(multiparams[0](0), (list, tuple, dict)):
    +            if hasattr(multiparams[0](0), '__iter__'):
                     return multiparams
                 else:
                     return [multiparams](multiparams)
    

    a not-yet-working patch is attached.

    Right now I think if you have a ResultProxy, you've got a live cursor. If you want to use an iterable as an argument, you should be explicit in converting it to a stable datastructure before passing it - SQLA shouldn't do that job.

  2. Log in to comment