7 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/191ff82647ca/
Changeset: 191ff82647ca
User: Wouter van Ackooy
Date: 2013-05-20 14:37:58
Summary: Fixed issue #306: Keywords and markers are now matched in a
defined way. Also applied some pep8 formatting while fixing.
Affected #: 3 files
diff -r 7c468f83e347c21fbed87eeae457f645bfcc7a66 -r
191ff82647ca3e61116861483efb8fe2c2985e82 _pytest/main.py
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -216,6 +216,9 @@
#: keywords/markers collected from all scopes
self.keywords = NodeKeywords(self)
+ #: allow adding of extra keywords to use for matching
+ self.extra_keyword_matches = []
+
#self.extrainit()
@property
@@ -307,6 +310,15 @@
chain.reverse()
return chain
+ def listextrakeywords(self):
+ """ Return a list of all extra keywords in self and any parents."""
+ extra_keywords = []
+ item = self
+ while item is not None:
+ extra_keywords.extend(item.extra_keyword_matches)
+ item = item.parent
+ return extra_keywords
+
def listnames(self):
return [x.name for x in self.listchain()]
diff -r 7c468f83e347c21fbed87eeae457f645bfcc7a66 -r
191ff82647ca3e61116861483efb8fe2c2985e82 _pytest/mark.py
--- a/_pytest/mark.py
+++ b/_pytest/mark.py
@@ -1,44 +1,56 @@
""" generic mechanism for marking and selecting python functions. """
import pytest, py
+
def pytest_namespace():
return {'mark': MarkGenerator()}
+
def pytest_addoption(parser):
group = parser.getgroup("general")
- group._addoption('-k',
+ group._addoption(
+ '-k',
action="store", dest="keyword", default='', metavar="EXPRESSION",
help="only run tests which match the given substring expression. "
"An expression is a python evaluatable expression "
- "where all names are substring-matched against test names "
- "and keywords. Example: -k 'test_method or test_other' "
- "matches all test functions whose name contains "
- "'test_method' or 'test_other'.")
+ "where all names are substring-matched against test names"
+ "and their parent classes. Example: -k 'test_method or test "
+ "other' matches all test functions and classes whose name "
+ "contains 'test_method' or 'test_other'. "
+ "Additionally keywords are matched to classes and functions "
+ "containing extra names in their 'extra_keyword_matches' list, "
+ "as well as functions which have names assigned directly to them."
+ )
- group._addoption("-m",
+ group._addoption(
+ "-m",
action="store", dest="markexpr", default="", metavar="MARKEXPR",
help="only run tests matching given mark expression. "
"example: -m 'mark1 and not mark2'."
- )
+ )
- group.addoption("--markers", action="store_true", help=
- "show markers (builtin, plugin and per-project ones).")
+ group.addoption(
+ "--markers", action="store_true",
+ help="show markers (builtin, plugin and per-project ones)."
+ )
parser.addini("markers", "markers for test functions", 'linelist')
+
def pytest_cmdline_main(config):
if config.option.markers:
config.pluginmanager.do_configure(config)
tw = py.io.TerminalWriter()
for line in config.getini("markers"):
name, rest = line.split(":", 1)
- tw.write("@pytest.mark.%s:" % name, bold=True)
+ tw.write("@pytest.mark.%s:" % name, bold=True)
tw.line(rest)
tw.line()
config.pluginmanager.do_unconfigure(config)
return 0
pytest_cmdline_main.tryfirst = True
+
def pytest_collection_modifyitems(items, config):
keywordexpr = config.option.keyword
matchexpr = config.option.markexpr
@@ -67,32 +79,76 @@
config.hook.pytest_deselected(items=deselected)
items[:] = remaining
-class BoolDict:
- def __init__(self, mydict):
- self._mydict = mydict
- 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:
+class MarkMapping:
+ """Provides a local mapping for markers.
+ Only the marker names from the given :class:`NodeKeywords` will be mapped,
+ so the names are taken only from :class:`MarkInfo` or
+ :class:`MarkDecorator` items.
+ """
+ def __init__(self, keywords):
+ mymarks = []
+ for key, value in keywords.items():
+ if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator):
+ mymarks.append(key)
+ self._mymarks = mymarks
+
+ def __getitem__(self, markname):
+ return markname in self._mymarks
+
+
+class KeywordMapping:
+ """Provides a local mapping for keywords.
+ Given a list of names, map any substring of one of these names to True.
+ """
+ def __init__(self, names):
+ self._names = names
+
+ def __getitem__(self, subname):
+ for name in self._names:
+ if subname in name:
return True
return False
-def matchmark(colitem, matchexpr):
- return eval(matchexpr, {}, BoolDict(colitem.keywords))
+
+def matchmark(colitem, markexpr):
+ """Tries to match on any marker names, attached to the given colitem."""
+ return eval(markexpr, {}, MarkMapping(colitem.keywords))
+
def matchkeyword(colitem, keywordexpr):
+ """Tries to match given keyword expression to given collector item.
+
+ Will match on the name of colitem, including the names of its parents.
+ Only matches names of items which are either a :class:`Class` or a
+ :class:`Function`.
+ Additionally, matches on names in the 'extra_keyword_matches' list of
+ any item, as well as names directly assigned to test functions.
+ """
keywordexpr = keywordexpr.replace("-", "not ")
- return eval(keywordexpr, {}, SubstringDict(colitem.keywords))
+ mapped_names = []
+
+ # Add the names of the current item and any parent items
+ for item in colitem.listchain():
+ if isinstance(item, pytest.Class) or isinstance(item, pytest.Function):
+ mapped_names.append(item.name)
+
+ # Add the names added as extra keywords to current or parent items
+ for name in colitem.listextrakeywords():
+ mapped_names.append(name)
+
+ # Add the names attached to the current function through direct assignment
+ for name in colitem.function.func_dict:
+ mapped_names.append(name)
+
+ return eval(keywordexpr, {}, KeywordMapping(mapped_names))
+
def pytest_configure(config):
if config.option.strict:
pytest.mark._config = config
+
class MarkGenerator:
""" Factory for :class:`MarkDecorator` objects - exposed as
a ``py.test.mark`` singleton instance. Example::
@@ -126,6 +182,7 @@
if name not in self._markers:
raise AttributeError("%r not a registered marker" % (name,))
+
class MarkDecorator:
""" A decorator for test functions and test classes. When applied
it will create :class:`MarkInfo` objects which may be
@@ -149,7 +206,7 @@
def __repr__(self):
d = self.__dict__.copy()
name = d.pop('markname')
- return "<MarkDecorator %r %r>" %(name, d)
+ return "<MarkDecorator %r %r>" % (name, d)
def __call__(self, *args, **kwargs):
""" if passed a single callable argument: decorate it with mark info.
@@ -162,15 +219,17 @@
if hasattr(func, 'pytestmark'):
l = func.pytestmark
if not isinstance(l, list):
- func.pytestmark = [l, self]
+ func.pytestmark = [l, self]
else:
- l.append(self)
+ l.append(self)
else:
- func.pytestmark = [self]
+ func.pytestmark = [self]
else:
holder = getattr(func, self.markname, None)
if holder is None:
- holder = MarkInfo(self.markname, self.args,
self.kwargs)
+ holder = MarkInfo(
+ self.markname, self.args, self.kwargs
+ )
setattr(func, self.markname, holder)
else:
holder.add(self.args, self.kwargs)
@@ -180,6 +239,7 @@
args = self.args + args
return self.__class__(self.markname, args=args, kwargs=kw)
+
class MarkInfo:
""" Marking object created by :class:`MarkDecorator` instances. """
def __init__(self, name, args, kwargs):
@@ -193,7 +253,8 @@
def __repr__(self):
return "<MarkInfo %r args=%r kwargs=%r>" % (
- self.name, self.args, self.kwargs)
+ self.name, self.args, self.kwargs
+ )
def add(self, args, kwargs):
""" add a MarkInfo with the given args and kwargs. """
@@ -205,4 +266,3 @@
""" yield MarkInfo objects each relating to a marking-call. """
for args, kwargs in self._arglist:
yield MarkInfo(self.name, args, kwargs)
-
diff -r 7c468f83e347c21fbed87eeae457f645bfcc7a66 -r
191ff82647ca3e61116861483efb8fe2c2985e82 testing/test_mark.py
--- a/testing/test_mark.py
+++ b/testing/test_mark.py
@@ -382,7 +382,6 @@
assert len(reprec.getcalls('pytest_deselected')) == 1
for keyword in ['test_one', 'est_on']:
- #yield check, keyword, 'test_one'
check(keyword, 'test_one')
check('TestClass and test', 'test_method_one')
@@ -401,7 +400,7 @@
def pytest_pycollect_makeitem(__multicall__, name):
if name == "TestClass":
item = __multicall__.execute()
- item.keywords["xxx"] = True
+ item.extra_keyword_matches.append("xxx")
return item
""")
reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword)
https://bitbucket.org/hpk42/pytest/commits/64a8b6828ebc/
Changeset: 64a8b6828ebc
User: Wouter van Ackooy
Date: 2013-05-22 07:41:46
Summary: Added lost space.
Affected #: 1 file
diff -r 191ff82647ca3e61116861483efb8fe2c2985e82 -r
64a8b6828ebcf2e8cd9066bd44c6c83b7b89a9b1 _pytest/mark.py
--- a/_pytest/mark.py
+++ b/_pytest/mark.py
@@ -13,7 +13,7 @@
action="store", dest="keyword", default='', metavar="EXPRESSION",
help="only run tests which match the given substring expression. "
"An expression is a python evaluatable expression "
- "where all names are substring-matched against test names"
+ "where all names are substring-matched against test names "
"and their parent classes. Example: -k 'test_method or test "
"other' matches all test functions and classes whose name "
"contains 'test_method' or 'test_other'. "
https://bitbucket.org/hpk42/pytest/commits/88815889e4a3/
Changeset: 88815889e4a3
User: Wouter van Ackooy
Date: 2013-05-23 09:12:50
Summary: Added a test to check there is no matching on magic values.
Affected #: 1 file
diff -r 64a8b6828ebcf2e8cd9066bd44c6c83b7b89a9b1 -r
88815889e4a3dd27082f20187232050f17f05424 testing/test_mark.py
--- a/testing/test_mark.py
+++ b/testing/test_mark.py
@@ -439,3 +439,21 @@
reprec = testdir.inline_run("-k", "mykeyword", p)
passed, skipped, failed = reprec.countoutcomes()
assert failed == 1
+
+ def test_no_magic_values(self, testdir):
+ """Make sure the tests do not match on magic values,
+ no double underscored values, like '__dict__',
+ and no instance values, like '()'.
+ """
+ p = testdir.makepyfile("""
+ def test_one(): assert 1
+ """)
+ def assert_test_is_not_selected(keyword):
+ reprec = testdir.inline_run("-k", keyword, p)
+ passed, skipped, failed = reprec.countoutcomes()
+ dlist = reprec.getcalls("pytest_deselected")
+ assert passed + skipped + failed == 0
+ assert len(dlist) == 1
+
+ assert_test_is_not_selected("__")
+ assert_test_is_not_selected("()")
https://bitbucket.org/hpk42/pytest/commits/13c86754a55e/
Changeset: 13c86754a55e
User: Wouter van Ackooy
Date: 2013-05-23 12:21:40
Summary: Added new test to check on matching markers to full test names,
which was possible before. Also adjusted check on number of deselected tests.
Affected #: 1 file
diff -r 88815889e4a3dd27082f20187232050f17f05424 -r
13c86754a55e774c40cff5c2d256c7f3cba56b3d testing/test_mark.py
--- a/testing/test_mark.py
+++ b/testing/test_mark.py
@@ -345,6 +345,24 @@
assert l[0].args == ("pos0",)
assert l[1].args == ("pos1",)
+ def test_no_marker_match_on_unmarked_names(self, testdir):
+ p = testdir.makepyfile("""
+ import pytest
+ @pytest.mark.shouldmatch
+ def test_marked():
+ assert 1
+
+ def test_unmarked():
+ assert 1
+ """)
+ reprec = testdir.inline_run("-m", "test_unmarked", p)
+ passed, skipped, failed = reprec.listoutcomes()
+ assert len(passed) + len(skipped) + len(failed) == 0
+ dlist = reprec.getcalls("pytest_deselected")
+ deselected_tests = dlist[0].items
+ assert len(deselected_tests) == 2
+
+
def test_keywords_at_node_level(self, testdir):
p = testdir.makepyfile("""
import pytest
@@ -453,7 +471,8 @@
passed, skipped, failed = reprec.countoutcomes()
dlist = reprec.getcalls("pytest_deselected")
assert passed + skipped + failed == 0
- assert len(dlist) == 1
+ deselected_tests = dlist[0].items
+ assert len(deselected_tests) == 1
assert_test_is_not_selected("__")
assert_test_is_not_selected("()")
https://bitbucket.org/hpk42/pytest/commits/1a919511ae4f/
Changeset: 1a919511ae4f
User: Wouter van Ackooy
Date: 2013-05-27 17:58:39
Summary: Issue 306: Use the names of all the parents in the chain for
matching, except the Instance objects.
Affected #: 1 file
diff -r 13c86754a55e774c40cff5c2d256c7f3cba56b3d -r
1a919511ae4ffbdfd0aadfce7bf4924436c83290 _pytest/mark.py
--- a/_pytest/mark.py
+++ b/_pytest/mark.py
@@ -130,7 +130,7 @@
# Add the names of the current item and any parent items
for item in colitem.listchain():
- if isinstance(item, pytest.Class) or isinstance(item, pytest.Function):
+ if not isinstance(item, pytest.Instance):
mapped_names.append(item.name)
# Add the names added as extra keywords to current or parent items
https://bitbucket.org/hpk42/pytest/commits/c3bc70bc6704/
Changeset: c3bc70bc6704
User: Wouter van Ackooy
Date: 2013-05-27 18:14:35
Summary: Issue 306: Used a set for the extra_keywords, and used listchain
for parent iteration.
Affected #: 3 files
diff -r 1a919511ae4ffbdfd0aadfce7bf4924436c83290 -r
c3bc70bc6704b95ed26b1072ab719c696cde68a4 _pytest/main.py
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -217,7 +217,7 @@
self.keywords = NodeKeywords(self)
#: allow adding of extra keywords to use for matching
- self.extra_keyword_matches = []
+ self.extra_keyword_matches = set()
#self.extrainit()
@@ -311,12 +311,11 @@
return chain
def listextrakeywords(self):
- """ Return a list of all extra keywords in self and any parents."""
- extra_keywords = []
+ """ Return a set of all extra keywords in self and any parents."""
+ extra_keywords = set()
item = self
- while item is not None:
- extra_keywords.extend(item.extra_keyword_matches)
- item = item.parent
+ for item in self.listchain():
+ extra_keywords.update(item.extra_keyword_matches)
return extra_keywords
def listnames(self):
diff -r 1a919511ae4ffbdfd0aadfce7bf4924436c83290 -r
c3bc70bc6704b95ed26b1072ab719c696cde68a4 _pytest/mark.py
--- a/_pytest/mark.py
+++ b/_pytest/mark.py
@@ -18,7 +18,7 @@
"other' matches all test functions and classes whose name "
"contains 'test_method' or 'test_other'. "
"Additionally keywords are matched to classes and functions "
- "containing extra names in their 'extra_keyword_matches' list, "
+ "containing extra names in their 'extra_keyword_matches' set, "
"as well as functions which have names assigned directly to them."
)
@@ -87,10 +87,10 @@
:class:`MarkDecorator` items.
"""
def __init__(self, keywords):
- mymarks = []
+ mymarks = set()
for key, value in keywords.items():
if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator):
- mymarks.append(key)
+ mymarks.add(key)
self._mymarks = mymarks
def __getitem__(self, markname):
@@ -122,24 +122,24 @@
Will match on the name of colitem, including the names of its parents.
Only matches names of items which are either a :class:`Class` or a
:class:`Function`.
- Additionally, matches on names in the 'extra_keyword_matches' list of
+ Additionally, matches on names in the 'extra_keyword_matches' set of
any item, as well as names directly assigned to test functions.
"""
keywordexpr = keywordexpr.replace("-", "not ")
- mapped_names = []
+ mapped_names = set()
# Add the names of the current item and any parent items
for item in colitem.listchain():
if not isinstance(item, pytest.Instance):
- mapped_names.append(item.name)
+ mapped_names.add(item.name)
# Add the names added as extra keywords to current or parent items
for name in colitem.listextrakeywords():
- mapped_names.append(name)
+ mapped_names.add(name)
# Add the names attached to the current function through direct assignment
for name in colitem.function.func_dict:
- mapped_names.append(name)
+ mapped_names.add(name)
return eval(keywordexpr, {}, KeywordMapping(mapped_names))
diff -r 1a919511ae4ffbdfd0aadfce7bf4924436c83290 -r
c3bc70bc6704b95ed26b1072ab719c696cde68a4 testing/test_mark.py
--- a/testing/test_mark.py
+++ b/testing/test_mark.py
@@ -418,7 +418,7 @@
def pytest_pycollect_makeitem(__multicall__, name):
if name == "TestClass":
item = __multicall__.execute()
- item.extra_keyword_matches.append("xxx")
+ item.extra_keyword_matches.add("xxx")
return item
""")
reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword)
https://bitbucket.org/hpk42/pytest/commits/5ce621f0b3d2/
Changeset: 5ce621f0b3d2
User: hpk42
Date: 2013-05-27 21:40:41
Summary: Merged in w00t0r/pytest-fixes (pull request #35)
Fixed issue #306: Keywords and markers are now matched in a defined way. Also
applied some pep8 formatting while fixing.
Affected #: 3 files
diff -r 6865f468f15242e1a399fd20e9bc9e5ad44cb02d -r
5ce621f0b3d2857ce7035b765cd18836ec8ea73f _pytest/main.py
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -216,6 +216,9 @@
#: keywords/markers collected from all scopes
self.keywords = NodeKeywords(self)
+ #: allow adding of extra keywords to use for matching
+ self.extra_keyword_matches = set()
+
#self.extrainit()
@property
@@ -307,6 +310,14 @@
chain.reverse()
return chain
+ def listextrakeywords(self):
+ """ Return a set of all extra keywords in self and any parents."""
+ extra_keywords = set()
+ item = self
+ for item in self.listchain():
+ extra_keywords.update(item.extra_keyword_matches)
+ return extra_keywords
+
def listnames(self):
return [x.name for x in self.listchain()]
diff -r 6865f468f15242e1a399fd20e9bc9e5ad44cb02d -r
5ce621f0b3d2857ce7035b765cd18836ec8ea73f _pytest/mark.py
--- a/_pytest/mark.py
+++ b/_pytest/mark.py
@@ -1,44 +1,56 @@
""" generic mechanism for marking and selecting python functions. """
import pytest, py
+
def pytest_namespace():
return {'mark': MarkGenerator()}
+
def pytest_addoption(parser):
group = parser.getgroup("general")
- group._addoption('-k',
+ group._addoption(
+ '-k',
action="store", dest="keyword", default='', metavar="EXPRESSION",
help="only run tests which match the given substring expression. "
"An expression is a python evaluatable expression "
"where all names are substring-matched against test names "
- "and keywords. Example: -k 'test_method or test_other' "
- "matches all test functions whose name contains "
- "'test_method' or 'test_other'.")
+ "and their parent classes. Example: -k 'test_method or test "
+ "other' matches all test functions and classes whose name "
+ "contains 'test_method' or 'test_other'. "
+ "Additionally keywords are matched to classes and functions "
+ "containing extra names in their 'extra_keyword_matches' set, "
+ "as well as functions which have names assigned directly to them."
+ )
- group._addoption("-m",
+ group._addoption(
+ "-m",
action="store", dest="markexpr", default="", metavar="MARKEXPR",
help="only run tests matching given mark expression. "
"example: -m 'mark1 and not mark2'."
- )
+ )
- group.addoption("--markers", action="store_true", help=
- "show markers (builtin, plugin and per-project ones).")
+ group.addoption(
+ "--markers", action="store_true",
+ help="show markers (builtin, plugin and per-project ones)."
+ )
parser.addini("markers", "markers for test functions", 'linelist')
+
def pytest_cmdline_main(config):
if config.option.markers:
config.pluginmanager.do_configure(config)
tw = py.io.TerminalWriter()
for line in config.getini("markers"):
name, rest = line.split(":", 1)
- tw.write("@pytest.mark.%s:" % name, bold=True)
+ tw.write("@pytest.mark.%s:" % name, bold=True)
tw.line(rest)
tw.line()
config.pluginmanager.do_unconfigure(config)
return 0
pytest_cmdline_main.tryfirst = True
+
def pytest_collection_modifyitems(items, config):
keywordexpr = config.option.keyword
matchexpr = config.option.markexpr
@@ -67,32 +79,76 @@
config.hook.pytest_deselected(items=deselected)
items[:] = remaining
-class BoolDict:
- def __init__(self, mydict):
- self._mydict = mydict
- 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:
+class MarkMapping:
+ """Provides a local mapping for markers.
+ Only the marker names from the given :class:`NodeKeywords` will be mapped,
+ so the names are taken only from :class:`MarkInfo` or
+ :class:`MarkDecorator` items.
+ """
+ def __init__(self, keywords):
+ mymarks = set()
+ for key, value in keywords.items():
+ if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator):
+ mymarks.add(key)
+ self._mymarks = mymarks
+
+ def __getitem__(self, markname):
+ return markname in self._mymarks
+
+
+class KeywordMapping:
+ """Provides a local mapping for keywords.
+ Given a list of names, map any substring of one of these names to True.
+ """
+ def __init__(self, names):
+ self._names = names
+
+ def __getitem__(self, subname):
+ for name in self._names:
+ if subname in name:
return True
return False
-def matchmark(colitem, matchexpr):
- return eval(matchexpr, {}, BoolDict(colitem.keywords))
+
+def matchmark(colitem, markexpr):
+ """Tries to match on any marker names, attached to the given colitem."""
+ return eval(markexpr, {}, MarkMapping(colitem.keywords))
+
def matchkeyword(colitem, keywordexpr):
+ """Tries to match given keyword expression to given collector item.
+
+ Will match on the name of colitem, including the names of its parents.
+ Only matches names of items which are either a :class:`Class` or a
+ :class:`Function`.
+ Additionally, matches on names in the 'extra_keyword_matches' set of
+ any item, as well as names directly assigned to test functions.
+ """
keywordexpr = keywordexpr.replace("-", "not ")
- return eval(keywordexpr, {}, SubstringDict(colitem.keywords))
+ mapped_names = set()
+
+ # Add the names of the current item and any parent items
+ for item in colitem.listchain():
+ if not isinstance(item, pytest.Instance):
+ mapped_names.add(item.name)
+
+ # Add the names added as extra keywords to current or parent items
+ for name in colitem.listextrakeywords():
+ mapped_names.add(name)
+
+ # Add the names attached to the current function through direct assignment
+ for name in colitem.function.func_dict:
+ mapped_names.add(name)
+
+ return eval(keywordexpr, {}, KeywordMapping(mapped_names))
+
def pytest_configure(config):
if config.option.strict:
pytest.mark._config = config
+
class MarkGenerator:
""" Factory for :class:`MarkDecorator` objects - exposed as
a ``py.test.mark`` singleton instance. Example::
@@ -126,6 +182,7 @@
if name not in self._markers:
raise AttributeError("%r not a registered marker" % (name,))
+
class MarkDecorator:
""" A decorator for test functions and test classes. When applied
it will create :class:`MarkInfo` objects which may be
@@ -149,7 +206,7 @@
def __repr__(self):
d = self.__dict__.copy()
name = d.pop('markname')
- return "<MarkDecorator %r %r>" %(name, d)
+ return "<MarkDecorator %r %r>" % (name, d)
def __call__(self, *args, **kwargs):
""" if passed a single callable argument: decorate it with mark info.
@@ -162,15 +219,17 @@
if hasattr(func, 'pytestmark'):
l = func.pytestmark
if not isinstance(l, list):
- func.pytestmark = [l, self]
+ func.pytestmark = [l, self]
else:
- l.append(self)
+ l.append(self)
else:
- func.pytestmark = [self]
+ func.pytestmark = [self]
else:
holder = getattr(func, self.markname, None)
if holder is None:
- holder = MarkInfo(self.markname, self.args,
self.kwargs)
+ holder = MarkInfo(
+ self.markname, self.args, self.kwargs
+ )
setattr(func, self.markname, holder)
else:
holder.add(self.args, self.kwargs)
@@ -180,6 +239,7 @@
args = self.args + args
return self.__class__(self.markname, args=args, kwargs=kw)
+
class MarkInfo:
""" Marking object created by :class:`MarkDecorator` instances. """
def __init__(self, name, args, kwargs):
@@ -193,7 +253,8 @@
def __repr__(self):
return "<MarkInfo %r args=%r kwargs=%r>" % (
- self.name, self.args, self.kwargs)
+ self.name, self.args, self.kwargs
+ )
def add(self, args, kwargs):
""" add a MarkInfo with the given args and kwargs. """
@@ -205,4 +266,3 @@
""" yield MarkInfo objects each relating to a marking-call. """
for args, kwargs in self._arglist:
yield MarkInfo(self.name, args, kwargs)
-
diff -r 6865f468f15242e1a399fd20e9bc9e5ad44cb02d -r
5ce621f0b3d2857ce7035b765cd18836ec8ea73f testing/test_mark.py
--- a/testing/test_mark.py
+++ b/testing/test_mark.py
@@ -345,6 +345,24 @@
assert l[0].args == ("pos0",)
assert l[1].args == ("pos1",)
+ def test_no_marker_match_on_unmarked_names(self, testdir):
+ p = testdir.makepyfile("""
+ import pytest
+ @pytest.mark.shouldmatch
+ def test_marked():
+ assert 1
+
+ def test_unmarked():
+ assert 1
+ """)
+ reprec = testdir.inline_run("-m", "test_unmarked", p)
+ passed, skipped, failed = reprec.listoutcomes()
+ assert len(passed) + len(skipped) + len(failed) == 0
+ dlist = reprec.getcalls("pytest_deselected")
+ deselected_tests = dlist[0].items
+ assert len(deselected_tests) == 2
+
+
def test_keywords_at_node_level(self, testdir):
p = testdir.makepyfile("""
import pytest
@@ -382,7 +400,6 @@
assert len(reprec.getcalls('pytest_deselected')) == 1
for keyword in ['test_one', 'est_on']:
- #yield check, keyword, 'test_one'
check(keyword, 'test_one')
check('TestClass and test', 'test_method_one')
@@ -401,7 +418,7 @@
def pytest_pycollect_makeitem(__multicall__, name):
if name == "TestClass":
item = __multicall__.execute()
- item.keywords["xxx"] = True
+ item.extra_keyword_matches.add("xxx")
return item
""")
reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword)
@@ -440,3 +457,22 @@
reprec = testdir.inline_run("-k", "mykeyword", p)
passed, skipped, failed = reprec.countoutcomes()
assert failed == 1
+
+ def test_no_magic_values(self, testdir):
+ """Make sure the tests do not match on magic values,
+ no double underscored values, like '__dict__',
+ and no instance values, like '()'.
+ """
+ p = testdir.makepyfile("""
+ def test_one(): assert 1
+ """)
+ def assert_test_is_not_selected(keyword):
+ reprec = testdir.inline_run("-k", keyword, p)
+ passed, skipped, failed = reprec.countoutcomes()
+ dlist = reprec.getcalls("pytest_deselected")
+ assert passed + skipped + failed == 0
+ deselected_tests = dlist[0].items
+ assert len(deselected_tests) == 1
+
+ assert_test_is_not_selected("__")
+ assert_test_is_not_selected("()")
Repository URL: https://bitbucket.org/hpk42/pytest/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
pytest-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pytest-commit