mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-28 19:44:50 -04:00
Add initiator argument to set_attribute
Added new argument :paramref:`.attributes.set_attribute.inititator` to the :func:`.attributes.set_attribute` function, allowing an event token received from a listener function to be propagated to subsequent set events. Change-Id: I6ede21e42153026ab46a1d2ec33aa3f999db98e2
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
|
||||
Added new argument :paramref:`.attributes.set_attribute.inititator`
|
||||
to the :func:`.attributes.set_attribute` function, allowing an
|
||||
event token received from a listener function to be propagated
|
||||
to subsequent set events.
|
||||
@@ -1592,7 +1592,7 @@ def set_committed_value(instance, key, value):
|
||||
state.manager[key].impl.set_committed_value(state, dict_, value)
|
||||
|
||||
|
||||
def set_attribute(instance, key, value):
|
||||
def set_attribute(instance, key, value, initiator=None):
|
||||
"""Set the value of an attribute, firing history events.
|
||||
|
||||
This function may be used regardless of instrumentation
|
||||
@@ -1601,9 +1601,24 @@ def set_attribute(instance, key, value):
|
||||
of this method to establish attribute state as understood
|
||||
by SQLAlchemy.
|
||||
|
||||
:param instance: the object that will be modified
|
||||
|
||||
:param key: string name of the attribute
|
||||
|
||||
:param value: value to assign
|
||||
|
||||
:param initiator: an instance of :class:`.Event` that would have
|
||||
been propagated from a previous event listener. This argument
|
||||
is used when the :func:`.set_attribute` function is being used within
|
||||
an existing event listening function where an :class:`.Event` object
|
||||
is being supplied; the object may be used to track the origin of the
|
||||
chain of events.
|
||||
|
||||
.. versionadded:: 1.2.3
|
||||
|
||||
"""
|
||||
state, dict_ = instance_state(instance), instance_dict(instance)
|
||||
state.manager[key].impl.set(state, dict_, value, None)
|
||||
state.manager[key].impl.set(state, dict_, value, initiator)
|
||||
|
||||
|
||||
def get_attribute(instance, key):
|
||||
|
||||
@@ -1014,6 +1014,42 @@ class UtilTest(fixtures.ORMTest):
|
||||
attributes.del_attribute(f1, "coll")
|
||||
assert "coll" not in f1.__dict__
|
||||
|
||||
def test_initiator_arg(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
|
||||
class Bar(object):
|
||||
pass
|
||||
|
||||
instrumentation.register_class(Foo)
|
||||
instrumentation.register_class(Bar)
|
||||
attributes.register_attribute(
|
||||
Foo, "a", uselist=False, useobject=False)
|
||||
attributes.register_attribute(
|
||||
Bar, "b", uselist=False, useobject=False)
|
||||
|
||||
@event.listens_for(Foo.a, "set")
|
||||
def sync_a(target, value, oldvalue, initiator):
|
||||
parentclass = initiator.parent_token.class_
|
||||
if parentclass is Foo:
|
||||
attributes.set_attribute(target.bar, "b", value, initiator)
|
||||
|
||||
@event.listens_for(Bar.b, "set")
|
||||
def sync_b(target, value, oldvalue, initiator):
|
||||
parentclass = initiator.parent_token.class_
|
||||
if parentclass is Bar:
|
||||
attributes.set_attribute(target.foo, "a", value, initiator)
|
||||
|
||||
f1 = Foo()
|
||||
b1 = Bar()
|
||||
f1.bar = b1
|
||||
b1.foo = f1
|
||||
|
||||
f1.a = 'x'
|
||||
eq_(b1.b, 'x')
|
||||
b1.b = 'y'
|
||||
eq_(f1.a, 'y')
|
||||
|
||||
|
||||
class BackrefTest(fixtures.ORMTest):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user