summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-05-29 19:54:51 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-05-29 19:54:51 -0400
commit752f2e0fc8dec13e313a00f7c9720d24d21429ed (patch)
treeb8e8c5aa2ade21e1a80fa55f2d4a9f9756cf9088 /test
parenta04f0c1e3719d38e71509635cc1cba43a67ce090 (diff)
downloadsqlalchemy-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.py78
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 = []