Skip to content

Commit 3fbd386

Browse files
bp72adamchainz
andauthored
Fix class decorator for classmethod overrides (#404)
Co-authored-by: Adam Johnson <me@adamj.eu>
1 parent 46c66af commit 3fbd386

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

CHANGELOG.rst

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ Changelog
66

77
Thanks to Konstantin Baikov in `PR #424 <https://github.com/adamchainz/time-machine/pull/424>`__.
88

9+
* Fix class decorator for classmethod overrides.
10+
11+
Thanks to Pavel Bitiukov for the reproducer in `PR #404 <https://github.com/adamchainz/time-machine/pull/404>`__.
12+
913
* Avoid calling deprecated ``uuid._load_system_functions()`` on Python 3.9+.
1014

1115
Thanks to Nikita Sobolev for the ping in `CPython Issue #113308 <https://github.com/python/cpython/issues/113308>`__.

src/time_machine/__init__.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -293,24 +293,26 @@ def __call__(
293293
raise TypeError("Can only decorate unittest.TestCase subclasses.")
294294

295295
# Modify the setUpClass method
296-
orig_setUpClass = wrapped.setUpClass
296+
orig_setUpClass = wrapped.setUpClass.__func__ # type: ignore[attr-defined]
297297

298298
@functools.wraps(orig_setUpClass)
299299
def setUpClass(cls: type[TestCase]) -> None:
300300
self.__enter__()
301301
try:
302-
orig_setUpClass()
302+
orig_setUpClass(cls)
303303
except Exception:
304304
self.__exit__(*sys.exc_info())
305305
raise
306306

307307
wrapped.setUpClass = classmethod(setUpClass) # type: ignore[assignment]
308308

309-
orig_tearDownClass = wrapped.tearDownClass
309+
orig_tearDownClass = (
310+
wrapped.tearDownClass.__func__ # type: ignore[attr-defined]
311+
)
310312

311313
@functools.wraps(orig_tearDownClass)
312314
def tearDownClass(cls: type[TestCase]) -> None:
313-
orig_tearDownClass()
315+
orig_tearDownClass(cls)
314316
self.__exit__(None, None, None)
315317

316318
wrapped.tearDownClass = classmethod( # type: ignore[assignment]

tests/test_time_machine.py

+24
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,30 @@ class Something:
558558
assert excinfo.value.args == ("Can only decorate unittest.TestCase subclasses.",)
559559

560560

561+
@time_machine.travel(EPOCH)
562+
class ClassDecoratorInheritanceBase(TestCase):
563+
prop: bool
564+
565+
@classmethod
566+
def setUpClass(cls):
567+
super().setUpClass()
568+
cls.setUpTestData()
569+
570+
@classmethod
571+
def setUpTestData(cls) -> None:
572+
cls.prop = True
573+
574+
575+
class ClassDecoratorInheritanceTests(ClassDecoratorInheritanceBase):
576+
@classmethod
577+
def setUpTestData(cls) -> None:
578+
super().setUpTestData()
579+
cls.prop = False
580+
581+
def test_ineheritance_correctly_rebound(self):
582+
assert self.prop is False
583+
584+
561585
class TestMethodDecorator:
562586
@time_machine.travel(EPOCH + 95.0)
563587
def test_method_decorator(self):

0 commit comments

Comments
 (0)