From: RamonWill Date: Thu, 13 Aug 2020 21:23:16 +0000 (-0400) Subject: Raise UnmappedInstanceError if the attribute of a database object is an unmapped... X-Git-Tag: rel_1_4_0b1~156^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=da4302a92de49a3819061ac21663266fc9890cf0;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Raise UnmappedInstanceError if the attribute of a database object is an unmapped object. The proposed change will raise an UnmappedInstanceError instead of an attribute error if an instance an Instrumented Attribute is unmapped. ### Description If a user tries to access an attribute of a database object that is unmapped then an error is raised. The reason for this is because the __get__ descriptor uses instance_state(instance) which uses the operator.attrgetter method to see if the object in question has the attribute "_sa_instance_state" that mapped objects have. If it doesn't contain this attribute it means that the object is unmapped. This pull request is: - [ ] A documentation / typographical error fix - Good to go, no issue or tests are needed - [X ] A short code fix - please include the issue number, and create an issue if none exists, which must include a complete example of the issue. one line code fixes without an issue and demonstration will not be accepted. - Please include: `Fixes: #` in the commit message - please include tests. one line code fixes without tests will not be accepted. - [ ] A new feature implementation - please include the issue number, and create an issue if none exists, which must include a complete example of how the feature would look. - Please include: `Fixes: #` in the commit message - please include tests. **Have a nice day!** Fixes: #3858 Closes: #5478 Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5478 Pull-request-sha: 853051c9225446b69f52b13ade78709ad2617f6d Change-Id: I5989c81227e55e628babdd11406d1e8ec0e8d93a --- diff --git a/doc/build/changelog/unreleased_14/3858.rst b/doc/build/changelog/unreleased_14/3858.rst new file mode 100644 index 0000000000..62d57cc7e5 --- /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 2e1b9dc75e..07b147f10f 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 43a7d8dc83..671c75fa7c 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