Skip to content

synonym_for without docstring break Sphinx autodoc builds (infinite recursion) #4767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tlandschoff-scale opened this issue Jul 16, 2019 · 6 comments
Labels
bug Something isn't working orm
Milestone

Comments

@tlandschoff-scale
Copy link

Hi *,

the following code illustrates the fundamental problem: Accessing the __name__ property of a synonym causes recursion:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import *

Base = declarative_base()


# Parent must exist before child ;-)

class Parent(Base):
    __tablename__ = "parent"
    id = Column(Integer, primary_key=True)
    _contents = relation("Child", backref="_parent")


class Child(Base):
    __tablename__ = "child"

    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("parent.id"))

    @property
    def parent(self):
        """Parent object"""
        return self._parent

    @synonym_for("_parent")
    @parent.setter
    def parent(self, value):
        self._parent = parent

With this, the following attribute access recurses:

>>> from depth import Child
>>> Child.parent.__name__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../site-packages/sqlalchemy/orm/attributes.py", line 306, in __getattr__
    return getattr(self.comparator, attribute)
  File ".../site-packages/sqlalchemy/orm/attributes.py", line 306, in __getattr__
    return getattr(self.comparator, attribute)
...
  File ".../site-packages/sqlalchemy/util/langhelpers.py", line 853, in __getattr__
    return self._fallback_getattr(key)
  File ".../site-packages/sqlalchemy/util/langhelpers.py", line 831, in _fallback_getattr
    raise AttributeError(key)
RuntimeError: maximum recursion depth exceeded while calling a Python object

For this reason our sphinx documentation does not build anymore (as properties from mixin classes did not supply a docstring). Took a while to find the cause...

No idea what's going on inside SQLAlchemy here though.

@tlandschoff-scale
Copy link
Author

Here is a full example configured with tox (against python 2.7 and 3.5):

gh4767.zip

Output for me:

$ unzip gh4767.zip
$ cd gh4767
$ python -m tox
...
updating environment: 2 added, 0 changed, 0 removed
reading sources... [ 50%] depth

Recursion error:
maximum recursion depth exceeded

This can happen with very large or deeply nested source files.  You can carefully increase the default Python recursion limit of 1000 in conf.py with e.g.:
    import sys; sys.setrecursionlimit(1500)

@zzzeek zzzeek added bug Something isn't working orm labels Jul 16, 2019
@zzzeek zzzeek added this to the 1.3.xx milestone Jul 16, 2019
@zzzeek
Copy link
Member

zzzeek commented Jul 16, 2019

no workaround other than call configure_mappers() or apply a name, fix will be in next release

@sqla-tester
Copy link
Collaborator

Mike Bayer has proposed a fix for this issue in the master branch:

Intercept uncompiled comparator attrbute error for attr access https://gerrit.sqlalchemy.org/1358

@tlandschoff-scale
Copy link
Author

no workaround other than call configure_mappers() or apply a name, fix will be in next release

Actually I found another one: Add the missing docstring :-)

Thanks for the hint about configure_mappers(), wondered about that functionality as well.

Greetings, Torsten

@zzzeek
Copy link
Member

zzzeek commented Jul 17, 2019

OK now that I've gotten to look at this,the special thing you are doing is making a synonym to an attribute that does not exist yet, until the configure_mappers() sets up the backref. that's why this case is special. if you use two relationships with back_populates instead you should not get this problem.

@sqla-tester
Copy link
Collaborator

Mike Bayer has proposed a fix for this issue in the rel_1_3 branch:

Intercept unresolveable comparator attrbute error for attr access https://gerrit.sqlalchemy.org/1359

sqlalchemy-bot pushed a commit that referenced this issue Jul 17, 2019
Fixed bug where a synonym created against a mapped attribute that does not
exist yet, as is the case when it refers to backref before mappers are
configured, would raise recursion errors when trying to test for attributes
on it which ultimately don't exist (as occurs when the classes are run
through Sphinx autodoc), as the unconfigured state of the synonym would put
it into an attribute not found loop.

Fixes: #4767
Change-Id: I9aade8628349fbf538181a0049416cec0a17179c
(cherry picked from commit 234723f)
@zzzeek zzzeek modified the milestones: 1.3.xx, 1.3.x Dec 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working orm
Projects
None yet
Development

No branches or pull requests

3 participants