diff --git a/CHANGELOG b/CHANGELOG index 559783681..2bc4ac41a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,13 @@ Changes between 2.3.3 and 2.3.4.dev ----------------------------------- - fix issue91 - add/discuss package/directory level setups in example -- allow to dynamically define markers/keywords via - item.keywords[...]=assignment +- allow to dynamically define markers via + item.keywords[...]=assignment integrating with "-m" option +- make "-k" accept an expressions the same as with "-m" so that one + can write: -k "name1 or name2" etc. This is a slight incompatibility + if you used special syntax like "TestClass.test_method" which you now + need to write as -k "TestClass and test_method" to match a certain + method in a certain test class. Changes between 2.3.2 and 2.3.3 ----------------------------------- diff --git a/_pytest/__init__.py b/_pytest/__init__.py index a02f81d00..2c6317352 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.3.4.dev2' +__version__ = '2.3.4.dev3' diff --git a/_pytest/mark.py b/_pytest/mark.py index adcc14259..c2ab3e18b 100644 --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -51,7 +51,7 @@ def pytest_collection_modifyitems(items, config): remaining = [] deselected = [] for colitem in items: - if keywordexpr and skipbykeyword(colitem, keywordexpr): + if keywordexpr and not matchkeyword(colitem, keywordexpr): deselected.append(colitem) else: if selectuntil: @@ -72,37 +72,26 @@ class BoolDict: def __getitem__(self, name): return name in self._mydict +class SubstringDict: + def __init__(self, mydict): + self._mydict = mydict + def __getitem__(self, name): + for key in self._mydict: + if name in key: + return True + return False + def matchmark(colitem, matchexpr): return eval(matchexpr, {}, BoolDict(colitem.keywords)) +def matchkeyword(colitem, keywordexpr): + keywordexpr = keywordexpr.replace("-", "not ") + return eval(keywordexpr, {}, SubstringDict(colitem.keywords)) + def pytest_configure(config): if config.option.strict: pytest.mark._config = config -def skipbykeyword(colitem, keywordexpr): - """ return True if they given keyword expression means to - skip this collector/item. - """ - if not keywordexpr: - return - - itemkeywords = colitem.keywords - for key in filter(None, keywordexpr.split()): - eor = key[:1] == '-' - if eor: - key = key[1:] - if not (eor ^ matchonekeyword(key, itemkeywords)): - return True - -def matchonekeyword(key, itemkeywords): - for elem in key.split("."): - for kw in itemkeywords: - if elem in kw: - break - else: - return False - return True - class MarkGenerator: """ Factory for :class:`MarkDecorator` objects - exposed as a ``py.test.mark`` singleton instance. Example:: diff --git a/setup.py b/setup.py index 5047bf89e..041c4bda7 100644 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.3.4.dev2', + version='2.3.4.dev3', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/test_mark.py b/testing/test_mark.py index 2f0884eeb..48ca5204e 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -162,6 +162,24 @@ def test_mark_option_custom(spec, testdir): assert len(passed) == len(passed_result) assert list(passed) == list(passed_result) +@pytest.mark.multi(spec=[ + ("interface", ("test_interface",)), + ("not interface", ("test_nointer",)), +]) +def test_keyword_option_custom(spec, testdir): + testdir.makepyfile(""" + def test_interface(): + pass + def test_nointer(): + 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: def test_mark_per_function(self, testdir): @@ -366,11 +384,11 @@ class TestKeywordSelection: for keyword in ['test_one', 'est_on']: #yield check, keyword, 'test_one' check(keyword, 'test_one') - check('TestClass.test', 'test_method_one') + check('TestClass and test', 'test_method_one') @pytest.mark.parametrize("keyword", [ - 'xxx', 'xxx test_2', 'TestClass', 'xxx -test_1', - 'TestClass test_2', 'xxx TestClass test_2']) + 'xxx', 'xxx and test_2', 'TestClass', 'xxx and -test_1', + 'TestClass and test_2', 'xxx and TestClass and test_2']) def test_select_extra_keywords(self, testdir, keyword): p = testdir.makepyfile(test_select=""" def test_1():