Synonym for Association Proxy results in infinite recursion
Hi everyone,
I ran into an issue where accessing the prop
attribute of a synonym for an association proxy makes SQLAlchemy go into an infinite recursion resulting in the program crashing. I'm using SQLAlchemy 1.1.13, Python 3.5.2, SQLite 3.8.11 on Windows 8.1 machine.
Let me know if you need any more details.
Thanks!
Code that reproduces the issue:
from sqlalchemy import (
create_engine, Column, Integer, ForeignKey
)
from sqlalchemy.orm import sessionmaker, relationship, synonym
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
engine = create_engine('sqlite://')
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
class Parent(Base):
__tablename__ = 'Parent'
id = Column('Id', Integer, primary_key=True)
class Child(Base):
__tablename__ = 'Child'
id = Column('Id', Integer, primary_key=True)
parent_id = Column('ParentId', Integer, ForeignKey('Parent.Id'), nullable=False)
parent = relationship(Parent)
id_of_parent = association_proxy('parent', 'id')
also_id_of_parent = synonym('id_of_parent')
Base.metadata.create_all(session.bind)
print('also_id_of_parent:', Child.also_id_of_parent.prop)
Stack trace of the error (I'm not sure if I should add it as an attachment to the ticket or not)
#!
C:\Users\root\virtualenv\random\Scripts\python.exe C:/Users/root/python/random-scripts/synonym_association_proxy/reproduce.py
Traceback (most recent call last):
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\attributes.py", line 303, in __getattr__
return getattr(descriptor, attribute)
AttributeError: 'property' object has no attribute 'prop'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\attributes.py", line 303, in __getattr__
return getattr(descriptor, attribute)
AttributeError: 'property' object has no attribute 'comparator'
rm\attributes.py", line 306, in __getattr__
return getattr(self.comparator, attribute)
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\attributes.py", line 306, in __getattr__
return getattr(self.comparator, attribute)
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\attributes.py", line 306, in __getattr__
...
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\attributes.py", line 306, in __getattr__
return getattr(self.comparator, attribute)
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\attributes.py", line 306, in __getattr__
return getattr(self.comparator, attribute)
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\util\langhelpers.py", line 764, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\attributes.py", line 276, in comparator
self._comparator = self._comparator()
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\descriptor_props.py", line 71, in <lambda>
lambda: self._comparator_factory(mapper),
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\descriptor_props.py", line 580, in _comparator_factory
prop = self._proxied_property
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\util\langhelpers.py", line 764, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "C:\Users\root\virtualenv\random\lib\site-packages\sqlalchemy\orm\descriptor_props.py", line 577, in _proxied_property
return getattr(self.parent.class_, self.name).property
RecursionError: maximum recursion depth exceeded
Process finished with exit code 1
Comments (5)
-
repo owner -
repo owner this is one of those AttributeError endless things in proxied_property() and it will take some effort to extricate from inside the loop, even in py36 it gets caught inside of Proxy.getattr()
-
repo owner - edited description
-
repo owner - changed status to resolved
Check for non-mapped property in synonym
An :class:
.InvalidRequestError
is raised when a :func:.synonym
is used against an attribute that is not against a :class:.MapperProperty
, such as an association proxy. Previously, a recursion overflow would occur trying to locate non-existent attributes.Change-Id: If2ce38c429a69951df4c94b71b74edbd59d775e3 Fixes:
#4067→ <<cset 130f31ca79c7>>
-
repo owner Check for non-mapped property in synonym
An :class:
.InvalidRequestError
is raised when a :func:.synonym
is used against an attribute that is not against a :class:.MapperProperty
, such as an association proxy. Previously, a recursion overflow would occur trying to locate non-existent attributes.Change-Id: If2ce38c429a69951df4c94b71b74edbd59d775e3 Fixes:
#4067(cherry picked from commit 130f31ca79c7b40b2cb8aa1a4af7049408074d12)→ <<cset 8ec1369eb3dc>>
- Log in to comment
So you don't normally want to put an entire recursion overflow stack trace on the issue, for those you should trim out the redundant parts, but there we are.
This is a bug but synonym() does not support assocaition proxies in the first place, so the way I'd fix this for the time being would be for synonym to detect that it's being used against something that is not a "mapped" property, e.g. column property or relationship(), and just raise an error.