fix issue357 - special case "-k" expressions to allow for

filtering with simple strings that are not valid python expressions.
Examples: "-k 1.3" matches all tests parametrized with 1.3.
"-k None" filters all tests that have "None" in their name
and conversely "-k 'not None'".
Previously these examples would raise syntax errors.

Also add a note to the docs about what is allowed.
This commit is contained in:
holger krekel 2013-11-21 15:25:16 +01:00
parent 663f824fc4
commit 08f3a0791d
4 changed files with 48 additions and 2 deletions

View File

@ -11,6 +11,13 @@ Unreleased
help with random "xdist" collection failures. Thanks to help with random "xdist" collection failures. Thanks to
Ronny Pfannschmidt and Donald Stufft for helping to isolate it. Ronny Pfannschmidt and Donald Stufft for helping to isolate it.
- fix issue357 - special case "-k" expressions to allow for
filtering with simple strings that are not valid python expressions.
Examples: "-k 1.3" matches all tests parametrized with 1.3.
"-k None" filters all tests that have "None" in their name
and conversely "-k 'not None'".
Previously these examples would raise syntax errors.
- fix issue384 by removing the trial support code - fix issue384 by removing the trial support code
since the unittest compat enhancements allow since the unittest compat enhancements allow
trial to handle it on its own trial to handle it on its own

View File

@ -140,7 +140,13 @@ def matchkeyword(colitem, keywordexpr):
for name in colitem.function.__dict__: for name in colitem.function.__dict__:
mapped_names.add(name) mapped_names.add(name)
return eval(keywordexpr, {}, KeywordMapping(mapped_names)) mapping = KeywordMapping(mapped_names)
if " " not in keywordexpr:
# special case to allow for simple "-k pass" and "-k 1.3"
return mapping[keywordexpr]
elif keywordexpr.startswith("not ") and " " not in keywordexpr[4:]:
return not mapping[keywordexpr[4:]]
return eval(keywordexpr, {}, mapping)
def pytest_configure(config): def pytest_configure(config):

View File

@ -95,6 +95,17 @@ Or to select "http" and "quick" tests::
================= 1 tests deselected by '-khttp or quick' ================== ================= 1 tests deselected by '-khttp or quick' ==================
================== 2 passed, 1 deselected in 0.01 seconds ================== ================== 2 passed, 1 deselected in 0.01 seconds ==================
.. note::
If you are using expressions such as "X and Y" then both X and Y
need to be simple non-keyword names. For example, "pass" or "from"
will result in SyntaxErrors because "-k" evaluates the expression.
However, if the "-k" argument is a simple string, no such restrictions
apply. Also "-k 'not STRING'" has no restrictions. You can also
specify numbers like "-k 1.3" to match tests which are parametrized
with the float "1.3".
Registering markers Registering markers
------------------------------------- -------------------------------------

View File

@ -174,7 +174,9 @@ def test_mark_option_custom(spec, testdir):
@pytest.mark.parametrize("spec", [ @pytest.mark.parametrize("spec", [
("interface", ("test_interface",)), ("interface", ("test_interface",)),
("not interface", ("test_nointer",)), ("not interface", ("test_nointer", "test_pass")),
("pass", ("test_pass",)),
("not pass", ("test_interface", "test_nointer")),
]) ])
def test_keyword_option_custom(spec, testdir): def test_keyword_option_custom(spec, testdir):
testdir.makepyfile(""" testdir.makepyfile("""
@ -182,6 +184,8 @@ def test_keyword_option_custom(spec, testdir):
pass pass
def test_nointer(): def test_nointer():
pass pass
def test_pass():
pass
""") """)
opt, passed_result = spec opt, passed_result = spec
rec = testdir.inline_run("-k", opt) rec = testdir.inline_run("-k", opt)
@ -191,6 +195,24 @@ def test_keyword_option_custom(spec, testdir):
assert list(passed) == list(passed_result) assert list(passed) == list(passed_result)
@pytest.mark.parametrize("spec", [
("None", ("test_func[None]",)),
("1.3", ("test_func[1.3]",))
])
def test_keyword_option_parametrize(spec, testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.parametrize("arg", [None, 1.3])
def test_func(arg):
pass
""")
opt, passed_result = spec
rec = testdir.inline_run("-k", opt)
passed, skipped, fail = rec.listoutcomes()
passed = [x.nodeid.split("::")[-1] for x in passed]
assert len(passed) == len(passed_result)
assert list(passed) == list(passed_result)
class TestFunctional: class TestFunctional:
def test_mark_per_function(self, testdir): def test_mark_per_function(self, testdir):