Hi All, I'm having some trouble using an OrderingList as a relationship "collection_class". I suspect there is a bug in the implementation of the `__reduce__` function on the OrderingList class.
I'm using SQLAlchemy version 1.1.11. Posting a MWE or my actual code is going to take a fair bit of time, so instead let me explain my situation and what testing I have done. I'm using a relationship between two classes of objects in the usual way, but with an ordered_list as the collection class: class TraitMappingBase(bases.PersistenceBase, bases.SQLAlchemyBase): __tablename__ = "trait_mappings" # Note this table is shared with TraitMapping and SubTraitMapping classes. _db_type = sa.Column('type', sa.String(50)) __mapper_args__ = {'polymorphic_on': "_db_type"} _database_id = sa.Column(sa.Integer, sa.Sequence('trait_mapping_seq'), primary_key=True) _db_trait_class = sa.Column(sa.String) _parent_id = sa.Column(sa.Integer, sa.ForeignKey('trait_mappings._database_id')) _db_trait_property_mappings = relationship( 'TraitPropertyMapping', order_by='TraitPropertyMapping.ordering', collection_class=ordering_list('ordering')) # type: List[TraitPropertyMapping] class TraitPropertyMapping(bases.SQLAlchemyBase, bases.PersistenceBase): # Database fields and setup (SQLAlchemy) __tablename__ = "trait_property_mappings" database_id = sa.Column(sa.Integer, sa.Sequence('trait_mapping_seq'), primary_key=True) name = sa.Column(sa.String) id = sa.Column(sa.String) ordering = sa.Column(sa.Integer) # Column for ordering index. _trait_mappings = relationship('TraitMappingBase', back_populates='_db_trait_property_mappings') _trait_mapping_id = sa.Column(sa.Integer, sa.ForeignKey('trait_mappings._database_id')) Alchemy reports an exception when it tries to add an object of the TraitMappingBase class to the session: Traceback (most recent call last): File "/Users/agreen/Documents/ASVO/code/git-repository/python_packages/fidia_tests/test_archive.py", line 111, in example_archive return ExampleArchive(basepath=test_data_dir) File "/Users/agreen/Documents/ASVO/code/git-repository/python_packages/fidia/archive/archive.py", line 287, in __new__ fidia.mappingdb_session.add(archive) File "/Users/agreen/python/virtualenvs/asvo-server/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 1711, in add self._save_or_update_state(state) File "/Users/agreen/python/virtualenvs/asvo-server/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 1729, in _save_or_update_state halt_on=self._contains_state): File "/Users/agreen/python/virtualenvs/asvo-server/lib/python3.4/site-packages/sqlalchemy/orm/mapper.py", line 2709, in cascade_iterator visited_states, halt_on)) File "/Users/agreen/python/virtualenvs/asvo-server/lib/python3.4/site-packages/sqlalchemy/orm/relationships.py", line 1553, in cascade_iterator get_all_pending(state, dict_) File "/Users/agreen/python/virtualenvs/asvo-server/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 929, in get_all_pending for c in current] File "/Users/agreen/python/virtualenvs/asvo-server/lib/python3.4/site-packages/sqlalchemy/orm/collections.py", line 654, in __iter__ return iter(self._data()._sa_iterator()) AttributeError: 'NoneType' object has no attribute '_sa_iterator' Now, some investigating has revealed the following information: - commenting out the `__reduce__` function on OrderedList seems to make everything work correctly (including the unit tests on orderinglist.py). This function is definitely being called, though my code is not pickling the object (perhaps SQLAlchemy is calling this?) - in the last frame of the above traceback, self._data() is a weakref, and the fact that it is returning None suggests the object (which I believe would be the instance of OrderingList in this case) has been deleted. I can only explain this if somehow the relationship list is being replaced, though I can find no indication this is true in my code. - Simply replacing the collection_class with `list` makes the code work as expected - The unit tests for orderinglist (py.test test/ext/test_orderinglist.py) all pass. I'm out of time to debug this, and orderinglist doesn't provide quite what I need anyway (which is really more an order preserving dict such as OrderedDict), so I'm afraid I can't offer a lot more here. It seems to me that `ordering_list` is not actually working at all currently, but that the unit tests don't actually save and restore an object containing this relationship to a database, and hence it isn't being picked up. I suspect that `__reduce__` is being called, and it is inadvertently replacing the OrderingList created when the relationship is created, and hence the original object is being garbage collected and therefore the weakref mentioned above is void, causing the exception. Quick fix would be to simply not have a `__reduce__` function on OrderingList, but I'm afraid I don't understand enough about pickling to know if this would cause problems. Cheers, Andy -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- 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.