_dependency_processor Attribute Error Bug in orm.dependency with viewonly many to many relationships

Issue #1507 resolved
Former user created an issue

It appears that orm.properties.RelationProperty. _post_init does not create a _dependency_processor attribute if the relation is viewonly.

Line1016:

        if not self.viewonly:
            self._dependency_processor = dependency.create_dependency_processor(self)

This causes orm.dependency._check_reverse_action to fail as the attribute does not exist.

The patch I applied is to add attribute existence verification:

Line 142:

        for r in self.prop._reverse_property:
            if hasattr(r, '_dependency_processor') :
                if (r._dependency_processor, action, parent, child) in uowcommit.attributes:
                    return True
        return False

Here's a test case that reproduces the bug:

from sqlalchemy import Table, create_engine, MetaData, Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker, scoped_session, relation, mapper, backref

engine = create_engine(<engine params>)
metadata = MetaData(bind=engine)
scoped_sess = scoped_session(sessionmaker(autoflush=False))

owner_table = Table('owners', metadata,
                    Column('id', Integer, primary_key=True),
                    Column('name', String(50), nullable=False))

pet_table = Table('pets', metadata,
                  Column('id', Integer, primary_key=True),
                  Column('name', String(50), nullable=False))

owner_to_pet_table = Table('owner_to_pets', metadata,
                           Column('owner_id', Integer, ForeignKey('owners.id')),
                           Column('pet_id', Integer, ForeignKey('pets.id')))


metadata.create_all(engine)

class Pet(object) :
    pass

pet_mapper = mapper(Pet, pet_table)



class Owner(object) :
    pass

owner_mapper = mapper(Owner, owner_table,
                      properties=
                      {
                         'pets':relation(Pet,
                                 secondary=owner_to_pet_table,
                                 primaryjoin=owner_table.c.id == owner_to_pet_table.c.owner_id,
                                 secondaryjoin=owner_to_pet_table.c.pet_id == pet_table.c.id,
                                 backref=backref('owners', viewonly=True))
                      })

session = scoped_sess()


owner = Owner()
owner.id=1
owner.name='George'

pet = Pet()
pet.id=1
pet.name = 'Ruffles'

owner.pets.append(pet)

session.add(owner)
session.flush()

Comments (3)

  1. Mike Bayer repo owner

    this is the patch:

    Index: lib/sqlalchemy/orm/dependency.py
    ===================================================================
    --- lib/sqlalchemy/orm/dependency.py    (revision 6287)
    +++ lib/sqlalchemy/orm/dependency.py    (working copy)
    @@ -131,7 +131,7 @@
    
             """
             raise NotImplementedError()
    -
    +        
         def _check_reverse_action(self, uowcommit, parent, child, action):
             """Determine if an action has been performed by the 'reverse' property of this property.
    
    @@ -140,7 +140,7 @@
    
             """
             for r in self.prop._reverse_property:
    -            if (r._dependency_processor, action, parent, child) in uowcommit.attributes:
    +            if not r.viewonly and (r._dependency_processor, action, parent, child) in uowcommit.attributes:
                     return True
             return False
    

    unit test should go into orm/test_relationships.py or orm/test_manytomany.py.

  2. Log in to comment