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) |             argnames = getfuncargnames(func, cls=cls) | ||||||
|         else: |         else: | ||||||
|             argnames = () |             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 = argnames | ||||||
|         initialnames = tuple(usefixtures) + initialnames |         initialnames = tuple(usefixtures) + initialnames | ||||||
|         fm = node.session._fixturemanager |         fm = node.session._fixturemanager | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ class MarkEvaluator(object): | ||||||
|         return not hasattr(self, 'exc') |         return not hasattr(self, 'exc') | ||||||
| 
 | 
 | ||||||
|     def _get_marks(self): |     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): |     def invalidraise(self, exc): | ||||||
|         raises = self.get('raises') |         raises = self.get('raises') | ||||||
|  |  | ||||||
|  | @ -183,21 +183,33 @@ class Node(object): | ||||||
|         self.keywords[marker.name] = marker |         self.keywords[marker.name] = marker | ||||||
|         self.own_markers.append(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 |         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 |         iterate over all markers of the node | ||||||
|         returns sequence of tuples (node, mark) |         returns sequence of tuples (node, mark) | ||||||
|         """ |         """ | ||||||
|         for node in reversed(self.listchain()): |         for node in reversed(self.listchain()): | ||||||
|             for mark in node.own_markers: |             for mark in node.own_markers: | ||||||
|  |                 if name is None or getattr(mark, 'name', None) == name: | ||||||
|                     yield node, mark |                     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): |     def get_marker(self, name): | ||||||
|         """ get a marker object from this node or None if |         """ get a marker object from this node or None if | ||||||
|         the node doesn't have a marker with that name. |         the node doesn't have a marker with that name. | ||||||
|  | @ -206,7 +218,7 @@ class Node(object): | ||||||
| 
 | 
 | ||||||
|           deprecated |           deprecated | ||||||
|         """ |         """ | ||||||
|         markers = [x for x in self.iter_markers() if x.name == name] |         markers = list(self.iter_markers(name=name)) | ||||||
|         if markers: |         if markers: | ||||||
|             return MarkInfo(markers) |             return MarkInfo(markers) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -118,8 +118,7 @@ def pytest_generate_tests(metafunc): | ||||||
|         if hasattr(metafunc.function, attr): |         if hasattr(metafunc.function, attr): | ||||||
|             msg = "{0} has '{1}', spelling should be 'parametrize'" |             msg = "{0} has '{1}', spelling should be 'parametrize'" | ||||||
|             raise MarkerError(msg.format(metafunc.function.__name__, attr)) |             raise MarkerError(msg.format(metafunc.function.__name__, attr)) | ||||||
|     for marker in metafunc.definition.iter_markers(): |     for marker in metafunc.definition.iter_markers(name='parametrize'): | ||||||
|         if marker.name == 'parametrize': |  | ||||||
|         metafunc.parametrize(*marker.args, **marker.kwargs) |         metafunc.parametrize(*marker.args, **marker.kwargs) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -64,9 +64,7 @@ def pytest_runtest_setup(item): | ||||||
|         item._skipped_by_mark = True |         item._skipped_by_mark = True | ||||||
|         skip(eval_skipif.getexplanation()) |         skip(eval_skipif.getexplanation()) | ||||||
| 
 | 
 | ||||||
|     for skip_info in item.iter_markers(): |     for skip_info in item.iter_markers(name='skip'): | ||||||
|         if skip_info.name != 'skip': |  | ||||||
|             continue |  | ||||||
|         item._skipped_by_mark = True |         item._skipped_by_mark = True | ||||||
|         if 'reason' in skip_info.kwargs: |         if 'reason' in skip_info.kwargs: | ||||||
|             skip(skip_info.kwargs['reason']) |             skip(skip_info.kwargs['reason']) | ||||||
|  |  | ||||||
|  | @ -60,8 +60,7 @@ def catch_warnings_for_item(item): | ||||||
|         for arg in inifilters: |         for arg in inifilters: | ||||||
|             _setoption(warnings, arg) |             _setoption(warnings, arg) | ||||||
| 
 | 
 | ||||||
|         for mark in item.iter_markers(): |         for mark in item.iter_markers(name='filterwarnings'): | ||||||
|             if mark.name == 'filterwarnings': |  | ||||||
|             for arg in mark.args: |             for arg in mark.args: | ||||||
|                 warnings._setoption(arg) |                 warnings._setoption(arg) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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") |             "env(name): mark test to run only on named environment") | ||||||
| 
 | 
 | ||||||
