introduce name filtering for marker iteration again
This commit is contained in:
		
							parent
							
								
									35f53a7353
								
							
						
					
					
						commit
						4914135fdf
					
				|  | @ -988,7 +988,7 @@ class FixtureManager(object): | |||
|             argnames = getfuncargnames(func, cls=cls) | ||||
|         else: | ||||
|             argnames = () | ||||
|         usefixtures = flatten(mark.args for mark in node.iter_markers() if mark.name == "usefixtures") | ||||
|         usefixtures = flatten(mark.args for mark in node.iter_markers(name="usefixtures")) | ||||
|         initialnames = argnames | ||||
|         initialnames = tuple(usefixtures) + initialnames | ||||
|         fm = node.session._fixturemanager | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ class MarkEvaluator(object): | |||
|         return not hasattr(self, 'exc') | ||||
| 
 | ||||
|     def _get_marks(self): | ||||
|         return [x for x in self.item.iter_markers() if x.name == self._mark_name] | ||||
|         return list(self.item.iter_markers(name=self._mark_name)) | ||||
| 
 | ||||
|     def invalidraise(self, exc): | ||||
|         raises = self.get('raises') | ||||
|  |  | |||
|  | @ -183,20 +183,32 @@ class Node(object): | |||
|         self.keywords[marker.name] = marker | ||||
|         self.own_markers.append(marker) | ||||
| 
 | ||||
|     def iter_markers(self): | ||||
|     def iter_markers(self, name=None): | ||||
|         """ | ||||
|         :param name: if given, filter the results by the name attribute | ||||
| 
 | ||||
|         iterate over all markers of the node | ||||
|         """ | ||||
|         return (x[1] for x in self.iter_markers_with_node()) | ||||
|         return (x[1] for x in self.iter_markers_with_node(name=name)) | ||||
| 
 | ||||
|     def iter_markers_with_node(self): | ||||
|     def iter_markers_with_node(self, name=None): | ||||
|         """ | ||||
|         :param name: if given, filter the results by the name attribute | ||||
| 
 | ||||
|         iterate over all markers of the node | ||||
|         returns sequence of tuples (node, mark) | ||||
|         """ | ||||
|         for node in reversed(self.listchain()): | ||||
|             for mark in node.own_markers: | ||||
|                 yield node, mark | ||||
|                 if name is None or getattr(mark, 'name', None) == name: | ||||
|                     yield node, mark | ||||
| 
 | ||||
|     def get_closest_marker(self, name, default=None): | ||||
|         """return the first marker matching the name | ||||
|         :param default: fallback return value of no marker was found | ||||
|         :param name: name to filter by | ||||
|         """ | ||||
|         return next(self.iter_markers(name=name), default) | ||||
| 
 | ||||
|     def get_marker(self, name): | ||||
|         """ get a marker object from this node or None if | ||||
|  | @ -206,7 +218,7 @@ class Node(object): | |||
| 
 | ||||
|           deprecated | ||||
|         """ | ||||
|         markers = [x for x in self.iter_markers() if x.name == name] | ||||
|         markers = list(self.iter_markers(name=name)) | ||||
|         if markers: | ||||
|             return MarkInfo(markers) | ||||
| 
 | ||||
|  |  | |||
|  | @ -118,9 +118,8 @@ def pytest_generate_tests(metafunc): | |||
|         if hasattr(metafunc.function, attr): | ||||
|             msg = "{0} has '{1}', spelling should be 'parametrize'" | ||||
|             raise MarkerError(msg.format(metafunc.function.__name__, attr)) | ||||
|     for marker in metafunc.definition.iter_markers(): | ||||
|         if marker.name == 'parametrize': | ||||
|             metafunc.parametrize(*marker.args, **marker.kwargs) | ||||
|     for marker in metafunc.definition.iter_markers(name='parametrize'): | ||||
|         metafunc.parametrize(*marker.args, **marker.kwargs) | ||||
| 
 | ||||
| 
 | ||||
| def pytest_configure(config): | ||||
|  |  | |||
|  | @ -64,9 +64,7 @@ def pytest_runtest_setup(item): | |||
|         item._skipped_by_mark = True | ||||
|         skip(eval_skipif.getexplanation()) | ||||
| 
 | ||||
|     for skip_info in item.iter_markers(): | ||||
|         if skip_info.name != 'skip': | ||||
|             continue | ||||
|     for skip_info in item.iter_markers(name='skip'): | ||||
|         item._skipped_by_mark = True | ||||
|         if 'reason' in skip_info.kwargs: | ||||
|             skip(skip_info.kwargs['reason']) | ||||
|  |  | |||
|  | @ -60,10 +60,9 @@ def catch_warnings_for_item(item): | |||
|         for arg in inifilters: | ||||
|             _setoption(warnings, arg) | ||||
| 
 | ||||
|         for mark in item.iter_markers(): | ||||
|             if mark.name == 'filterwarnings': | ||||
|                 for arg in mark.args: | ||||
|                     warnings._setoption(arg) | ||||
|         for mark in item.iter_markers(name='filterwarnings'): | ||||
|             for arg in mark.args: | ||||
|                 warnings._setoption(arg) | ||||
| 
 | ||||
|         yield | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| introduce node.get_closest_marker(name, default=None) to support simple marker usage setups. | ||||
|  | @ -0,0 +1 @@ | |||
| Introduce optional name based filtering for iter_markers | ||||
|  | @ -330,7 +330,7 @@ specifies via named environments:: | |||
|             "env(name): mark test to run only on named environment") | ||||
| 
 | ||||
