diff --git a/changelog/4026.bugfix.rst b/changelog/4026.bugfix.rst new file mode 100644 index 000000000..ce7bd572b --- /dev/null +++ b/changelog/4026.bugfix.rst @@ -0,0 +1 @@ +Improve error message when it is not possible to determine a function's signature. diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 0cf0e41c2..78bf1bc04 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -13,7 +13,7 @@ from contextlib import contextmanager import py import _pytest -from _pytest.outcomes import TEST_OUTCOME +from _pytest.outcomes import TEST_OUTCOME, fail from six import text_type import six @@ -131,9 +131,17 @@ def getfuncargnames(function, is_method=False, cls=None): # ordered mapping of parameter names to Parameter instances. This # creates a tuple of the names of the parameters that don't have # defaults. + try: + parameters = signature(function).parameters + except (ValueError, TypeError) as e: + fail( + "Could not determine arguments of {!r}: {}".format(function, e), + pytrace=False, + ) + arg_names = tuple( p.name - for p in signature(function).parameters.values() + for p in parameters.values() if ( p.kind is Parameter.POSITIONAL_OR_KEYWORD or p.kind is Parameter.KEYWORD_ONLY diff --git a/testing/test_collection.py b/testing/test_collection.py index fb3860f99..9cd085778 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -952,3 +952,23 @@ def test_collect_init_tests(testdir): "*", ] ) + + +def test_collect_invalid_signature_message(testdir): + """Check that we issue a proper message when we can't determine the signature of a test + function (#4026). + """ + testdir.makepyfile( + """ + import pytest + + class TestCase: + @pytest.fixture + def fix(): + pass + """ + ) + result = testdir.runpytest() + result.stdout.fnmatch_lines( + ["Could not determine arguments of *.fix *: invalid method signature"] + )