From b29e2954cadcb8a640b5fe81917207ba8947d6ac Mon Sep 17 00:00:00 2001 From: antonblr Date: Tue, 29 Dec 2020 19:47:22 -0800 Subject: [PATCH 1/2] Fix failing staticmethod tests if they are inherited --- AUTHORS | 1 + changelog/8061.bugfix.rst | 1 + src/_pytest/compat.py | 2 +- testing/python/fixtures.py | 14 ++++++++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 changelog/8061.bugfix.rst diff --git a/AUTHORS b/AUTHORS index 20798f3093d..abac9f010a1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,6 +29,7 @@ Andy Freeland Anthon van der Neut Anthony Shaw Anthony Sottile +Anton Grinevich Anton Lodder Antony Lee Arel Cordero diff --git a/changelog/8061.bugfix.rst b/changelog/8061.bugfix.rst new file mode 100644 index 00000000000..2c8980fb34e --- /dev/null +++ b/changelog/8061.bugfix.rst @@ -0,0 +1 @@ +Fixed failing staticmethod test cases if they are inherited from a parent test class. diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index c7f86ea9c0a..04c0b518f9d 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -162,7 +162,7 @@ def getfuncargnames( # it's passed as an unbound method or function, remove the first # parameter name. if is_method or ( - cls and not isinstance(cls.__dict__.get(name, None), staticmethod) + cls and not isinstance(inspect.getattr_static(cls, name), staticmethod) ): arg_names = arg_names[1:] # Remove any names that will be replaced with mocks. diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 862a65abe10..12340e690eb 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -59,6 +59,20 @@ def static(arg1, arg2, x=1): assert getfuncargnames(A.static, cls=A) == ("arg1", "arg2") +def test_getfuncargnames_staticmethod_inherited() -> None: + """Test getfuncargnames for inherited staticmethods (#8061)""" + + class A: + @staticmethod + def static(arg1, arg2, x=1): + raise NotImplementedError() + + class B(A): + pass + + assert getfuncargnames(B.static, cls=B) == ("arg1", "arg2") + + def test_getfuncargnames_partial(): """Check getfuncargnames for methods defined with functools.partial (#5701)""" import functools From 0bf451be494680dab456a54923f8663d266ffffa Mon Sep 17 00:00:00 2001 From: antonblr Date: Wed, 30 Dec 2020 15:17:39 -0800 Subject: [PATCH 2/2] add comments, set default=None --- src/_pytest/compat.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 04c0b518f9d..c7b755c834c 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -162,7 +162,12 @@ def getfuncargnames( # it's passed as an unbound method or function, remove the first # parameter name. if is_method or ( - cls and not isinstance(inspect.getattr_static(cls, name), staticmethod) + # Not using `getattr` because we don't want to resolve the staticmethod. + # Not using `cls.__dict__` because we want to check the entire MRO. + cls + and not isinstance( + inspect.getattr_static(cls, name, default=None), staticmethod + ) ): arg_names = arg_names[1:] # Remove any names that will be replaced with mocks.