From 3d18c9c1c6e58e30da97e74fc79efb91f1aae24e Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sun, 18 Dec 2016 21:30:00 +0000 Subject: [PATCH 01/46] 'xfail' markers without a condition no longer rely on the underlying `Item` deriving from `PyobjMixin` --- _pytest/skipping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/skipping.py b/_pytest/skipping.py index a8eaea98a..cfaed2fa7 100644 --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -119,7 +119,6 @@ class MarkEvaluator: if hasattr(self, 'result'): return self.result if self.holder: - d = self._getglobals() if self.holder.args or 'condition' in self.holder.kwargs: self.result = False # "holder" might be a MarkInfo or a MarkDecorator; only @@ -135,6 +134,7 @@ class MarkEvaluator: for expr in args: self.expr = expr if isinstance(expr, py.builtin._basestring): + d = self._getglobals() result = cached_eval(self.item.config, expr, d) else: if "reason" not in kwargs: From 8db9915374f60d00780b758b98ada8d3f80af9bb Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sun, 18 Dec 2016 21:39:35 +0000 Subject: [PATCH 02/46] Update AUTHORS, CHANGELOG --- AUTHORS | 1 + CHANGELOG.rst | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 8c6fa1b5d..3999db9b3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,6 +16,7 @@ Antony Lee Armin Rigo Aron Curzon Aviv Palivoda +Barney Gale Ben Webb Benjamin Peterson Bernard Pratz diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7c3df0327..64453f259 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,10 @@ 3.0.6.dev0 (unreleased) ======================= -* +* Conditionless ``xfail`` markers no longer rely on the underlying test item + being an instance of ``PyobjMixin``, and can therefore apply to tests not + collected by the built-in python test collector. Thanks `@barneygale`_ for the + PR. * pytest no longer recognizes coroutine functions as yield tests (`#2129`_). Thanks to `@malinoff`_ for the PR. From df409a0c0ee9948d3725ee79c4a0a91960466af7 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Mon, 2 Jan 2017 22:01:40 +0000 Subject: [PATCH 03/46] Fix CHANGELOG.rst --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 64453f259..eca520bbc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,7 @@ * +.. _@barneygale: https://github.com/barneygale .. _@lesteve: https://github.com/lesteve .. _@malinoff: https://github.com/malinoff .. _@pelme: https://github.com/pelme From d1c725078a8c2fccfc573772e1944b9fe2a902e6 Mon Sep 17 00:00:00 2001 From: mbyt Date: Mon, 30 Jan 2017 21:20:12 +0100 Subject: [PATCH 04/46] Allow to skip unittests if --pdb active closes #2137 --- CHANGELOG.rst | 7 ++++++- _pytest/unittest.py | 14 ++++++++++++-- testing/test_pdb.py | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 006c0ed0f..7f24a3282 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,8 @@ 3.0.7 (unreleased) ======================= -* +* Fix regression, pytest now skips unittest correctly if run with ``--pdb`` + (`#2137`_). Thanks to `@gst`_ for the report and `@mbyt`_ for the PR. * @@ -9,6 +10,10 @@ * +.. _@gst: https://github.com/gst + +.. _#2137: https://github.com/pytest-dev/pytest/issues/2137 + 3.0.6 (2017-01-22) ================== diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 73224010b..4d303e7e3 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -65,7 +65,6 @@ class UnitTestCase(pytest.Class): yield TestCaseFunction('runTest', parent=self) - class TestCaseFunction(pytest.Function): _excinfo = None @@ -157,9 +156,20 @@ class TestCaseFunction(pytest.Function): self._testcase(result=self) else: # disables tearDown and cleanups for post mortem debugging (see #1890) + # but still implements the skipping machinery (see #2137) + testMethod = getattr(self._testcase, self._testcase._testMethodName) + if (getattr(self._testcase.__class__, "__unittest_skip__", False) or + getattr(testMethod, "__unittest_skip__", False)): + # If the class or method was skipped. + skip_why = (getattr(self._testcase.__class__, '__unittest_skip_why__', '') + or getattr(testMethod, '__unittest_skip_why__', '')) + try: + self._testcase._addSkip(self, self._testcase, skip_why) + except TypeError: # PY2 + self._testcase._addSkip(self, skip_why) + return self._testcase.debug() - def _prunetraceback(self, excinfo): pytest.Function._prunetraceback(self, excinfo) traceback = excinfo.traceback.filter( diff --git a/testing/test_pdb.py b/testing/test_pdb.py index df58dad87..8a2efdb87 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -106,6 +106,20 @@ class TestPDB: assert 'debug.me' in rest self.flush(child) + def test_pdb_unittest_skip(self, testdir): + p1 = testdir.makepyfile(""" + import unittest + @unittest.skipIf(True, 'Skipping also with pdb active') + class MyTestCase(unittest.TestCase): + def test_one(self): + assert 0 + """) + child = testdir.spawn_pytest("-rs --pdb %s" % p1) + child.expect('Skipping also with pdb active') + child.expect('1 skipped in') + child.sendeof() + self.flush(child) + def test_pdb_interaction_capture(self, testdir): p1 = testdir.makepyfile(""" def test_1(): From 36b6f17727589defa28101142009410c9c771289 Mon Sep 17 00:00:00 2001 From: mbyt Date: Tue, 31 Jan 2017 21:03:49 +0100 Subject: [PATCH 05/46] fixing code-style, keep flake8 happy --- _pytest/unittest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 4d303e7e3..0126ff838 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -161,8 +161,8 @@ class TestCaseFunction(pytest.Function): if (getattr(self._testcase.__class__, "__unittest_skip__", False) or getattr(testMethod, "__unittest_skip__", False)): # If the class or method was skipped. - skip_why = (getattr(self._testcase.__class__, '__unittest_skip_why__', '') - or getattr(testMethod, '__unittest_skip_why__', '')) + skip_why = (getattr(self._testcase.__class__, '__unittest_skip_why__', '') or + getattr(testMethod, '__unittest_skip_why__', '')) try: self._testcase._addSkip(self, self._testcase, skip_why) except TypeError: # PY2 From e1c5314d80ad7b90257bfaf7a807a3d2e10f4494 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 1 Feb 2017 02:37:55 -0200 Subject: [PATCH 06/46] Replace 'raise StopIteration' usages in the code by 'return's in accordance to PEP-479 Fix #2160 --- CHANGELOG.rst | 11 +++++++++-- _pytest/python.py | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 006c0ed0f..612ee0f3b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,10 @@ 3.0.7 (unreleased) -======================= +================== + +* + +* Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). + Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. * @@ -7,7 +12,9 @@ * -* +.. _#2160: https://github.com/pytest-dev/pytest/issues/2160 + +.. _PEP-479: https://www.python.org/dev/peps/pep-0479/ 3.0.6 (2017-01-22) diff --git a/_pytest/python.py b/_pytest/python.py index e46f2f1bc..2973d43d6 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -174,7 +174,7 @@ def pytest_pycollect_makeitem(collector, name, obj): outcome = yield res = outcome.get_result() if res is not None: - raise StopIteration + return # nothing was collected elsewhere, let's do it here if isclass(obj): if collector.istestclass(obj, name): From ad56cd8027756a8bc1aa83402bbfffeae3520129 Mon Sep 17 00:00:00 2001 From: mbyt Date: Thu, 2 Feb 2017 05:01:51 +0100 Subject: [PATCH 07/46] extract a _handle_skip method, secure PY2 branch --- _pytest/unittest.py | 30 +++++++++++++++++++----------- testing/test_pdb.py | 1 + 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 0126ff838..34eb9885b 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -151,22 +151,30 @@ class TestCaseFunction(pytest.Function): def stopTest(self, testcase): pass + def _handle_skip(self): + # implements the skipping machinery (see #2137) + # analog to pythons Lib/unittest/case.py:run + testMethod = getattr(self._testcase, self._testcase._testMethodName) + if (getattr(self._testcase.__class__, "__unittest_skip__", False) or + getattr(testMethod, "__unittest_skip__", False)): + # If the class or method was skipped. + skip_why = (getattr(self._testcase.__class__, '__unittest_skip_why__', '') or + getattr(testMethod, '__unittest_skip_why__', '')) + try: # PY3, unittest2 on PY2 + self._testcase._addSkip(self, self._testcase, skip_why) + except TypeError: # PY2 + if sys.version_info[0] != 2: + raise + self._testcase._addSkip(self, skip_why) + return True + return False + def runtest(self): if self.config.pluginmanager.get_plugin("pdbinvoke") is None: self._testcase(result=self) else: # disables tearDown and cleanups for post mortem debugging (see #1890) - # but still implements the skipping machinery (see #2137) - testMethod = getattr(self._testcase, self._testcase._testMethodName) - if (getattr(self._testcase.__class__, "__unittest_skip__", False) or - getattr(testMethod, "__unittest_skip__", False)): - # If the class or method was skipped. - skip_why = (getattr(self._testcase.__class__, '__unittest_skip_why__', '') or - getattr(testMethod, '__unittest_skip_why__', '')) - try: - self._testcase._addSkip(self, self._testcase, skip_why) - except TypeError: # PY2 - self._testcase._addSkip(self, skip_why) + if self._handle_skip(): return self._testcase.debug() diff --git a/testing/test_pdb.py b/testing/test_pdb.py index 8a2efdb87..52a75d916 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -107,6 +107,7 @@ class TestPDB: self.flush(child) def test_pdb_unittest_skip(self, testdir): + """Test for issue #2137""" p1 = testdir.makepyfile(""" import unittest @unittest.skipIf(True, 'Skipping also with pdb active') From bad261279c5af15e2126023a03f08389c189b2d5 Mon Sep 17 00:00:00 2001 From: Vidar Tonaas Fauske Date: Fri, 3 Feb 2017 16:04:34 +0100 Subject: [PATCH 08/46] Do not asssume `Item.obj` in 'skipping' plugin See #2231 for discussion. --- _pytest/skipping.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_pytest/skipping.py b/_pytest/skipping.py index 91a34169f..591977efd 100644 --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -112,7 +112,8 @@ class MarkEvaluator: def _getglobals(self): d = {'os': os, 'sys': sys, 'config': self.item.config} - d.update(self.item.obj.__globals__) + if hasattr(self.item, 'obj'): + d.update(self.item.obj.__globals__) return d def _istrue(self): From 1a88a91c7a04ed996bee3c8957e07d9a0c735de1 Mon Sep 17 00:00:00 2001 From: Vidar Tonaas Fauske Date: Fri, 3 Feb 2017 16:29:43 +0100 Subject: [PATCH 09/46] Update authors/history --- AUTHORS | 1 + CHANGELOG.rst | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index c2400f508..d1a4aa675 100644 --- a/AUTHORS +++ b/AUTHORS @@ -141,5 +141,6 @@ Trevor Bekolay Tyler Goodlet Vasily Kuznetsov Victor Uriarte +Vidar T. Fauske Wouter van Ackooy Xuecong Liao diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 612ee0f3b..b81803324 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,8 @@ * Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. -* +* Skipping plugin now also works with test items generated by custom collectors (`#2231`_). + Thanks to `@vidartf`_. * @@ -16,6 +17,10 @@ .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ +.. _#2231: https://github.com/pytest-dev/pytest/issues/2231 + +.. _@vidartf: https://github.com/vidartf + 3.0.6 (2017-01-22) ================== From 832c89dd5fa7c310ae05ddcffc81025bed7a3c14 Mon Sep 17 00:00:00 2001 From: Vidar Tonaas Fauske Date: Fri, 3 Feb 2017 16:59:30 +0100 Subject: [PATCH 10/46] Test for `pytest.mark.xfail` with non-Python Item --- testing/test_skipping.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/testing/test_skipping.py b/testing/test_skipping.py index 2e7868d3a..ac4412fcb 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -969,3 +969,26 @@ def test_module_level_skip_error(testdir): result.stdout.fnmatch_lines( "*Using pytest.skip outside of a test is not allowed*" ) + + +def test_mark_xfail_item(testdir): + # Ensure pytest.mark.xfail works with non-Python Item + testdir.makeconftest(""" + import pytest + + class MyItem(pytest.Item): + nodeid = 'foo' + def setup(self): + marker = pytest.mark.xfail(True, reason="Expected failure") + self.add_marker(marker) + def runtest(self): + assert False + + def pytest_collect_file(path, parent): + return MyItem("foo", parent) + """) + result = testdir.inline_run() + passed, skipped, failed = result.listoutcomes() + assert not failed + xfailed = [r for r in skipped if hasattr(r, 'wasxfail')] + assert xfailed From 87fb689ab1d05935bfd75ff29fcbc1de4161f606 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 7 Feb 2017 14:00:13 +0200 Subject: [PATCH 11/46] Remove an unneeded `except KeyboardInterrupt` KeyboardInterrupt is a subclass of BaseException, but not of Exception. Hence if we remove this except, KeyboardInterrupts will still be raised so the behavior stays the same. --- _pytest/fixtures.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index 28bcd4d8d..c5bf75386 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -124,8 +124,6 @@ def getfixturemarker(obj): exceptions.""" try: return getattr(obj, "_pytestfixturefunction", None) - except KeyboardInterrupt: - raise except Exception: # some objects raise errors like request (from flask import request) # we don't expect them to be fixture functions From 3a0a0c2df93ecfcf4fb09a0f7c24bf3a06d1bae5 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sun, 5 Feb 2017 23:55:39 +0200 Subject: [PATCH 12/46] Ignore errors raised from descriptors when collecting fixtures Descriptors (e.g. properties) such as in the added test case are triggered during collection, executing arbitrary code which can raise. Previously, such exceptions were propagated and failed the collection. Now these exceptions are caught and the corresponding attributes are silently ignored. A better solution would be to completely skip access to all custom descriptors, such that the offending code doesn't even trigger. However I think this requires manually going through the instance and all of its MRO for each and every attribute checking if it might be a proper fixture before accessing it. So I took the easy route here. In other words, putting something like this in your test class is still a bad idea...: @property def innocent(self): os.system('rm -rf /') Fixes #2234. --- AUTHORS | 1 + CHANGELOG.rst | 7 +++++++ _pytest/fixtures.py | 5 ++++- testing/python/collect.py | 10 ++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index fa1140d4d..b09516a1d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -118,6 +118,7 @@ Piotr Banaszkiewicz Punyashloka Biswal Quentin Pradet Ralf Schmitt +Ran Benita Raphael Pierzina Raquel Alegre Roberto Polli diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9ff2afd5..c11200d64 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,9 @@ * +* Ignore exceptions raised from descriptors (e.g. properties) during Python test collection (`#2234`_). + Thanks to `@bluetech`_. + * Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. @@ -16,6 +19,10 @@ * +.. _#2234: https://github.com/pytest-dev/pytest/issues/2234 + +.. _@bluetech: https://github.com/bluetech + .. _#2160: https://github.com/pytest-dev/pytest/issues/2160 .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index c5bf75386..248708f6e 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -14,6 +14,7 @@ from _pytest.compat import ( getfslineno, get_real_func, is_generator, isclass, getimfunc, getlocation, getfuncargnames, + safe_getattr, ) def pytest_sessionstart(session): @@ -1066,7 +1067,9 @@ class FixtureManager: self._holderobjseen.add(holderobj) autousenames = [] for name in dir(holderobj): - obj = getattr(holderobj, name, None) + # The attribute can be an arbitrary descriptor, so the attribute + # access below can raise. safe_getatt() ignores such exceptions. + obj = safe_getattr(holderobj, name, None) # fixture functions have a pytest_funcarg__ prefix (pre-2.3 style) # or are "@pytest.fixture" marked marker = getfixturemarker(obj) diff --git a/testing/python/collect.py b/testing/python/collect.py index 1e69f2da9..cce934ddc 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -166,6 +166,16 @@ class TestClass: "because it has a __new__ constructor*" ) + def test_issue2234_property(self, testdir): + testdir.makepyfile(""" + class TestCase(object): + @property + def prop(self): + raise NotImplementedError() + """) + result = testdir.runpytest() + assert result.ret == EXIT_NOTESTSCOLLECTED + class TestGenerator: def test_generative_functions(self, testdir): From 9eb1d7395107edbb0401eca83a69cb94dbc79308 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 8 Feb 2017 22:39:34 -0200 Subject: [PATCH 13/46] --override-ini now correctly overrides some fundamental options like "python_files" #2238 --- CHANGELOG.rst | 5 ++++- _pytest/config.py | 19 ++++++++++--------- testing/test_config.py | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f33663b2a..a8583d09f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,7 +7,8 @@ * Ignore exceptions raised from descriptors (e.g. properties) during Python test collection (`#2234`_). Thanks to `@bluetech`_. -* +* ``--override-ini`` now correctly overrides some fundamental options like ``python_files`` (`#2238`_). + Thanks `@sirex`_ for the report and `@nicoddemus`_ for the PR. * Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. @@ -28,12 +29,14 @@ .. _@bluetech: https://github.com/bluetech .. _@gst: https://github.com/gst +.. _@sirex: https://github.com/sirex .. _@vidartf: https://github.com/vidartf .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 .. _#2160: https://github.com/pytest-dev/pytest/issues/2160 .. _#2231: https://github.com/pytest-dev/pytest/issues/2231 .. _#2234: https://github.com/pytest-dev/pytest/issues/2234 +.. _#2238: https://github.com/pytest-dev/pytest/issues/2238 .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ diff --git a/_pytest/config.py b/_pytest/config.py index 42d1a118a..c73416f0a 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -877,6 +877,7 @@ class Config(object): self.trace = self.pluginmanager.trace.root.get("config") self.hook = self.pluginmanager.hook self._inicache = {} + self._override_ini = () self._opt2dest = {} self._cleanup = [] self._warn = self.pluginmanager._warn @@ -977,6 +978,7 @@ class Config(object): self.invocation_dir = py.path.local() self._parser.addini('addopts', 'extra command line options', 'args') self._parser.addini('minversion', 'minimally required pytest version') + self._override_ini = ns.override_ini or () def _consider_importhook(self, args, entrypoint_name): """Install the PEP 302 import hook if using assertion re-writing. @@ -1159,15 +1161,14 @@ class Config(object): # and -o foo1=bar1 -o foo2=bar2 options # always use the last item if multiple value set for same ini-name, # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2 - if self.getoption("override_ini", None): - for ini_config_list in self.option.override_ini: - for ini_config in ini_config_list: - try: - (key, user_ini_value) = ini_config.split("=", 1) - except ValueError: - raise UsageError("-o/--override-ini expects option=value style.") - if key == name: - value = user_ini_value + for ini_config_list in self._override_ini: + for ini_config in ini_config_list: + try: + (key, user_ini_value) = ini_config.split("=", 1) + except ValueError: + raise UsageError("-o/--override-ini expects option=value style.") + if key == name: + value = user_ini_value return value def getoption(self, name, default=notset, skip=False): diff --git a/testing/test_config.py b/testing/test_config.py index e6aa423e8..3ce51d639 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -778,6 +778,21 @@ class TestOverrideIniArgs: result = testdir.runpytest("--override-ini", 'xdist_strict True', "-s") result.stderr.fnmatch_lines(["*ERROR* *expects option=value*"]) + @pytest.mark.parametrize('with_ini', [True, False]) + def test_override_ini_handled_asap(self, testdir, with_ini): + """-o should be handled as soon as possible and always override what's in ini files (#2238)""" + if with_ini: + testdir.makeini(""" + [pytest] + python_files=test_*.py + """) + testdir.makepyfile(unittest_ini_handle=""" + def test(): + pass + """) + result = testdir.runpytest("--override-ini", 'python_files=unittest_*.py') + result.stdout.fnmatch_lines(["*1 passed in*"]) + def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch): monkeypatch.chdir(str(tmpdir)) a = tmpdir.mkdir("a") From b536fb7ace7ab4da584b942395235e12d962ae36 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 14 Feb 2017 11:45:39 +0000 Subject: [PATCH 14/46] Mention next training event. --- doc/en/talks.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/en/talks.rst b/doc/en/talks.rst index c35fba0b0..85faf6455 100644 --- a/doc/en/talks.rst +++ b/doc/en/talks.rst @@ -4,7 +4,9 @@ Talks and Tutorials .. sidebar:: Next Open Trainings - `pytest workshop `_, 8th December 2016, Bern, Switzerland + `Professional Testing with Python + `_, + 26-28 April 2017, Leipzig, Germany. .. _`funcargs`: funcargs.html From 58ce3a9e8c48fe557bfdc644a96df234936247e1 Mon Sep 17 00:00:00 2001 From: Patrick Hayes Date: Tue, 14 Feb 2017 16:54:32 -0800 Subject: [PATCH 15/46] Safer sys.modules delete --- _pytest/assertion/rewrite.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index abf5b491f..7408c4746 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -215,7 +215,8 @@ class AssertionRewritingHook(object): mod.__loader__ = self py.builtin.exec_(co, mod.__dict__) except: - del sys.modules[name] + if name in sys.modules: + del sys.modules[name] raise return sys.modules[name] From 00ec30353b090f8bc5ab36b7a6738f74477df0ba Mon Sep 17 00:00:00 2001 From: Patrick Hayes Date: Tue, 14 Feb 2017 17:08:42 -0800 Subject: [PATCH 16/46] Update docs as requested --- AUTHORS | 1 + CHANGELOG.rst | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/AUTHORS b/AUTHORS index b09516a1d..b49405bf7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -113,6 +113,7 @@ Nicolas Delaby Oleg Pidsadnyi Oliver Bestwalter Omar Kohl +Patrick Hayes Pieter Mulder Piotr Banaszkiewicz Punyashloka Biswal diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f33663b2a..394c57fa4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,9 @@ 3.0.7 (unreleased) ================== +* Fix issue when trying to import the `anydbm` module. (`#2248`_). + Thanks `@pfhayes`_ for the PR. + * Fix regression, pytest now skips unittest correctly if run with ``--pdb`` (`#2137`_). Thanks to `@gst`_ for the report and `@mbyt`_ for the PR. @@ -30,6 +33,7 @@ .. _@gst: https://github.com/gst .. _@vidartf: https://github.com/vidartf +.. _#2248: https://github.com/pytest-dev/pytest/issues/2248 .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 .. _#2160: https://github.com/pytest-dev/pytest/issues/2160 .. _#2231: https://github.com/pytest-dev/pytest/issues/2231 From 49289fed52eb99f3a3258d71e2e6ab24a850658a Mon Sep 17 00:00:00 2001 From: Patrick Hayes Date: Tue, 14 Feb 2017 17:21:20 -0800 Subject: [PATCH 17/46] Fix docs --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 394c57fa4..f172be1ea 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,6 +29,7 @@ * +.. _@pfhayes: https://github.com/pfhayes .. _@bluetech: https://github.com/bluetech .. _@gst: https://github.com/gst .. _@vidartf: https://github.com/vidartf From 6b5566db66300f9a566efecf1d9389842dc9581a Mon Sep 17 00:00:00 2001 From: Patrick Hayes Date: Tue, 14 Feb 2017 17:47:42 -0800 Subject: [PATCH 18/46] Update changelog --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f172be1ea..23ff64320 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,9 @@ 3.0.7 (unreleased) ================== -* Fix issue when trying to import the `anydbm` module. (`#2248`_). +* Fix issue in assertion rewriting breaking due to modules silently discarding + other modules when importing fails + Notably, importing the `anydbm` module is fixed. (`#2248`_). Thanks `@pfhayes`_ for the PR. * Fix regression, pytest now skips unittest correctly if run with ``--pdb`` From c4d974460ca611cfcd51d05ab742ebb166df4d2a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 15 Feb 2017 11:57:03 -0200 Subject: [PATCH 19/46] Improve pytest_plugins docs As discussed in #2246 --- doc/en/writing_plugins.rst | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index 770f81e46..de0aa1390 100644 --- a/doc/en/writing_plugins.rst +++ b/doc/en/writing_plugins.rst @@ -236,20 +236,31 @@ import ``helper.py`` normally. The contents of Requiring/Loading plugins in a test module or conftest file ----------------------------------------------------------- -You can require plugins in a test module or a conftest file like this:: +You can require plugins in a test module or a ``conftest.py`` file like this: - pytest_plugins = "name1", "name2", +.. code-block:: python + + pytest_plugins = ["name1", "name2"] When the test module or conftest plugin is loaded the specified plugins -will be loaded as well. You can also use dotted path like this:: +will be loaded as well. Any module can be blessed as a plugin, including internal +application modules: + +.. code-block:: python pytest_plugins = "myapp.testsupport.myplugin" -which will import the specified module as a ``pytest`` plugin. +``pytest_plugins`` variables are processed recursively, so note that in the example above +if ``myapp.testsupport.myplugin`` also declares ``pytest_plugins``, the contents +of the variable will also be loaded as plugins, and so on. -Plugins imported like this will automatically be marked to require -assertion rewriting using the :func:`pytest.register_assert_rewrite` -mechanism. However for this to have any effect the module must not be +This mechanism makes it easy to share textures within applications or even +external applications without the need to create external plugins using +the ``setuptools``'s entry point technique. + +Plugins imported by ``pytest_plugins`` will also automatically be marked +for assertion rewriting (see :func:`pytest.register_assert_rewrite`). +However for this to have any effect the module must not be imported already; if it was already imported at the time the ``pytest_plugins`` statement is processed, a warning will result and assertions inside the plugin will not be re-written. To fix this you From eeb6603d71737385cea62633d4db28f9e0db269b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Wed, 15 Feb 2017 16:54:53 +0200 Subject: [PATCH 20/46] Python 3.6 invalid escape sequence deprecation fixes --- _pytest/pytester.py | 2 +- _pytest/tmpdir.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 6c63bbbbf..977e1f9ad 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -332,7 +332,7 @@ def testdir(request, tmpdir_factory): return Testdir(request, tmpdir_factory) -rex_outcome = re.compile("(\d+) ([\w-]+)") +rex_outcome = re.compile(r"(\d+) ([\w-]+)") class RunResult: """The result of running a command. diff --git a/_pytest/tmpdir.py b/_pytest/tmpdir.py index 28a6b0636..0f878ad01 100644 --- a/_pytest/tmpdir.py +++ b/_pytest/tmpdir.py @@ -116,7 +116,7 @@ def tmpdir(request, tmpdir_factory): path object. """ name = request.node.name - name = re.sub("[\W]", "_", name) + name = re.sub(r"[\W]", "_", name) MAXVAL = 30 if len(name) > MAXVAL: name = name[:MAXVAL] From ede4e9171f3411d71ad280280fcaa45b1e5fc371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Wed, 15 Feb 2017 17:00:18 +0200 Subject: [PATCH 21/46] Spelling fixes --- CHANGELOG.rst | 2 +- _pytest/cacheprovider.py | 2 +- _pytest/hookspec.py | 2 +- _pytest/main.py | 2 +- _pytest/mark.py | 2 +- _pytest/pytester.py | 6 +++--- _pytest/python.py | 2 +- _pytest/unittest.py | 2 +- testing/test_assertion.py | 2 +- testing/test_assertrewrite.py | 2 +- testing/test_capture.py | 2 +- testing/test_session.py | 2 +- tox.ini | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f33663b2a..3c0d6aa40 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2401,7 +2401,7 @@ Bug fixes: teardown function are called earlier. - add an all-powerful metafunc.parametrize function which allows to parametrize test function arguments in multiple steps and therefore - from indepdenent plugins and palces. + from independent plugins and places. - add a @pytest.mark.parametrize helper which allows to easily call a test function with different argument values - Add examples to the "parametrize" example page, including a quick port diff --git a/_pytest/cacheprovider.py b/_pytest/cacheprovider.py index 0657001f2..893f0eae5 100755 --- a/_pytest/cacheprovider.py +++ b/_pytest/cacheprovider.py @@ -1,7 +1,7 @@ """ merged implementation of the cache provider -the name cache was not choosen to ensure pluggy automatically +the name cache was not chosen to ensure pluggy automatically ignores the external pytest-cache """ diff --git a/_pytest/hookspec.py b/_pytest/hookspec.py index b5f51eccf..f01235455 100644 --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -255,7 +255,7 @@ def pytest_assertrepr_compare(config, op, left, right): Return None for no custom explanation, otherwise return a list of strings. The strings will be joined by newlines but any newlines *in* a string will be escaped. Note that all but the first line will - be indented sligthly, the intention is for the first line to be a summary. + be indented slightly, the intention is for the first line to be a summary. """ # ------------------------------------------------------------------------- diff --git a/_pytest/main.py b/_pytest/main.py index a32352793..b66b661c8 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -81,7 +81,7 @@ def pytest_namespace(): def pytest_configure(config): - pytest.config = config # compatibiltiy + pytest.config = config # compatibility def wrap_session(config, doit): diff --git a/_pytest/mark.py b/_pytest/mark.py index 357a60492..d406bca6b 100644 --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -66,7 +66,7 @@ def pytest_collection_modifyitems(items, config): return # pytest used to allow "-" for negating # but today we just allow "-" at the beginning, use "not" instead - # we probably remove "-" alltogether soon + # we probably remove "-" altogether soon if keywordexpr.startswith("-"): keywordexpr = "not " + keywordexpr[1:] selectuntil = False diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 6c63bbbbf..25f7c5de7 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -566,7 +566,7 @@ class Testdir: def mkpydir(self, name): """Create a new python package. - This creates a (sub)direcotry with an empty ``__init__.py`` + This creates a (sub)directory with an empty ``__init__.py`` file so that is recognised as a python package. """ @@ -661,7 +661,7 @@ class Testdir: def inline_genitems(self, *args): """Run ``pytest.main(['--collectonly'])`` in-process. - Retuns a tuple of the collected items and a + Returns a tuple of the collected items and a :py:class:`HookRecorder` instance. This runs the :py:func:`pytest.main` function to run all of @@ -857,7 +857,7 @@ class Testdir: :py:meth:`parseconfigure`. :param withinit: Whether to also write a ``__init__.py`` file - to the temporarly directory to ensure it is a package. + to the temporary directory to ensure it is a package. """ kw = {self.request.function.__name__: Source(source).strip()} diff --git a/_pytest/python.py b/_pytest/python.py index 2973d43d6..3e865e9df 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -629,7 +629,7 @@ class Generator(FunctionMixin, PyCollector): def getcallargs(self, obj): if not isinstance(obj, (tuple, list)): obj = (obj,) - # explict naming + # explicit naming if isinstance(obj[0], py.builtin._basestring): name = obj[0] obj = obj[1:] diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 34eb9885b..276b9ba16 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -5,7 +5,7 @@ import sys import traceback import pytest -# for transfering markers +# for transferring markers import _pytest._code from _pytest.python import transfer_markers from _pytest.skipping import MarkEvaluator diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 9115d25e2..dfc9f60fb 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -364,7 +364,7 @@ class TestAssert_reprcompare: expl = '\n'.join(callequal(left, right, verbose=True)) assert expl.endswith(textwrap.dedent(expected).strip()) - def test_list_different_lenghts(self): + def test_list_different_lengths(self): expl = callequal([0, 1], [0, 1, 2]) assert len(expl) > 1 expl = callequal([0, 1, 2], [0, 1]) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index fdf674f25..7cc58e8a8 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -271,7 +271,7 @@ class TestAssertionRewrite: getmsg(f, must_pass=True) - def test_short_circut_evaluation(self): + def test_short_circuit_evaluation(self): def f(): assert True or explode # noqa diff --git a/testing/test_capture.py b/testing/test_capture.py index cbb5fc81b..763e28315 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -604,7 +604,7 @@ def test_capture_binary_output(testdir): def test_error_during_readouterr(testdir): - """Make sure we suspend capturing if errors occurr during readouterr""" + """Make sure we suspend capturing if errors occur during readouterr""" testdir.makepyfile(pytest_xyz=""" from _pytest.capture import FDCapture def bad_snap(self): diff --git a/testing/test_session.py b/testing/test_session.py index a7dcb27a4..f494dbc11 100644 --- a/testing/test_session.py +++ b/testing/test_session.py @@ -197,7 +197,7 @@ class TestNewSession(SessionTests): colfail = [x for x in finished if x.failed] assert len(colfail) == 1 - def test_minus_x_overriden_by_maxfail(self, testdir): + def test_minus_x_overridden_by_maxfail(self, testdir): testdir.makepyfile(__init__="") testdir.makepyfile(test_one="xxxx", test_two="yyyy", test_third="zzz") reprec = testdir.inline_run("-x", "--maxfail=2", testdir.tmpdir) diff --git a/tox.ini b/tox.ini index e57fabd4b..1b9fb9f5a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] minversion=2.0 distshare={homedir}/.tox/distshare -# make sure to update enviroment list on appveyor.yml +# make sure to update environment list on appveyor.yml envlist= linting py26 From 8f98ac5ae8774e51ac6336faa43d465fe013e747 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 15 Feb 2017 13:15:53 -0200 Subject: [PATCH 22/46] Fix typo in docs "textures" -> "fixtures" --- doc/en/writing_plugins.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index de0aa1390..f6ed6e4e3 100644 --- a/doc/en/writing_plugins.rst +++ b/doc/en/writing_plugins.rst @@ -254,7 +254,7 @@ application modules: if ``myapp.testsupport.myplugin`` also declares ``pytest_plugins``, the contents of the variable will also be loaded as plugins, and so on. -This mechanism makes it easy to share textures within applications or even +This mechanism makes it easy to share fixtures within applications or even external applications without the need to create external plugins using the ``setuptools``'s entry point technique. From 58d7f4e0487bb4049c0472f1019a6117c6f25af4 Mon Sep 17 00:00:00 2001 From: Victor Uriarte Date: Thu, 16 Feb 2017 22:52:06 -0700 Subject: [PATCH 23/46] Correct typo --- _pytest/hookspec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/hookspec.py b/_pytest/hookspec.py index f01235455..ea1f0443d 100644 --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -246,7 +246,7 @@ def pytest_unconfigure(config): # ------------------------------------------------------------------------- -# hooks for customising the assert methods +# hooks for customizing the assert methods # ------------------------------------------------------------------------- def pytest_assertrepr_compare(config, op, left, right): From a88017cf262b7d1b8d62d756232db1b5aa81542c Mon Sep 17 00:00:00 2001 From: Victor Uriarte Date: Thu, 16 Feb 2017 22:53:51 -0700 Subject: [PATCH 24/46] Add note documenting #2257 --- _pytest/hookspec.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/_pytest/hookspec.py b/_pytest/hookspec.py index ea1f0443d..552a06575 100644 --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -263,7 +263,14 @@ def pytest_assertrepr_compare(config, op, left, right): # ------------------------------------------------------------------------- def pytest_report_header(config, startdir): - """ return a string to be displayed as header info for terminal reporting.""" + """ return a string to be displayed as header info for terminal reporting. + + .. note:: + + This function should be implemented only in plugins or ``conftest.py`` + files situated at the tests root directory due to how pytest + :ref:`discovers plugins during startup `. + """ @hookspec(firstresult=True) def pytest_report_teststatus(report): From f1900bbea6d7402fb511d84d2b1e58e17b59a03d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 18 Feb 2017 10:34:41 -0200 Subject: [PATCH 25/46] Revert subclassing explicitly from object introduced by accident in #2260 --- _pytest/vendored_packages/pluggy.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_pytest/vendored_packages/pluggy.py b/_pytest/vendored_packages/pluggy.py index 11658c3b1..9c13932b3 100644 --- a/_pytest/vendored_packages/pluggy.py +++ b/_pytest/vendored_packages/pluggy.py @@ -75,7 +75,7 @@ __all__ = ["PluginManager", "PluginValidationError", "HookCallError", _py3 = sys.version_info > (3, 0) -class HookspecMarker(object): +class HookspecMarker: """ Decorator helper class for marking functions as hook specifications. You can instantiate it with a project_name to get a decorator. @@ -113,7 +113,7 @@ class HookspecMarker(object): return setattr_hookspec_opts -class HookimplMarker(object): +class HookimplMarker: """ Decorator helper class for marking functions as hook implementations. You can instantiate with a project_name to get a decorator. @@ -167,7 +167,7 @@ def normalize_hookimpl_opts(opts): opts.setdefault("optionalhook", False) -class _TagTracer(object): +class _TagTracer: def __init__(self): self._tag2proc = {} self.writer = None @@ -214,7 +214,7 @@ class _TagTracer(object): self._tag2proc[tags] = processor -class _TagTracerSub(object): +class _TagTracerSub: def __init__(self, root, tags): self.root = root self.tags = tags @@ -254,7 +254,7 @@ def _wrapped_call(wrap_controller, func): return call_outcome.get_result() -class _CallOutcome(object): +class _CallOutcome: """ Outcome of a function call, either an exception or a proper result. Calling the ``get_result`` method will return the result or reraise the exception raised when the function was called. """ @@ -286,7 +286,7 @@ def _reraise(cls, val, tb): """) -class _TracedHookExecution(object): +class _TracedHookExecution: def __init__(self, pluginmanager, before, after): self.pluginmanager = pluginmanager self.before = before @@ -580,7 +580,7 @@ class PluginManager(object): return orig -class _MultiCall(object): +class _MultiCall: """ execute a call into multiple python functions/methods. """ # XXX note that the __multicall__ argument is supported only @@ -673,7 +673,7 @@ def varnames(func, startindex=None): return x -class _HookRelay(object): +class _HookRelay: """ hook holder object for performing 1:N hook calls where N is the number of registered plugins. @@ -770,7 +770,7 @@ class _HookCaller(object): proc(res[0]) -class HookImpl(object): +class HookImpl: def __init__(self, plugin, plugin_name, function, hook_impl_opts): self.function = function self.argnames = varnames(self.function) From 5fd010c4c3f53d69bcef396989e52a6cbfa59c4e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 19 Feb 2017 09:02:35 -0800 Subject: [PATCH 26/46] Simplify travis.yml with tox environment variables --- .travis.yml | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index f701302d9..1dedddfb4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,34 +8,34 @@ install: "pip install -U tox" env: matrix: # coveralls is not listed in tox's envlist, but should run in travis - - TESTENV=coveralls + - TOXENV=coveralls # note: please use "tox --listenvs" to populate the build matrix below - - TESTENV=linting - - TESTENV=py26 - - TESTENV=py27 - - TESTENV=py33 - - TESTENV=py34 - - TESTENV=py35 - - TESTENV=pypy - - TESTENV=py27-pexpect - - TESTENV=py27-xdist - - TESTENV=py27-trial - - TESTENV=py35-pexpect - - TESTENV=py35-xdist - - TESTENV=py35-trial - - TESTENV=py27-nobyte - - TESTENV=doctesting - - TESTENV=freeze - - TESTENV=docs + - TOXENV=linting + - TOXENV=py26 + - TOXENV=py27 + - TOXENV=py33 + - TOXENV=py34 + - TOXENV=py35 + - TOXENV=pypy + - TOXENV=py27-pexpect + - TOXENV=py27-xdist + - TOXENV=py27-trial + - TOXENV=py35-pexpect + - TOXENV=py35-xdist + - TOXENV=py35-trial + - TOXENV=py27-nobyte + - TOXENV=doctesting + - TOXENV=freeze + - TOXENV=docs matrix: include: - - env: TESTENV=py36 + - env: TOXENV=py36 python: '3.6-dev' - - env: TESTENV=py37 + - env: TOXENV=py37 python: 'nightly' -script: tox --recreate -e $TESTENV +script: tox --recreate notifications: irc: From d3a6be413014b112227cbdb489c62483ec4d9192 Mon Sep 17 00:00:00 2001 From: Katerina Koukiou Date: Wed, 22 Feb 2017 14:17:45 +0100 Subject: [PATCH 27/46] junitxml: Fix double system-out tags per testcase In the xml report we now have two occurences for the system-out tag if the testcase writes to stdout both on call and teardown and fails in teardown. This behaviour is against the xsd. This patch makes sure that the system-out section exists only once per testcase. --- CHANGELOG.rst | 4 ++++ _pytest/junitxml.py | 9 ++++----- testing/test_junitxml.py | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a07062437..d309125d9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,9 @@ 3.0.7 (unreleased) ================== +* junitxml: Fix problematic case where system-out tag occured twice per testcase + element in the XML report. Thanks `@kkoukiou`_ for the PR. + * Fix regression, pytest now skips unittest correctly if run with ``--pdb`` (`#2137`_). Thanks to `@gst`_ for the report and `@mbyt`_ for the PR. @@ -31,6 +34,7 @@ .. _@gst: https://github.com/gst .. _@sirex: https://github.com/sirex .. _@vidartf: https://github.com/vidartf +.. _@kkoukiou: https://github.com/KKoukiou .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 .. _#2160: https://github.com/pytest-dev/pytest/issues/2160 diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py index 317382e63..3f371c9d3 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -119,7 +119,7 @@ class _NodeReporter(object): node = kind(data, message=message) self.append(node) - def _write_captured_output(self, report): + def write_captured_output(self, report): for capname in ('out', 'err'): content = getattr(report, 'capstd' + capname) if content: @@ -128,7 +128,6 @@ class _NodeReporter(object): def append_pass(self, report): self.add_stats('passed') - self._write_captured_output(report) def append_failure(self, report): # msg = str(report.longrepr.reprtraceback.extraline) @@ -147,7 +146,6 @@ class _NodeReporter(object): fail = Junit.failure(message=message) fail.append(bin_xml_escape(report.longrepr)) self.append(fail) - self._write_captured_output(report) def append_collect_error(self, report): # msg = str(report.longrepr.reprtraceback.extraline) @@ -165,7 +163,6 @@ class _NodeReporter(object): msg = "test setup failure" self._add_simple( Junit.error, msg, report.longrepr) - self._write_captured_output(report) def append_skipped(self, report): if hasattr(report, "wasxfail"): @@ -180,7 +177,7 @@ class _NodeReporter(object): Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason), type="pytest.skip", message=skipreason)) - self._write_captured_output(report) + self.write_captured_output(report) def finalize(self): data = self.to_xml().unicode(indent=0) @@ -345,6 +342,8 @@ class LogXML(object): reporter.append_skipped(report) self.update_testcase_duration(report) if report.when == "teardown": + reporter = self._opentestcase(report) + reporter.write_captured_output(report) self.finalize(report) def update_testcase_duration(self, report): diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index abbc9cd33..d167f735d 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -557,6 +557,25 @@ class TestPython: systemout = pnode.find_first_by_tag("system-err") assert "hello-stderr" in systemout.toxml() + def test_avoid_double_stdout(self, testdir): + testdir.makepyfile(""" + import sys + import pytest + + @pytest.fixture + def arg(request): + yield + sys.stdout.write('hello-stdout teardown') + raise ValueError() + def test_function(arg): + sys.stdout.write('hello-stdout call') + """) + result, dom = runandparse(testdir) + node = dom.find_first_by_tag("testsuite") + pnode = node.find_first_by_tag("testcase") + systemout = pnode.find_first_by_tag("system-out") + assert "hello-stdout call" in systemout.toxml() + assert "hello-stdout teardown" in systemout.toxml() def test_mangle_test_address(): from _pytest.junitxml import mangle_test_address From 6ba3475448d3ab78b4bf7de9aa81baa47357a70d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 19 Feb 2017 09:16:32 -0800 Subject: [PATCH 28/46] Make capsys more like stdio streams in python3. Resolves #1407. --- AUTHORS | 1 + CHANGELOG.rst | 9 +++++++++ _pytest/capture.py | 4 ++-- _pytest/compat.py | 16 ++++++++++++++++ testing/test_capture.py | 24 ++++++++++++++++++------ 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index e9e7f7c82..d17963e73 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Andrzej Ostrowski Andy Freeland Anthon van der Neut Antony Lee +Anthony Sottile Armin Rigo Aron Curzon Aviv Palivoda diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 23b87b18c..ee3eae097 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -55,6 +55,14 @@ Changes Thanks `@The-Compiler`_ for the PR. +Bug Fixes +--------- + +* Fix ``AttributeError`` on ``sys.stdout.buffer`` / ``sys.stderr.buffer`` + while using ``capsys`` fixture in python 3. (`#1407`_). + Thanks to `@asottile`_. + + .. _@davidszotten: https://github.com/davidszotten .. _@fushi: https://github.com/fushi .. _@mattduck: https://github.com/mattduck @@ -65,6 +73,7 @@ Changes .. _@unsignedint: https://github.com/unsignedint .. _@Kriechi: https://github.com/Kriechi +.. _#1407: https://github.com/pytest-dev/pytest/issues/1407 .. _#1512: https://github.com/pytest-dev/pytest/issues/1512 .. _#1874: https://github.com/pytest-dev/pytest/pull/1874 .. _#1952: https://github.com/pytest-dev/pytest/pull/1952 diff --git a/_pytest/capture.py b/_pytest/capture.py index 3fe1816d8..6a1cae41d 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -12,8 +12,8 @@ from tempfile import TemporaryFile import py import pytest +from _pytest.compat import CaptureIO -from py.io import TextIO unicode = py.builtin.text patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} @@ -403,7 +403,7 @@ class SysCapture(object): if name == "stdin": tmpfile = DontReadFromInput() else: - tmpfile = TextIO() + tmpfile = CaptureIO() self.tmpfile = tmpfile def start(self): diff --git a/_pytest/compat.py b/_pytest/compat.py index e097dee51..09df385d1 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -251,3 +251,19 @@ else: except UnicodeError: errors = 'replace' return v.encode('ascii', errors) + + +if _PY2: + from py.io import TextIO as CaptureIO +else: + import io + + class CaptureIO(io.TextIOWrapper): + def __init__(self): + super(CaptureIO, self).__init__( + io.BytesIO(), + encoding='UTF-8', newline='', write_through=True, + ) + + def getvalue(self): + return self.buffer.getvalue().decode('UTF-8') diff --git a/testing/test_capture.py b/testing/test_capture.py index 365329f59..364281fe6 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -281,7 +281,7 @@ class TestLoggingInteraction(object): def test_logging(): import logging import pytest - stream = capture.TextIO() + stream = capture.CaptureIO() logging.basicConfig(stream=stream) stream.close() # to free memory/release resources """) @@ -622,16 +622,16 @@ def test_error_during_readouterr(testdir): ]) -class TestTextIO(object): +class TestCaptureIO(object): def test_text(self): - f = capture.TextIO() + f = capture.CaptureIO() f.write("hello") s = f.getvalue() assert s == "hello" f.close() def test_unicode_and_str_mixture(self): - f = capture.TextIO() + f = capture.CaptureIO() if sys.version_info >= (3, 0): f.write("\u00f6") pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") @@ -642,6 +642,18 @@ class TestTextIO(object): f.close() assert isinstance(s, unicode) + @pytest.mark.skipif( + sys.version_info[0] == 2, + reason='python 3 only behaviour', + ) + def test_write_bytes_to_buffer(self): + """In python3, stdout / stderr are text io wrappers (exposing a buffer + property of the underlying bytestream). See issue #1407 + """ + f = capture.CaptureIO() + f.buffer.write(b'foo\r\n') + assert f.getvalue() == 'foo\r\n' + def test_bytes_io(): f = py.io.BytesIO() @@ -900,8 +912,8 @@ class TestStdCapture(object): with self.getcapture() as cap: sys.stdout.write("hello") sys.stderr.write("world") - sys.stdout = capture.TextIO() - sys.stderr = capture.TextIO() + sys.stdout = capture.CaptureIO() + sys.stderr = capture.CaptureIO() print ("not seen") sys.stderr.write("not seen\n") out, err = cap.readouterr() From 8b598f00e9f06a366eef36826070e42e7673fa24 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 19 Feb 2017 10:24:41 -0800 Subject: [PATCH 29/46] Make pytester use pytest's capture implementation --- _pytest/pytester.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 723f8bbb4..17cba5700 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -14,6 +14,7 @@ from weakref import WeakKeyDictionary from py.builtin import print_ +from _pytest.capture import MultiCapture, SysCapture from _pytest._code import Source import py import pytest @@ -737,7 +738,8 @@ class Testdir(object): if kwargs.get("syspathinsert"): self.syspathinsert() now = time.time() - capture = py.io.StdCapture() + capture = MultiCapture(Capture=SysCapture) + capture.start_capturing() try: try: reprec = self.inline_run(*args, **kwargs) @@ -752,7 +754,8 @@ class Testdir(object): class reprec(object): ret = 3 finally: - out, err = capture.reset() + out, err = capture.readouterr() + capture.stop_capturing() sys.stdout.write(out) sys.stderr.write(err) From bb5f200ed7bd75934235e53bc3acfac9c9251c7e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 25 Feb 2017 12:06:51 -0300 Subject: [PATCH 30/46] Improve docs for yield-fixture and with statement a bit Fix #2262 --- doc/en/fixture.rst | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 0a9000611..8547a89a6 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -243,7 +243,9 @@ Fixture finalization / executing teardown code pytest supports execution of fixture specific finalization code when the fixture goes out of scope. By using a ``yield`` statement instead of ``return``, all -the code after the *yield* statement serves as the teardown code.:: +the code after the *yield* statement serves as the teardown code: + +.. code-block:: python # content of conftest.py @@ -275,22 +277,23 @@ occur around each single test. In either case the test module itself does not need to change or know about these details of fixture setup. -Note that we can also seamlessly use the ``yield`` syntax with ``with`` statements:: +Note that we can also seamlessly use the ``yield`` syntax with ``with`` statements: + +.. code-block:: python # content of test_yield2.py + import smtplib import pytest - @pytest.fixture - def passwd(): - with open("/etc/passwd") as f: - yield f.readlines() + @pytest.fixture(scope="module") + def smtp(request): + with smtplib.SMTP("smtp.gmail.com") as smtp: + yield smtp # provide the fixture value - def test_has_lines(passwd): - assert len(passwd) >= 1 -The file ``f`` will be closed after the test finished execution -because the Python ``file`` object supports finalization when +The ``smtp`` connection will be closed after the test finished execution +because the ``smtp`` object automatically closes when the ``with`` statement ends. From 26e50f116233e64d56aef40d491679e76e8d38a1 Mon Sep 17 00:00:00 2001 From: Katerina Koukiou Date: Fri, 3 Feb 2017 10:30:28 +0100 Subject: [PATCH 31/46] junitxml: adjust junitxml output file to comply with JUnit xsd Change XML file structure in the manner that failures in call and errors in teardown in one test will appear under separate testcase elements in the XML report. --- CHANGELOG.rst | 9 ++++++++- _pytest/junitxml.py | 38 ++++++++++++++++++++++++++++++++++++-- testing/test_junitxml.py | 23 +++++++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ee3eae097..44ac7baf3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -87,7 +87,10 @@ Bug Fixes 3.0.7 (unreleased) ======================= -* +* Change junitxml.py to produce reports that comply with Junitxml schema. + If the same test fails with failure in call and then errors in teardown + we split testcase element into two, one containing the error and the other + the failure. (`#2228`_) Thanks to `@kkoukiou`_ for the PR. * @@ -95,6 +98,10 @@ Bug Fixes * +.. _@kkoukiou: https://github.com/KKoukiou + +.. _#2228: https://github.com/pytest-dev/pytest/issues/2228 + 3.0.6 (2017-01-22) ================== diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py index f486ea10c..4f7792aec 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -273,6 +273,9 @@ class LogXML(object): self.node_reporters = {} # nodeid -> _NodeReporter self.node_reporters_ordered = [] self.global_properties = [] + # List of reports that failed on call but teardown is pending. + self.open_reports = [] + self.cnt_double_fail_tests = 0 def finalize(self, report): nodeid = getattr(report, 'nodeid', report) @@ -332,14 +335,33 @@ class LogXML(object): -> teardown node2 -> teardown node1 """ + close_report = None if report.passed: if report.when == "call": # ignore setup/teardown reporter = self._opentestcase(report) reporter.append_pass(report) elif report.failed: + if report.when == "teardown": + # The following vars are needed when xdist plugin is used + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + (rep for rep in self.open_reports + if (rep.nodeid == report.nodeid and + getattr(rep, "item_index", None) == report_ii and + getattr(rep, "worker_id", None) == report_wid + ) + ), None) + if close_report: + # We need to open new testcase in case we have failure in + # call and error in teardown in order to follow junit + # schema + self.finalize(close_report) + self.cnt_double_fail_tests += 1 reporter = self._opentestcase(report) if report.when == "call": reporter.append_failure(report) + self.open_reports.append(report) else: reporter.append_error(report) elif report.skipped: @@ -348,6 +370,17 @@ class LogXML(object): self.update_testcase_duration(report) if report.when == "teardown": self.finalize(report) + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + (rep for rep in self.open_reports + if (rep.nodeid == report.nodeid and + getattr(rep, "item_index", None) == report_ii and + getattr(rep, "worker_id", None) == report_wid + ) + ), None) + if close_report: + self.open_reports.remove(close_report) def update_testcase_duration(self, report): """accumulates total duration for nodeid from given report and updates @@ -380,8 +413,9 @@ class LogXML(object): suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time - numtests = self.stats['passed'] + self.stats['failure'] + self.stats['skipped'] + self.stats['error'] - + numtests = (self.stats['passed'] + self.stats['failure'] + + self.stats['skipped'] + self.stats['error'] - + self.cnt_double_fail_tests) logfile.write('') logfile.write(Junit.testsuite( diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 70c02332c..b4e4c5b14 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -189,6 +189,29 @@ class TestPython(object): fnode.assert_attr(message="test teardown failure") assert "ValueError" in fnode.toxml() + def test_call_failure_teardown_error(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def arg(): + yield + raise Exception("Teardown Exception") + def test_function(arg): + raise Exception("Call Exception") + """) + result, dom = runandparse(testdir) + assert result.ret + node = dom.find_first_by_tag("testsuite") + node.assert_attr(errors=1, failures=1, tests=1) + first, second = dom.find_by_tag("testcase") + if not first or not second or first == second: + assert 0 + fnode = first.find_first_by_tag("failure") + fnode.assert_attr(message="Exception: Call Exception") + snode = second.find_first_by_tag("error") + snode.assert_attr(message="test teardown failure") + def test_skip_contains_name_reason(self, testdir): testdir.makepyfile(""" import pytest From 6a52fe165070dcbeda9b7c5b622975effcab5f40 Mon Sep 17 00:00:00 2001 From: Omer Hadari Date: Sat, 4 Mar 2017 10:26:46 +0200 Subject: [PATCH 32/46] fixed internal error on unprintable raised AssertionErrors --- _pytest/_code/code.py | 6 ++++-- testing/test_assertion.py | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index 616d5c431..6eceb0c7f 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -352,6 +352,8 @@ class ExceptionInfo(object): help for navigating the traceback. """ _striptext = '' + _assert_start_repr = "AssertionError(u\'assert " if sys.version_info[0] < 3 else "AssertionError(\'assert " + def __init__(self, tup=None, exprinfo=None): import _pytest._code if tup is None: @@ -359,8 +361,8 @@ class ExceptionInfo(object): if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], 'msg', None) if exprinfo is None: - exprinfo = py._builtin._totext(tup[1]) - if exprinfo and exprinfo.startswith('assert '): + exprinfo = py.io.saferepr(tup[1]) + if exprinfo and exprinfo.startswith(self._assert_start_repr): self._striptext = 'AssertionError: ' self._excinfo = tup #: the exception class diff --git a/testing/test_assertion.py b/testing/test_assertion.py index dfc9f60fb..bc814590a 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -916,6 +916,25 @@ def test_assert_with_unicode(monkeypatch, testdir): result = testdir.runpytest() result.stdout.fnmatch_lines(['*AssertionError*']) +def test_raise_unprintable_assertion_error(testdir): + testdir.makepyfile(r""" + def test_raise_assertion_error(): + raise AssertionError('\xff') + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([r"> raise AssertionError('\xff')", 'E AssertionError: *']) + +def test_raise_assertion_error_raisin_repr(testdir): + testdir.makepyfile(u""" + class RaisingRepr(object): + def __repr__(self): + raise Exception() + def test_raising_repr(): + raise AssertionError(RaisingRepr()) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['E AssertionError: ']) + def test_issue_1944(testdir): testdir.makepyfile(""" def f(): From 6aaf7ae18b2c786bbf7ff07d223860ee3f98c20c Mon Sep 17 00:00:00 2001 From: Omer Hadari Date: Sat, 4 Mar 2017 10:32:14 +0200 Subject: [PATCH 33/46] added to authors and changelog --- AUTHORS | 1 + CHANGELOG.rst | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index b49405bf7..c55be41e3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -147,3 +147,4 @@ Victor Uriarte Vidar T. Fauske Wouter van Ackooy Xuecong Liao +Omer Hadari diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 32726274f..de3f334c2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -22,7 +22,8 @@ * Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. -* +* Fix internal errors when an unprintable ``AssertionError`` is raised inside a test. + Thanks `@omerhadari`_ for the PR. * Skipping plugin now also works with test items generated by custom collectors (`#2231`_). Thanks to `@vidartf`_. From f71467f5b1c84fd662d4f1cca582e2d2d34a08d7 Mon Sep 17 00:00:00 2001 From: Omer Hadari Date: Sat, 4 Mar 2017 10:55:59 +0200 Subject: [PATCH 34/46] added link to changelog --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index de3f334c2..216891484 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -43,6 +43,7 @@ .. _@sirex: https://github.com/sirex .. _@vidartf: https://github.com/vidartf .. _@kkoukiou: https://github.com/KKoukiou +.. _@omerhadari: https://github.com/omerhadari .. _#2248: https://github.com/pytest-dev/pytest/issues/2248 .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 From b61dcded3781bdcd4c76ccb614e1df58a622e982 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 4 Mar 2017 07:17:39 -0300 Subject: [PATCH 35/46] Allow py37-nightly to fail on Travis Related to #2285 --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1dedddfb4..41537a466 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,9 @@ matrix: python: '3.6-dev' - env: TOXENV=py37 python: 'nightly' + allow_failures: + - env: TOXENV=py37 + python: 'nightly' script: tox --recreate From 02dc54531150d715725885cb678209a4048142fb Mon Sep 17 00:00:00 2001 From: Omer Hadari Date: Sat, 4 Mar 2017 12:49:00 +0200 Subject: [PATCH 36/46] added in the correct alphabitcal order --- AUTHORS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index c55be41e3..2332a51ef 100644 --- a/AUTHORS +++ b/AUTHORS @@ -101,7 +101,6 @@ Mathieu Clabaut Matt Bachmann Matt Williams Matthias Hafner -mbyt Michael Aquilina Michael Birtwell Michael Droettboom @@ -113,6 +112,7 @@ Nicolas Delaby Oleg Pidsadnyi Oliver Bestwalter Omar Kohl +Omer Hadari Patrick Hayes Pieter Mulder Piotr Banaszkiewicz @@ -147,4 +147,4 @@ Victor Uriarte Vidar T. Fauske Wouter van Ackooy Xuecong Liao -Omer Hadari +mbyt From dd25ae7f3369fdbb4ec9fe3d50f0e4b25c9e6c25 Mon Sep 17 00:00:00 2001 From: Omer Hadari Date: Sat, 4 Mar 2017 12:50:02 +0200 Subject: [PATCH 37/46] added in the correct alphabitcal order --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 2332a51ef..821bd2a6d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -101,6 +101,7 @@ Mathieu Clabaut Matt Bachmann Matt Williams Matthias Hafner +mbyt Michael Aquilina Michael Birtwell Michael Droettboom @@ -147,4 +148,3 @@ Victor Uriarte Vidar T. Fauske Wouter van Ackooy Xuecong Liao -mbyt From e05ff0338a0220b63de93461eacf0706d55f8623 Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Mon, 6 Mar 2017 01:01:55 +0800 Subject: [PATCH 38/46] assert.rst: typographical correction --- doc/en/assert.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index d93da178d..aeb9a5d35 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -287,5 +287,5 @@ For further information, Benjamin Peterson wrote up `Behind the scenes of pytest ``--nomagic``. .. versionchanged:: 3.0 - Removes the ``--no-assert`` and``--nomagic`` options. + Removes the ``--no-assert`` and ``--nomagic`` options. Removes the ``--assert=reinterp`` option. From cee578e32786986cb79495a2ea0e5c5e4eb425ce Mon Sep 17 00:00:00 2001 From: fbjorn Date: Sun, 5 Mar 2017 22:44:13 +0300 Subject: [PATCH 39/46] Fix trailing whitespace in terminal output --- AUTHORS | 1 + CHANGELOG.rst | 6 ++++-- _pytest/terminal.py | 4 ++-- testing/test_config.py | 2 +- testing/test_terminal.py | 9 +++++++++ 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 821bd2a6d..ce19f1f21 100644 --- a/AUTHORS +++ b/AUTHORS @@ -43,6 +43,7 @@ Dave Hunt David Díaz-Barquero David Mohr David Vierra +Denis Kirisov Diego Russo Dmitry Dygalo Duncan Betts diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 216891484..cf3df9c87 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,8 +27,8 @@ * Skipping plugin now also works with test items generated by custom collectors (`#2231`_). Thanks to `@vidartf`_. - -* + +* Fix trailing whitespace in console output if no .ini file presented (`#2281`_). Thanks `@fbjorn`_ for the PR. * Conditionless ``xfail`` markers no longer rely on the underlying test item being an instance of ``PyobjMixin``, and can therefore apply to tests not @@ -44,6 +44,7 @@ .. _@vidartf: https://github.com/vidartf .. _@kkoukiou: https://github.com/KKoukiou .. _@omerhadari: https://github.com/omerhadari +.. _@fbjorn: https://github.com/fbjorn .. _#2248: https://github.com/pytest-dev/pytest/issues/2248 .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 @@ -51,6 +52,7 @@ .. _#2231: https://github.com/pytest-dev/pytest/issues/2231 .. _#2234: https://github.com/pytest-dev/pytest/issues/2234 .. _#2238: https://github.com/pytest-dev/pytest/issues/2238 +.. _#2281: https://github.com/pytest-dev/pytest/issues/2281 .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ diff --git a/_pytest/terminal.py b/_pytest/terminal.py index 16bf75733..79e065329 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -295,8 +295,8 @@ class TerminalReporter: def pytest_report_header(self, config): inifile = "" if config.inifile: - inifile = config.rootdir.bestrelpath(config.inifile) - lines = ["rootdir: %s, inifile: %s" %(config.rootdir, inifile)] + inifile = " " + config.rootdir.bestrelpath(config.inifile) + lines = ["rootdir: %s, inifile:%s" % (config.rootdir, inifile)] plugininfo = config.pluginmanager.list_plugin_distinfo() if plugininfo: diff --git a/testing/test_config.py b/testing/test_config.py index 3ce51d639..b6ccd7085 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -519,7 +519,7 @@ def test_consider_args_after_options_for_rootdir_and_inifile(testdir, args): args[i] = d2 with root.as_cwd(): result = testdir.runpytest(*args) - result.stdout.fnmatch_lines(['*rootdir: *myroot, inifile: ']) + result.stdout.fnmatch_lines(['*rootdir: *myroot, inifile:']) @pytest.mark.skipif("sys.platform == 'win32'") diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 3efd7b1f9..0f919b5ed 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -906,3 +906,12 @@ def test_summary_stats(exp_line, exp_color, stats_arg): print("Actually got: \"%s\"; with color \"%s\"" % (line, color)) assert line == exp_line assert color == exp_color + + +def test_no_trailing_whitespace_after_inifile_word(testdir): + result = testdir.runpytest('') + assert 'inifile:\n' in result.stdout.str() + + testdir.makeini('[pytest]') + result = testdir.runpytest('') + assert 'inifile: tox.ini\n' in result.stdout.str() From 22864b75ee080c8c600813b4f8985d2a70870dcb Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 9 Mar 2017 23:08:50 -0300 Subject: [PATCH 40/46] Refactor recwarn to use warnings.catch_warnings instead of custom code Since we dropped 2.5, we can now use warnings.catch_warnings to do the "catch warnings" magic for us, simplifying the code a bit. --- _pytest/recwarn.py | 42 +++++++++-------------------------------- testing/test_recwarn.py | 4 ---- 2 files changed, 9 insertions(+), 37 deletions(-) diff --git a/_pytest/recwarn.py b/_pytest/recwarn.py index 9031bdbda..43f68ed12 100644 --- a/_pytest/recwarn.py +++ b/_pytest/recwarn.py @@ -6,11 +6,10 @@ import py import sys import warnings import pytest -from collections import namedtuple @pytest.yield_fixture -def recwarn(request): +def recwarn(): """Return a WarningsRecorder instance that provides these methods: * ``pop(category=None)``: return last warning matching the category. @@ -115,19 +114,14 @@ def warns(expected_warning, *args, **kwargs): return func(*args[1:], **kwargs) -RecordedWarning = namedtuple('RecordedWarning', ( - 'message', 'category', 'filename', 'lineno', 'file', 'line', -)) - - -class WarningsRecorder(object): +class WarningsRecorder(warnings.catch_warnings): """A context manager to record raised warnings. Adapted from `warnings.catch_warnings`. """ - def __init__(self, module=None): - self._module = sys.modules['warnings'] if module is None else module + def __init__(self): + super(WarningsRecorder, self).__init__(record=True) self._entered = False self._list = [] @@ -164,38 +158,20 @@ class WarningsRecorder(object): if self._entered: __tracebackhide__ = True raise RuntimeError("Cannot enter %r twice" % self) - self._entered = True - self._filters = self._module.filters - self._module.filters = self._filters[:] - self._showwarning = self._module.showwarning - - def showwarning(message, category, filename, lineno, - file=None, line=None): - self._list.append(RecordedWarning( - message, category, filename, lineno, file, line)) - - # still perform old showwarning functionality - self._showwarning( - message, category, filename, lineno, file=file, line=line) - - self._module.showwarning = showwarning - - # allow the same warning to be raised more than once - - self._module.simplefilter('always') + self._list = super(WarningsRecorder, self).__enter__() + warnings.simplefilter('always') return self def __exit__(self, *exc_info): if not self._entered: __tracebackhide__ = True raise RuntimeError("Cannot exit %r without entering first" % self) - self._module.filters = self._filters - self._module.showwarning = self._showwarning + super(WarningsRecorder, self).__exit__(*exc_info) class WarningsChecker(WarningsRecorder): - def __init__(self, expected_warning=None, module=None): - super(WarningsChecker, self).__init__(module=module) + def __init__(self, expected_warning=None): + super(WarningsChecker, self).__init__() msg = ("exceptions must be old-style classes or " "derived from Warning, not %s") diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 231ef028e..c5244411c 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -217,7 +217,6 @@ class TestWarns(object): excinfo.match(re.escape(message_template.format(warning_classes, [each.message for each in warninfo]))) - def test_record(self): with pytest.warns(UserWarning) as record: warnings.warn("user", UserWarning) @@ -225,9 +224,6 @@ class TestWarns(object): assert len(record) == 1 assert str(record[0].message) == "user" - print(repr(record[0])) - assert str(record[0].message) in repr(record[0]) - def test_record_only(self): with pytest.warns(None) as record: warnings.warn("user", UserWarning) From b1ab2ca963b776fb145f71e49f2186e2b4c02618 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 13 Mar 2017 18:37:49 -0400 Subject: [PATCH 41/46] Bump to version 3.0.7 and update CHANGELOG --- CHANGELOG.rst | 3 +-- _pytest/__init__.py | 2 +- doc/en/announce/release-3.0.7.rst | 33 +++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 doc/en/announce/release-3.0.7.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cf3df9c87..19b62a1d0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,4 +1,4 @@ -3.0.7 (unreleased) +3.0.7 (2017-03-14) ================== @@ -35,7 +35,6 @@ collected by the built-in python test collector. Thanks `@barneygale`_ for the PR. -* .. _@pfhayes: https://github.com/pfhayes .. _@bluetech: https://github.com/bluetech diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 16616ffb0..45375bc4c 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.7.dev0' +__version__ = '3.0.7' diff --git a/doc/en/announce/release-3.0.7.rst b/doc/en/announce/release-3.0.7.rst new file mode 100644 index 000000000..591557aa7 --- /dev/null +++ b/doc/en/announce/release-3.0.7.rst @@ -0,0 +1,33 @@ +pytest-3.0.7 +============ + +pytest 3.0.7 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Anthony Sottile +* Barney Gale +* Bruno Oliveira +* Florian Bruhin +* Floris Bruynooghe +* Ionel Cristian Mărieș +* Katerina Koukiou +* NODA, Kai +* Omer Hadari +* Patrick Hayes +* Ran Benita +* Ronny Pfannschmidt +* Victor Uriarte +* Vidar Tonaas Fauske +* Ville Skyttä +* fbjorn +* mbyt + +Happy testing, +The pytest Development Team From d58780f9a6c5b5422570e51d682f38f4504b945a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 13 Mar 2017 18:41:20 -0400 Subject: [PATCH 42/46] Update regendoc --- doc/en/assert.rst | 10 +++--- doc/en/cache.rst | 16 ++++----- doc/en/capture.rst | 4 +-- doc/en/doctest.rst | 2 +- doc/en/example/markers.rst | 56 ++++++++++++++--------------- doc/en/example/nonpython.rst | 12 +++---- doc/en/example/parametrize.rst | 32 ++++++++--------- doc/en/example/pythoncollection.rst | 6 ++-- doc/en/example/reportingdemo.rst | 32 ++++++++--------- doc/en/example/simple.rst | 44 +++++++++++------------ doc/en/fixture.rst | 30 ++++++++-------- doc/en/getting-started.rst | 8 ++--- doc/en/index.rst | 4 +-- doc/en/parametrize.rst | 12 +++---- doc/en/skipping.rst | 4 +-- doc/en/tmpdir.rst | 4 +-- doc/en/unittest.rst | 4 +-- 17 files changed, 138 insertions(+), 142 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index aeb9a5d35..b674f90b0 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -26,8 +26,8 @@ you will see the return value of the function call:: $ pytest test_assert1.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_assert1.py F @@ -170,8 +170,8 @@ if you run this module:: $ pytest test_assert2.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_assert2.py F @@ -183,7 +183,7 @@ if you run this module:: set1 = set("1308") set2 = set("8035") > assert set1 == set2 - E assert {'0', '1', '3', '8'} == {'0', '3', '5', '8'} + E AssertionError: assert {'0', '1', '3', '8'} == {'0', '3', '5', '8'} E Extra items in the left set: E '1' E Extra items in the right set: diff --git a/doc/en/cache.rst b/doc/en/cache.rst index 3b4703bf5..b3b992507 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -80,9 +80,9 @@ If you then run it with ``--lf``:: $ pytest --lf ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 run-last-failure: rerun last 2 failures - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items test_50.py FF @@ -122,9 +122,9 @@ of ``FF`` and dots):: $ pytest --ff ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 run-last-failure: rerun last 2 failures first - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items test_50.py FF................................................ @@ -227,14 +227,14 @@ You can always peek at the content of the cache using the $ py.test --cache-show ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: cachedir: $REGENDOC_TMPDIR/.cache ------------------------------- cache values ------------------------------- - example/value contains: - 42 cache/lastfailed contains: {'test_caching.py::test_function': True} + example/value contains: + 42 ======= no tests ran in 0.12 seconds ======== diff --git a/doc/en/capture.rst b/doc/en/capture.rst index 201006637..2f666b7bc 100644 --- a/doc/en/capture.rst +++ b/doc/en/capture.rst @@ -64,8 +64,8 @@ of the failing function and hide the other one:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items test_module.py .F diff --git a/doc/en/doctest.rst b/doc/en/doctest.rst index 4cbf92b13..fd92eb7be 100644 --- a/doc/en/doctest.rst +++ b/doc/en/doctest.rst @@ -49,7 +49,7 @@ then you can just invoke ``pytest`` without command line options:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini collected 1 items diff --git a/doc/en/example/markers.rst b/doc/en/example/markers.rst index 7dd5c8359..0c96d408c 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -31,9 +31,9 @@ You can then restrict a test run to only run tests marked with ``webtest``:: $ pytest -v -m webtest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items test_server.py::test_send_http PASSED @@ -45,9 +45,9 @@ Or the inverse, running all tests except the webtest ones:: $ pytest -v -m "not webtest" ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items test_server.py::test_something_quick PASSED @@ -66,9 +66,9 @@ tests based on their module, class, method, or function name:: $ pytest -v test_server.py::TestClass::test_method ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 5 items test_server.py::TestClass::test_method PASSED @@ -79,9 +79,9 @@ You can also select on the class:: $ pytest -v test_server.py::TestClass ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items test_server.py::TestClass::test_method PASSED @@ -92,9 +92,9 @@ Or select multiple nodes:: $ pytest -v test_server.py::TestClass test_server.py::test_send_http ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items test_server.py::TestClass::test_method PASSED @@ -130,9 +130,9 @@ select tests based on their names:: $ pytest -v -k http # running with the above defined example module ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items test_server.py::test_send_http PASSED @@ -144,9 +144,9 @@ And you can also run all tests except the ones that match the keyword:: $ pytest -k "not send_http" -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items test_server.py::test_something_quick PASSED @@ -160,9 +160,9 @@ Or to select "http" and "quick" tests:: $ pytest -k "http or quick" -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items test_server.py::test_send_http PASSED @@ -352,8 +352,8 @@ the test needs:: $ pytest -E stage2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_someenv.py s @@ -364,8 +364,8 @@ and here is one that specifies exactly the environment needed:: $ pytest -E stage1 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_someenv.py . @@ -485,8 +485,8 @@ then you will see two tests skipped and two executed tests as expected:: $ pytest -rs # this option reports skip reasons ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items test_plat.py s.s. @@ -499,8 +499,8 @@ Note that if you specify a platform via the marker-command line option like this $ pytest -m linux ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items test_plat.py . @@ -551,8 +551,8 @@ We can now use the ``-m option`` to select one set:: $ pytest -m interface --tb=short ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items test_module.py FF @@ -573,8 +573,8 @@ or to select both "event" and "interface" tests:: $ pytest -m "interface or event" --tb=short ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items test_module.py FFF diff --git a/doc/en/example/nonpython.rst b/doc/en/example/nonpython.rst index 6510c861c..38918dba4 100644 --- a/doc/en/example/nonpython.rst +++ b/doc/en/example/nonpython.rst @@ -27,8 +27,8 @@ now execute the test specification:: nonpython $ pytest test_simple.yml ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR/nonpython, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collected 2 items test_simple.yml F. @@ -59,9 +59,9 @@ consulted when reporting in ``verbose`` mode:: nonpython $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR/nonpython, inifile: + rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collecting ... collected 2 items test_simple.yml::hello FAILED @@ -81,8 +81,8 @@ interesting to just look at the collection tree:: nonpython $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR/nonpython, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collected 2 items diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index 609158590..9dd2829de 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -130,8 +130,8 @@ objects, they are still using the default pytest representation:: $ pytest test_time.py --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 6 items @@ -181,8 +181,8 @@ this is a fully self-contained example which you can run with:: $ pytest test_scenarios.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items test_scenarios.py .... @@ -194,8 +194,8 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia $ pytest --collect-only test_scenarios.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -259,8 +259,8 @@ Let's first see how it looks like at collection time:: $ pytest test_backends.py --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -320,8 +320,8 @@ The result of this test will be successful:: $ pytest test_indirect_list.py --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -397,12 +397,10 @@ is to be run with different sets of arguments for its three arguments: Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize):: . $ pytest -rs -q multipython.py - sssssssssssssssssssssssssssssssssssssssssssss... + sssssssssssssss.........sss.........sss......... ======= short test summary info ======== - SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.6' not found - SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python3.4' not found - SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.7' not found - 3 passed, 45 skipped in 0.12 seconds + SKIP [21] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.6' not found + 27 passed, 21 skipped in 0.12 seconds Indirect parametrization of optional implementations/imports -------------------------------------------------------------------- @@ -449,8 +447,8 @@ If you run this with reporting for skips enabled:: $ pytest -rs test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items test_module.py .s diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index 0d53b0593..428b832f7 100644 --- a/doc/en/example/pythoncollection.rst +++ b/doc/en/example/pythoncollection.rst @@ -117,7 +117,7 @@ then the test collection looks like this:: $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini collected 2 items @@ -163,7 +163,7 @@ You can always peek at the collection tree without running tests like this:: . $ pytest --collect-only pythoncollection.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini collected 3 items @@ -230,7 +230,7 @@ will be left out:: $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini collected 0 items diff --git a/doc/en/example/reportingdemo.rst b/doc/en/example/reportingdemo.rst index 141208321..1323f1933 100644 --- a/doc/en/example/reportingdemo.rst +++ b/doc/en/example/reportingdemo.rst @@ -11,8 +11,8 @@ get on the terminal - we are working on that):: assertion $ pytest failure_demo.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR/assertion, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR/assertion, inifile: collected 42 items failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF @@ -81,7 +81,7 @@ get on the terminal - we are working on that):: def test_eq_text(self): > assert 'spam' == 'eggs' - E assert 'spam' == 'eggs' + E AssertionError: assert 'spam' == 'eggs' E - spam E + eggs @@ -92,7 +92,7 @@ get on the terminal - we are working on that):: def test_eq_similar_text(self): > assert 'foo 1 bar' == 'foo 2 bar' - E assert 'foo 1 bar' == 'foo 2 bar' + E AssertionError: assert 'foo 1 bar' == 'foo 2 bar' E - foo 1 bar E ? ^ E + foo 2 bar @@ -105,7 +105,7 @@ get on the terminal - we are working on that):: def test_eq_multiline_text(self): > assert 'foo\nspam\nbar' == 'foo\neggs\nbar' - E assert 'foo\nspam\nbar' == 'foo\neggs\nbar' + E AssertionError: assert 'foo\nspam\nbar' == 'foo\neggs\nbar' E foo E - spam E + eggs @@ -120,7 +120,7 @@ get on the terminal - we are working on that):: a = '1'*100 + 'a' + '2'*100 b = '1'*100 + 'b' + '2'*100 > assert a == b - E assert '111111111111...2222222222222' == '1111111111111...2222222222222' + E AssertionError: assert '111111111111...2222222222222' == '1111111111111...2222222222222' E Skipping 90 identical leading characters in diff, use -v to show E Skipping 91 identical trailing characters in diff, use -v to show E - 1111111111a222222222 @@ -137,7 +137,7 @@ get on the terminal - we are working on that):: a = '1\n'*100 + 'a' + '2\n'*100 b = '1\n'*100 + 'b' + '2\n'*100 > assert a == b - E assert '1\n1\n1\n1\n...n2\n2\n2\n2\n' == '1\n1\n1\n1\n1...n2\n2\n2\n2\n' + E AssertionError: assert '1\n1\n1\n1\n...n2\n2\n2\n2\n' == '1\n1\n1\n1\n1...n2\n2\n2\n2\n' E Skipping 190 identical leading characters in diff, use -v to show E Skipping 191 identical trailing characters in diff, use -v to show E 1 @@ -183,7 +183,7 @@ get on the terminal - we are working on that):: def test_eq_dict(self): > assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} - E assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} + E AssertionError: assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} E Omitting 1 identical items, use -v to show E Differing items: E {'b': 1} != {'b': 2} @@ -238,7 +238,7 @@ get on the terminal - we are working on that):: def test_not_in_text_multiline(self): text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' > assert 'foo' not in text - E assert 'foo' not in 'some multiline\ntext\nw...ncludes foo\nand a\ntail' + E AssertionError: assert 'foo' not in 'some multiline\ntext\nw...ncludes foo\nand a\ntail' E 'foo' is contained here: E some multiline E text @@ -256,7 +256,7 @@ get on the terminal - we are working on that):: def test_not_in_text_single(self): text = 'single foo line' > assert 'foo' not in text - E assert 'foo' not in 'single foo line' + E AssertionError: assert 'foo' not in 'single foo line' E 'foo' is contained here: E single foo line E ? +++ @@ -269,7 +269,7 @@ get on the terminal - we are working on that):: def test_not_in_text_single_long(self): text = 'head ' * 50 + 'foo ' + 'tail ' * 20 > assert 'foo' not in text - E assert 'foo' not in 'head head head head hea...ail tail tail tail tail ' + E AssertionError: assert 'foo' not in 'head head head head hea...ail tail tail tail tail ' E 'foo' is contained here: E head head foo tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail E ? +++ @@ -282,7 +282,7 @@ get on the terminal - we are working on that):: def test_not_in_text_single_long_term(self): text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 > assert 'f'*70 not in text - E assert 'fffffffffff...ffffffffffff' not in 'head head he...l tail tail ' + E AssertionError: assert 'fffffffffff...ffffffffffff' not in 'head head he...l tail tail ' E 'ffffffffffffffffff...fffffffffffffffffff' is contained here: E head head fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffftail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail E ? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -305,7 +305,7 @@ get on the terminal - we are working on that):: class Foo(object): b = 1 > assert Foo().b == 2 - E assert 1 == 2 + E AssertionError: assert 1 == 2 E + where 1 = .Foo object at 0xdeadbeef>.b E + where .Foo object at 0xdeadbeef> = .Foo'>() @@ -338,7 +338,7 @@ get on the terminal - we are working on that):: class Bar(object): b = 2 > assert Foo().b == Bar().b - E assert 1 == 2 + E AssertionError: assert 1 == 2 E + where 1 = .Foo object at 0xdeadbeef>.b E + where .Foo object at 0xdeadbeef> = .Foo'>() E + and 2 = .Bar object at 0xdeadbeef>.b @@ -480,7 +480,7 @@ get on the terminal - we are working on that):: s = "123" g = "456" > assert s.startswith(g) - E assert False + E AssertionError: assert False E + where False = ('456') E + where = '123'.startswith @@ -495,7 +495,7 @@ get on the terminal - we are working on that):: def g(): return "456" > assert f().startswith(g()) - E assert False + E AssertionError: assert False E + where False = ('456') E + where = '123'.startswith E + where '123' = .f at 0xdeadbeef>() diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index d4b3fba43..b9f3daecc 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -113,8 +113,8 @@ directory with the above conftest.py:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items ======= no tests ran in 0.12 seconds ======== @@ -164,8 +164,8 @@ and when running it will see a skipped "slow" test:: $ pytest -rs # "-rs" means report details on the little 's' ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items test_module.py .s @@ -178,8 +178,8 @@ Or run it including the ``slow`` marked test:: $ pytest --runslow ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items test_module.py .. @@ -302,9 +302,9 @@ which will add the string to the test header accordingly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 project deps: mylib-1.1 - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items ======= no tests ran in 0.12 seconds ======== @@ -327,11 +327,11 @@ which will add info only when run with "--v":: $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache info1: did you know that ... did you? - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 0 items ======= no tests ran in 0.12 seconds ======== @@ -340,8 +340,8 @@ and nothing when run plainly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items ======= no tests ran in 0.12 seconds ======== @@ -374,8 +374,8 @@ Now we can profile which test functions execute the slowest:: $ pytest --durations=3 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items test_some_are_slow.py ... @@ -440,8 +440,8 @@ If we run this:: $ pytest -rx ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items test_step.py .Fx. @@ -519,8 +519,8 @@ We can run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 7 items test_step.py .Fx. @@ -627,8 +627,8 @@ and run them:: $ pytest test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items test_module.py FF @@ -721,8 +721,8 @@ and run it:: $ pytest -s test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items test_module.py Esetting up a test failed! test_module.py::test_setup_fails diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 8547a89a6..01706479d 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -70,8 +70,8 @@ marked ``smtp`` fixture function. Running the test looks like this:: $ pytest test_smtpsimple.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_smtpsimple.py F @@ -188,8 +188,8 @@ inspect what is going on and can now run the tests:: $ pytest test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items test_module.py FF @@ -355,8 +355,8 @@ again, nothing much has changed:: $ pytest -s -q --tb=no FFfinalizing (smtp.gmail.com) - . - 2 failed, 1 passed in 0.12 seconds + + 2 failed in 0.12 seconds Let's quickly create another test module that actually sets the server URL in its module namespace:: @@ -453,7 +453,7 @@ So let's just do another run:: response, msg = smtp.ehlo() assert response == 250 > assert b"smtp.gmail.com" in msg - E assert b'smtp.gmail.com' in b'mail.python.org\nSIZE 51200000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN\nSMTPUTF8' + E AssertionError: assert b'smtp.gmail.com' in b'mail.python.org\nSIZE 51200000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN\nSMTPUTF8' test_module.py:5: AssertionError -------------------------- Captured stdout setup --------------------------- @@ -523,9 +523,9 @@ Running the above tests results in the following test IDs being used:: $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: - collected 11 items + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: + collected 10 items @@ -539,8 +539,6 @@ Running the above tests results in the following test IDs being used:: - - ======= no tests ran in 0.12 seconds ======== @@ -576,9 +574,9 @@ Here we declare an ``app`` fixture which receives the previously defined $ pytest -v test_appsetup.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 2 items test_appsetup.py::test_smtp_exists[smtp.gmail.com] PASSED @@ -645,9 +643,9 @@ Let's run the tests in verbose mode and with looking at the print-output:: $ pytest -v -s test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache - rootdir: $REGENDOC_TMPDIR, inifile: + rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items test_module.py::test_0[1] SETUP otherarg 1 diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 557e8245d..c65cfe94f 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -26,7 +26,7 @@ Installation:: To check your installation has installed the correct version:: $ pytest --version - This is pytest version 3.0.6, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py + This is pytest version 3.0.7, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py .. _`simpletest`: @@ -46,8 +46,8 @@ That's it. You can execute the test function now:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_sample.py F @@ -134,7 +134,7 @@ run the module by passing its filename:: def test_two(self): x = "hello" > assert hasattr(x, 'check') - E assert False + E AssertionError: assert False E + where False = hasattr('hello', 'check') test_class.py:8: AssertionError diff --git a/doc/en/index.rst b/doc/en/index.rst index 32671ddb2..24ae67957 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -25,8 +25,8 @@ To execute it:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_sample.py F diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index a3499ea3b..b93099e7d 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -55,8 +55,8 @@ them in turn:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items test_expectation.py ..F @@ -73,7 +73,7 @@ them in turn:: ]) def test_eval(test_input, expected): > assert eval(test_input) == expected - E assert 54 == 42 + E AssertionError: assert 54 == 42 E + where 54 = eval('6*9') test_expectation.py:8: AssertionError @@ -103,8 +103,8 @@ Let's run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items test_expectation.py ..x @@ -186,7 +186,7 @@ Let's also run with a stringinput that will lead to a failing test:: def test_valid_string(stringinput): > assert stringinput.isalpha() - E assert False + E AssertionError: assert False E + where False = () E + where = '!'.isalpha diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index 0a2e18208..0597c76e7 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -224,8 +224,8 @@ Running it with the report-on-xfail option gives this output:: example $ pytest -rx xfail_demo.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR/example, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR/example, inifile: collected 7 items xfail_demo.py xxxxxxx diff --git a/doc/en/tmpdir.rst b/doc/en/tmpdir.rst index 7a23c84de..637047195 100644 --- a/doc/en/tmpdir.rst +++ b/doc/en/tmpdir.rst @@ -29,8 +29,8 @@ Running this would result in a passed test except for the last $ pytest test_tmpdir.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items test_tmpdir.py F diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 1bee0e146..6809f68fd 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -108,8 +108,8 @@ the ``self.db`` values in the traceback:: $ pytest test_unittest_db.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items test_unittest_db.py FF From 3c07072bfd3580bcd1b7334f77d2352cb8a9814d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 13 Mar 2017 19:52:35 -0300 Subject: [PATCH 43/46] Fix test_recwarn in Python 3.6 No longer test for implementation details of recwarn since warnings.catch_warnings has changed significantly in 3.6. --- testing/test_recwarn.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index c5244411c..1269af431 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -8,25 +8,19 @@ from _pytest.recwarn import WarningsRecorder def test_recwarn_functional(testdir): reprec = testdir.inline_runsource(""" import warnings - oldwarn = warnings.showwarning def test_method(recwarn): - assert warnings.showwarning != oldwarn warnings.warn("hello") warn = recwarn.pop() assert isinstance(warn.message, UserWarning) - def test_finalized(): - assert warnings.showwarning == oldwarn """) res = reprec.countoutcomes() - assert tuple(res) == (2, 0, 0), res + assert tuple(res) == (1, 0, 0), res class TestWarningsRecorderChecker(object): - def test_recording(self, recwarn): - showwarning = py.std.warnings.showwarning + def test_recording(self): rec = WarningsRecorder() with rec: - assert py.std.warnings.showwarning != showwarning assert not rec.list py.std.warnings.warn_explicit("hello", UserWarning, "xyz", 13) assert len(rec.list) == 1 @@ -40,8 +34,6 @@ class TestWarningsRecorderChecker(object): assert l is rec.list pytest.raises(AssertionError, "rec.pop()") - assert showwarning == py.std.warnings.showwarning - def test_typechecking(self): from _pytest.recwarn import WarningsChecker with pytest.raises(TypeError): From 90c934e25ed378bd517da9039dfed65c1ea570ba Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 13 Mar 2017 18:59:15 -0400 Subject: [PATCH 44/46] Include release 3.0.7 announce in index.rst --- doc/en/announce/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 5cf8b4dcb..52dd90de0 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-3.0.7 release-3.0.6 release-3.0.5 release-3.0.4 From 92b49d246ebea56d75b1bd45afea0919e670006b Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 13 Mar 2017 23:04:44 -0300 Subject: [PATCH 45/46] Clarify that record_xml_property is experimental, not junitxml Related to #2306 --- doc/en/usage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/usage.rst b/doc/en/usage.rst index 15b3d71b0..a6fd4892e 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -192,7 +192,7 @@ This will add an extra property ``example_key="1"`` to the generated .. warning:: - This is an experimental feature, and its interface might be replaced + ``record_xml_property`` is an experimental feature, and its interface might be replaced by something more powerful and general in future versions. The functionality per-se will be kept, however. From fa15ae754500916eb5226adb1efaaf95f0ce4618 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 18:07:44 -0300 Subject: [PATCH 46/46] Post 3.0.7 release handling --- CHANGELOG.rst | 14 ++++++++++++++ _pytest/__init__.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 19b62a1d0..beb0542be 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,17 @@ +3.0.8 (unreleased) +================== + +* + +* + +* + +* + +* + + 3.0.7 (2017-03-14) ================== diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 45375bc4c..dd7876046 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.7' +__version__ = '3.0.8.dev'