or exclude_properties would result in UnmappedColumnError.
[ticket:1995]
+ - A warning is emitted in the unusual case that an
+ append or similar event on a collection occurs after
+ the parent object has been dereferenced, which
+ prevents the parent from being marked as "dirty"
+ in the session. This will be an exception in 0.7.
+ [ticket:2046]
+
- sql
- Column.copy(), as used in table.tometadata(), copies the
'doc' attribute. [ticket:2028]
import weakref
from sqlalchemy import util
from sqlalchemy.orm.attributes import PASSIVE_NO_RESULT, PASSIVE_OFF, \
- NEVER_SET, NO_VALUE, manager_of_class, \
- ATTR_WAS_SET
-from sqlalchemy.orm import attributes, exc as orm_exc, interfaces
+ NEVER_SET, NO_VALUE, manager_of_class, ATTR_WAS_SET
+from sqlalchemy.orm import attributes, exc as orm_exc, interfaces, \
+ util as orm_util
import sys
attributes.state = sys.modules['sqlalchemy.orm.state']
instance_dict._modified.add(self)
self._strong_obj = self.obj()
-
+ if self._strong_obj is None:
+ util.warn(
+ "Can't emit change event for attribute '%s.%s' "
+ "- parent object of type %s has been garbage "
+ "collected."
+ % (
+ self.class_.__name__,
+ attr.key,
+ orm_util.state_class_str(self)
+ ))
self.modified = True
def commit(self, dict_, keys):
else:
return '<%s at 0x%x>' % (state.class_.__name__, id(state.obj()))
+def state_class_str(state):
+ """Return a string describing an instance's class via its InstanceState."""
+
+ if state is None:
+ return "None"
+ else:
+ return '<%s>' % (state.class_.__name__, )
+
def attribute_str(instance, attribute):
return instance_str(instance) + "." + attribute
from sqlalchemy.orm.interfaces import AttributeExtension
from sqlalchemy import exc as sa_exc
from sqlalchemy.test import *
-from sqlalchemy.test.testing import eq_, ne_, assert_raises
+from sqlalchemy.test.testing import eq_, ne_, assert_raises, assert_raises_message
from test.orm import _base
from sqlalchemy.test.util import gc_collect
from sqlalchemy.util import cmp, jython
assert state.obj() is None
assert state.dict == {}
+ def test_object_dereferenced_error(self):
+ class Foo(object):
+ pass
+ class Bar(object):
+ def __init__(self):
+ gc_collect()
+
+ attributes.register_class(Foo)
+ attributes.register_class(Bar)
+ attributes.register_attribute(Foo,
+ 'bars',
+ uselist=True,
+ useobject=True)
+
+ assert_raises_message(
+ sa_exc.SAWarning,
+ "Can't emit change event for attribute "
+ "'Foo.bars' - parent object of type <Foo> "
+ "has been garbage collected.",
+ lambda: Foo().bars.append(Bar())
+ )
+
def test_deferred(self):
class Foo(object):pass