|     def pytest_runtest_setup(item): |     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 envnames: | ||||||
|             if item.config.getoption("-E") not in envnames: |             if item.config.getoption("-E") not in envnames: | ||||||
|                 pytest.skip("test requires env in %r" % envnames) |                 pytest.skip("test requires env in %r" % envnames) | ||||||
|  | @ -402,8 +402,7 @@ Below is the config file that will be used in the next examples:: | ||||||
|     import sys |     import sys | ||||||
| 
 | 
 | ||||||
|     def pytest_runtest_setup(item): |     def pytest_runtest_setup(item): | ||||||
|         for marker in item.iter_markers(): |         for marker in item.iter_markers(name='my_marker'): | ||||||
|             if marker.name == 'my_marker': |  | ||||||
|             print(marker) |             print(marker) | ||||||
|             sys.stdout.flush() |             sys.stdout.flush() | ||||||
| 
 | 
 | ||||||
|  | @ -458,8 +457,7 @@ test function.  From a conftest file we can read it like this:: | ||||||
|     import sys |     import sys | ||||||
| 
 | 
 | ||||||
|     def pytest_runtest_setup(item): |     def pytest_runtest_setup(item): | ||||||
|         for mark in item.iter_markers(): |         for mark in item.iter_markers(name='glob'): | ||||||
|             if mark.name == 'glob': |  | ||||||
|             print ("glob args=%s kwargs=%s" %(mark.args, mark.kwargs)) |             print ("glob args=%s kwargs=%s" %(mark.args, mark.kwargs)) | ||||||
|             sys.stdout.flush() |             sys.stdout.flush() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -274,8 +274,7 @@ Alternatively, you can integrate this functionality with custom markers: | ||||||
| 
 | 
 | ||||||
|     def pytest_collection_modifyitems(session, config, items): |     def pytest_collection_modifyitems(session, config, items): | ||||||
|         for item in items: |         for item in items: | ||||||
|             for marker in item.iter_markers(): |             for marker in item.iter_markers(name='test_id'): | ||||||
|                 if marker.name == 'test_id': |  | ||||||
|                 test_id = marker.args[0] |                 test_id = marker.args[0] | ||||||
|                 item.user_properties.append(('test_id', test_id)) |                 item.user_properties.append(('test_id', test_id)) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -553,7 +553,6 @@ class TestFunctional(object): | ||||||
|         self.assert_markers(items, test_foo=('a', 'b'), test_bar=('a',)) |         self.assert_markers(items, test_foo=('a', 'b'), test_bar=('a',)) | ||||||
| 
 | 
 | ||||||
|     @pytest.mark.issue568 |     @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): |     def test_mark_should_not_pass_to_siebling_class(self, testdir): | ||||||
|         p = testdir.makepyfile(""" |         p = testdir.makepyfile(""" | ||||||
|             import pytest |             import pytest | ||||||
|  | @ -573,8 +572,16 @@ class TestFunctional(object): | ||||||
|         """) |         """) | ||||||
|         items, rec = testdir.inline_genitems(p) |         items, rec = testdir.inline_genitems(p) | ||||||
|         base_item, sub_item, sub_item_other = items |         base_item, sub_item, sub_item_other = items | ||||||
|         assert not hasattr(base_item.obj, 'b') |         print(items, [x.nodeid for x in items]) | ||||||
|         assert not hasattr(sub_item_other.obj, 'b') |         # 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): |     def test_mark_decorator_baseclasses_merged(self, testdir): | ||||||
|         p = testdir.makepyfile(""" |         p = testdir.makepyfile(""" | ||||||
|  | @ -598,6 +605,26 @@ class TestFunctional(object): | ||||||
|         self.assert_markers(items, test_foo=('a', 'b', 'c'), |         self.assert_markers(items, test_foo=('a', 'b', 'c'), | ||||||
|                             test_bar=('a', 'b', 'd')) |                             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): |     def test_mark_with_wrong_marker(self, testdir): | ||||||
|         reprec = testdir.inline_runsource(""" |         reprec = testdir.inline_runsource(""" | ||||||
|                 import pytest |                 import pytest | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue