Merge remote-tracking branch 'upstream/master' into pastebin-py3
This commit is contained in:
		
						commit
						a54e4e64cd
					
				|  | @ -9,6 +9,12 @@ | ||||||
| - fix #1198: ``--pastebin`` option now works on Python 3. Thanks | - fix #1198: ``--pastebin`` option now works on Python 3. Thanks | ||||||
|   Mehdy Khoshnoody for the PR. |   Mehdy Khoshnoody for the PR. | ||||||
| 
 | 
 | ||||||
|  | - fix #1204: another error when collecting with a nasty __getattr__(). | ||||||
|  |   Thanks Florian Bruhin for the PR. | ||||||
|  | 
 | ||||||
|  | - fix the summary printed when no tests did run. | ||||||
|  |   Thanks Florian Bruhin for the PR. | ||||||
|  | 
 | ||||||
| 2.8.3 | 2.8.3 | ||||||
| ----- | ----- | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -115,7 +115,7 @@ tags: feature | ||||||
| 
 | 
 | ||||||
| - introduce pytest.mark.nocollect for not considering a function for | - introduce pytest.mark.nocollect for not considering a function for | ||||||
|   test collection at all.  maybe also introduce a pytest.mark.test to |   test collection at all.  maybe also introduce a pytest.mark.test to | ||||||
|   explicitely mark a function to become a tested one.  Lookup JUnit ways |   explicitly mark a function to become a tested one.  Lookup JUnit ways | ||||||
|   of tagging tests. |   of tagging tests. | ||||||
| 
 | 
 | ||||||
| introduce pytest.mark.importorskip | introduce pytest.mark.importorskip | ||||||
|  |  | ||||||
|  | @ -384,12 +384,13 @@ class PyobjMixin(PyobjContext): | ||||||
|     def reportinfo(self): |     def reportinfo(self): | ||||||
|         # XXX caching? |         # XXX caching? | ||||||
|         obj = self.obj |         obj = self.obj | ||||||
|         if hasattr(obj, 'compat_co_firstlineno'): |         compat_co_firstlineno = getattr(obj, 'compat_co_firstlineno', None) | ||||||
|  |         if isinstance(compat_co_firstlineno, int): | ||||||
|             # nose compatibility |             # nose compatibility | ||||||
|             fspath = sys.modules[obj.__module__].__file__ |             fspath = sys.modules[obj.__module__].__file__ | ||||||
|             if fspath.endswith(".pyc"): |             if fspath.endswith(".pyc"): | ||||||
|                 fspath = fspath[:-1] |                 fspath = fspath[:-1] | ||||||
|             lineno = obj.compat_co_firstlineno |             lineno = compat_co_firstlineno | ||||||
|         else: |         else: | ||||||
|             fspath, lineno = getfslineno(obj) |             fspath, lineno = getfslineno(obj) | ||||||
|         modpath = self.getmodpath() |         modpath = self.getmodpath() | ||||||
|  | @ -405,7 +406,10 @@ class PyCollector(PyobjMixin, pytest.Collector): | ||||||
|         """ Look for the __test__ attribute, which is applied by the |         """ Look for the __test__ attribute, which is applied by the | ||||||
|         @nose.tools.istest decorator |         @nose.tools.istest decorator | ||||||
|         """ |         """ | ||||||
|         return safe_getattr(obj, '__test__', False) |         # We explicitly check for "is True" here to not mistakenly treat | ||||||
|  |         # classes with a custom __getattr__ returning something truthy (like a | ||||||
|  |         # function) as test classes. | ||||||
|  |         return safe_getattr(obj, '__test__', False) is True | ||||||
| 
 | 
 | ||||||
|     def classnamefilter(self, name): |     def classnamefilter(self, name): | ||||||
|         return self._matches_prefix_or_glob_option('python_classes', name) |         return self._matches_prefix_or_glob_option('python_classes', name) | ||||||
|  |  | ||||||
|  | @ -469,7 +469,7 @@ def skip(msg=""): | ||||||
| skip.Exception = Skipped | skip.Exception = Skipped | ||||||
| 
 | 
 | ||||||
| def fail(msg="", pytrace=True): | def fail(msg="", pytrace=True): | ||||||
|     """ explicitely fail an currently-executing test with the given Message. |     """ explicitly fail an currently-executing test with the given Message. | ||||||
| 
 | 
 | ||||||
|     :arg pytrace: if false the msg represents the full failure information |     :arg pytrace: if false the msg represents the full failure information | ||||||
|                   and no python traceback will be reported. |                   and no python traceback will be reported. | ||||||
|  |  | ||||||
|  | @ -544,7 +544,11 @@ def build_summary_stats_line(stats): | ||||||
|         if val: |         if val: | ||||||
|             key_name = key_translation.get(key, key) |             key_name = key_translation.get(key, key) | ||||||
|             parts.append("%d %s" % (len(val), key_name)) |             parts.append("%d %s" % (len(val), key_name)) | ||||||
|     line = ", ".join(parts) | 
 | ||||||
|  |     if parts: | ||||||
|  |         line = ", ".join(parts) | ||||||
|  |     else: | ||||||
|  |         line = "no tests ran" | ||||||
| 
 | 
 | ||||||
|     if 'failed' in stats or 'error' in stats: |     if 'failed' in stats or 'error' in stats: | ||||||
|         color = 'red' |         color = 'red' | ||||||
|  |  | ||||||
|  | @ -573,7 +573,7 @@ class _MultiCall: | ||||||
| 
 | 
 | ||||||
