diff options
| -rw-r--r-- | doc/build/changelog/unreleased_14/3858.rst | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 9 | ||||
| -rw-r--r-- | test/orm/test_attributes.py | 20 |
3 files changed, 35 insertions, 1 deletions
diff --git a/doc/build/changelog/unreleased_14/3858.rst b/doc/build/changelog/unreleased_14/3858.rst new file mode 100644 index 000000000..62d57cc7e --- /dev/null +++ b/doc/build/changelog/unreleased_14/3858.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: bug, orm + :tickets: 3858 + + An ``UnmappedInstanceError`` is now raised for :class:`.InstrumentedAttribute` + if an instance is an unmapped object. Prior to this an ``AttributeError`` + was raised. Pull request courtesy Ramon Williams. diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 2e1b9dc75..07b147f10 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -353,7 +353,14 @@ class InstrumentedAttribute(QueryableAttribute): if self._supports_population and self.key in dict_: return dict_[self.key] else: - return self.impl.get(instance_state(instance), dict_) + try: + state = instance_state(instance) + except AttributeError as err: + util.raise_( + orm_exc.UnmappedInstanceError(instance), + replace_context=err, + ) + return self.impl.get(state, dict_) HasEntityNamespace = util.namedtuple( diff --git a/test/orm/test_attributes.py b/test/orm/test_attributes.py index 43a7d8dc8..671c75fa7 100644 --- a/test/orm/test_attributes.py +++ b/test/orm/test_attributes.py @@ -361,6 +361,26 @@ class AttributesTest(fixtures.ORMTest): lambda: Foo().bars.append(Bar()), ) + def test_unmapped_instance_raises(self): + class User(object): + pass + + instrumentation.register_class(User) + attributes.register_attribute( + User, "user_name", uselist=False, useobject=False + ) + + class Blog(object): + name = User.user_name + + def go(): + b = Blog() + return b.name + + assert_raises( + orm_exc.UnmappedInstanceError, go, + ) + def test_del_scalar_nonobject(self): class Foo(object): pass |
