Hello, Some legacy code at work that I don't fully understand (and whose authors are all long gone) does the following to eventually insert some values into the table it gets:
meta = sqlalchemy.MetaData(bind=session.get_bind()) meta.reflect() table = sqlalchemy.Table(TableName.__tablename__, meta, autoload=True) The meta.reflect() call fails if the session comes from a sessionmaker bound to a copy of an engine that has a non-default isolation level, for example: engine = sqlalchemy.create_engine(setup) maker = sqlalchemy.orm.sessionmaker(bind=engine.execution_options( isolation_level='SERIALIZABLE')) session = maker() The error message it gives is "AttributeError: 'OptionEngine' object has no attribute 'engine'". The reason seems to be that in this case, session.get_bind() returns an OptionEngine, which seems to be a facade around the original Engine; it proxies to the original one. See below for a minimal complete example [A] with a Conda environment [B]. I can get around this by checking whether the get_bind() call gives me an OptionEngine, and pull the proxied Engine out of the object if it does, but that involves using internal SQLAlchemy object variables and might break in the future. 1. Should what I'm doing here work at all? That is, should OptionEngine define 'engine' and have it resolve to whatever original Engine it was created from? 2. If not, and what I've inherited is horrifying, does anyone have ideas on how to make it better? The only comments around this piece of code say they do this dance to be able to insert values into columns that are in the DB table but not the SQLAlchemy ORM table. Thank you, Gunnar [A] Minimal example (done here in sqlite3, also works on SQL Server): import sqlalchemy import sqlalchemy.orm import sqlalchemy.ext.declarative Base = sqlalchemy.ext.declarative.declarative_base() class Foo(Base): __tablename__ = 'foos' id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) val = sqlalchemy.Column(sqlalchemy.Integer) if __name__ == '__main__': db = sqlalchemy.create_engine('sqlite:///') Foo.metadata.create_all(db) maker = sqlalchemy.orm.sessionmaker(bind=db.execution_options( isolation_level='SERIALIZABLE')) session = maker() bind = session.get_bind() meta = sqlalchemy.MetaData(bind=bind) meta.reflect() table = sqlalchemy.Table(Foo.__tablename__, meta, autoload=True) vals = list(range(100)) ins = table.insert().values(vals) session.execute(ins) session.commit() session.close() [B] Conda environment that reproduces the problem in the example: # Name Version Build Channel _libgcc_mutex 0.1 main ca-certificates 2019.5.15 0 certifi 2019.6.16 py37_0 libedit 3.1.20181209 hc058e9b_0 libffi 3.2.1 hd88cf55_4 libgcc-ng 9.1.0 hdf63c60_0 libstdcxx-ng 9.1.0 hdf63c60_0 ncurses 6.1 he6710b0_1 openssl 1.1.1c h7b6447c_1 pip 19.1.1 py37_0 python 3.7.3 h0371630_0 readline 7.0 h7b6447c_5 setuptools 41.0.1 py37_0 sqlalchemy 1.3.5 py37h7b6447c_0 sqlite 3.28.0 h7b6447c_0 tk 8.6.8 hbc83047_0 wheel 0.33.4 py37_0 xz 5.2.4 h14c3975_4 zlib 1.2.11 h7b6447c_3 -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/d81b41c0-5e38-4601-a487-c763d3896b91%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.