1. Michael Bayer
  2. sqlalchemy
  3. Issues


Issue #3061 resolved

set attribute history to None when we do an implicit get() of an unset attribute?

Michael Bayer
repo owner created an issue

see #3060. We have a lot of problems here due to the fact that:

x = Obj()
x.foo  # is None, sets it to None, doesn't write any history
inspect(x).attrs.foo.history # shows no history due to the get() above.

Comments (5)

  1. Michael Bayer reporter

    this is going well. More tests need to be fixed, usually entails finding places where we check for PASSIVE_NO_RESULT and also need to check for NEVER_SET. We might want to make some kind of function for this.

  2. Michael Bayer reporter
    • Adjustment to attribute mechanics concerning when a value is implicitly initialized to None via first access; this action, which has always resulted in a population of the attribute, now emits an attribute event just like any other attribute set operation and generates the same kind of history as one. Additionally, many mapper internal operations will no longer implicitly generate these "None" values when various never-set attributes are checked. These are subtle behavioral fixes to attribute mechanics which provide a better solution to the problem of 🎫3060, which also involves recognition of attributes explicitly set to None vs. attributes that were never set. fixes #3061

    → <<cset 752f2e0fc8de>>

  3. Michael Bayer reporter
    • changed status to open

    I want this to pass. this is going to really confuse people otherwise

        def test_init_produces_event(self):
            A, B, C = self._fixture()
            sess = Session()
            c1 = C()
            # here, the fact that we fetch b1.c produces an event,
            # and that cancels out that we are setting cid.
            # yuk.
            b1 = B()
            assert b1.c is None
            b1.cid = c1.id
            assert b1.cid is not None
  4. Michael Bayer reporter
    • reverse course in #3061 so that we instead no longer set None in the attribute when we do a get; we return the None as always but we leave the dict blank and the loader callable still in place. The case for this implicit get on a pending object is not super common and there really should be no change in state at all when this operation proceeds. This change is more dramatic as it reverses a behavior SQLA has had since the first release. fixes #3061

    → <<cset f10eb28d90cb>>

  5. Log in to comment