|     def pytest_runtest_setup(item): | ||||
|         envnames = [mark.args[0] for mark in item.iter_markers() if mark.name == "env"] | ||||
|         envnames = [mark.args[0] for mark in item.iter_markers(name='env')] | ||||
|         if envnames: | ||||
|             if item.config.getoption("-E") not in envnames: | ||||
|                 pytest.skip("test requires env in %r" % envnames) | ||||
|  | @ -402,10 +402,9 @@ Below is the config file that will be used in the next examples:: | |||
|     import sys | ||||
| 
 | ||||
|     def pytest_runtest_setup(item): | ||||
|         for marker in item.iter_markers(): | ||||
|             if marker.name == 'my_marker': | ||||
|                 print(marker) | ||||
|                 sys.stdout.flush() | ||||
|         for marker in item.iter_markers(name='my_marker'): | ||||
|             print(marker) | ||||
|             sys.stdout.flush() | ||||
| 
 | ||||
| A custom marker can have its argument set, i.e. ``args`` and ``kwargs`` properties, defined by either invoking it as a callable or using ``pytest.mark.MARKER_NAME.with_args``. These two methods achieve the same effect most of the time. | ||||
| 
 | ||||
|  | @ -458,10 +457,9 @@ test function.  From a conftest file we can read it like this:: | |||
|     import sys | ||||
| 
 | ||||
|     def pytest_runtest_setup(item): | ||||
|         for mark in item.iter_markers(): | ||||
|             if mark.name == 'glob': | ||||
|                 print ("glob args=%s kwargs=%s" %(mark.args, mark.kwargs)) | ||||
|                 sys.stdout.flush() | ||||
|         for mark in item.iter_markers(name='glob'): | ||||
|             print ("glob args=%s kwargs=%s" %(mark.args, mark.kwargs)) | ||||
|             sys.stdout.flush() | ||||
| 
 | ||||
| Let's run this without capturing output and see what we get:: | ||||
| 
 | ||||
|  |  | |||
|  | @ -274,10 +274,9 @@ Alternatively, you can integrate this functionality with custom markers: | |||
| 
 | ||||
|     def pytest_collection_modifyitems(session, config, items): | ||||
|         for item in items: | ||||
|             for marker in item.iter_markers(): | ||||
|                 if marker.name == 'test_id': | ||||
|                     test_id = marker.args[0] | ||||
|                     item.user_properties.append(('test_id', test_id)) | ||||
|             for marker in item.iter_markers(name='test_id'): | ||||
|                 test_id = marker.args[0] | ||||
|                 item.user_properties.append(('test_id', test_id)) | ||||
| 
 | ||||
| And in your tests: | ||||
| 
 | ||||
|  |  | |||
|  | @ -553,7 +553,6 @@ class TestFunctional(object): | |||
|         self.assert_markers(items, test_foo=('a', 'b'), test_bar=('a',)) | ||||
| 
 | ||||
|     @pytest.mark.issue568 | ||||
|     @pytest.mark.xfail(reason="markers smear on methods of base classes") | ||||
|     def test_mark_should_not_pass_to_siebling_class(self, testdir): | ||||
|         p = testdir.makepyfile(""" | ||||
|             import pytest | ||||
|  | @ -573,8 +572,16 @@ class TestFunctional(object): | |||
|         """) | ||||
|         items, rec = testdir.inline_genitems(p) | ||||
|         base_item, sub_item, sub_item_other = items | ||||
|         assert not hasattr(base_item.obj, 'b') | ||||
|         assert not hasattr(sub_item_other.obj, 'b') | ||||
|         print(items, [x.nodeid for x in items]) | ||||
|         # legacy api smears | ||||
|         assert hasattr(base_item.obj, 'b') | ||||
|         assert hasattr(sub_item_other.obj, 'b') | ||||
|         assert hasattr(sub_item.obj, 'b') | ||||
| 
 | ||||
|         # new api seregates | ||||
|         assert not list(base_item.iter_markers(name='b')) | ||||
|         assert not list(sub_item_other.iter_markers(name='b')) | ||||
|         assert list(sub_item.iter_markers(name='b')) | ||||
| 
 | ||||
|     def test_mark_decorator_baseclasses_merged(self, testdir): | ||||
|         p = testdir.makepyfile(""" | ||||
|  | @ -598,6 +605,26 @@ class TestFunctional(object): | |||
|         self.assert_markers(items, test_foo=('a', 'b', 'c'), | ||||
|                             test_bar=('a', 'b', 'd')) | ||||
| 
 | ||||
|     def test_mark_closest(self, testdir): | ||||
|         p = testdir.makepyfile(""" | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.mark.c(location="class") | ||||
|             class Test: | ||||
|                 @pytest.mark.c(location="function") | ||||
|                 def test_has_own(): | ||||
|                     pass | ||||
| 
 | ||||
|                 def test_has_inherited(): | ||||
|                     pass | ||||
| 
 | ||||
|         """) | ||||
|         items, rec = testdir.inline_genitems(p) | ||||
|         has_own, has_inherited = items | ||||
|         assert has_own.get_closest_marker('c').kwargs == {'location': 'function'} | ||||
|         assert has_inherited.get_closest_marker('c').kwargs == {'location': 'class'} | ||||
|         assert has_own.get_closest_marker('missing') is None | ||||
| 
 | ||||
|     def test_mark_with_wrong_marker(self, testdir): | ||||
|         reprec = testdir.inline_runsource(""" | ||||
|                 import pytest | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue