summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sqlalchemy/orm/attributes.py9
-rw-r--r--test/orm/test_mapper.py37
2 files changed, 45 insertions, 1 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index e98740287..2405d91c0 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -1118,6 +1118,15 @@ class ClassManager(dict):
"""
if hasattr(instance, self.STATE_ATTR):
return False
+ elif self.class_ is not instance.__class__ and \
+ self.is_mapped:
+ # this will create a new ClassManager for the
+ # subclass, without a mapper. This is likely a
+ # user error situation but allow the object
+ # to be constructed, so that it is usable
+ # in a non-ORM context at least.
+ return self._subclass_manager(instance.__class__).\
+ _new_state_if_none(instance)
else:
state = self._create_instance_state(instance)
setattr(instance, self.STATE_ATTR, state)
diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py
index 2de77fd2c..be135316d 100644
--- a/test/orm/test_mapper.py
+++ b/test/orm/test_mapper.py
@@ -1076,7 +1076,7 @@ class MapperTest(_fixtures.FixtureTest):
assert_raises(sa.orm.exc.UnmappedClassError, sa.orm.compile_mappers)
@testing.resolve_artifact_names
- def test_unmapped_subclass_error(self):
+ def test_unmapped_subclass_error_postmap(self):
class Base(object):
pass
class Sub(Base):
@@ -1084,9 +1084,44 @@ class MapperTest(_fixtures.FixtureTest):
mapper(Base, users)
sa.orm.compile_mappers()
+
+ # we can create new instances, set attributes.
+ s = Sub()
+ s.name = 'foo'
+ eq_(s.name, 'foo')
+ eq_(
+ attributes.get_history(s, 'name'),
+ (['foo'], (), ())
+ )
+
+ # using it with an ORM operation, raises
assert_raises(sa.orm.exc.UnmappedClassError,
create_session().add, Sub())
+
+ @testing.resolve_artifact_names
+ def test_unmapped_subclass_error_premap(self):
+ class Base(object):
+ pass
+
+ mapper(Base, users)
+ class Sub(Base):
+ pass
+
+ sa.orm.compile_mappers()
+
+ # we can create new instances, set attributes.
+ s = Sub()
+ s.name = 'foo'
+ eq_(s.name, 'foo')
+ eq_(
+ attributes.get_history(s, 'name'),
+ (['foo'], (), ())
+ )
+
+ # using it with an ORM operation, raises
+ assert_raises(sa.orm.exc.UnmappedClassError,
+ create_session().add, Sub())
@testing.resolve_artifact_names
def test_oldstyle_mixin(self):