diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-05-29 19:54:51 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-05-29 19:54:51 -0400 |
| commit | 752f2e0fc8dec13e313a00f7c9720d24d21429ed (patch) | |
| tree | b8e8c5aa2ade21e1a80fa55f2d4a9f9756cf9088 /test | |
| parent | a04f0c1e3719d38e71509635cc1cba43a67ce090 (diff) | |
| download | sqlalchemy-752f2e0fc8dec13e313a00f7c9720d24d21429ed.tar.gz | |
- 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 :ticket:`3060`, which also
involves recognition of attributes explicitly set to ``None``
vs. attributes that were never set.
fixes #3061
Diffstat (limited to 'test')
| -rw-r--r-- | test/orm/test_attributes.py | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/test/orm/test_attributes.py b/test/orm/test_attributes.py index b44f883c9..ab9b9f5d5 100644 --- a/test/orm/test_attributes.py +++ b/test/orm/test_attributes.py @@ -906,7 +906,7 @@ class GetNoValueTest(fixtures.ORMTest): "attr", useobject=True, uselist=False) - f1 = Foo() + f1 = self.f1 = Foo() return Foo.attr.impl,\ attributes.instance_state(f1), \ attributes.instance_dict(f1) @@ -1566,6 +1566,31 @@ class HistoryTest(fixtures.TestBase): f.someattr = 'hi' eq_(self._someattr_history(f), (['hi'], (), ())) + def test_scalar_set_None(self): + # note - compare: + # test_scalar_set_None, + # test_scalar_get_first_set_None, + # test_use_object_set_None, + # test_use_object_get_first_set_None + Foo = self._fixture(uselist=False, useobject=False, + active_history=False) + f = Foo() + f.someattr = None + eq_(self._someattr_history(f), ([None], (), ())) + + def test_scalar_get_first_set_None(self): + # note - compare: + # test_scalar_set_None, + # test_scalar_get_first_set_None, + # test_use_object_set_None, + # test_use_object_get_first_set_None + Foo = self._fixture(uselist=False, useobject=False, + active_history=False) + f = Foo() + assert f.someattr is None + f.someattr = None + eq_(self._someattr_history(f), ([None], (), ())) + def test_scalar_set_commit(self): Foo = self._fixture(uselist=False, useobject=False, active_history=False) @@ -1954,20 +1979,27 @@ class HistoryTest(fixtures.TestBase): eq_(self._someattr_history(f), ((), [there], ())) def test_use_object_set_None(self): + # note - compare: + # test_scalar_set_None, + # test_scalar_get_first_set_None, + # test_use_object_set_None, + # test_use_object_get_first_set_None Foo, Bar = self._two_obj_fixture(uselist=False) f = Foo() f.someattr = None - # we'd expect ([None], (), ()), however because - # we set to None w/o setting history if we were to "get" first, - # it is more consistent that this doesn't set history. - eq_(self._someattr_history(f), ((), [None], ())) + eq_(self._someattr_history(f), ([None], (), ())) def test_use_object_get_first_set_None(self): + # note - compare: + # test_scalar_set_None, + # test_scalar_get_first_set_None, + # test_use_object_set_None, + # test_use_object_get_first_set_None Foo, Bar = self._two_obj_fixture(uselist=False) f = Foo() assert f.someattr is None f.someattr = None - eq_(self._someattr_history(f), ((), [None], ())) + eq_(self._someattr_history(f), ([None], (), ())) def test_use_object_set_dict_set_None(self): Foo, Bar = self._two_obj_fixture(uselist=False) @@ -2526,6 +2558,40 @@ class ListenerTest(fixtures.ORMTest): f1.barlist.remove(None) eq_(canary, [(f1, b1), (f1, None), (f1, b2), (f1, None)]) + def test_none_init_scalar(self): + canary = Mock() + class Foo(object): + pass + instrumentation.register_class(Foo) + attributes.register_attribute(Foo, 'bar') + + event.listen(Foo.bar, "set", canary) + + f1 = Foo() + eq_(f1.bar, None) + eq_(canary.mock_calls, [ + call( + f1, None, attributes.NEVER_SET, + attributes.Event(Foo.bar.impl, attributes.OP_REPLACE)) + ]) + + def test_none_init_object(self): + canary = Mock() + class Foo(object): + pass + instrumentation.register_class(Foo) + attributes.register_attribute(Foo, 'bar', useobject=True) + + event.listen(Foo.bar, "set", canary) + + f1 = Foo() + eq_(f1.bar, None) + eq_(canary.mock_calls, [ + call( + f1, None, attributes.NEVER_SET, + attributes.Event(Foo.bar.impl, attributes.OP_REPLACE)) + ]) + def test_propagate(self): classes = [None, None, None] canary = [] |
