AttributeError: _data_appender on append to backref list

Issue #438 resolved
J Pellerin created an issue

Here are the errors I'm seeing with 0.3.4 with appending to backref lists, in code that worked with 0.3.3:

 File "(redacted)", line 162, in test_offer_interfaces
    offer_resp.options.append(offer_opt)
  File
"/home/jhp/work/sqlalchemy_0_3_4/lib/sqlalchemy/orm/attributes.py",
line 418, in append
    self._data_appender(item)
  File
"/home/jhp/work/sqlalchemy_0_3_4/lib/sqlalchemy/orm/attributes.py",
line 390, in __getattr__
    return getattr(self.data, attr)
  File "/home/jhp/work/sqlalchemy_0_3_4/lib/sqlalchemy/orm/query.py",
line 301, in __getattr__
    raise AttributeError(key)
AttributeError: _data_appender

The relation is a normal one-many, set up using assign_mapper on the many side:

assign_mapper(CTX, OfferOption, offer_option, properties={
    'offer': relation(OfferResponse, backref='options')
    })

Comments (6)

  1. Mike Bayer repo owner

    try this patch which will throw an error for the given data collection:

    Index: lib/sqlalchemy/orm/attributes.py

    --- lib/sqlalchemy/orm/attributes.py (revision 2240) +++ lib/sqlalchemy/orm/attributes.py (working copy) @@ -331,6 +331,8 @@ elif hasattr(self.data, 'add'): self._data_appender = self.data.add self._clear_data = self._clear_set + else: + raise exceptions.ArgumentError("Collection type " + repr(type(self.data)) + " has no append() or add() method") if isinstance(self.data, dict): self._clear_data = self._clear_dict

  2. J Pellerin reporter

    Looking around in pdb at the stack frames above the point of failure, something jumps out:

    (Pdb) up
    > (redacted)/models.py(245)add_option()
    -> self.options.append(opt)
    (Pdb) self
    <g2b.db.models.OfferResponse object at 0x2b87f7dfdd90>
    (Pdb) self.options
    <sqlalchemy.orm.query.Query object at 0x2b87f7dfd690>
    

    That sure doesn't look right to me -- shouldn't options there be an InstrumentedList, given the mapper relationship?

    I'll try the patch in a bit -- I think it will show the same thing.

  3. J Pellerin reporter

    Update, with the patch:

    ArgumentError: Collection type <class 'sqlalchemy.orm.query.Query'> has no append() or add() method
    

    I'll try to compose a simple test case this afternoon.

  4. J Pellerin reporter

    Ok, I think I've tracked this down. The error is occurring because the name of the backref is 'options', which as of d1ede4c75c9c878b8678565c97b4776ffb8aa1b9 is being overwritten by assign_mapper.

    I'm not sure what's the right thing to do here. I don't think assign_mapper can avoid stepping on backrefs like this one, since (I think) the backref doesn't exist when assign_mapper is monkeypatching the domain model class.

  5. Mike Bayer repo owner

    workaround:

    assign_mapper(CTX, OfferOption, offer_option, properties={ 'offer': relation(OfferResponse, backref=backref('options', collection_class=list)) })

    added a unit test illustrating the issue in changeset:2249. when we remove class-level specification of collections, this issue will go away.

  6. Log in to comment