--- /dev/null
+.. change::
+ :tags: bug, orm
+ :tickets: 4084
+
+ Fixed issue where the :func:`.make_transient_to_detached` function
+ would expire all attributes on the target object, including "deferred"
+ attributes, which has the effect of the attribute being undeferred
+ for the next refesh, causing an unexpected load of the attribute.
def unmodified_intersection(self, keys):
"""Return self.unmodified.intersection(keys)."""
+
return set(keys).intersection(self.manager).\
difference(self.committed_state)
difference(self.committed_state).\
difference(self.dict)
+ @property
+ def unloaded_expirable(self):
+ """Return the set of keys which do not have a loaded value.
+
+ This includes expired attributes and any other attribute that
+ was never populated or modified.
+
+ """
+ return self.unloaded.intersection(
+ attr for attr in self.manager
+ if self.manager[attr].impl.expire_missing)
+
@property
def _unloaded_non_object(self):
return self.unloaded.intersection(
from sqlalchemy.testing import fixtures
from test.orm import _fixtures
from sqlalchemy.sql import select
+from sqlalchemy.orm import make_transient_to_detached
class ExpireTest(_fixtures.FixtureTest):
.expired_attributes
assert 'addresses' not in attributes.instance_state(u1).callables
+ def test_deferred_expire_w_transient_to_detached(self):
+ orders, Order = self.tables.orders, self.classes.Order
+ mapper(Order, orders, properties={
+ "description": deferred(orders.c.description)
+ })
+
+ s = Session()
+ item = Order(id=1)
+
+ make_transient_to_detached(item)
+ s.add(item)
+ item.isopen
+ assert 'description' not in item.__dict__
+
+ def test_deferred_expire_normally(self):
+ orders, Order = self.tables.orders, self.classes.Order
+ mapper(Order, orders, properties={
+ "description": deferred(orders.c.description)
+ })
+
+ s = Session()
+
+ item = s.query(Order).first()
+ s.expire(item)
+ item.isopen
+ assert 'description' not in item.__dict__
+
+ def test_deferred_expire_explicit_attrs(self):
+ orders, Order = self.tables.orders, self.classes.Order
+ mapper(Order, orders, properties={
+ "description": deferred(orders.c.description)
+ })
+
+ s = Session()
+
+ item = s.query(Order).first()
+ s.expire(item, ['isopen', 'description'])
+ item.isopen
+ assert 'description' in item.__dict__
+
class PolymorphicExpireTest(fixtures.MappedTest):
run_inserts = 'once'