diff --git a/AUTHORS b/AUTHORS index 6efc41d97..bbb8e463d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -246,6 +246,7 @@ Segev Finer Serhii Mozghovyi Seth Junot Simon Gomizelj +Simon Kerr Skylar Downes Srinivas Reddy Thatiparthy Stefan Farmbauer diff --git a/changelog/4583.bugfix.rst b/changelog/4583.bugfix.rst new file mode 100644 index 000000000..f0a820303 --- /dev/null +++ b/changelog/4583.bugfix.rst @@ -0,0 +1 @@ +Prevent crashing and provide a user-friendly error when a marker expression (-m) invoking of eval() raises any exception. diff --git a/src/_pytest/mark/legacy.py b/src/_pytest/mark/legacy.py index 80a520a0a..eb50340f2 100644 --- a/src/_pytest/mark/legacy.py +++ b/src/_pytest/mark/legacy.py @@ -84,8 +84,8 @@ def matchmark(colitem, markexpr): """Tries to match on any marker names, attached to the given colitem.""" try: return eval(markexpr, {}, MarkMapping.from_item(colitem)) - except SyntaxError as e: - raise SyntaxError(str(e) + "\nMarker expression must be valid Python!") + except Exception: + raise UsageError("Wrong expression passed to '-m': {}".format(markexpr)) def matchkeyword(colitem, keywordexpr): diff --git a/testing/test_mark.py b/testing/test_mark.py index 530f9f168..2aad2b1ba 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -601,18 +601,6 @@ class TestFunctional: deselected_tests = dlist[0].items assert len(deselected_tests) == 2 - def test_invalid_m_option(self, testdir): - testdir.makepyfile( - """ - def test_a(): - pass - """ - ) - result = testdir.runpytest("-m bogus/") - result.stdout.fnmatch_lines( - ["INTERNALERROR> Marker expression must be valid Python!"] - ) - def test_keywords_at_node_level(self, testdir): testdir.makepyfile( """ @@ -1022,3 +1010,20 @@ def test_pytest_param_id_requires_string(): @pytest.mark.parametrize("s", (None, "hello world")) def test_pytest_param_id_allows_none_or_string(s): assert pytest.param(id=s) + + +@pytest.mark.parametrize("expr", ("NOT internal_err", "NOT (internal_err)", "bogus/")) +def test_marker_expr_eval_failure_handling(testdir, expr): + foo = testdir.makepyfile( + """ + import pytest + + @pytest.mark.internal_err + def test_foo(): + pass + """ + ) + expected = "ERROR: Wrong expression passed to '-m': {}".format(expr) + result = testdir.runpytest(foo, "-m", expr) + result.stderr.fnmatch_lines([expected]) + assert result.ret == ExitCode.USAGE_ERROR