[Sqlalchemy-tickets] Issue #4153: Eager loading of specific polymorphic subtypes triggers errors in
Brought to you by:
zzzeek
From: Theron L. <iss...@bi...> - 2018-01-04 20:42:13
|
New issue 4153: Eager loading of specific polymorphic subtypes triggers errors in lazy loaded relationships https://bitbucket.org/zzzeek/sqlalchemy/issues/4153/eager-loading-of-specific-polymorphic Theron Luhn: Congrats on 1.2.0 and thanks for your hard work! I'm excited to upgrade and especially looking forward to selectin loading. While attempting to upgrade, I'm getting errors caused by eager loading on polymorphic subtypes (the loading strategy detailed [here](http://docs.sqlalchemy.org/en/latest/orm/inheritance_loading.html#eager-loading-of-specific-or-polymorphic-subtypes)). It was very difficult to pin down, but I finally am able to make a reproducible test case: ``` #!python from sqlalchemy import String, Integer, Column, create_engine, ForeignKey, inspect from sqlalchemy.orm import relationship, Session, subqueryload from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Company(Base): __tablename__ = 'company' id = Column(Integer, primary_key=True) name = Column(String, nullable=False) employees = relationship('Employee') slogans = relationship('Slogan') class Slogan(Base): __tablename__ = 'slogan' id = Column(Integer, primary_key=True) text = Column(String) company_id = Column(Integer, ForeignKey('company.id'), nullable=False) class Employee(Base): __tablename__ = 'employee' id = Column(Integer, primary_key=True) type = Column(String, nullable=False) name = Column(String, nullable=False) company_id = Column(Integer, ForeignKey('company.id'), nullable=False) __mapper_args__ = { 'polymorphic_on': 'type', 'with_polymorphic': '*', } class Programmer(Employee): __tablename__ = 'programmer' id = Column(Integer, ForeignKey('employee.id'), primary_key=True) languages = relationship('Language') __mapper_args__ = { 'polymorphic_identity': 'programmer', } class Language(Base): __tablename__ = 'language' id = Column(Integer, primary_key=True) programmer_id = Column( Integer, ForeignKey('programmer.id'), nullable=False, ) name = Column(String, nullable=False) engine = create_engine('postgresql://localhost:5432/sa') Base.metadata.drop_all(engine) Base.metadata.create_all(engine) db = Session(engine) company = Company( id=1, name='Foobar Corp', employees=[Programmer( id=1, name='John Smith', languages=[Language(id=1, name='Python')], )], slogans=[Slogan( id=1, text='Because I said so.', )], ) db.add(company) db.flush() db.expunge_all() company = db.query(Company).filter( Company.id == 1, ).options( subqueryload(Company.employees.of_type(Programmer)).subqueryload(Programmer.languages), ).one() print(company.employees) # Eager-loaded relationships work print(company.slogans) # Any lazy-loaded relationships trigger error ``` This script triggers the following error: ``` Traceback (most recent call last): File "polybug.py", line 87, in <module> print(company.slogans) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/attributes.py", line 242, in __get__ return self.impl.get(instance_state(instance), dict_) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/attributes.py", line 603, in get value = self.callable_(state, passive) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", line 623, in _load_for_state return self._emit_lazyload(session, state, ident_key, passive) File "<string>", line 1, in <lambda> File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", line 703, in _emit_lazyload state.load_options, effective_path File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/ext/baked.py", line 178, in _add_lazyload_options cache_key = opt._generate_cache_key(cache_path) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/strategy_options.py", line 404, in _generate_cache_key c_key = opt._generate_cache_key(path) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/strategy_options.py", line 93, in _generate_cache_key for token in chopped: TypeError: 'NoneType' object is not iterable ``` This is running on Python 3.6.2 with SQLAlchemy 1.2.0. SQLAlchemy 1.1.10 behaves as expected and does not trigger an error. I'm using psycopg2 v2.7.3.2 and Postgres 10.1 |