test_ok1/pytest/plugin/keyword.py

66 lines
2.0 KiB
Python

def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('-k',
action="store", dest="keyword", default='',
help="only run test items matching the given "
"space separated keywords. precede a keyword with '-' to negate. "
"Terminate the expression with ':' to treat a match as a signal "
"to run all subsequent tests. ")
def pytest_collection_modifyitems(items, config):
keywordexpr = config.option.keyword
if not keywordexpr:
return
selectuntil = False
if keywordexpr[-1] == ":":
selectuntil = True
keywordexpr = keywordexpr[:-1]
remaining = []
deselected = []
for colitem in items:
if keywordexpr and skipbykeyword(colitem, keywordexpr):
deselected.append(colitem)
else:
remaining.append(colitem)
if selectuntil:
keywordexpr = None
if deselected:
config.hook.pytest_deselected(items=deselected)
items[:] = remaining
def skipbykeyword(colitem, keywordexpr):
""" return True if they given keyword expression means to
skip this collector/item.
"""
if not keywordexpr:
return
chain = colitem.listchain()
for key in filter(None, keywordexpr.split()):
eor = key[:1] == '-'
if eor:
key = key[1:]
if not (eor ^ matchonekeyword(key, chain)):
return True
def matchonekeyword(key, chain):
elems = key.split(".")
# XXX O(n^2), anyone cares?
chain = [item.keywords for item in chain if item.keywords]
for start, _ in enumerate(chain):
if start + len(elems) > len(chain):
return False
for num, elem in enumerate(elems):
for keyword in chain[num + start]:
ok = False
if elem in keyword:
ok = True
break
if not ok:
break
if num == len(elems) - 1 and ok:
return True
return False