From 3213f9428bef89a41e4aba0c842b93cfbd9f2272 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 22 Jun 2026 11:36:02 -0400 Subject: [PATCH] use @classmethod per pytest guidance Fixed class-scoped pytest fixtures that were defined as instance methods using ``self``, which is deprecated as of pytest 9.1 and will be removed in pytest 10. Fixtures are now decorated with a compatibility ``@classmethod`` decorator and use ``cls`` as the first parameter. Fixes: #13392 Change-Id: I866de54e22569c9d55eb97dce165670994ec4a57 --- doc/build/changelog/unreleased_20/13392.rst | 8 ++++++++ lib/sqlalchemy/testing/fixtures/mypy.py | 8 +++++--- lib/sqlalchemy/testing/fixtures/orm.py | 4 ++-- lib/sqlalchemy/testing/fixtures/sql.py | 4 ++-- lib/sqlalchemy/testing/plugin/pytestplugin.py | 7 +++++++ test/aaa_profiling/test_misc.py | 3 ++- test/ext/test_mutable.py | 3 ++- 7 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 doc/build/changelog/unreleased_20/13392.rst diff --git a/doc/build/changelog/unreleased_20/13392.rst b/doc/build/changelog/unreleased_20/13392.rst new file mode 100644 index 0000000000..cd9089b07e --- /dev/null +++ b/doc/build/changelog/unreleased_20/13392.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, tests + :tickets: 13392 + + Fixed class-scoped pytest fixtures that were defined as instance methods + using ``self``, which is deprecated as of pytest 9.1 and will be removed in + pytest 10. Fixtures are now decorated with a compatibility ``@classmethod`` + decorator and use ``cls`` as the first parameter. diff --git a/lib/sqlalchemy/testing/fixtures/mypy.py b/lib/sqlalchemy/testing/fixtures/mypy.py index 44576b2a16..cfcd3ab426 100644 --- a/lib/sqlalchemy/testing/fixtures/mypy.py +++ b/lib/sqlalchemy/testing/fixtures/mypy.py @@ -39,10 +39,12 @@ class MypyTest(TestBase): yield from self._cachedir() @config.fixture(scope="class") - def cachedir(self): - yield from self._cachedir() + @classmethod + def cachedir(cls): + yield from cls._cachedir() - def _cachedir(self): + @classmethod + def _cachedir(cls): # as of mypy 0.971 i think we need to keep mypy_path empty mypy_path = "" diff --git a/lib/sqlalchemy/testing/fixtures/orm.py b/lib/sqlalchemy/testing/fixtures/orm.py index 65693b719c..c42a19f259 100644 --- a/lib/sqlalchemy/testing/fixtures/orm.py +++ b/lib/sqlalchemy/testing/fixtures/orm.py @@ -40,8 +40,8 @@ class MappedTest(ORMTest, TablesTest, assertions.AssertsExecutionResults): classes: Any = None @config.fixture(autouse=True, scope="class") - def _setup_tables_test_class(self): - cls = self.__class__ + @classmethod + def _setup_tables_test_class(cls): cls._init_class() if cls.classes is None: diff --git a/lib/sqlalchemy/testing/fixtures/sql.py b/lib/sqlalchemy/testing/fixtures/sql.py index eafab02865..8a2f08264e 100644 --- a/lib/sqlalchemy/testing/fixtures/sql.py +++ b/lib/sqlalchemy/testing/fixtures/sql.py @@ -54,8 +54,8 @@ class TablesTest(TestBase): sequences = None @config.fixture(autouse=True, scope="class") - def _setup_tables_test_class(self): - cls = self.__class__ + @classmethod + def _setup_tables_test_class(cls): cls._init_class() cls._setup_once_tables() diff --git a/lib/sqlalchemy/testing/plugin/pytestplugin.py b/lib/sqlalchemy/testing/plugin/pytestplugin.py index 391b24576b..77f6e96e26 100644 --- a/lib/sqlalchemy/testing/plugin/pytestplugin.py +++ b/lib/sqlalchemy/testing/plugin/pytestplugin.py @@ -862,10 +862,17 @@ class PytestFixtureFunctions(plugin_base.FixtureFunctions): # now apply wrappers to the function, including fixture itself def wrap(fn): + is_classmethod = isinstance(fn, classmethod) + if is_classmethod: + fn = fn.__func__ + if config.any_async: fn = asyncio._maybe_async_wrapper(fn) # other wrappers may be added here + if is_classmethod: + fn = classmethod(fn) + # now apply FixtureFunctionMarker fn = fixture(fn) diff --git a/test/aaa_profiling/test_misc.py b/test/aaa_profiling/test_misc.py index c51648c677..b1423ddfad 100644 --- a/test/aaa_profiling/test_misc.py +++ b/test/aaa_profiling/test_misc.py @@ -56,7 +56,8 @@ class CacheKeyTest(fixtures.TestBase): __requires__ = ("cpython", "python_profiling_backend") @testing.fixture(scope="class") - def mapping_fixture(self): + @classmethod + def mapping_fixture(cls): # note in order to work nicely with "fixture" we are emerging # a whole new model of setup/teardown, since pytest "fixture" # sort of purposely works badly with setup/teardown diff --git a/test/ext/test_mutable.py b/test/ext/test_mutable.py index c72f182f8f..216945450b 100644 --- a/test/ext/test_mutable.py +++ b/test/ext/test_mutable.py @@ -1078,7 +1078,8 @@ class _MutableSetTestBase(_MutableSetTestFixture): class _MutableNoHashFixture: @testing.fixture(autouse=True, scope="class") - def set_class(self): + @classmethod + def set_class(cls): global Foo _replace_foo = Foo -- 2.47.3