From: Mike Bayer Date: Mon, 1 Oct 2018 20:34:50 +0000 (-0400) Subject: Add .info to InstanceState X-Git-Tag: rel_1_3_0b1~56^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b171a2ed0351aff755c34ca9cf51e8e33c2df95e;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Add .info to InstanceState Added ``.info`` dictionary to the :class:`.InstanceState` class, the object that comes from calling :func:`.inspect` on a mapped object. Fixes: #4257 Change-Id: I32d043f369edb708a17eec2e0b8876db0c1891b4 --- diff --git a/doc/build/changelog/migration_13.rst b/doc/build/changelog/migration_13.rst index 5000626869..08f62bb027 100644 --- a/doc/build/changelog/migration_13.rst +++ b/doc/build/changelog/migration_13.rst @@ -20,6 +20,25 @@ potentially backwards-incompatible changes in behavior. New Features and Improvements - ORM =================================== +.. _change_4257: + +info dictionary added to InstanceState +-------------------------------------- + +Added the ``.info`` dictionary to the :class:`.InstanceState` class, the object +that comes from calling :func:`.inspect` on a mapped object. This allows custom +recipes to add additional information about an object that will be carried +along with that object's full lifecycle in memory:: + + from sqlalchemy import inspect + + u1 = User(id=7, name='ed') + + inspect(u1).info['user_info'] = '7|ed' + + +:ticket:`4257` + Key Behavioral Changes - ORM ============================= diff --git a/doc/build/changelog/unreleased_13/4257.rst b/doc/build/changelog/unreleased_13/4257.rst new file mode 100644 index 0000000000..72cac1e1b7 --- /dev/null +++ b/doc/build/changelog/unreleased_13/4257.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: feature, orm + :tickets: 4257 + + Added ``.info`` dictionary to the :class:`.InstanceState` class, the object + that comes from calling :func:`.inspect` on a mapped object. + + .. seealso:: + + :ref:`change_4257` diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 03d68ab820..935e7df19f 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -24,7 +24,7 @@ from . import base @inspection._self_inspects -class InstanceState(interfaces.InspectionAttr): +class InstanceState(interfaces.InspectionAttrInfo): """tracks state information at the instance level. The :class:`.InstanceState` is a key object used by the @@ -440,7 +440,7 @@ class InstanceState(interfaces.InspectionAttr): (k, self.__dict__[k]) for k in ( 'committed_state', '_pending_mutations', 'modified', 'expired', 'callables', 'key', 'parents', 'load_options', - 'class_', 'expired_attributes' + 'class_', 'expired_attributes', 'info' ) if k in self.__dict__ ) if self.load_path: @@ -467,6 +467,8 @@ class InstanceState(interfaces.InspectionAttr): self.parents = state_dict.get('parents', {}) self.modified = state_dict.get('modified', False) self.expired = state_dict.get('expired', False) + if 'info' in state_dict: + self.info.update(state_dict['info']) if 'callables' in state_dict: self.callables = state_dict['callables'] diff --git a/test/orm/test_inspect.py b/test/orm/test_inspect.py index 37cafe599f..0eaca3136a 100644 --- a/test/orm/test_inspect.py +++ b/test/orm/test_inspect.py @@ -309,6 +309,13 @@ class TestORMInspection(_fixtures.FixtureTest): insp = inspect(u1) is_(insp, instance_state(u1)) + def test_instance_state_info(self): + User = self.classes.User + u1 = User() + insp = inspect(u1) + insp.info['some_key'] = 'value' + eq_(inspect(u1).info['some_key'], 'value') + def test_instance_state_attr(self): User = self.classes.User u1 = User(name='ed') diff --git a/test/orm/test_pickled.py b/test/orm/test_pickled.py index d9c30f6bf0..ff8b9e429c 100644 --- a/test/orm/test_pickled.py +++ b/test/orm/test_pickled.py @@ -333,6 +333,22 @@ class PickleTest(fixtures.MappedTest): eq_(state.identity_token, None) eq_(state.identity_key, (User, (1,), None)) + def test_state_info_pickle(self): + users = self.tables.users + mapper(User, users) + + u1 = User(id=1, name='ed') + + sa.inspect(u1).info['some_key'] = 'value' + + state_dict = sa.inspect(u1).__getstate__() + + state = sa_state.InstanceState.__new__(sa_state.InstanceState) + state.__setstate__(state_dict) + + u2 = state.obj() + eq_(sa.inspect(u2).info['some_key'], 'value') + @testing.requires.non_broken_pickle def test_options_with_descriptors(self): users, addresses, dingalings = (self.tables.users,