|     # XXX note that the __multicall__ argument is supported only |     # XXX note that the __multicall__ argument is supported only | ||||||
|     # for pytest compatibility reasons.  It was never officially |     # for pytest compatibility reasons.  It was never officially | ||||||
|     # supported there and is explicitely deprecated since 2.8 |     # supported there and is explicitly deprecated since 2.8 | ||||||
|     # so we can remove it soon, allowing to avoid the below recursion |     # so we can remove it soon, allowing to avoid the below recursion | ||||||
|     # in execute() and simplify/speed up the execute loop. |     # in execute() and simplify/speed up the execute loop. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -219,7 +219,7 @@ For an example on how to add and work with markers from a plugin, see | ||||||
| 
 | 
 | ||||||
| .. note:: | .. note:: | ||||||
| 
 | 
 | ||||||
|     It is recommended to explicitely register markers so that: |     It is recommended to explicitly register markers so that: | ||||||
| 
 | 
 | ||||||
|     * there is one place in your test suite defining your markers |     * there is one place in your test suite defining your markers | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -386,7 +386,7 @@ are expected. | ||||||
| 
 | 
 | ||||||
| For an example, see `newhooks.py`_ from :ref:`xdist`. | For an example, see `newhooks.py`_ from :ref:`xdist`. | ||||||
| 
 | 
 | ||||||
| .. _`newhooks.py`: https://bitbucket.org/pytest-dev/pytest-xdist/src/52082f70e7dd04b00361091b8af906c60fd6700f/xdist/newhooks.py?at=default | .. _`newhooks.py`: https://github.com/pytest-dev/pytest-xdist/blob/974bd566c599dc6a9ea291838c6f226197208b46/xdist/newhooks.py | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Optionally using hooks from 3rd party plugins | Optionally using hooks from 3rd party plugins | ||||||
|  |  | ||||||
|  | @ -880,6 +880,21 @@ class TestReportInfo: | ||||||
|                     pass |                     pass | ||||||
|        """ |        """ | ||||||
| 
 | 
 | ||||||
|  |     def test_reportinfo_with_nasty_getattr(self, testdir): | ||||||
|  |         # https://github.com/pytest-dev/pytest/issues/1204 | ||||||
|  |         modcol = testdir.getmodulecol(""" | ||||||
|  |             # lineno 0 | ||||||
|  |             class TestClass: | ||||||
|  |                 def __getattr__(self, name): | ||||||
|  |                     return "this is not an int" | ||||||
|  | 
 | ||||||
|  |                 def test_foo(self): | ||||||
|  |                     pass | ||||||
|  |         """) | ||||||
|  |         classcol = testdir.collect_by_name(modcol, "TestClass") | ||||||
|  |         instance = classcol.collect()[0] | ||||||
|  |         fspath, lineno, msg = instance.reportinfo() | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| def test_customized_python_discovery(testdir): | def test_customized_python_discovery(testdir): | ||||||
|     testdir.makeini(""" |     testdir.makeini(""" | ||||||
|  |  | ||||||
|  | @ -283,6 +283,35 @@ class TestNoselikeTestAttribute: | ||||||
|         assert len(call.items) == 1 |         assert len(call.items) == 1 | ||||||
|         assert call.items[0].cls.__name__ == "TC" |         assert call.items[0].cls.__name__ == "TC" | ||||||
| 
 | 
 | ||||||
|  |     def test_class_with_nasty_getattr(self, testdir): | ||||||
|  |         """Make sure we handle classes with a custom nasty __getattr__ right. | ||||||
|  | 
 | ||||||
|  |         With a custom __getattr__ which e.g. returns a function (like with a | ||||||
|  |         RPC wrapper), we shouldn't assume this meant "__test__ = True". | ||||||
|  |         """ | ||||||
|  |         # https://github.com/pytest-dev/pytest/issues/1204 | ||||||
|  |         testdir.makepyfile(""" | ||||||
|  |             class MetaModel(type): | ||||||
|  | 
 | ||||||
|  |                 def __getattr__(cls, key): | ||||||
|  |                     return lambda: None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             BaseModel = MetaModel('Model', (), {}) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             class Model(BaseModel): | ||||||
|  | 
 | ||||||
|  |                 __metaclass__ = MetaModel | ||||||
|  | 
 | ||||||
|  |                 def test_blah(self): | ||||||
|  |                     pass | ||||||
|  |         """) | ||||||
|  |         reprec = testdir.inline_run() | ||||||
|  |         assert not reprec.getfailedcollections() | ||||||
|  |         call = reprec.getcalls("pytest_collection_modifyitems")[0] | ||||||
|  |         assert not call.items | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| @pytest.mark.issue351 | @pytest.mark.issue351 | ||||||
| class TestParameterize: | class TestParameterize: | ||||||
|  |  | ||||||
|  | @ -779,10 +779,10 @@ def test_terminal_summary(testdir): | ||||||
|     ("green", "1 passed, 1 xpassed", {"xpassed": (1,), "passed": (1,)}), |     ("green", "1 passed, 1 xpassed", {"xpassed": (1,), "passed": (1,)}), | ||||||
| 
 | 
 | ||||||
|     # Likewise if no tests were found at all |     # Likewise if no tests were found at all | ||||||
|     ("yellow", "", {}), |     ("yellow", "no tests ran", {}), | ||||||
| 
 | 
 | ||||||
|     # Test the empty-key special case |     # Test the empty-key special case | ||||||
|     ("yellow", "", {"": (1,)}), |     ("yellow", "no tests ran", {"": (1,)}), | ||||||
|     ("green", "1 passed", {"": (1,), "passed": (1,)}), |     ("green", "1 passed", {"": (1,), "passed": (1,)}), | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue