un-GC'ed / un-configured mappers can be in _mapper_registry

Issue #3664 wontfix
Mike Bayer repo owner created an issue

not sure how to detect that these mappers are defunct without just calling gc.collect(), which seems a little heavy handed:

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

Base = declarative_base()

atob = Table(
    'atob', Base.metadata,
    Column('aid', ForeignKey('a.id')),
    Column('bid', ForeignKey('b.id'))
)


class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)
    bs = relationship("B", secondary=lambda: globals().get('atob'))


class B(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)

if True:
    del A
    del B
    del atob
    del Base

    Base = declarative_base()


class C(Base):
    __tablename__ = 'c'
    id = Column(Integer, primary_key=True)

configure_mappers()

output:

#!


  File "test2.py", line 37, in <module>
    configure_mappers()
  File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/mapper.py", line 2831, in configure_mappers
    mapper._post_configure_properties()
  File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/mapper.py", line 1756, in _post_configure_properties
    prop.init()
  File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/interfaces.py", line 183, in init
    self.do_init()
  File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/relationships.py", line 1634, in do_init
    self._setup_join_conditions()
  File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/relationships.py", line 1709, in _setup_join_conditions
    can_be_synced_fn=self._columns_are_mapped
  File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/relationships.py", line 1978, in __init__
    self._determine_joins()
  File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/relationships.py", line 2082, in _determine_joins
    "specify a 'primaryjoin' expression." % self.prop)
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship A.bs - there are no foreign keys linking these tables.  

specifically you'd see this kind of thing if those mappers are part of a module that was garbage collected, like an alembic module.

this patch resolves but gc.collect() doesn't behave the same across Python VMs:

diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 2236b2f..06b2b81 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -2808,6 +2808,9 @@ def configure_mappers():
             if not Mapper._new_mappers:
                 return

+            import gc
+            gc.collect()
+
             Mapper.dispatch._for_class(Mapper).before_configured()
             # initialize properties on all mappers
             # note that _mapper_registry is unordered, which

there's no other indicator on the objects that they're no longer dereferenced since theyre in a cycle.

Comments (1)

  1. Mike Bayer reporter

    dont see a solution to this, having garbage collection being a side effect of a mapper configure is not appropriate

  2. Log in to comment