From ed7eb6f7f19bd26e984bc3be065243f8ead38b25 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 9 Jun 2022 09:53:43 -0400 Subject: [PATCH] dont transfer __weakref__ to regenerated class Repaired a deprecation warning class decorator that was preventing key objects such as :class:`_engine.Connection` from having a proper ``__weakref__`` attribute, causing operations like Python standard library ``inspect.getmembers()`` to fail. Fixes: #8115 Change-Id: Ifd0bc2325fb9dc9e1431998c308b7fc081968373 (cherry picked from commit cc7cc3c9ec73055703acc78c8d92eb0242e5cd20) --- doc/build/changelog/unreleased_14/8115.rst | 9 +++++ lib/sqlalchemy/util/deprecations.py | 1 + test/base/test_warnings.py | 46 ++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 doc/build/changelog/unreleased_14/8115.rst diff --git a/doc/build/changelog/unreleased_14/8115.rst b/doc/build/changelog/unreleased_14/8115.rst new file mode 100644 index 0000000000..856a76a42e --- /dev/null +++ b/doc/build/changelog/unreleased_14/8115.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, engine + :tickets: 8115 + + Repaired a deprecation warning class decorator that was preventing key + objects such as :class:`_engine.Connection` from having a proper + ``__weakref__`` attribute, causing operations like Python standard library + ``inspect.getmembers()`` to fail. + diff --git a/lib/sqlalchemy/util/deprecations.py b/lib/sqlalchemy/util/deprecations.py index fe2f968040..b61516d85c 100644 --- a/lib/sqlalchemy/util/deprecations.py +++ b/lib/sqlalchemy/util/deprecations.py @@ -356,6 +356,7 @@ def _decorate_cls_with_warning( clsdict = dict(cls.__dict__) clsdict["__doc__"] = doc clsdict.pop("__dict__", None) + clsdict.pop("__weakref__", None) cls = type(cls.__name__, cls.__bases__, clsdict) if constructor is not None: constructor_fn = clsdict[constructor] diff --git a/test/base/test_warnings.py b/test/base/test_warnings.py index 0cbab7f282..be34f958b2 100644 --- a/test/base/test_warnings.py +++ b/test/base/test_warnings.py @@ -1,6 +1,9 @@ +from sqlalchemy import testing +from sqlalchemy.exc import SADeprecationWarning from sqlalchemy.testing import eq_ from sqlalchemy.testing import expect_deprecated from sqlalchemy.testing import fixtures +from sqlalchemy.util.deprecations import _decorate_cls_with_warning from sqlalchemy.util.deprecations import warn_deprecated_limited from sqlalchemy.util.langhelpers import _hash_limit_string @@ -34,3 +37,46 @@ class WarnDeprecatedLimitedTest(fixtures.TestBase): eq_(len(printouts), occurrences) eq_(len(messages), cap) + + +class ClsWarningTest(fixtures.TestBase): + @testing.fixture + def dep_cls_fixture(self): + class Connectable(object): + """a docstring""" + + some_member = "foo" + + Connectable = _decorate_cls_with_warning( + Connectable, + None, + SADeprecationWarning, + "a message", + "2.0", + "another message", + ) + + return Connectable + + def test_dep_inspectable(self, dep_cls_fixture): + """test #8115""" + + import inspect + + class PlainClass(object): + some_member = "bar" + + pc_keys = dict(inspect.getmembers(PlainClass())) + insp_keys = dict(inspect.getmembers(dep_cls_fixture())) + + assert set(insp_keys).intersection( + ( + "__class__", + "__doc__", + "__eq__", + "__dict__", + "__weakref__", + "some_member", + ) + ) + eq_(set(pc_keys), set(insp_keys)) -- 2.47.2