Hi there -
Can you post a stack trace, and also is your test suite making use of clear_mappers() ? The sys.modules activity is not really the primary cause, it's that alembic makes use of a module object in a temporary way. > On Feb 21, 2016, at 1:48 PM, Will Angenent <w.angen...@gmail.com> wrote: > > Hi, > > We had this interesting issue recently, and I've been trying to figure out if > we deserve this, if this is simply unavoidable, or whether it can be > considered a bug. We're using python 2.7.6, sqlalchemy 1.0.12 and alembic > 0.8.4. > > Summary: > > This statement in alembic.util.pyfiles.load_python_file(): > del sys.modules[module_id] > randomly causes the reference count of the module object to become zero; > triggering cleanup of the object. This effectively causes all variables in > the migration file to become None, leading to an sqlalchemy mapper problem > initializing a mapper configuration for a many-to-many relationship in a > model defined in the migration file. > > Are we being stupid to be using the ORM in alembic migrations? If not, is it > worth for me to spend more time on this? Is there any way to get this to > behave non-randomly? More details are below. > > Thanks, > Will > > Long version... > > What happened is that someone in my team added an alembic migration. He used > the sqlalchemy ORM and used a declarative_base with a couple of model files > to get the job done. The migration was fine and everyone was happy. Then, > about a week later, I added an import statement in a totally unrelated area > of code, and suddenly running alembic upgrade starting failing with a ORM > mapper error. I didn't spend much time on it, but refactored a couple of > things and the problem vanished. > > Then a couple of days later, our tests started failing with the same error. > We had a closer look and found the failure to be random. The inclusion of the > import statment seemed to trigger the random behavior. It wasn't just the > import statement though, other changes, such as removing a property in an ORM > class could make the problem appear or go away. What we were doing in this > particualr failure mode, is running py.test which would, in order: > > - import this random 3rd party module > - use the alembic API to upgrade to ensure a postgres database is up to date > - later on, in an unrelated test, do a query, triggering the initialization > of the mappings and crashing > > At first, I thought it might be a problem with sqlalchemy. Spurred on by this > comment in mapper.py: > > # initialize properties on all mappers > # note that _mapper_registry is unordered, which > # may randomly conceal/reveal issues related to > # the order of mapper compilation > > I added a couple of sorted() statements throughout the code, but it made no > difference. Finally, I found that the problem was a lambda function in a > relationship with a secondary. Something like e.g. > > tag_to_resource = Table( > 'tag_to_resource', Base.metadata, > Column('tag_id', ForeignKey('tags.id', ondelete='CASCADE'), > primary_key=True, index=True), > Column('resource_id', ForeignKey('resources.id', ondelete='CASCADE'), > primary_key=True, index=True) > ) > > class Resource(Base): > __tablename__ = 'resources' > id = Column(UUIDType(binary=True), primary_key=True, default=uuid.uuid4) > > tags = relationship("Tag", secondary=lambda: tag_to_resource, > backref='resources') > > The lambda function called in _process_dependent_arguments() was returning > None instead of tag_to_resource. Resulting in a: > > sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between > parent/child tables on relationship Resource.tags - there are no foreign keys > linking these tables. Ensure that referencing columns are associated with a > ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression. > > Looking deeper I found that __name__ was also None. This kind of thing > happens when sys.modules is messed with. I looked at the alembic code and > found this in load_python_file(): > > del sys.modules[module_id] > > If I remove that statement, the problem goes away. > > Could it be that the reference count of the module object is becoming zero > randomly, causing python to delete the data, as explained in this post? > http://stackoverflow.com/questions/5365562/why-is-the-value-of-name-changing-after-assignment-to-sys-modules-name > > I've narrowed the problem down to a python test script, but it still imports > a load of other stuff. I can trigger the good + bad case by just removing an > import statement. I've been trying to get this down to a simple script in an > attempt to prove what's going on, but the problem tends to come and go while > I'm deleting code; making it difficult to narrow down. For example, I was > convinced one day that the problem vanished by upgrading to sql alchemy > 1.0.12, but the very next day the same code started failing again! > > -- > 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. > For more options, visit https://groups.google.com/d/optout. -- 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. For more options, visit https://groups.google.com/d/optout.