holger krekel committed d16cc2d

allow to pass expressions to "-k" option, just like with the "-m" option

Comments (0)

Files changed (5)

 - 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


-__version__ = '2.3.4.dev2'
+__version__ = '2.3.4.dev3'
     remaining = []
     deselected = []
     for colitem in items:
-        if keywordexpr and skipbykeyword(colitem, keywordexpr):
+        if keywordexpr and not matchkeyword(colitem, keywordexpr):
             if selectuntil:
     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::
         description='py.test: simple powerful testing with Python',
         long_description = long_description,
-        version='2.3.4.dev2',
+        version='2.3.4.dev3',
         license='MIT license',
         platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],


     assert len(passed) == len(passed_result)
     assert list(passed) == list(passed_result)
+        ("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):
         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():
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.