From 2f11a8569806933a0e585a576e6e6af652ae6bfb Mon Sep 17 00:00:00 2001 From: Raquel Alegre Date: Tue, 23 Aug 2016 16:41:11 +0100 Subject: [PATCH 001/201] Import pkg_resources only when necessary. --- _pytest/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/config.py b/_pytest/config.py index 2a1215811..a401bb068 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -5,7 +5,6 @@ import traceback import types import warnings -import pkg_resources import py # DON't import pytest here because it causes import cycle troubles import sys, os @@ -942,6 +941,7 @@ class Config(object): and find all the installed plugins to mark them for re-writing by the importhook. """ + import pkg_resources ns, unknown_args = self._parser.parse_known_and_unknown_args(args) mode = ns.assertmode if mode == 'rewrite': From 7d498fdc8247ed06c79a0407ddd5fb0f781ce20f Mon Sep 17 00:00:00 2001 From: Raquel Alegre Date: Tue, 23 Aug 2016 16:47:15 +0100 Subject: [PATCH 002/201] Added myself as AUTHOR as requested on PR. --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 2e487e772..895310caa 100644 --- a/AUTHORS +++ b/AUTHORS @@ -103,6 +103,7 @@ Punyashloka Biswal Quentin Pradet Ralf Schmitt Raphael Pierzina +Raquel Alegre Roberto Polli Romain Dorgueil Roman Bolshakov From a1597aca89aa05e35499ce775f1135ab4be5fed4 Mon Sep 17 00:00:00 2001 From: Raquel Alegre Date: Tue, 23 Aug 2016 16:48:24 +0100 Subject: [PATCH 003/201] Added #1853 to changelog as requested on PR. --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d571a2bf3..f6f233314 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,7 @@ * Fix loader error when running ``pytest`` embedded in a zipfile. Thanks `@mbachry`_ for the PR. -* +* Fix pkg_resources import error in Jython projects (`#1853`). * From d3f4b3d14ae385526e26b7c74e469584d769f486 Mon Sep 17 00:00:00 2001 From: Raquel Alegre Date: Tue, 23 Aug 2016 16:50:00 +0100 Subject: [PATCH 004/201] mend --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f6f233314..6c9aaaffa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,8 +8,9 @@ * Fix loader error when running ``pytest`` embedded in a zipfile. Thanks `@mbachry`_ for the PR. - + * Fix pkg_resources import error in Jython projects (`#1853`). + Thanks `@raquel-ucl`_ for the PR. * From 8f516d27fa2c32b9f90e410c0dbacd26117fd873 Mon Sep 17 00:00:00 2001 From: Raquel Alegre Date: Wed, 24 Aug 2016 10:25:01 +0100 Subject: [PATCH 005/201] Moved import pkg_resources to else clause. --- _pytest/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/config.py b/_pytest/config.py index a401bb068..8d115ea65 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -941,7 +941,6 @@ class Config(object): and find all the installed plugins to mark them for re-writing by the importhook. """ - import pkg_resources ns, unknown_args = self._parser.parse_known_and_unknown_args(args) mode = ns.assertmode if mode == 'rewrite': @@ -950,6 +949,7 @@ class Config(object): except SystemError: mode = 'plain' else: + import pkg_resources self.pluginmanager.rewrite_hook = hook for entrypoint in pkg_resources.iter_entry_points('pytest11'): for entry in entrypoint.dist._get_metadata('RECORD'): From 77d842ceb2d99883f481881a50ec6990e0116414 Mon Sep 17 00:00:00 2001 From: mbyt Date: Sat, 17 Sep 2016 19:58:27 +0200 Subject: [PATCH 006/201] better doc for #1890 based on #1932 --- doc/en/unittest.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 3d1ebbbf3..853d93fde 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -38,7 +38,11 @@ the general ``pytest`` documentation for many more examples. Running tests from ``unittest.TestCase`` subclasses with ``--pdb`` will disable tearDown and cleanup methods for the case that an Exception occurs. This allows proper post mortem debugging for all applications - which have significant logic in their tearDown machinery. + which have significant logic in their tearDown machinery. However, + supporting this feature has the following side effect: If people + overwrite ``unittest.TestCase`` ``__call__`` or ``run``, they need to + to overwrite ``debug`` in the same way (this is also true for standard + unittest). Mixing pytest fixtures into unittest.TestCase style tests ----------------------------------------------------------- From 8639bf75549e50a74cb49d4f48d790d2c8788a87 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Mon, 19 Sep 2016 10:20:36 +0100 Subject: [PATCH 007/201] fixup! Merge pkg_resources workaround --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8933ec4d0..43bec4fb4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,7 @@ .. _@philpep: https://github.com/philpep +.. _@raquel-ucl: https://github.com/raquel-ucl .. _#1905: https://github.com/pytest-dev/pytest/issues/1905 .. _#1934: https://github.com/pytest-dev/pytest/issues/1934 From 65be1231b12367de3ff14b5718125d12a54b26b1 Mon Sep 17 00:00:00 2001 From: Lev Maximov Date: Sun, 18 Sep 2016 22:34:48 +0700 Subject: [PATCH 008/201] AttributeError chaining bug #1944 fix --- _pytest/python.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 33e7cff66..f26c128ca 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -205,11 +205,10 @@ class PyobjContext(object): class PyobjMixin(PyobjContext): def obj(): def fget(self): - try: - return self._obj - except AttributeError: + obj = getattr(self, '_obj', None) + if obj is None: self._obj = obj = self._getobj() - return obj + return obj def fset(self, value): self._obj = value return property(fget, fset, None, "underlying python object") From 6b56c36ae7712cc68b3e7bf2ffd86ba90cde6e0f Mon Sep 17 00:00:00 2001 From: Lev Maximov Date: Sun, 18 Sep 2016 23:14:29 +0700 Subject: [PATCH 009/201] added to changelog and authors --- AUTHORS | 1 + CHANGELOG.rst | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/AUTHORS b/AUTHORS index 636fe7f7b..cce84a3c6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -78,6 +78,7 @@ Kale Kundert Katarzyna Jachim Kevin Cox Lee Kamentsky +Lev Maximov Lukas Bednar Maciek Fijalkowski Maho diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 43bec4fb4..61fb9b5b3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,14 +12,20 @@ * Fix pkg_resources import error in Jython projects (`#1853`). Thanks `@raquel-ucl`_ for the PR. +* Got rid of ``AttributeError: 'Module' object has no attribute '_obj'`` exception + in Python 3 (`#1944`_). + Thanks `@axil`_ for the PR. + * .. _@philpep: https://github.com/philpep .. _@raquel-ucl: https://github.com/raquel-ucl +.. _@axil: https://github.com/axil .. _#1905: https://github.com/pytest-dev/pytest/issues/1905 .. _#1934: https://github.com/pytest-dev/pytest/issues/1934 +.. _#1944: https://github.com/pytest-dev/pytest/issues/1944 3.0.2 From 8cba033bbb16b73726249da8723a9ffec9024ecc Mon Sep 17 00:00:00 2001 From: Lev Maximov Date: Tue, 20 Sep 2016 02:16:04 +0700 Subject: [PATCH 010/201] added a test --- testing/test_assertion.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index af7e7e0fe..2d4761431 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -864,3 +864,15 @@ def test_assert_with_unicode(monkeypatch, testdir): """) result = testdir.runpytest() result.stdout.fnmatch_lines(['*AssertionError*']) + +def test_issue_1944(testdir): + testdir.makepyfile(""" + def f(): + return + + assert f() == 10 + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*1 error*"]) + assert "AttributeError: 'Module' object has no attribute '_obj'" not in result.stdout.str() + From 6db2f315face61d3bed7a2a95a9ed58183c0607f Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 6 Sep 2016 14:16:25 -0400 Subject: [PATCH 011/201] Explain a bad scope value to the user --- AUTHORS | 1 + CHANGELOG.rst | 5 ++++- _pytest/fixtures.py | 24 +++++++++++++++++++++++- _pytest/python.py | 5 +++-- testing/python/fixture.py | 16 ++++++++++++++++ testing/python/metafunc.py | 8 ++++++++ 6 files changed, 55 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index cce84a3c6..d8c431dc0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -127,6 +127,7 @@ Ted Xiao Thomas Grainger Tom Viner Trevor Bekolay +Tyler Goodlet Vasily Kuznetsov Wouter van Ackooy Xuecong Liao diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 61fb9b5b3..a67ec4eee 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,18 +16,21 @@ in Python 3 (`#1944`_). Thanks `@axil`_ for the PR. -* +* Explain a bad scope value passed to ``@fixture`` declarations or + a ``MetaFunc.parametrize()`` call. Thanks `@tgoodlet`_ for the PR. .. _@philpep: https://github.com/philpep .. _@raquel-ucl: https://github.com/raquel-ucl .. _@axil: https://github.com/axil +.. _@tgoodlet: https://github.com/tgoodlet .. _#1905: https://github.com/pytest-dev/pytest/issues/1905 .. _#1934: https://github.com/pytest-dev/pytest/issues/1934 .. _#1944: https://github.com/pytest-dev/pytest/issues/1944 + 3.0.2 ===== diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index cf3e9dd93..3f08b7c6d 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -599,12 +599,29 @@ class ScopeMismatchError(Exception): which has a lower scope (e.g. a Session one calls a function one) """ + scopes = "session module class function".split() scopenum_function = scopes.index("function") + + def scopemismatch(currentscope, newscope): return scopes.index(newscope) > scopes.index(currentscope) +def scope2index(scope, descr, where=None): + """Look up the index of ``scope`` and raise a descriptive value error + if not defined. + """ + try: + return scopes.index(scope) + except ValueError: + raise ValueError( + "{0} {1}has an unsupported scope value '{2}'".format( + descr, 'from {0} '.format(where) if where else '', + scope) + ) + + class FixtureLookupError(LookupError): """ could not return a requested Fixture (missing or invalid). """ def __init__(self, argname, request, msg=None): @@ -703,6 +720,7 @@ def call_fixture_func(fixturefunc, request, kwargs): res = fixturefunc(**kwargs) return res + class FixtureDef: """ A container for a factory definition. """ def __init__(self, fixturemanager, baseid, argname, func, scope, params, @@ -713,7 +731,11 @@ class FixtureDef: self.func = func self.argname = argname self.scope = scope - self.scopenum = scopes.index(scope or "function") + self.scopenum = scope2index( + scope or "function", + descr='fixture {0}'.format(func.__name__), + where=baseid + ) self.params = params startindex = unittest and 1 or None self.argnames = getfuncargnames(func, startindex=startindex) diff --git a/_pytest/python.py b/_pytest/python.py index f26c128ca..a361af874 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -770,7 +770,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): It will also override any fixture-function defined scope, allowing to set a dynamic scope using test context or configuration. """ - from _pytest.fixtures import scopes + from _pytest.fixtures import scope2index from _pytest.mark import extract_argvalue from py.io import saferepr @@ -799,7 +799,8 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): if scope is None: scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect) - scopenum = scopes.index(scope) + scopenum = scope2index( + scope, descr='call to {0}'.format(self.parametrize)) valtypes = {} for arg in argnames: if arg not in self.fixturenames: diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 5ff459cbc..d6b7840c6 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1063,6 +1063,22 @@ class TestFixtureUsages: "*1 error*" ]) + def test_invalid_scope(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope="functions") + def badscope(): + pass + + def test_nothing(badscope): + pass + """) + result = testdir.runpytest_inprocess() + result.stdout.fnmatch_lines( + ("*ValueError: fixture badscope from test_invalid_scope.py has an unsupported" + " scope value 'functions'") + ) + def test_funcarg_parametrized_and_used_twice(self, testdir): testdir.makepyfile(""" import pytest diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index b9bf589c3..9d71df20a 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -96,6 +96,14 @@ class TestMetafunc: pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5,6])) pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5,6])) + def test_parametrize_bad_scope(self, testdir): + def func(x): pass + metafunc = self.Metafunc(func) + try: + metafunc.parametrize("x", [1], scope='doggy') + except ValueError as ve: + assert "has an unsupported scope value 'doggy'" in str(ve) + def test_parametrize_and_id(self): def func(x, y): pass metafunc = self.Metafunc(func) From 940ed7e943c63e2eb9df1d537775692021ff0a53 Mon Sep 17 00:00:00 2001 From: Roy Williams Date: Wed, 21 Sep 2016 17:44:25 -0700 Subject: [PATCH 012/201] Fix `DeprecationWarnings` found when running py.test in Python 2.7 with the -3 flag. Running through some of my tests with the `-3` flag in python2.7 I encountered some errors within py.test itself. This fixes those errors so we can use py.test in order to identify problems with Python 3. --- _pytest/_code/code.py | 4 ++++ _pytest/_code/source.py | 3 +++ _pytest/assertion/util.py | 2 +- _pytest/python.py | 6 ++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index 9a6d32665..21e1460fd 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -12,6 +12,7 @@ if sys.version_info[0] >= 3: else: from ._py2traceback import format_exception_only + class Code(object): """ wrapper around Python code objects """ def __init__(self, rawcode): @@ -28,6 +29,9 @@ class Code(object): def __eq__(self, other): return self.raw == other.raw + def __hash__(self): + return hash(self.raw) + def __ne__(self, other): return not self == other diff --git a/_pytest/_code/source.py b/_pytest/_code/source.py index a1521f8a2..ae9f0463f 100644 --- a/_pytest/_code/source.py +++ b/_pytest/_code/source.py @@ -52,6 +52,9 @@ class Source(object): return str(self) == other return False + def __hash__(self): + return hash(self.lines) + def __getitem__(self, key): if isinstance(key, int): return self.lines[key] diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py index 2481cf34c..4a0a4e431 100644 --- a/_pytest/assertion/util.py +++ b/_pytest/assertion/util.py @@ -105,7 +105,7 @@ except NameError: def assertrepr_compare(config, op, left, right): """Return specialised explanations for some operators/operands""" width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width/2)) + left_repr = py.io.saferepr(left, maxsize=int(width//2)) right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr)) diff --git a/_pytest/python.py b/_pytest/python.py index f26c128ca..ebfb8e1d1 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1356,6 +1356,9 @@ class approx(object): return False return all(a == x for a, x in zip(actual, self.expected)) + def __hash__(self): + return hash(self.expected) + def __ne__(self, actual): return not (actual == self) @@ -1435,6 +1438,9 @@ class ApproxNonIterable(object): # Return true if the two numbers are within the tolerance. return abs(self.expected - actual) <= self.tolerance + def __hash__(self): + return hash((self.expected, self.tolerance)) + def __ne__(self, actual): return not (actual == self) From 24db3c123d784d476bc2b5d77e04cb7bb0956174 Mon Sep 17 00:00:00 2001 From: Roy Williams Date: Thu, 22 Sep 2016 09:22:12 -0700 Subject: [PATCH 013/201] Explicitly set to None to have consistent behavior in Python 2 and Python 3 --- _pytest/_code/code.py | 3 +-- _pytest/_code/source.py | 3 +-- _pytest/python.py | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index 21e1460fd..30e12940b 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -29,8 +29,7 @@ class Code(object): def __eq__(self, other): return self.raw == other.raw - def __hash__(self): - return hash(self.raw) + __hash__ = None def __ne__(self, other): return not self == other diff --git a/_pytest/_code/source.py b/_pytest/_code/source.py index ae9f0463f..2d55cd07f 100644 --- a/_pytest/_code/source.py +++ b/_pytest/_code/source.py @@ -52,8 +52,7 @@ class Source(object): return str(self) == other return False - def __hash__(self): - return hash(self.lines) + __hash__ = None def __getitem__(self, key): if isinstance(key, int): diff --git a/_pytest/python.py b/_pytest/python.py index ebfb8e1d1..ea194f85f 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1356,8 +1356,7 @@ class approx(object): return False return all(a == x for a, x in zip(actual, self.expected)) - def __hash__(self): - return hash(self.expected) + __hash__ = None def __ne__(self, actual): return not (actual == self) @@ -1438,8 +1437,7 @@ class ApproxNonIterable(object): # Return true if the two numbers are within the tolerance. return abs(self.expected - actual) <= self.tolerance - def __hash__(self): - return hash((self.expected, self.tolerance)) + __hash__ = None def __ne__(self, actual): return not (actual == self) From f1c4cfea2ccbc392521c12d8927519de12ca76f2 Mon Sep 17 00:00:00 2001 From: Roy Williams Date: Fri, 23 Sep 2016 09:43:56 -0700 Subject: [PATCH 014/201] Remove implementation of `__getslice__` `__getslice__` has been Deprecated since Python 2.0 and is removed in Python 3. See https://docs.python.org/2/reference/datamodel.html#object.__getslice__ Unfortunately, Python 2 will still dispatch to `__getslice__` over `__getitem__`, See http://bugs.python.org/issue2041, which causes Warnings when running with `-3` in 2.7. --- _pytest/_code/source.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/_pytest/_code/source.py b/_pytest/_code/source.py index 2d55cd07f..846e3cced 100644 --- a/_pytest/_code/source.py +++ b/_pytest/_code/source.py @@ -60,16 +60,13 @@ class Source(object): else: if key.step not in (None, 1): raise IndexError("cannot slice a Source with a step") - return self.__getslice__(key.start, key.stop) + newsource = Source() + newsource.lines = self.lines[key.start:key.stop] + return newsource def __len__(self): return len(self.lines) - def __getslice__(self, start, end): - newsource = Source() - newsource.lines = self.lines[start:end] - return newsource - def strip(self): """ return new source object with trailing and leading blank lines removed. From 73cab772490e97aa7cdf7dd61c942c51b9a07616 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 25 Sep 2016 18:39:31 -0300 Subject: [PATCH 015/201] Pin hypothesis to 3.5.0 because 3.5.1 breaks the test suite Related to HypothesisWorks/hypothesis-python#368 --- tox.ini | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 3c12a8da3..e165b7a60 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,8 @@ envlist= commands= pytest --lsof -rfsxX {posargs:testing} passenv = USER USERNAME deps= - hypothesis + # pin to 3.5.0 until 3.5.2 is released + hypothesis==3.5.0 nose mock requests @@ -47,7 +48,8 @@ commands = flake8 pytest.py _pytest testing deps=pytest-xdist>=1.13 mock nose - hypothesis + # pin to 3.5.0 until 3.5.2 is released + hypothesis==3.5.0 commands= pytest -n1 -rfsxX {posargs:testing} @@ -71,8 +73,10 @@ commands= pytest -rfsxX test_pdb.py test_terminal.py test_unittest.py [testenv:py27-nobyte] -deps=pytest-xdist>=1.13 - hypothesis +deps= + pytest-xdist>=1.13 + # pin to 3.5.0 until 3.5.2 is released + hypothesis==3.5.0 distribute=true setenv= PYTHONDONTWRITEBYTECODE=1 From da201c7d290dd8258f87c6923c5193970021c70f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 25 Sep 2016 23:21:37 -0300 Subject: [PATCH 016/201] Disable pypy on AppVeyor until #1963 gets fixed --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 38f3d6fad..3144f2095 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,8 @@ environment: matrix: # create multiple jobs to execute a set of tox runs on each; this is to workaround having # builds timing out in AppVeyor - - TOXENV: "linting,py26,py27,py33,py34,py35,pypy" + # pypy is disabled until #1963 gets fixed + - TOXENV: "linting,py26,py27,py33,py34,py35" - TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial" - TOXENV: "py27-nobyte,doctesting,freeze,docs" From 835328d86203bb5c6e882166871098f607fb71db Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 25 Sep 2016 21:12:04 -0300 Subject: [PATCH 017/201] Vendor pluggy 0.4.0 Fix #1637 --- CHANGELOG.rst | 10 +++++ _pytest/vendored_packages/README.md | 2 +- .../pluggy-0.3.1.dist-info/RECORD | 8 ---- .../pluggy-0.3.1.dist-info/metadata.json | 1 - .../pluggy-0.3.1.dist-info/pbr.json | 1 - .../DESCRIPTION.rst | 1 + .../pluggy-0.4.0.dist-info/INSTALLER | 1 + .../pluggy-0.4.0.dist-info/LICENSE.txt | 22 ++++++++++ .../METADATA | 5 ++- .../pluggy-0.4.0.dist-info/RECORD | 9 ++++ .../WHEEL | 2 +- .../pluggy-0.4.0.dist-info/metadata.json | 1 + .../top_level.txt | 0 _pytest/vendored_packages/pluggy.py | 41 +++++++++++++++---- 14 files changed, 82 insertions(+), 22 deletions(-) delete mode 100644 _pytest/vendored_packages/pluggy-0.3.1.dist-info/RECORD delete mode 100644 _pytest/vendored_packages/pluggy-0.3.1.dist-info/metadata.json delete mode 100644 _pytest/vendored_packages/pluggy-0.3.1.dist-info/pbr.json rename _pytest/vendored_packages/{pluggy-0.3.1.dist-info => pluggy-0.4.0.dist-info}/DESCRIPTION.rst (99%) create mode 100644 _pytest/vendored_packages/pluggy-0.4.0.dist-info/INSTALLER create mode 100644 _pytest/vendored_packages/pluggy-0.4.0.dist-info/LICENSE.txt rename _pytest/vendored_packages/{pluggy-0.3.1.dist-info => pluggy-0.4.0.dist-info}/METADATA (95%) create mode 100644 _pytest/vendored_packages/pluggy-0.4.0.dist-info/RECORD rename _pytest/vendored_packages/{pluggy-0.3.1.dist-info => pluggy-0.4.0.dist-info}/WHEEL (70%) create mode 100644 _pytest/vendored_packages/pluggy-0.4.0.dist-info/metadata.json rename _pytest/vendored_packages/{pluggy-0.3.1.dist-info => pluggy-0.4.0.dist-info}/top_level.txt (100%) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a67ec4eee..124246900 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,15 @@ * Explain a bad scope value passed to ``@fixture`` declarations or a ``MetaFunc.parametrize()`` call. Thanks `@tgoodlet`_ for the PR. +* This version includes ``pluggy-0.4.0``, which correctly handles + ``VersionConflict`` errors in plugins (`#704`_). + Thanks `@nicoddemus`_ for the PR. + +* + +* + + .. _@philpep: https://github.com/philpep .. _@raquel-ucl: https://github.com/raquel-ucl @@ -28,6 +37,7 @@ .. _#1905: https://github.com/pytest-dev/pytest/issues/1905 .. _#1934: https://github.com/pytest-dev/pytest/issues/1934 .. _#1944: https://github.com/pytest-dev/pytest/issues/1944 +.. _#704: https://github.com/pytest-dev/pytest/issues/704 diff --git a/_pytest/vendored_packages/README.md b/_pytest/vendored_packages/README.md index eab7c714f..b5fe6febb 100644 --- a/_pytest/vendored_packages/README.md +++ b/_pytest/vendored_packages/README.md @@ -10,4 +10,4 @@ $ pip install -U pluggy== --no-compile --target=_pytest/vendored_packag ``` And commit the modified files. The `pluggy-.dist-info` directory -created by `pip` should be ignored. +created by `pip` should be added as well. diff --git a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/RECORD b/_pytest/vendored_packages/pluggy-0.3.1.dist-info/RECORD deleted file mode 100644 index 9626673c4..000000000 --- a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/RECORD +++ /dev/null @@ -1,8 +0,0 @@ -pluggy.py,sha256=v_RfWzyW6DPU1cJu_EFoL_OHq3t13qloVdR6UaMCXQA,29862 -pluggy-0.3.1.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7 -pluggy-0.3.1.dist-info/pbr.json,sha256=xX3s6__wOcAyF-AZJX1sdZyW6PUXT-FkfBlM69EEUCg,47 -pluggy-0.3.1.dist-info/RECORD,, -pluggy-0.3.1.dist-info/metadata.json,sha256=nLKltOT78dMV-00uXD6Aeemp4xNsz2q59j6ORSDeLjw,1027 -pluggy-0.3.1.dist-info/METADATA,sha256=1b85Ho2u4iK30M099k7axMzcDDhLcIMb-A82JUJZnSo,1334 -pluggy-0.3.1.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 -pluggy-0.3.1.dist-info/DESCRIPTION.rst,sha256=P5Akh1EdIBR6CeqtV2P8ZwpGSpZiTKPw0NyS7jEiD-g,306 diff --git a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/metadata.json b/_pytest/vendored_packages/pluggy-0.3.1.dist-info/metadata.json deleted file mode 100644 index 426a3a7ad..000000000 --- a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"license": "MIT license", "name": "pluggy", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "plugin and hook calling mechanisms for python", "platform": "unix", "version": "0.3.1", "extensions": {"python.details": {"document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "holger at merlinux.eu", "name": "Holger Krekel"}]}}, "classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Libraries", "Topic :: Utilities", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"]} \ No newline at end of file diff --git a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/pbr.json b/_pytest/vendored_packages/pluggy-0.3.1.dist-info/pbr.json deleted file mode 100644 index d6b798640..000000000 --- a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/pbr.json +++ /dev/null @@ -1 +0,0 @@ -{"is_release": false, "git_version": "7d4c9cd"} \ No newline at end of file diff --git a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/DESCRIPTION.rst b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/DESCRIPTION.rst similarity index 99% rename from _pytest/vendored_packages/pluggy-0.3.1.dist-info/DESCRIPTION.rst rename to _pytest/vendored_packages/pluggy-0.4.0.dist-info/DESCRIPTION.rst index aa3bbf812..da0e7a6ed 100644 --- a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/DESCRIPTION.rst +++ b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/DESCRIPTION.rst @@ -1,3 +1,4 @@ + Plugin registration and hook calling for Python =============================================== diff --git a/_pytest/vendored_packages/pluggy-0.4.0.dist-info/INSTALLER b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/_pytest/vendored_packages/pluggy-0.4.0.dist-info/LICENSE.txt b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/LICENSE.txt new file mode 100644 index 000000000..121017d08 --- /dev/null +++ b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 holger krekel (rather uses bitbucket/hpk42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/METADATA b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/METADATA similarity index 95% rename from _pytest/vendored_packages/pluggy-0.3.1.dist-info/METADATA rename to _pytest/vendored_packages/pluggy-0.4.0.dist-info/METADATA index ec81f0a6b..bd88517c9 100644 --- a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/METADATA +++ b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/METADATA @@ -1,8 +1,8 @@ Metadata-Version: 2.0 Name: pluggy -Version: 0.3.1 +Version: 0.4.0 Summary: plugin and hook calling mechanisms for python -Home-page: UNKNOWN +Home-page: https://github.com/pytest-dev/pluggy Author: Holger Krekel Author-email: holger at merlinux.eu License: MIT license @@ -27,6 +27,7 @@ Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 + Plugin registration and hook calling for Python =============================================== diff --git a/_pytest/vendored_packages/pluggy-0.4.0.dist-info/RECORD b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/RECORD new file mode 100644 index 000000000..3003a3bf2 --- /dev/null +++ b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/RECORD @@ -0,0 +1,9 @@ +pluggy.py,sha256=u0oG9cv-oLOkNvEBlwnnu8pp1AyxpoERgUO00S3rvpQ,31543 +pluggy-0.4.0.dist-info/DESCRIPTION.rst,sha256=ltvjkFd40LW_xShthp6RRVM6OB_uACYDFR3kTpKw7o4,307 +pluggy-0.4.0.dist-info/LICENSE.txt,sha256=ruwhUOyV1HgE9F35JVL9BCZ9vMSALx369I4xq9rhpkM,1134 +pluggy-0.4.0.dist-info/METADATA,sha256=pe2hbsqKFaLHC6wAQPpFPn0KlpcPfLBe_BnS4O70bfk,1364 +pluggy-0.4.0.dist-info/RECORD,, +pluggy-0.4.0.dist-info/WHEEL,sha256=9Z5Xm-eel1bTS7e6ogYiKz0zmPEqDwIypurdHN1hR40,116 +pluggy-0.4.0.dist-info/metadata.json,sha256=T3go5L2qOa_-H-HpCZi3EoVKb8sZ3R-fOssbkWo2nvM,1119 +pluggy-0.4.0.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7 +pluggy-0.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 diff --git a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/WHEEL b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/WHEEL similarity index 70% rename from _pytest/vendored_packages/pluggy-0.3.1.dist-info/WHEEL rename to _pytest/vendored_packages/pluggy-0.4.0.dist-info/WHEEL index 9dff69d86..8b6dd1b5a 100644 --- a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/WHEEL +++ b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/WHEEL @@ -1,5 +1,5 @@ Wheel-Version: 1.0 -Generator: bdist_wheel (0.24.0) +Generator: bdist_wheel (0.29.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any diff --git a/_pytest/vendored_packages/pluggy-0.4.0.dist-info/metadata.json b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/metadata.json new file mode 100644 index 000000000..cde22aff0 --- /dev/null +++ b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Libraries", "Topic :: Utilities", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"], "extensions": {"python.details": {"contacts": [{"email": "holger at merlinux.eu", "name": "Holger Krekel", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "https://github.com/pytest-dev/pluggy"}}}, "generator": "bdist_wheel (0.29.0)", "license": "MIT license", "metadata_version": "2.0", "name": "pluggy", "platform": "unix", "summary": "plugin and hook calling mechanisms for python", "version": "0.4.0"} \ No newline at end of file diff --git a/_pytest/vendored_packages/pluggy-0.3.1.dist-info/top_level.txt b/_pytest/vendored_packages/pluggy-0.4.0.dist-info/top_level.txt similarity index 100% rename from _pytest/vendored_packages/pluggy-0.3.1.dist-info/top_level.txt rename to _pytest/vendored_packages/pluggy-0.4.0.dist-info/top_level.txt diff --git a/_pytest/vendored_packages/pluggy.py b/_pytest/vendored_packages/pluggy.py index 2f848b23d..9c13932b3 100644 --- a/_pytest/vendored_packages/pluggy.py +++ b/_pytest/vendored_packages/pluggy.py @@ -67,8 +67,9 @@ Pluggy currently consists of functionality for: import sys import inspect -__version__ = '0.3.1' -__all__ = ["PluginManager", "PluginValidationError", +__version__ = '0.4.0' + +__all__ = ["PluginManager", "PluginValidationError", "HookCallError", "HookspecMarker", "HookimplMarker"] _py3 = sys.version_info > (3, 0) @@ -308,7 +309,7 @@ class PluginManager(object): """ Core Pluginmanager class which manages registration of plugin objects and 1:N hook calling. - You can register new hooks by calling ``addhooks(module_or_class)``. + You can register new hooks by calling ``add_hookspec(module_or_class)``. You can register plugin objects (which contain hooks) by calling ``register(plugin)``. The Pluginmanager is initialized with a prefix that is searched for in the names of the dict of registered @@ -374,7 +375,10 @@ class PluginManager(object): def parse_hookimpl_opts(self, plugin, name): method = getattr(plugin, name) - res = getattr(method, self.project_name + "_impl", None) + try: + res = getattr(method, self.project_name + "_impl", None) + except Exception: + res = {} if res is not None and not isinstance(res, dict): # false positive res = None @@ -455,6 +459,10 @@ class PluginManager(object): """ Return a plugin or None for the given name. """ return self._name2plugin.get(name) + def has_plugin(self, name): + """ Return True if a plugin with the given name is registered. """ + return self.get_plugin(name) is not None + def get_name(self, plugin): """ Return name for registered plugin or None if not registered. """ for name, val in self._name2plugin.items(): @@ -492,7 +500,8 @@ class PluginManager(object): def load_setuptools_entrypoints(self, entrypoint_name): """ Load modules from querying the specified setuptools entrypoint name. Return the number of loaded plugins. """ - from pkg_resources import iter_entry_points, DistributionNotFound + from pkg_resources import (iter_entry_points, DistributionNotFound, + VersionConflict) for ep in iter_entry_points(entrypoint_name): # is the plugin registered or blocked? if self.get_plugin(ep.name) or self.is_blocked(ep.name): @@ -501,6 +510,9 @@ class PluginManager(object): plugin = ep.load() except DistributionNotFound: continue + except VersionConflict as e: + raise PluginValidationError( + "Plugin %r could not be loaded: %s!" % (ep.name, e)) self.register(plugin, name=ep.name) self._plugin_distinfo.append((plugin, ep.dist)) return len(self._plugin_distinfo) @@ -573,7 +585,7 @@ class _MultiCall: # XXX note that the __multicall__ argument is supported only # for pytest compatibility reasons. It was never officially - # supported there and is explicitly deprecated since 2.8 + # supported there and is explicitely deprecated since 2.8 # so we can remove it soon, allowing to avoid the below recursion # in execute() and simplify/speed up the execute loop. @@ -590,7 +602,13 @@ class _MultiCall: while self.hook_impls: hook_impl = self.hook_impls.pop() - args = [all_kwargs[argname] for argname in hook_impl.argnames] + try: + args = [all_kwargs[argname] for argname in hook_impl.argnames] + except KeyError: + for argname in hook_impl.argnames: + if argname not in all_kwargs: + raise HookCallError( + "hook call must provide argument %r" % (argname,)) if hook_impl.hookwrapper: return _wrapped_call(hook_impl.function(*args), self.execute) res = hook_impl.function(*args) @@ -629,7 +647,10 @@ def varnames(func, startindex=None): startindex = 1 else: if not inspect.isfunction(func) and not inspect.ismethod(func): - func = getattr(func, '__call__', func) + try: + func = getattr(func, '__call__', func) + except Exception: + return () if startindex is None: startindex = int(inspect.ismethod(func)) @@ -763,6 +784,10 @@ class PluginValidationError(Exception): """ plugin failed validation. """ +class HookCallError(Exception): + """ Hook was called wrongly. """ + + if hasattr(inspect, 'signature'): def _formatdef(func): return "%s%s" % ( From 94155ee62ad53995c39a5d98aa799305ebb333ea Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 24 Sep 2016 07:55:34 -0300 Subject: [PATCH 018/201] Add a note about pytest.skip not being allowed at module level --- doc/en/skipping.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index dde89705e..662fed5df 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -293,6 +293,18 @@ imperatively, in test or setup code:: # or pytest.skip("unsupported configuration") +Note that calling ``pytest.skip`` at the module level +is not allowed since pytest 3.0. To skip +all tests in a module given some runtime condition, you can +set a ``pytestmark`` variable: + +.. code-block:: python + + if SOME_CONDITION: + pytestmark = pytest.mark.skip('skipping all tests because SOME_CONDITION') + +``pytestmark`` applies a mark or list of marks to all tests in a module. + Skipping on a missing import dependency -------------------------------------------------- From 19766ef0bcfb9dbdb8a1b274c13b4b146a86f705 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 25 Sep 2016 19:02:46 -0300 Subject: [PATCH 019/201] Add a summary on how to skip all tests in a module in different situations --- doc/en/skipping.rst | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index 662fed5df..42c43c3dc 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -294,14 +294,16 @@ imperatively, in test or setup code:: pytest.skip("unsupported configuration") Note that calling ``pytest.skip`` at the module level -is not allowed since pytest 3.0. To skip -all tests in a module given some runtime condition, you can -set a ``pytestmark`` variable: +is not allowed since pytest 3.0. If you are upgrading +and ``pytest.skip`` was being used at the module level, you can set a +``pytestmark`` variable: .. code-block:: python - if SOME_CONDITION: - pytestmark = pytest.mark.skip('skipping all tests because SOME_CONDITION') + # before pytest 3.0 + pytest.skip('skipping all tests because of reasons') + # after pytest 3.0 + pytestmark = pytest.mark.skip('skipping all tests because of reasons') ``pytestmark`` applies a mark or list of marks to all tests in a module. @@ -383,3 +385,27 @@ The equivalent with "boolean conditions" is:: imported before pytest's argument parsing takes place. For example, ``conftest.py`` files are imported before command line parsing and thus ``config.getvalue()`` will not execute correctly. + + +Summary +------- + +Here's a quick guide on how to skip tests in a module in different situations: + +1. Skip all tests in a module unconditionally: + + .. code-block:: python + + pytestmark = pytest.mark.skip('all tests still WIP') + +2. Skip all tests in a module based on some condition: + + .. code-block:: python + + pytestmark = pytest.mark.skipif(sys.platform == 'win32', 'tests for linux only') + +3. Skip all tests in a module if some import is missing: + + .. code-block:: python + + pexpect = pytest.importorskip('pexpect') From f31447b82bf3fc85b0f40e63e0d4e3b961d9c822 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 26 Sep 2016 09:07:10 -0300 Subject: [PATCH 020/201] Use hypothesis >= 3.5.2 Related to #1962 --- tox.ini | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index e165b7a60..ca55e7813 100644 --- a/tox.ini +++ b/tox.ini @@ -10,9 +10,8 @@ envlist= [testenv] commands= pytest --lsof -rfsxX {posargs:testing} passenv = USER USERNAME -deps= - # pin to 3.5.0 until 3.5.2 is released - hypothesis==3.5.0 +deps= + hypothesis>=3.5.2 nose mock requests @@ -48,8 +47,7 @@ commands = flake8 pytest.py _pytest testing deps=pytest-xdist>=1.13 mock nose - # pin to 3.5.0 until 3.5.2 is released - hypothesis==3.5.0 + hypothesis>=3.5.2 commands= pytest -n1 -rfsxX {posargs:testing} @@ -75,8 +73,7 @@ commands= [testenv:py27-nobyte] deps= pytest-xdist>=1.13 - # pin to 3.5.0 until 3.5.2 is released - hypothesis==3.5.0 + hypothesis>=3.5.2 distribute=true setenv= PYTHONDONTWRITEBYTECODE=1 From dda17994ecc1df4902e059bab32405dce15ec1ef Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 28 Sep 2016 16:33:38 -0400 Subject: [PATCH 021/201] Prepare for 3.0.3 release --- CHANGELOG.rst | 9 ++------- _pytest/__init__.py | 2 +- doc/en/announce/release-3.0.3.rst | 27 +++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 doc/en/announce/release-3.0.3.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 124246900..4f6be4f90 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,5 @@ -3.0.3.dev0 -========== +3.0.3 +===== * The ``ids`` argument to ``parametrize`` again accepts ``unicode`` strings in Python 2 (`#1905`_). @@ -23,11 +23,6 @@ ``VersionConflict`` errors in plugins (`#704`_). Thanks `@nicoddemus`_ for the PR. -* - -* - - .. _@philpep: https://github.com/philpep .. _@raquel-ucl: https://github.com/raquel-ucl diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 4d8be3d3a..4c3823e5c 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.3.dev0' +__version__ = '3.0.3' diff --git a/doc/en/announce/release-3.0.3.rst b/doc/en/announce/release-3.0.3.rst new file mode 100644 index 000000000..f00172195 --- /dev/null +++ b/doc/en/announce/release-3.0.3.rst @@ -0,0 +1,27 @@ +pytest-3.0.3 +============ + +pytest 3.0.3 has just been released to PyPI. + +This release fixes some regressions and bugs reported in the last version, +being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira +* Florian Bruhin +* Floris Bruynooghe +* Huayi Zhang +* Lev Maximov +* Raquel Alegre +* Ronny Pfannschmidt +* Roy Williams +* Tyler Goodlet +* mbyt + +Happy testing, +The pytest Development Team From 41d3b3f4f95706db48b7e97381b2c42d2bb47d0d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 28 Sep 2016 16:36:15 -0400 Subject: [PATCH 022/201] Regendoc for version 3.0.3 --- doc/en/assert.rst | 4 ++-- doc/en/cache.rst | 6 +++--- doc/en/capture.rst | 2 +- doc/en/doctest.rst | 2 +- doc/en/example/markers.rst | 28 ++++++++++++++-------------- doc/en/example/nonpython.rst | 6 +++--- doc/en/example/parametrize.rst | 12 ++++++------ doc/en/example/pythoncollection.rst | 6 +++--- doc/en/example/reportingdemo.rst | 2 +- doc/en/example/simple.rst | 22 +++++++++++----------- doc/en/fixture.rst | 10 +++++----- doc/en/getting-started.rst | 4 ++-- doc/en/index.rst | 2 +- doc/en/parametrize.rst | 4 ++-- doc/en/skipping.rst | 2 +- doc/en/tmpdir.rst | 2 +- doc/en/unittest.rst | 2 +- 17 files changed, 58 insertions(+), 58 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index 9a283b629..59d810c1d 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -26,7 +26,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -170,7 +170,7 @@ if you run this module:: $ pytest test_assert2.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/cache.rst b/doc/en/cache.rst index 5435d435d..d94020fdd 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -80,7 +80,7 @@ If you then run it with ``--lf``:: $ pytest --lf ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 run-last-failure: rerun last 2 failures rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -122,7 +122,7 @@ of ``FF`` and dots):: $ pytest --ff ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 run-last-failure: rerun last 2 failures first rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -227,7 +227,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: cachedir: $REGENDOC_TMPDIR/.cache ------------------------------- cache values ------------------------------- diff --git a/doc/en/capture.rst b/doc/en/capture.rst index f816628d1..afec55fdc 100644 --- a/doc/en/capture.rst +++ b/doc/en/capture.rst @@ -64,7 +64,7 @@ of the failing function and hide the other one:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/doctest.rst b/doc/en/doctest.rst index 198fb18da..1cdae8a78 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, 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 414deb89a..f0c9b0e5a 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -31,7 +31,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -45,7 +45,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -66,7 +66,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 5 items @@ -79,7 +79,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -92,7 +92,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items @@ -130,7 +130,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -144,7 +144,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -160,7 +160,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -352,7 +352,7 @@ the test needs:: $ pytest -E stage2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -364,7 +364,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -485,7 +485,7 @@ then you will see two test 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -499,7 +499,7 @@ Note that if you specify a platform via the marker-command line option like this $ pytest -m linux2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -551,7 +551,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -573,7 +573,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items diff --git a/doc/en/example/nonpython.rst b/doc/en/example/nonpython.rst index 9840e1079..4fc9bc503 100644 --- a/doc/en/example/nonpython.rst +++ b/doc/en/example/nonpython.rst @@ -27,7 +27,7 @@ now execute the test specification:: nonpython $ pytest test_simple.yml ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collected 2 items @@ -59,7 +59,7 @@ consulted when reporting in ``verbose`` mode:: nonpython $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collecting ... collected 2 items @@ -81,7 +81,7 @@ interesting to just look at the collection tree:: nonpython $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, 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 4ba743044..a5e6226ae 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -130,7 +130,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 6 items @@ -181,7 +181,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -194,7 +194,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -259,7 +259,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -320,7 +320,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -447,7 +447,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index 83fcace6e..15ec22e2b 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, 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 cddd13d2d..93704ea87 100644 --- a/doc/en/example/reportingdemo.rst +++ b/doc/en/example/reportingdemo.rst @@ -11,7 +11,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/assertion, inifile: collected 42 items diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 4d63eef7f..9c758e6a7 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -113,7 +113,7 @@ directory with the above conftest.py:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -164,7 +164,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -178,7 +178,7 @@ Or run it including the ``slow`` marked test:: $ pytest --runslow ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -302,7 +302,7 @@ which will add the string to the test header accordingly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 project deps: mylib-1.1 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -327,7 +327,7 @@ which will add info only when run with "--v":: $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache info1: did you know that ... did you? @@ -340,7 +340,7 @@ and nothing when run plainly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -374,7 +374,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -440,7 +440,7 @@ If we run this:: $ pytest -rx ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -519,7 +519,7 @@ We can run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 7 items @@ -627,7 +627,7 @@ and run them:: $ pytest test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -721,7 +721,7 @@ and run it:: $ pytest -s test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 7057024ab..d16f49e12 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -70,7 +70,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -188,7 +188,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -516,7 +516,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 11 items @@ -569,7 +569,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 2 items @@ -638,7 +638,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 83462e3dc..bc23ba51b 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.2, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py + This is pytest version 3.0.3, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py .. _`simpletest`: @@ -46,7 +46,7 @@ That's it. You can execute the test function now:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/index.rst b/doc/en/index.rst index 7544b8716..282b0b59a 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -25,7 +25,7 @@ To execute it:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index 825fda8e8..b095ff434 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -55,7 +55,7 @@ them in turn:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -103,7 +103,7 @@ Let's run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index 42c43c3dc..68a2d628b 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -224,7 +224,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/example, inifile: collected 7 items diff --git a/doc/en/tmpdir.rst b/doc/en/tmpdir.rst index 880be2d73..5413c136e 100644 --- a/doc/en/tmpdir.rst +++ b/doc/en/tmpdir.rst @@ -29,7 +29,7 @@ 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.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 853d93fde..61a0e8841 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -100,7 +100,7 @@ the ``self.db`` values in the traceback:: $ pytest test_unittest_db.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 + platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items From ba6ecc14c80b6b8a045143bada89598f1f3f8c9c Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 28 Sep 2016 17:16:57 -0400 Subject: [PATCH 023/201] Include release-3.0.3 into the announce toctree --- 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 90e6fcb6e..9cb4527ad 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-3.0.3 release-3.0.2 release-3.0.1 release-3.0.0 From a87b1c79c17128a1e62832149ae5cae454ecf6b2 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 29 Sep 2016 18:58:17 -0300 Subject: [PATCH 024/201] post 3.0.3 release changes --- CHANGELOG.rst | 12 ++++++++++++ _pytest/__init__.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4f6be4f90..6abd5006a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,15 @@ +3.0.4.dev +========= + +* + +* + +* + +* + + 3.0.3 ===== diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 4c3823e5c..d9f72e9b4 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.3' +__version__ = '3.0.4.dev' From 57bb3c6922ec32dcc7af17029eed357ed0742546 Mon Sep 17 00:00:00 2001 From: Nikolaus Rath Date: Mon, 26 Sep 2016 21:07:46 -0700 Subject: [PATCH 025/201] Improve error message when using pytest.skip at module level As discussed in issue #1959. --- _pytest/python.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index eacea994d..548d7cfa5 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -435,9 +435,9 @@ class Module(pytest.File, PyCollector): if e.allow_module_level: raise raise self.CollectError( - "Using @pytest.skip outside of a test (e.g. as a test " - "function decorator) is not allowed. Use @pytest.mark.skip or " - "@pytest.mark.skipif instead." + "Using pytest.skip outside of a test is not allowed. If you are " + "trying to decorate a test function, use the @pytest.mark.skip " + "or @pytest.mark.skipif decorators instead." ) self.config.pluginmanager.consider_module(mod) return mod From 336d7900c587caa35c0bb9067bf6820fe66a89ea Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 1 Oct 2016 13:38:41 -0300 Subject: [PATCH 026/201] Fix test about pytest.skip message being used at global level Fix #1959 --- testing/test_skipping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test_skipping.py b/testing/test_skipping.py index 12b18ca33..2e7868d3a 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -967,5 +967,5 @@ def test_module_level_skip_error(testdir): """) result = testdir.runpytest() result.stdout.fnmatch_lines( - "*Using @pytest.skip outside of a test * is not allowed*" + "*Using pytest.skip outside of a test is not allowed*" ) From 7d66e4eae1cc5989df07e140f2ff6949416c2c18 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 3 Oct 2016 20:47:44 -0300 Subject: [PATCH 027/201] Display full traceback from Import errors when collecting test modules Fix #1976 --- CHANGELOG.rst | 9 ++++++++- _pytest/python.py | 13 ++++++++----- testing/acceptance_test.py | 2 +- testing/python/collect.py | 22 +++++++++++++++++++++- testing/test_collection.py | 11 ----------- testing/test_terminal.py | 2 +- 6 files changed, 39 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6abd5006a..96a257781 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,13 +3,20 @@ * -* +* Import errors when collecting test modules now display the full traceback (`#1976`_). + Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. * * +.. _@cwitty: https://github.com/cwitty + +.. _#1976: https://github.com/pytest-dev/pytest/issues/1976 + + + 3.0.3 ===== diff --git a/_pytest/python.py b/_pytest/python.py index 548d7cfa5..74bb4de43 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -424,12 +424,15 @@ class Module(pytest.File, PyCollector): % e.args ) except ImportError: - exc_class, exc, _ = sys.exc_info() + import traceback + stream = py.io.TextIO() + traceback.print_exc(file=stream) + formatted_tb = stream.getvalue() raise self.CollectError( - "ImportError while importing test module '%s'.\n" - "Original error message:\n'%s'\n" - "Make sure your test modules/packages have valid Python names." - % (self.fspath, exc or exc_class) + "ImportError while importing test module '{fspath}'.\n" + "Hint: make sure your test modules/packages have valid Python names.\n" + "Original traceback:\n" + "{traceback}".format(fspath=self.fspath, traceback=formatted_tb) ) except _pytest.runner.Skipped as e: if e.allow_module_level: diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index b03f7fe4c..88e3fa449 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -120,7 +120,7 @@ class TestGeneralUsage: result.stdout.fnmatch_lines([ #XXX on jython this fails: "> import import_fails", "ImportError while importing test module*", - "'No module named *does_not_work*", + "*No module named *does_not_work*", ]) assert result.ret == 2 diff --git a/testing/python/collect.py b/testing/python/collect.py index 843f26a73..04ce53a54 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -68,9 +68,29 @@ class TestModule: result = testdir.runpytest("-rw") result.stdout.fnmatch_lines([ "ImportError while importing test module*test_one.part1*", - "Make sure your test modules/packages have valid Python names.", + "Hint: make sure your test modules/packages have valid Python names.", ]) + def test_show_full_traceback_import_error(self, testdir): + """Import errors when collecting modules should display the full traceback (#1976).""" + testdir.makepyfile( + foo_traceback_import_error=""" + from bar_traceback_import_error import NOT_AVAILABLE + """, + bar_traceback_import_error="", + ) + testdir.makepyfile(""" + import foo_traceback_import_error + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "ImportError while importing test module*", + "Original traceback:", + "*from bar_traceback_import_error import NOT_AVAILABLE", + "*cannot import name *NOT_AVAILABLE*", + ]) + assert result.ret == 2 + class TestClass: def test_class_with_init_warning(self, testdir): diff --git a/testing/test_collection.py b/testing/test_collection.py index 8e44ba55d..71a64c3c9 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -172,17 +172,6 @@ class TestCollectPluginHookRelay: assert "world" in wascalled class TestPrunetraceback: - def test_collection_error(self, testdir): - p = testdir.makepyfile(""" - import not_exists - """) - result = testdir.runpytest(p) - assert "__import__" not in result.stdout.str(), "too long traceback" - result.stdout.fnmatch_lines([ - "*ERROR collecting*", - "ImportError while importing test module*", - "'No module named *not_exists*", - ]) def test_custom_repr_failure(self, testdir): p = testdir.makepyfile(""" diff --git a/testing/test_terminal.py b/testing/test_terminal.py index fc6f3b7b1..66214c80e 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -667,7 +667,7 @@ class TestGenericReporting: result = testdir.runpytest(*option.args) result.stdout.fnmatch_lines([ "ImportError while importing*", - "'No module named *xyz*", + "*No module named *xyz*", "*1 error*", ]) From a1d446b8e809f1e6488ce183ace93ab6693f827c Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 3 Oct 2016 21:46:44 -0300 Subject: [PATCH 028/201] Display traceback from Import errors using pytest's short representation Also omit pytest's own modules and internal libraries (py and pluggy) in low verbosity Fix #1976 --- _pytest/python.py | 21 ++++++++++++++------- testing/python/collect.py | 21 +++++++++++++++++---- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 74bb4de43..62d2896ea 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -22,11 +22,16 @@ from _pytest.compat import ( getlocation, enum, ) -cutdir2 = py.path.local(_pytest.__file__).dirpath() cutdir1 = py.path.local(pluggy.__file__.rstrip("oc")) +cutdir2 = py.path.local(_pytest.__file__).dirpath() +cutdir3 = py.path.local(py.__file__).dirpath() def filter_traceback(entry): + """Return True if a TracebackEntry instance should be removed from tracebacks: + * dynamically generated code (no code to show up for it); + * internal traceback from pytest or its internal libraries, py and pluggy. + """ # entry.path might sometimes return a str object when the entry # points to dynamically generated code # see https://bitbucket.org/pytest-dev/py/issues/71 @@ -37,7 +42,7 @@ def filter_traceback(entry): # entry.path might point to an inexisting file, in which case it will # alsso return a str object. see #1133 p = py.path.local(entry.path) - return p != cutdir1 and not p.relto(cutdir2) + return p != cutdir1 and not p.relto(cutdir2) and not p.relto(cutdir3) @@ -424,14 +429,16 @@ class Module(pytest.File, PyCollector): % e.args ) except ImportError: - import traceback - stream = py.io.TextIO() - traceback.print_exc(file=stream) - formatted_tb = stream.getvalue() + from _pytest._code.code import ExceptionInfo + exc_info = ExceptionInfo() + if self.config.getoption('verbose') < 2: + exc_info.traceback = exc_info.traceback.filter(filter_traceback) + exc_repr = exc_info.getrepr(style='short') if exc_info.traceback else exc_info.exconly() + formatted_tb = py._builtin._totext(exc_repr) raise self.CollectError( "ImportError while importing test module '{fspath}'.\n" "Hint: make sure your test modules/packages have valid Python names.\n" - "Original traceback:\n" + "Traceback:\n" "{traceback}".format(fspath=self.fspath, traceback=formatted_tb) ) except _pytest.runner.Skipped as e: diff --git a/testing/python/collect.py b/testing/python/collect.py index 04ce53a54..2913b11a4 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import os import sys from textwrap import dedent @@ -71,8 +72,12 @@ class TestModule: "Hint: make sure your test modules/packages have valid Python names.", ]) - def test_show_full_traceback_import_error(self, testdir): - """Import errors when collecting modules should display the full traceback (#1976).""" + @pytest.mark.parametrize('verbose', [0, 1, 2]) + def test_show_traceback_import_error(self, testdir, verbose): + """Import errors when collecting modules should display the traceback (#1976). + + With low verbosity we omit pytest and internal modules, otherwise show all traceback entries. + """ testdir.makepyfile( foo_traceback_import_error=""" from bar_traceback_import_error import NOT_AVAILABLE @@ -82,15 +87,23 @@ class TestModule: testdir.makepyfile(""" import foo_traceback_import_error """) - result = testdir.runpytest() + args = ('-v',) * verbose + result = testdir.runpytest(*args) result.stdout.fnmatch_lines([ "ImportError while importing test module*", - "Original traceback:", + "Traceback:", "*from bar_traceback_import_error import NOT_AVAILABLE", "*cannot import name *NOT_AVAILABLE*", ]) assert result.ret == 2 + stdout = result.stdout.str() + for name in ('_pytest', os.path.join('py', '_path')): + if verbose == 2: + assert name in stdout + else: + assert name not in stdout + class TestClass: def test_class_with_init_warning(self, testdir): From c93a9e33617a5a5a79c59f8f51b9bf5112fb7690 Mon Sep 17 00:00:00 2001 From: Tom V Date: Tue, 4 Oct 2016 14:41:09 +0100 Subject: [PATCH 029/201] Fix #1981, improve ini-options help text --- _pytest/helpconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py index 84f419a08..538a763ca 100644 --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -71,8 +71,8 @@ def showhelp(config): tw.write(config._parser.optparser.format_help()) tw.line() tw.line() - tw.line("[pytest] ini-options in the next " - "pytest.ini|tox.ini|setup.cfg file:") + tw.line("[pytest] ini-options in the first " + "pytest.ini|tox.ini|setup.cfg file found:") tw.line() for name in config._parser._ininames: From 50b960c1f065e4ead2343bb266433c6cec594b42 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 5 Oct 2016 12:57:40 -0300 Subject: [PATCH 030/201] Add note about not monkey-patching builtins (#1986) * Add note about not monkey-patching builtins Related to #1985 * Mention -s as well --- doc/en/monkeypatch.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/en/monkeypatch.rst b/doc/en/monkeypatch.rst index e85d94d6d..806e910bd 100644 --- a/doc/en/monkeypatch.rst +++ b/doc/en/monkeypatch.rst @@ -55,6 +55,14 @@ will delete the method ``request.session.Session.request`` so that any attempts within tests to create http requests will fail. +.. note:: + + Be advised that it is not recommended to patch builtin functions such as ``open``, + ``compile``, etc., because it might break pytest's internals. If that's + unavoidable, passing ``--tb=native``, ``--assert=plain`` and ``--capture=no`` might + help althought there's no guarantee. + + Method reference of the monkeypatch fixture ------------------------------------------- From 10433db2258c1461f48b80b0bac5fb4604272bdb Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 5 Oct 2016 15:36:38 -0300 Subject: [PATCH 031/201] Mention small doc fixes don't need tests/changelog entries in PR template --- .github/PULL_REQUEST_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 198780a2a..1191fad27 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,6 +3,9 @@ Thanks for submitting a PR, your contribution is really appreciated! Here's a quick checklist that should be present in PRs: - [ ] Target: for bug or doc fixes, target `master`; for new features, target `features`; + +Unless your change is trivial documentation fix (e.g., a typo or reword of a small section) please: + - [ ] Make sure to include one or more tests for your change; - [ ] Add yourself to `AUTHORS`; - [ ] Add a new entry to `CHANGELOG.rst` From 65ebc75ee8d8b16b37eeff4ed725f52bd22578a5 Mon Sep 17 00:00:00 2001 From: Grigorii Eremeev Date: Wed, 5 Oct 2016 20:49:28 +0300 Subject: [PATCH 032/201] Update fixture.rst Removed redundant word --- AUTHORS | 1 + doc/en/fixture.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index d8c431dc0..910a82e49 100644 --- a/AUTHORS +++ b/AUTHORS @@ -59,6 +59,7 @@ Georgy Dyuldin Graham Horler Greg Price Grig Gheorghiu +Grigorii Eremeev (budulianin) Guido Wesdorp Harald Armin Massa Ian Bicking diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index d16f49e12..443e6b6be 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -701,7 +701,7 @@ Using fixtures from classes, modules or projects Sometimes test functions do not directly need access to a fixture object. For example, tests may require to operate with an empty directory as the current working directory but otherwise do not care for the concrete -directory. Here is how you can can use the standard `tempfile +directory. Here is how you can use the standard `tempfile `_ and pytest fixtures to achieve it. We separate the creation of the fixture into a conftest.py file:: From 78eec0d7f8bf177a368575271483ca575c11ad92 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 12 Oct 2016 17:46:47 -0300 Subject: [PATCH 033/201] Handle import errors with non-ascii messages when importing plugins Fix #1998 --- CHANGELOG.rst | 4 +++- _pytest/compat.py | 16 +++++++++++++++- _pytest/config.py | 3 ++- testing/test_pluginmanager.py | 12 +++++++++--- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 96a257781..c03e58a4c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,8 @@ * Import errors when collecting test modules now display the full traceback (`#1976`_). Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. -* +* When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). + Thanks `@nicoddemus`_ for the PR. * @@ -14,6 +15,7 @@ .. _@cwitty: https://github.com/cwitty .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 +.. _#1998: https://github.com/pytest-dev/pytest/issues/1998 diff --git a/_pytest/compat.py b/_pytest/compat.py index 1d8c2f331..51fc3bc5c 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -213,4 +213,18 @@ def _is_unittest_unexpected_success_a_failure(): Changed in version 3.4: Returns False if there were any unexpectedSuccesses from tests marked with the expectedFailure() decorator. """ - return sys.version_info >= (3, 4) \ No newline at end of file + return sys.version_info >= (3, 4) + + +if _PY3: + def safe_str(v): + """returns v as string""" + return str(v) +else: + def safe_str(v): + """returns v as string, converting to ascii if necessary""" + try: + return str(v) + except UnicodeError: + errors = 'replace' + return v.encode('ascii', errors) diff --git a/_pytest/config.py b/_pytest/config.py index 661a8513d..a169a68a2 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -12,6 +12,7 @@ import _pytest._code import _pytest.hookspec # the extension point definitions import _pytest.assertion from _pytest._pluggy import PluginManager, HookimplMarker, HookspecMarker +from _pytest.compat import safe_str hookimpl = HookimplMarker("pytest") hookspec = HookspecMarker("pytest") @@ -405,7 +406,7 @@ class PytestPluginManager(PluginManager): try: __import__(importspec) except ImportError as e: - new_exc = ImportError('Error importing plugin "%s": %s' % (modname, e)) + new_exc = ImportError('Error importing plugin "%s": %s' % (modname, safe_str(e.args[0]))) # copy over name and path attributes for attr in ('name', 'path'): if hasattr(e, attr): diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 36847638d..e61c84247 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -1,3 +1,4 @@ +# encoding: UTF-8 import pytest import py import os @@ -179,15 +180,20 @@ def test_default_markers(testdir): ]) -def test_importplugin_issue375(testdir, pytestpm): +def test_importplugin_error_message(testdir, pytestpm): """Don't hide import errors when importing plugins and provide an easy to debug message. + + See #375 and #1998. """ testdir.syspathinsert(testdir.tmpdir) - testdir.makepyfile(qwe="import aaaa") + testdir.makepyfile(qwe=""" + # encoding: UTF-8 + raise ImportError(u'Not possible to import: ☺') + """) with pytest.raises(ImportError) as excinfo: pytestpm.import_plugin("qwe") - expected = '.*Error importing plugin "qwe": No module named \'?aaaa\'?' + expected = '.*Error importing plugin "qwe": Not possible to import: .' assert py.std.re.match(expected, str(excinfo.value)) From bc1f8666aaee6458da9584ecf7ef3cb956b94e47 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 12 Oct 2016 17:58:58 -0300 Subject: [PATCH 034/201] Fix link in CHANGELOG for #1853 --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c03e58a4c..237ea478f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,7 +30,7 @@ (``pip install -e``) (`#1934`_). Thanks `@nicoddemus`_ for the PR. -* Fix pkg_resources import error in Jython projects (`#1853`). +* Fix pkg_resources import error in Jython projects (`#1853`_). Thanks `@raquel-ucl`_ for the PR. * Got rid of ``AttributeError: 'Module' object has no attribute '_obj'`` exception @@ -50,6 +50,7 @@ .. _@axil: https://github.com/axil .. _@tgoodlet: https://github.com/tgoodlet +.. _#1853: https://github.com/pytest-dev/pytest/issues/1853 .. _#1905: https://github.com/pytest-dev/pytest/issues/1905 .. _#1934: https://github.com/pytest-dev/pytest/issues/1934 .. _#1944: https://github.com/pytest-dev/pytest/issues/1944 From afc1e2b0e1cc67c33fcadbb9f83bed56c17d184a Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Tue, 18 Oct 2016 17:21:40 +0200 Subject: [PATCH 035/201] docs: remove mention of string args to main fixes #2008 string args got deprecated due to the insane amount of edge-cases wrt splitting on windows vs posix --- doc/en/usage.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/en/usage.rst b/doc/en/usage.rst index f87e1496d..ef63a8e06 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -310,10 +310,6 @@ You can pass in options and arguments:: pytest.main(['-x', 'mytestdir']) -or pass in a string:: - - pytest.main("-x mytestdir") - You can specify additional plugins to ``pytest.main``:: # content of myinvoke.py From 918af99a2ae21c133a0579a8c71e64efdcceba9c Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 20 Oct 2016 12:30:58 -0200 Subject: [PATCH 036/201] Remove example of obsolete pytest.main usage with string --- doc/en/goodpractices.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 7c2fdccf2..2a5d4d7c8 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -236,9 +236,10 @@ your own setuptools Test command for invoking pytest. self.pytest_args = [] def run_tests(self): + import shlex #import here, cause outside the eggs aren't loaded import pytest - errno = pytest.main(self.pytest_args) + errno = pytest.main(shlex.split(self.pytest_args)) sys.exit(errno) From 95007ddeca58bdae6f56b0d04a828463a10bc8e7 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 20 Oct 2016 18:56:54 -0200 Subject: [PATCH 037/201] Disable py35-trial while #1989 is not fixed --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f282e94b..8c36a298c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,8 @@ env: - TESTENV=py27-trial - TESTENV=py35-pexpect - TESTENV=py35-xdist - - TESTENV=py35-trial + # Disable py35-trial temporarily: #1989 + #- TESTENV=py35-trial - TESTENV=py27-nobyte - TESTENV=doctesting - TESTENV=freeze From 620b384b69ffaf0e98af015a721f385ceb13093c Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 20 Oct 2016 20:26:14 -0200 Subject: [PATCH 038/201] Fix cmdline help message for custom options with two or more metavars Fix #2004 --- CHANGELOG.rst | 5 +++++ _pytest/config.py | 2 +- testing/test_parseopt.py | 14 +++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 237ea478f..2fb15aa11 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,9 @@ * Import errors when collecting test modules now display the full traceback (`#1976`_). Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. +* Fix confusing command-line help message for custom options with two or more `metavar` properties (`#2004`_). + Thanks `@okulynyak`_ and `@davehunt`_ for the report and `@nicoddemus`_ for the PR. + * When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). Thanks `@nicoddemus`_ for the PR. @@ -13,9 +16,11 @@ .. _@cwitty: https://github.com/cwitty +.. _@okulynyak: https://github.com/okulynyak .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 .. _#1998: https://github.com/pytest-dev/pytest/issues/1998 +.. _#2004: https://github.com/pytest-dev/pytest/issues/2004 diff --git a/_pytest/config.py b/_pytest/config.py index a169a68a2..5df198e21 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -793,7 +793,7 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter): if len(option) == 2 or option[2] == ' ': return_list.append(option) if option[2:] == short_long.get(option.replace('-', '')): - return_list.append(option.replace(' ', '=')) + return_list.append(option.replace(' ', '=', 1)) action._formatted_action_invocation = ', '.join(return_list) return action._formatted_action_invocation diff --git a/testing/test_parseopt.py b/testing/test_parseopt.py index cc9aa23cd..fc9ded488 100644 --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -248,7 +248,19 @@ class TestParser: help="show help message and configuration info") parser.parse(['-h']) help = parser.optparser.format_help() - assert '-doit, --func-args foo' in help + assert '-doit, --func-args foo' in help + + def test_multiple_metavar_help(self, parser): + """ + Help text for options with a metavar tuple should display help + in the form "--preferences=value1 value2 value3" (#2004). + """ + group = parser.getgroup("general") + group.addoption('--preferences', metavar=('value1', 'value2', 'value3'), nargs=3) + group._addoption("-h", "--help", action="store_true", dest="help") + parser.parse(['-h']) + help = parser.optparser.format_help() + assert '--preferences=value1 value2 value3' in help def test_argcomplete(testdir, monkeypatch): From 2a2b8cee09a1a6b706423f7655129e17d7e0383d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 18 Oct 2016 22:58:31 -0200 Subject: [PATCH 039/201] Fix false-positive warnings from assertion rewrite hook Fix #2005 --- CHANGELOG.rst | 11 ++++++++++- _pytest/assertion/rewrite.py | 7 ++++++- testing/test_assertrewrite.py | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2fb15aa11..3abfc04f6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,15 @@ * When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). Thanks `@nicoddemus`_ for the PR. +* Fixed false-positives warnings from assertion rewrite hook for modules that were rewritten but + were later marked explicitly by ``pytest.register_assert_rewrite`` + or implicitly as a plugin (`#2005`_). + Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. + +* + +* + * @@ -21,7 +30,7 @@ .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 .. _#1998: https://github.com/pytest-dev/pytest/issues/1998 .. _#2004: https://github.com/pytest-dev/pytest/issues/2004 - +.. _#2005: https://github.com/pytest-dev/pytest/issues/2005 3.0.3 diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 80d6ee3ba..6b4c1f483 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -51,6 +51,7 @@ class AssertionRewritingHook(object): self.fnpats = config.getini("python_files") self.session = None self.modules = {} + self._rewritten_names = set() self._register_with_pkg_resources() self._must_rewrite = set() @@ -92,6 +93,8 @@ class AssertionRewritingHook(object): if not self._should_rewrite(name, fn_pypath, state): return None + self._rewritten_names.add(name) + # The requested module looks like a test file, so rewrite it. This is # the most magical part of the process: load the source, rewrite the # asserts, and load the rewritten source. We also cache the rewritten @@ -178,7 +181,9 @@ class AssertionRewritingHook(object): """ already_imported = set(names).intersection(set(sys.modules)) if already_imported: - self._warn_already_imported(already_imported) + for name in names: + if name not in self._rewritten_names: + self._warn_already_imported(already_imported) self._must_rewrite.update(names) def _warn_already_imported(self, names): diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index cedd435f8..e72266a18 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -543,6 +543,22 @@ def test_rewritten(): ''') assert testdir.runpytest_subprocess().ret == 0 + def test_remember_rewritten_modules(self, pytestconfig, testdir, monkeypatch): + """ + AssertionRewriteHook should remember rewritten modules so it + doesn't give false positives (#2005). + """ + monkeypatch.syspath_prepend(testdir.tmpdir) + testdir.makepyfile(test_remember_rewritten_modules='') + warnings = [] + hook = AssertionRewritingHook(pytestconfig) + monkeypatch.setattr(hook.config, 'warn', lambda code, msg: warnings.append(msg)) + hook.find_module('test_remember_rewritten_modules') + hook.load_module('test_remember_rewritten_modules') + hook.mark_rewrite('test_remember_rewritten_modules') + hook.mark_rewrite('test_remember_rewritten_modules') + assert warnings == [] + class TestAssertionRewriteHookDetails(object): def test_loader_is_package_false_for_module(self, testdir): From 37dcdfbc58441a266272d8ab4a8cc985ca51fb84 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 20 Oct 2016 23:39:28 -0200 Subject: [PATCH 040/201] Re-enable docstring testing of _pytest modules on CI * Fix doctests * List one env per line in tox.ini * "doctesting" tox env now also tests docstrings using doctest --- _pytest/python.py | 22 +++++++++++++--------- _pytest/recwarn.py | 7 ++++++- appveyor.yml | 9 +++++---- tox.ini | 28 ++++++++++++++++++---------- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 62d2896ea..a42e7185e 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1105,7 +1105,9 @@ def raises(expected_exception, *args, **kwargs): >>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"): ... pass - ... Failed: Expecting ZeroDivisionError + Traceback (most recent call last): + ... + Failed: Expecting ZeroDivisionError .. note:: @@ -1116,19 +1118,21 @@ def raises(expected_exception, *args, **kwargs): Lines of code after that, within the scope of the context manager will not be executed. For example:: - >>> with raises(OSError) as exc_info: - assert 1 == 1 # this will execute as expected - raise OSError(errno.EEXISTS, 'directory exists') - assert exc_info.value.errno == errno.EEXISTS # this will not execute + >>> value = 15 + >>> with raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... assert str(exc_info.value) == "value must be <= 10" # this will not execute Instead, the following approach must be taken (note the difference in scope):: - >>> with raises(OSError) as exc_info: - assert 1 == 1 # this will execute as expected - raise OSError(errno.EEXISTS, 'directory exists') + >>> with raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... + >>> assert str(exc_info.value) == "value must be <= 10" - assert exc_info.value.errno == errno.EEXISTS # this will now execute Or you can specify a callable by passing a to-be-called lambda:: diff --git a/_pytest/recwarn.py b/_pytest/recwarn.py index a89474c03..87823bfbc 100644 --- a/_pytest/recwarn.py +++ b/_pytest/recwarn.py @@ -36,8 +36,13 @@ def deprecated_call(func=None, *args, **kwargs): This function can be used as a context manager:: + >>> import warnings + >>> def api_call_v2(): + ... warnings.warn('use v3 of this api', DeprecationWarning) + ... return 200 + >>> with deprecated_call(): - ... myobject.deprecated_method() + ... assert api_call_v2() == 200 Note: we cannot use WarningsRecorder here because it is still subject to the mechanism that prevents warnings of the same type from being diff --git a/appveyor.yml b/appveyor.yml index 3144f2095..cd95611cb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,10 +20,11 @@ install: # install pypy using choco (redirect to a file and write to console in case # choco install returns non-zero, because choco install python.pypy is too # noisy) - - choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) - - set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy - - echo PyPy installed - - pypy --version + # pypy is disabled until #1963 gets fixed + #- choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) + #- set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy + #- echo PyPy installed + #- pypy --version - C:\Python35\python -m pip install tox diff --git a/tox.ini b/tox.ini index ca55e7813..53a76180b 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,18 @@ minversion=2.0 distshare={homedir}/.tox/distshare # make sure to update enviroment list on appveyor.yml envlist= - linting,py26,py27,py33,py34,py35,pypy, - {py27,py35}-{pexpect,xdist,trial}, - py27-nobyte,doctesting,freeze,docs + linting + py26 + py27 + py33 + py34 + py35 + pypy + {py27,py35}-{pexpect,xdist,trial} + py27-nobyte + doctesting + freeze + docs [testenv] commands= pytest --lsof -rfsxX {posargs:testing} @@ -90,10 +99,6 @@ deps={[testenv:py27-trial]deps} commands= pytest -ra {posargs:testing/test_unittest.py} -[testenv:doctest] -commands=pytest --doctest-modules _pytest -deps= - [testenv:docs] basepython=python changedir=doc/en @@ -106,9 +111,12 @@ commands= [testenv:doctesting] basepython = python -changedir=doc/en +usedevelop=True +skipsdist=True deps=PyYAML -commands= pytest -rfsxX {posargs} +commands= + pytest -rfsxX doc/en + pytest --doctest-modules {toxinidir}/_pytest [testenv:regen] changedir=doc/en @@ -139,7 +147,7 @@ commands= [testenv:coveralls] passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH COVERALLS_REPO_TOKEN usedevelop=True -basepython=python3.4 +basepython=python3.5 changedir=. deps = {[testenv]deps} From 11ec96a927e5571f39ab290d31fbb41200c791b8 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 21 Oct 2016 12:10:35 -0400 Subject: [PATCH 041/201] Extract child flush as a staticmethod --- testing/test_pdb.py | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/testing/test_pdb.py b/testing/test_pdb.py index d79d71262..aecf51bbc 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -76,6 +76,10 @@ class TestPDB: rest = child.read().decode("utf8") assert "1 failed" in rest assert "def test_1" not in rest + self.flush(child) + + @staticmethod + def flush(child): if child.isalive(): child.wait() @@ -95,8 +99,7 @@ class TestPDB: child.sendeof() rest = child.read().decode("utf8") assert 'debug.me' in rest - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_capture(self, testdir): p1 = testdir.makepyfile(""" @@ -111,8 +114,7 @@ class TestPDB: rest = child.read().decode("utf8") assert "1 failed" in rest assert "getrekt" not in rest - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_exception(self, testdir): p1 = testdir.makepyfile(""" @@ -130,8 +132,7 @@ class TestPDB: child.expect(".*function") child.sendeof() child.expect("1 failed") - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_on_collection_issue181(self, testdir): p1 = testdir.makepyfile(""" @@ -143,8 +144,7 @@ class TestPDB: child.expect("(Pdb)") child.sendeof() child.expect("1 error") - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_on_internal_error(self, testdir): testdir.makeconftest(""" @@ -156,8 +156,7 @@ class TestPDB: #child.expect(".*import pytest.*") child.expect("(Pdb)") child.sendeof() - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_capturing_simple(self, testdir): p1 = testdir.makepyfile(""" @@ -177,8 +176,7 @@ class TestPDB: assert "1 failed" in rest assert "def test_1" in rest assert "hello17" in rest # out is captured - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_set_trace_interception(self, testdir): p1 = testdir.makepyfile(""" @@ -193,8 +191,7 @@ class TestPDB: rest = child.read().decode("utf8") assert "1 failed" in rest assert "reading from stdin while output" not in rest - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_and_capsys(self, testdir): p1 = testdir.makepyfile(""" @@ -209,8 +206,7 @@ class TestPDB: child.expect("hello1") child.sendeof() child.read() - if child.isalive(): - child.wait() + self.flush(child) def test_set_trace_capturing_afterwards(self, testdir): p1 = testdir.makepyfile(""" @@ -229,8 +225,7 @@ class TestPDB: child.expect("hello") child.sendeof() child.read() - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_doctest(self, testdir): p1 = testdir.makepyfile(""" @@ -249,8 +244,7 @@ class TestPDB: child.sendeof() rest = child.read().decode("utf8") assert "1 failed" in rest - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_interaction_capturing_twice(self, testdir): p1 = testdir.makepyfile(""" @@ -276,8 +270,7 @@ class TestPDB: assert "def test_1" in rest assert "hello17" in rest # out is captured assert "hello18" in rest # out is captured - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_used_outside_test(self, testdir): p1 = testdir.makepyfile(""" @@ -331,8 +324,7 @@ class TestPDB: child.expect("enter_pdb_hook") child.send('c\n') child.sendeof() - if child.isalive(): - child.wait() + self.flush(child) def test_pdb_custom_cls(self, testdir): called = [] From 60a347aeb51582f6fee87497dfdb4f079a6f5c82 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 21 Oct 2016 12:11:35 -0400 Subject: [PATCH 042/201] Also use flush where wait was called unconditionally --- testing/test_pdb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/test_pdb.py b/testing/test_pdb.py index aecf51bbc..062ae1fb9 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -281,7 +281,7 @@ class TestPDB: child = testdir.spawn("%s %s" %(sys.executable, p1)) child.expect("x = 5") child.sendeof() - child.wait() + self.flush(child) def test_pdb_used_in_generate_tests(self, testdir): p1 = testdir.makepyfile(""" @@ -295,7 +295,7 @@ class TestPDB: child = testdir.spawn_pytest(str(p1)) child.expect("x = 5") child.sendeof() - child.wait() + self.flush(child) def test_pdb_collection_failure_is_shown(self, testdir): p1 = testdir.makepyfile("""xxx """) From f2c01c5407f3c7853bdd463b8aa2856e3a6398e1 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 21 Oct 2016 12:36:42 -0400 Subject: [PATCH 043/201] Restore pexpect tests and bypass isalive/wait on macOS. Ref #2022. --- _pytest/pytester.py | 2 -- testing/test_pdb.py | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 651160cc7..a8bb39794 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -1002,8 +1002,6 @@ class Testdir: pexpect = pytest.importorskip("pexpect", "3.0") if hasattr(sys, 'pypy_version_info') and '64' in platform.machine(): pytest.skip("pypy-64 bit not supported") - if sys.platform == "darwin": - pytest.xfail("pexpect does not work reliably on darwin?!") if sys.platform.startswith("freebsd"): pytest.xfail("pexpect does not work reliably on freebsd") logfile = self.tmpdir.join("spawn.out").open("wb") diff --git a/testing/test_pdb.py b/testing/test_pdb.py index 062ae1fb9..b22f5128e 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -1,4 +1,5 @@ import sys +import platform import _pytest._code import pytest @@ -80,6 +81,8 @@ class TestPDB: @staticmethod def flush(child): + if platform.system() == 'Darwin': + return if child.isalive(): child.wait() From 6f93ffb5d4de88fe6ad57d3195938d538988e45b Mon Sep 17 00:00:00 2001 From: Mathieu Clabaut Date: Sun, 30 Oct 2016 09:46:08 +0100 Subject: [PATCH 044/201] Report teardown output on test failure Until now, teardown stdout/stderr output was not reported upon test failure. However such output is sometime necessary to understand the failure. fix #442 --- AUTHORS | 1 + CHANGELOG.rst | 5 ++++- _pytest/terminal.py | 12 ++++++++++++ testing/test_terminal.py | 25 +++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 910a82e49..ae67fe429 100644 --- a/AUTHORS +++ b/AUTHORS @@ -90,6 +90,7 @@ Markus Unterwaditzer Martijn Faassen Martin K. Scherer Martin Prusse +Mathieu Clabaut Matt Bachmann Matt Williams Matthias Hafner diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3abfc04f6..dfedb0419 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,7 +17,8 @@ or implicitly as a plugin (`#2005`_). Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. -* +* Report teardown output on test failure (`#442`_). + Thanks `@matclab`_ or the PR. * @@ -26,7 +27,9 @@ .. _@cwitty: https://github.com/cwitty .. _@okulynyak: https://github.com/okulynyak +.. _@matclab: https://github.com/matclab +.. _#442: https://github.com/pytest-dev/pytest/issues/442 .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 .. _#1998: https://github.com/pytest-dev/pytest/issues/1998 .. _#2004: https://github.com/pytest-dev/pytest/issues/2004 diff --git a/_pytest/terminal.py b/_pytest/terminal.py index fdbe4ec36..16bf75733 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -458,6 +458,15 @@ class TerminalReporter: self.write_sep("_", msg) self._outrep_summary(rep) + def print_teardown_sections(self, rep): + for secname, content in rep.sections: + if 'teardown' in secname: + self._tw.sep('-', secname) + if content[-1:] == "\n": + content = content[:-1] + self._tw.line(content) + + def summary_failures(self): if self.config.option.tbstyle != "no": reports = self.getreports('failed') @@ -473,6 +482,9 @@ class TerminalReporter: markup = {'red': True, 'bold': True} self.write_sep("_", msg, **markup) self._outrep_summary(rep) + for report in self.getreports(''): + if report.nodeid == rep.nodeid and report.when == 'teardown': + self.print_teardown_sections(report) def summary_errors(self): if self.config.option.tbstyle != "no": diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 66214c80e..3efd7b1f9 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -370,6 +370,31 @@ class TestFixtureReporting: "*1 failed*1 error*", ]) + def test_setup_teardown_output_and_test_failure(self, testdir): + """ Test for issue #442 """ + testdir.makepyfile(""" + def setup_function(function): + print ("setup func") + + def test_fail(): + assert 0, "failingfunc" + + def teardown_function(function): + print ("teardown func") + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*test_fail*", + "*def test_fail():", + "*failingfunc*", + "*Captured stdout setup*", + "*setup func*", + "*Captured stdout teardown*", + "*teardown func*", + + "*1 failed*", + ]) + class TestTerminalFunctional: def test_deselected(self, testdir): testpath = testdir.makepyfile(""" From 382fa231a1c6a959e22c26eac1fcc42996314bd4 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 31 Oct 2016 06:49:06 +0100 Subject: [PATCH 045/201] Update "Next Open Trainings" --- doc/en/talks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/talks.rst b/doc/en/talks.rst index 1572832f0..46188bbe7 100644 --- a/doc/en/talks.rst +++ b/doc/en/talks.rst @@ -4,7 +4,7 @@ Talks and Tutorials .. sidebar:: Next Open Trainings - `professional testing with pytest and tox `_, 27-29th June 2016, Freiburg, Germany + `pytest workshop `_, 8th December 2016, Bern, Switzerland .. _`funcargs`: funcargs.html From e2bb4f893bd3e512179cdf98d24a9ad2f72411cf Mon Sep 17 00:00:00 2001 From: Georgy Dyuldin Date: Wed, 2 Nov 2016 15:45:40 +0300 Subject: [PATCH 046/201] Fix teardown error message in generated xUnit XML It was "test setup failure" even error happens on test teardown. --- CHANGELOG.rst | 8 +++++--- _pytest/junitxml.py | 6 +++++- testing/test_junitxml.py | 24 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dfedb0419..210359fb4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,7 +20,8 @@ * Report teardown output on test failure (`#442`_). Thanks `@matclab`_ or the PR. -* +* Fix teardown error message in generated xUnit XML. + Thanks `@gdyuldin`_ or the PR. * @@ -28,6 +29,7 @@ .. _@cwitty: https://github.com/cwitty .. _@okulynyak: https://github.com/okulynyak .. _@matclab: https://github.com/matclab +.. _@gdyuldin: https://github.com/gdyuldin .. _#442: https://github.com/pytest-dev/pytest/issues/442 .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 @@ -98,7 +100,7 @@ enabled. This allows proper post mortem debugging for all applications which have significant logic in their tearDown machinery (`#1890`_). Thanks `@mbyt`_ for the PR. - + * Fix use of deprecated ``getfuncargvalue`` method in the internal doctest plugin. Thanks `@ViviCoder`_ for the report (`#1898`_). @@ -395,7 +397,7 @@ time or change existing behaviors in order to make them less surprising/more use * Refined logic for determining the ``rootdir``, considering only valid paths which fixes a number of issues: `#1594`_, `#1435`_ and `#1471`_. - Updated the documentation according to current behavior. Thanks to + Updated the documentation according to current behavior. Thanks to `@blueyed`_, `@davehunt`_ and `@matthiasha`_ for the PR. * Always include full assertion explanation. The previous behaviour was hiding diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py index da190ff21..97d0675a6 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -156,8 +156,12 @@ class _NodeReporter(object): Junit.skipped, "collection skipped", report.longrepr) def append_error(self, report): + if getattr(report, 'when', None) == 'teardown': + msg = "test teardown failure" + else: + msg = "test setup failure" self._add_simple( - Junit.error, "test setup failure", report.longrepr) + Junit.error, msg, report.longrepr) self._write_captured_output(report) def append_skipped(self, report): diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index aec2741f1..85e49e451 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -165,6 +165,30 @@ class TestPython: fnode.assert_attr(message="test setup failure") assert "ValueError" in fnode.toxml() + def test_teardown_error(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def arg(): + yield + raise ValueError() + def test_function(arg): + pass + """) + result, dom = runandparse(testdir) + assert result.ret + node = dom.find_first_by_tag("testsuite") + tnode = node.find_first_by_tag("testcase") + tnode.assert_attr( + file="test_teardown_error.py", + line="6", + classname="test_teardown_error", + name="test_function") + fnode = tnode.find_first_by_tag("error") + fnode.assert_attr(message="test teardown failure") + assert "ValueError" in fnode.toxml() + def test_skip_contains_name_reason(self, testdir): testdir.makepyfile(""" import pytest From 006a901b861e9de28daf11ab4b10b87bed18aba1 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 27 Oct 2016 21:15:05 -0200 Subject: [PATCH 047/201] Properly handle exceptions in multiprocessing tasks Fix #1984 --- CHANGELOG.rst | 11 ++++++++- _pytest/_code/code.py | 15 ++++++++---- testing/code/test_excinfo.py | 44 ++++++++++++++++++++++++++++++++++++ testing/test_assertion.py | 31 +++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 210359fb4..44a7f9a39 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,7 @@ * Import errors when collecting test modules now display the full traceback (`#1976`_). Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. -* Fix confusing command-line help message for custom options with two or more `metavar` properties (`#2004`_). +* Fix confusing command-line help message for custom options with two or more ``metavar`` properties (`#2004`_). Thanks `@okulynyak`_ and `@davehunt`_ for the report and `@nicoddemus`_ for the PR. * When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). @@ -23,9 +23,17 @@ * Fix teardown error message in generated xUnit XML. Thanks `@gdyuldin`_ or the PR. +* Properly handle exceptions in ``multiprocessing`` tasks (`#1984`_). + Thanks `@adborden`_ for the report and `@nicoddemus`_ for the PR. + +* + +* + * +.. _@adborden: https://github.com/adborden .. _@cwitty: https://github.com/cwitty .. _@okulynyak: https://github.com/okulynyak .. _@matclab: https://github.com/matclab @@ -33,6 +41,7 @@ .. _#442: https://github.com/pytest-dev/pytest/issues/442 .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 +.. _#1984: https://github.com/pytest-dev/pytest/issues/1984 .. _#1998: https://github.com/pytest-dev/pytest/issues/1998 .. _#2004: https://github.com/pytest-dev/pytest/issues/2004 .. _#2005: https://github.com/pytest-dev/pytest/issues/2005 diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index 30e12940b..416ee0b1b 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -623,16 +623,23 @@ class FormattedExcinfo(object): e = excinfo.value descr = None while e is not None: - reprtraceback = self.repr_traceback(excinfo) - reprcrash = excinfo._getreprcrash() + if excinfo: + reprtraceback = self.repr_traceback(excinfo) + reprcrash = excinfo._getreprcrash() + else: + # fallback to native repr if the exception doesn't have a traceback: + # ExceptionInfo objects require a full traceback to work + reprtraceback = ReprTracebackNative(py.std.traceback.format_exception(type(e), e, None)) + reprcrash = None + repr_chain += [(reprtraceback, reprcrash, descr)] if e.__cause__ is not None: e = e.__cause__ - excinfo = ExceptionInfo((type(e), e, e.__traceback__)) + excinfo = ExceptionInfo((type(e), e, e.__traceback__)) if e.__traceback__ else None descr = 'The above exception was the direct cause of the following exception:' elif e.__context__ is not None: e = e.__context__ - excinfo = ExceptionInfo((type(e), e, e.__traceback__)) + excinfo = ExceptionInfo((type(e), e, e.__traceback__)) if e.__traceback__ else None descr = 'During handling of the above exception, another exception occurred:' else: e = None diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 283f8eb76..3aae9c71c 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -1050,6 +1050,50 @@ raise ValueError() assert line.endswith('mod.py') assert tw.lines[47] == ":15: AttributeError" + @pytest.mark.skipif("sys.version_info[0] < 3") + @pytest.mark.parametrize('reason, description', [ + ('cause', 'The above exception was the direct cause of the following exception:'), + ('context', 'During handling of the above exception, another exception occurred:'), + ]) + def test_exc_chain_repr_without_traceback(self, importasmod, reason, description): + """ + Handle representation of exception chains where one of the exceptions doesn't have a + real traceback, such as those raised in a subprocess submitted by the multiprocessing + module (#1984). + """ + from _pytest.pytester import LineMatcher + exc_handling_code = ' from e' if reason == 'cause' else '' + mod = importasmod(""" + def f(): + try: + g() + except Exception as e: + raise RuntimeError('runtime problem'){exc_handling_code} + def g(): + raise ValueError('invalid value') + """.format(exc_handling_code=exc_handling_code)) + + with pytest.raises(RuntimeError) as excinfo: + mod.f() + + # emulate the issue described in #1984 + attr = '__%s__' % reason + getattr(excinfo.value, attr).__traceback__ = None + + r = excinfo.getrepr() + tw = py.io.TerminalWriter(stringio=True) + tw.hasmarkup = False + r.toterminal(tw) + + matcher = LineMatcher(tw.stringio.getvalue().splitlines()) + matcher.fnmatch_lines([ + "ValueError: invalid value", + description, + "* except Exception as e:", + "> * raise RuntimeError('runtime problem')" + exc_handling_code, + "E *RuntimeError: runtime problem", + ]) + @pytest.mark.parametrize("style", ["short", "long"]) @pytest.mark.parametrize("encoding", [None, "utf8", "utf16"]) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 2d4761431..48cd26f02 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -749,6 +749,37 @@ def test_traceback_failure(testdir): "*test_traceback_failure.py:4: AssertionError" ]) + +@pytest.mark.skipif(sys.version_info[:2] <= (3, 3), reason='Python 3.4+ shows chained exceptions on multiprocess') +def test_exception_handling_no_traceback(testdir): + """ + Handle chain exceptions in tasks submitted by the multiprocess module (#1984). + """ + p1 = testdir.makepyfile(""" + from multiprocessing import Pool + + def process_task(n): + assert n == 10 + + def multitask_job(): + tasks = [1] + with Pool(processes=1) as pool: + pool.map(process_task, tasks) + + def test_multitask_job(): + multitask_job() + """) + result = testdir.runpytest(p1, "--tb=long") + result.stdout.fnmatch_lines([ + "====* FAILURES *====", + "*multiprocessing.pool.RemoteTraceback:*", + "Traceback (most recent call last):", + "*assert n == 10", + "The above exception was the direct cause of the following exception:", + "> * multitask_job()", + ]) + + @pytest.mark.skipif("'__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')" ) def test_warn_missing(testdir): testdir.makepyfile("") From a190ad27f2664272c52e6beabb9f60f65eaa2143 Mon Sep 17 00:00:00 2001 From: Manuel Jacob Date: Sun, 6 Nov 2016 09:00:04 +0100 Subject: [PATCH 048/201] Change version to be in normal form according to PEP 440. The version is changed from 3.0.4.dev to 3.0.4.dev0. Note that according to PEP 440 these are considered equivalent, but 3.0.4.dev0 is the normal form. This standard was followed when the version was set to 3.0.3.dev0 in commit ee284ec5, but in commit a87b1c79 the version was set to 3.0.4.dev, leaving the development number implicit again. --- CHANGELOG.rst | 4 ++-- _pytest/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 44a7f9a39..0f6f7ad02 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,5 @@ -3.0.4.dev -========= +3.0.4.dev0 +========== * diff --git a/_pytest/__init__.py b/_pytest/__init__.py index d9f72e9b4..b070c40d1 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.4.dev' +__version__ = '3.0.4.dev0' From e46e653794e3b72d7cc02d374086191224221501 Mon Sep 17 00:00:00 2001 From: Dan Wandschneider Date: Mon, 7 Nov 2016 18:24:10 -0800 Subject: [PATCH 049/201] Clean up unittest TestCase objects after tests are complete (#1649). Fix #1649 Users of unittest style TestCases will create expensive objects in setUp. We should clean up TestCase instances that are lying around so that they don't fill up memory. --- AUTHORS | 1 + CHANGELOG.rst | 5 ++++- _pytest/unittest.py | 3 +++ testing/test_unittest.py | 23 +++++++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index ae67fe429..378bac5a4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -36,6 +36,7 @@ Christopher Gilling Daniel Grana Daniel Hahler Daniel Nuri +Daniel Wandschneider Danielle Jenkins Dave Hunt David Díaz-Barquero diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0f6f7ad02..5dada862a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,7 +26,8 @@ * Properly handle exceptions in ``multiprocessing`` tasks (`#1984`_). Thanks `@adborden`_ for the report and `@nicoddemus`_ for the PR. -* +* Clean up unittest TestCase objects after tests are complete (`#1649`_). + Thanks `@d_b_w`_ for the report and PR. * @@ -38,6 +39,7 @@ .. _@okulynyak: https://github.com/okulynyak .. _@matclab: https://github.com/matclab .. _@gdyuldin: https://github.com/gdyuldin +.. _@d_b_w: https://github.com/d_b_w .. _#442: https://github.com/pytest-dev/pytest/issues/442 .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 @@ -45,6 +47,7 @@ .. _#1998: https://github.com/pytest-dev/pytest/issues/1998 .. _#2004: https://github.com/pytest-dev/pytest/issues/2004 .. _#2005: https://github.com/pytest-dev/pytest/issues/2005 +.. _#1649: https://github.com/pytest-dev/pytest/issues/1649 3.0.3 diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 47868f448..4355efe70 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -94,6 +94,9 @@ class TestCaseFunction(pytest.Function): def teardown(self): if hasattr(self._testcase, 'teardown_method'): self._testcase.teardown_method(self._obj) + # Allow garbage collection on TestCase instance attributes. + self._testcase = None + self._obj = None def startTest(self, testcase): pass diff --git a/testing/test_unittest.py b/testing/test_unittest.py index b6be95fa5..9625ae0f8 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -1,5 +1,6 @@ from _pytest.main import EXIT_NOTESTSCOLLECTED import pytest +import gc def test_simple_unittest(testdir): testpath = testdir.makepyfile(""" @@ -134,6 +135,28 @@ def test_teardown(testdir): assert passed == 2 assert passed + skipped + failed == 2 +def test_teardown_issue1649(testdir): + """ + Are TestCase objects cleaned up? Often unittest TestCase objects set + attributes that are large and expensive during setUp. + + The TestCase will not be cleaned up if the test fails, because it + would then exist in the stackframe. + """ + testpath = testdir.makepyfile(""" + import unittest + class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase): + def setUp(self): + self.an_expensive_object = 1 + def test_demo(self): + pass + + """) + testdir.inline_run("-s", testpath) + gc.collect() + for obj in gc.get_objects(): + assert type(obj).__name__ != 'TestCaseObjectsShouldBeCleanedUp' + @pytest.mark.skipif("sys.version_info < (2,7)") def test_unittest_skip_issue148(testdir): testpath = testdir.makepyfile(""" From 1e5b21cd6180009939130f6169c936427d0d4572 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 18 Oct 2016 00:56:44 +0200 Subject: [PATCH 050/201] Fix memory leak with pytest.raises by using weakref --- AUTHORS | 1 + CHANGELOG.rst | 3 +++ _pytest/_code/code.py | 5 +++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 378bac5a4..6de0a112b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -99,6 +99,7 @@ mbyt Michael Aquilina Michael Birtwell Michael Droettboom +Michael Seifert Mike Lundy Nicolas Delaby Oleg Pidsadnyi diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5dada862a..fb5395731 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,9 @@ * When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). Thanks `@nicoddemus`_ for the PR. +* Fixed memory leak in the RaisesContext (pytest.raises) (`#1965`_). + Thanks `@MSeifert04`_ for the report the PR. + * Fixed false-positives warnings from assertion rewrite hook for modules that were rewritten but were later marked explicitly by ``pytest.register_assert_rewrite`` or implicitly as a plugin (`#2005`_). diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index 416ee0b1b..5b4237939 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -1,6 +1,7 @@ import sys from inspect import CO_VARARGS, CO_VARKEYWORDS import re +from weakref import ref import py builtin_repr = repr @@ -230,7 +231,7 @@ class TracebackEntry(object): return False if py.builtin.callable(tbh): - return tbh(self._excinfo) + return tbh(None if self._excinfo is None else self._excinfo()) else: return tbh @@ -370,7 +371,7 @@ class ExceptionInfo(object): #: the exception type name self.typename = self.type.__name__ #: the exception traceback (_pytest._code.Traceback instance) - self.traceback = _pytest._code.Traceback(self.tb, excinfo=self) + self.traceback = _pytest._code.Traceback(self.tb, excinfo=ref(self)) def __repr__(self): return "" % (self.typename, len(self.traceback)) From 552c7d4286f582255752730d2c512d0aff4a44c4 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 18 Oct 2016 01:22:53 +0200 Subject: [PATCH 051/201] added test (thanks @nicoddemus) and added links in Changelog --- CHANGELOG.rst | 10 ++++++---- testing/python/raises.py | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fb5395731..35a54de4b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,7 +13,7 @@ Thanks `@nicoddemus`_ for the PR. * Fixed memory leak in the RaisesContext (pytest.raises) (`#1965`_). - Thanks `@MSeifert04`_ for the report the PR. + Thanks `@MSeifert04`_ for the report and the PR. * Fixed false-positives warnings from assertion rewrite hook for modules that were rewritten but were later marked explicitly by ``pytest.register_assert_rewrite`` @@ -39,12 +39,14 @@ .. _@adborden: https://github.com/adborden .. _@cwitty: https://github.com/cwitty -.. _@okulynyak: https://github.com/okulynyak -.. _@matclab: https://github.com/matclab -.. _@gdyuldin: https://github.com/gdyuldin .. _@d_b_w: https://github.com/d_b_w +.. _@gdyuldin: https://github.com/gdyuldin +.. _@matclab: https://github.com/matclab +.. _@MSeifert04: https://github.com/MSeifert04 +.. _@okulynyak: https://github.com/okulynyak .. _#442: https://github.com/pytest-dev/pytest/issues/442 +.. _#1965: https://github.com/pytest-dev/pytest/issues/1965 .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 .. _#1984: https://github.com/pytest-dev/pytest/issues/1984 .. _#1998: https://github.com/pytest-dev/pytest/issues/1998 diff --git a/testing/python/raises.py b/testing/python/raises.py index 59fd622fd..80c3df2ab 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -96,3 +96,21 @@ class TestRaises: assert e.msg == message else: assert False, "Expected pytest.raises.Exception" + + @pytest.mark.parametrize('method', ['function', 'with']) + def test_raises_memoryleak(self, method): + import weakref + + class T: + def __call__(self): + raise ValueError + + t = T() + if method == 'function': + pytest.raises(ValueError, t) + else: + with pytest.raises(ValueError): + t() + + t = weakref.ref(t) + assert t() is None From 1130b9f742d053a429149e56b8a0c8aec72a9968 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 8 Nov 2016 21:34:45 -0200 Subject: [PATCH 052/201] Fix the stubborn test about cyclic references left by pytest.raises In Python 2, a context manager's __exit__() leaves sys.exc_info with the exception values even when it was supposed to suppress the exception, so we explicitly call sys.exc_clear() which removes the traceback and allow the object to be released. Also updated the test to not depend on the immediate destruction of the object but instead to ensure it is not being tracked as a cyclic reference. Fix #1965 --- CHANGELOG.rst | 5 ++++- _pytest/python.py | 6 +++++- testing/python/raises.py | 22 +++++++++++++++++----- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 35a54de4b..e88eb5b09 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,10 @@ * When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). Thanks `@nicoddemus`_ for the PR. -* Fixed memory leak in the RaisesContext (pytest.raises) (`#1965`_). +* Fixed cyclic reference when ``pytest.raises`` is used in context-manager form (`#1965`_). Also as a + result of this fix, ``sys.exc_info()`` is left empty in both context-manager and function call usages. + Previously, ``sys.exc_info`` would contain the exception caught by the context manager, + even when the expected exception occurred. Thanks `@MSeifert04`_ for the report and the PR. * Fixed false-positives warnings from assertion rewrite hook for modules that were rewritten but diff --git a/_pytest/python.py b/_pytest/python.py index a42e7185e..18432c1e7 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1237,7 +1237,11 @@ class RaisesContext(object): exc_type, value, traceback = tp tp = exc_type, exc_type(value), traceback self.excinfo.__init__(tp) - return issubclass(self.excinfo.type, self.expected_exception) + suppress_exception = issubclass(self.excinfo.type, self.expected_exception) + if sys.version_info[0] == 2 and suppress_exception: + sys.exc_clear() + return suppress_exception + # builtin pytest.approx helper diff --git a/testing/python/raises.py b/testing/python/raises.py index 80c3df2ab..8f141cfa1 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -1,4 +1,6 @@ import pytest +import sys + class TestRaises: def test_raises(self): @@ -98,10 +100,13 @@ class TestRaises: assert False, "Expected pytest.raises.Exception" @pytest.mark.parametrize('method', ['function', 'with']) - def test_raises_memoryleak(self, method): - import weakref + def test_raises_cyclic_reference(self, method): + """ + Ensure pytest.raises does not leave a reference cycle (#1965). + """ + import gc - class T: + class T(object): def __call__(self): raise ValueError @@ -112,5 +117,12 @@ class TestRaises: with pytest.raises(ValueError): t() - t = weakref.ref(t) - assert t() is None + # ensure both forms of pytest.raises don't leave exceptions in sys.exc_info() + assert sys.exc_info() == (None, None, None) + + del t + + # ensure the t instance is not stuck in a cyclic reference + for o in gc.get_objects(): + assert type(o) is not T + From ff72db2f1a9ddd656738935909d1f83b71b2fd07 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 9 Nov 2016 19:38:11 -0200 Subject: [PATCH 053/201] Version bump to 3.0.4, CHANGELOG, announcement --- CHANGELOG.rst | 10 ++-------- _pytest/__init__.py | 2 +- doc/en/announce/index.rst | 1 + doc/en/announce/release-3.0.4.rst | 29 +++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 doc/en/announce/release-3.0.4.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e88eb5b09..178e5406f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,5 @@ -3.0.4.dev0 -========== - -* +3.0.4 +===== * Import errors when collecting test modules now display the full traceback (`#1976`_). Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. @@ -35,10 +33,6 @@ * Clean up unittest TestCase objects after tests are complete (`#1649`_). Thanks `@d_b_w`_ for the report and PR. -* - -* - .. _@adborden: https://github.com/adborden .. _@cwitty: https://github.com/cwitty diff --git a/_pytest/__init__.py b/_pytest/__init__.py index b070c40d1..97cf2527b 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.4.dev0' +__version__ = '3.0.4' diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 9cb4527ad..a1bf7bed7 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-3.0.4 release-3.0.3 release-3.0.2 release-3.0.1 diff --git a/doc/en/announce/release-3.0.4.rst b/doc/en/announce/release-3.0.4.rst new file mode 100644 index 000000000..852057037 --- /dev/null +++ b/doc/en/announce/release-3.0.4.rst @@ -0,0 +1,29 @@ +pytest-3.0.4 +============ + +pytest 3.0.4 has just been released to PyPI. + +This release fixes some regressions and bugs reported in the last version, +being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Bruno Oliveira +* Dan Wandschneider +* Florian Bruhin +* Georgy Dyuldin +* Grigorii Eremeev +* Jason R. Coombs +* Manuel Jacob +* Mathieu Clabaut +* Michael Seifert +* Nikolaus Rath +* Ronny Pfannschmidt +* Tom V + +Happy testing, +The pytest Development Team From ab274299fee959e64a4a749806e1124eb5d2f29b Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 9 Nov 2016 16:44:58 -0500 Subject: [PATCH 054/201] Regen doc for 3.0.4 --- doc/en/assert.rst | 4 ++-- doc/en/cache.rst | 6 +++--- doc/en/capture.rst | 2 +- doc/en/doctest.rst | 2 +- doc/en/example/markers.rst | 28 ++++++++++++++-------------- doc/en/example/nonpython.rst | 6 +++--- doc/en/example/parametrize.rst | 12 ++++++------ doc/en/example/pythoncollection.rst | 6 +++--- doc/en/example/reportingdemo.rst | 4 ++-- doc/en/example/simple.rst | 22 +++++++++++----------- doc/en/fixture.rst | 14 +++++++++----- doc/en/getting-started.rst | 4 ++-- doc/en/index.rst | 2 +- doc/en/parametrize.rst | 4 ++-- doc/en/skipping.rst | 2 +- doc/en/tmpdir.rst | 2 +- doc/en/unittest.rst | 2 +- 17 files changed, 63 insertions(+), 59 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index 59d810c1d..675dece57 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -26,7 +26,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -170,7 +170,7 @@ if you run this module:: $ pytest test_assert2.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/cache.rst b/doc/en/cache.rst index d94020fdd..4baae4c96 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -80,7 +80,7 @@ If you then run it with ``--lf``:: $ pytest --lf ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 run-last-failure: rerun last 2 failures rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -122,7 +122,7 @@ of ``FF`` and dots):: $ pytest --ff ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 run-last-failure: rerun last 2 failures first rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -227,7 +227,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: cachedir: $REGENDOC_TMPDIR/.cache ------------------------------- cache values ------------------------------- diff --git a/doc/en/capture.rst b/doc/en/capture.rst index afec55fdc..454655d7e 100644 --- a/doc/en/capture.rst +++ b/doc/en/capture.rst @@ -64,7 +64,7 @@ of the failing function and hide the other one:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/doctest.rst b/doc/en/doctest.rst index 1cdae8a78..5a1122515 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, 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 f0c9b0e5a..2f5f29e0d 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -31,7 +31,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -45,7 +45,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -66,7 +66,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 5 items @@ -79,7 +79,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -92,7 +92,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items @@ -130,7 +130,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -144,7 +144,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -160,7 +160,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -352,7 +352,7 @@ the test needs:: $ pytest -E stage2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -364,7 +364,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -485,7 +485,7 @@ then you will see two test 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -499,7 +499,7 @@ Note that if you specify a platform via the marker-command line option like this $ pytest -m linux2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -551,7 +551,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -573,7 +573,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items diff --git a/doc/en/example/nonpython.rst b/doc/en/example/nonpython.rst index 4fc9bc503..e0670aeba 100644 --- a/doc/en/example/nonpython.rst +++ b/doc/en/example/nonpython.rst @@ -27,7 +27,7 @@ now execute the test specification:: nonpython $ pytest test_simple.yml ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collected 2 items @@ -59,7 +59,7 @@ consulted when reporting in ``verbose`` mode:: nonpython $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collecting ... collected 2 items @@ -81,7 +81,7 @@ interesting to just look at the collection tree:: nonpython $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, 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 a5e6226ae..fee2b6dcc 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -130,7 +130,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 6 items @@ -181,7 +181,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -194,7 +194,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -259,7 +259,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -320,7 +320,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -447,7 +447,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index 15ec22e2b..f1e9a976d 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, 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 93704ea87..061097cc3 100644 --- a/doc/en/example/reportingdemo.rst +++ b/doc/en/example/reportingdemo.rst @@ -11,7 +11,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/assertion, inifile: collected 42 items @@ -359,7 +359,7 @@ get on the terminal - we are working on that):: > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1190>:1: ValueError + <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1204>:1: ValueError _______ TestRaises.test_raises_doesnt ________ self = diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 9c758e6a7..032f83c08 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -113,7 +113,7 @@ directory with the above conftest.py:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -164,7 +164,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -178,7 +178,7 @@ Or run it including the ``slow`` marked test:: $ pytest --runslow ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -302,7 +302,7 @@ which will add the string to the test header accordingly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 project deps: mylib-1.1 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -327,7 +327,7 @@ which will add info only when run with "--v":: $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache info1: did you know that ... did you? @@ -340,7 +340,7 @@ and nothing when run plainly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -374,7 +374,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -440,7 +440,7 @@ If we run this:: $ pytest -rx ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -519,7 +519,7 @@ We can run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 7 items @@ -627,7 +627,7 @@ and run them:: $ pytest test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -721,7 +721,7 @@ and run it:: $ pytest -s test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 443e6b6be..b0595bc9d 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -70,7 +70,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -188,7 +188,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -375,6 +375,8 @@ Running it:: assert 0, smtp.helo() E AssertionError: (250, b'mail.python.org') E assert 0 + ------------------------- Captured stdout teardown ------------------------- + finalizing (mail.python.org) voila! The ``smtp`` fixture function picked up our mail server name from the module namespace. @@ -464,6 +466,8 @@ So let's just do another run:: E assert 0 test_module.py:11: AssertionError + ------------------------- Captured stdout teardown ------------------------- + finalizing 4 failed in 0.12 seconds We see that our two test functions each ran twice, against the different @@ -516,7 +520,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 11 items @@ -569,7 +573,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 2 items @@ -638,7 +642,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index bc23ba51b..a3e21e54a 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.3, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py + This is pytest version 3.0.4, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py .. _`simpletest`: @@ -46,7 +46,7 @@ That's it. You can execute the test function now:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/index.rst b/doc/en/index.rst index 282b0b59a..aadabf222 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -25,7 +25,7 @@ To execute it:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index b095ff434..5cfedac8c 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -55,7 +55,7 @@ them in turn:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -103,7 +103,7 @@ Let's run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index 68a2d628b..a024b43a4 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -224,7 +224,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/example, inifile: collected 7 items diff --git a/doc/en/tmpdir.rst b/doc/en/tmpdir.rst index 5413c136e..3287ff30f 100644 --- a/doc/en/tmpdir.rst +++ b/doc/en/tmpdir.rst @@ -29,7 +29,7 @@ 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.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 61a0e8841..0bc0209e7 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -100,7 +100,7 @@ the ``self.db`` values in the traceback:: $ pytest test_unittest_db.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items From 84d70687237edab585c807fc81836da56a493921 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 9 Nov 2016 20:42:28 -0200 Subject: [PATCH 055/201] Add "check-manifest" to linting and remove unused scripts from root Fix #1 --- CONTRIBUTING.rst | 11 ++++------- MANIFEST.in | 9 +++------ plugin-test.sh | 20 -------------------- requirements-docs.txt | 3 --- runtox.py | 8 -------- tox.ini | 8 ++++++-- 6 files changed, 13 insertions(+), 46 deletions(-) delete mode 100644 plugin-test.sh delete mode 100644 requirements-docs.txt delete mode 100644 runtox.py diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 947d4e655..19b31c7f4 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -199,13 +199,10 @@ but here is a simple overview: You need to have Python 2.7 and 3.5 available in your system. Now running tests is as simple as issuing this command:: - $ python3 runtox.py -e linting,py27,py35 + $ tox -e linting,py27,py35 This command will run tests via the "tox" tool against Python 2.7 and 3.5 - and also perform "lint" coding-style checks. ``runtox.py`` is - a thin wrapper around ``tox`` which installs from a development package - index where newer (not yet released to PyPI) versions of dependencies - (especially ``py``) might be present. + and also perform "lint" coding-style checks. #. You can now edit your local working copy. @@ -214,11 +211,11 @@ but here is a simple overview: To run tests on Python 2.7 and pass options to pytest (e.g. enter pdb on failure) to pytest you can do:: - $ python3 runtox.py -e py27 -- --pdb + $ tox -e py27 -- --pdb Or to only run tests in a particular test module on Python 3.5:: - $ python3 runtox.py -e py35 -- testing/test_config.py + $ tox -e py35 -- testing/test_config.py #. Commit and push once your tests pass and you are happy with your change(s):: diff --git a/MANIFEST.in b/MANIFEST.in index 079b225ec..8e2cd6118 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -11,15 +11,12 @@ include setup.py include .coveragerc -include plugin-test.sh -include requirements-docs.txt -include runtox.py - recursive-include bench *.py recursive-include extra *.py graft testing graft doc +prune doc/en/_build exclude _pytest/impl @@ -27,6 +24,6 @@ graft _pytest/vendored_packages recursive-exclude * *.pyc *.pyo -exclude appveyor/install.ps1 exclude appveyor.yml -exclude appveyor +exclude .travis.yml +prune .github diff --git a/plugin-test.sh b/plugin-test.sh deleted file mode 100644 index 7830b7c7d..000000000 --- a/plugin-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# this assumes plugins are installed as sister directories - -set -e -cd ../pytest-pep8 -pytest -cd ../pytest-instafail -pytest -cd ../pytest-cache -pytest -cd ../pytest-xprocess -pytest -#cd ../pytest-cov -#pytest -cd ../pytest-capturelog -pytest -cd ../pytest-xdist -pytest - diff --git a/requirements-docs.txt b/requirements-docs.txt deleted file mode 100644 index be3a232e5..000000000 --- a/requirements-docs.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx==1.2.3 -regendoc -pyyaml diff --git a/runtox.py b/runtox.py deleted file mode 100644 index 8c13c53e1..000000000 --- a/runtox.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python - -if __name__ == "__main__": - import subprocess - import sys - subprocess.call([sys.executable, "-m", "tox", - "-i", "ALL=https://devpi.net/hpk/dev/", - "--develop"] + sys.argv[1:]) diff --git a/tox.ini b/tox.ini index 53a76180b..bbf300ce3 100644 --- a/tox.ini +++ b/tox.ini @@ -47,9 +47,13 @@ commands= pytest --genscript=pytest1 [testenv:linting] basepython = python2.7 -deps = flake8 +deps = + flake8 restructuredtext_lint -commands = flake8 pytest.py _pytest testing + check-manifest +commands = + check-manifest + flake8 pytest.py _pytest testing rst-lint CHANGELOG.rst HOWTORELEASE.rst [testenv:py27-xdist] From 26b151953400d277bb05ac0ee505570b28e78d9a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 9 Nov 2016 20:47:14 -0200 Subject: [PATCH 056/201] Add keywords to setup.py as suggested by pyroma Related to #1 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 23ac0eb03..cdcf3b3bb 100644 --- a/setup.py +++ b/setup.py @@ -72,6 +72,7 @@ def main(): entry_points={'console_scripts': ['pytest=pytest:main', 'py.test=pytest:main']}, classifiers=classifiers, + keywords="test unittest", cmdclass={'test': PyTest}, # the following should be enabled for release install_requires=install_requires, From aaa547e7638e4d6ff46b3cd60341d229b2ebd2a5 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 10 Nov 2016 08:48:56 -0200 Subject: [PATCH 057/201] Add some recursive-exclude related to hypothesis and freeze --- MANIFEST.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MANIFEST.in b/MANIFEST.in index 8e2cd6118..0c5bfd552 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -23,6 +23,10 @@ exclude _pytest/impl graft _pytest/vendored_packages recursive-exclude * *.pyc *.pyo +recursive-exclude testing/.hypothesis * +recursive-exclude testing/freeze/~ * +recursive-exclude testing/freeze/build * +recursive-exclude testing/freeze/dist * exclude appveyor.yml exclude .travis.yml From b8c6f13b37b58dd5c86075f6da5e2f63d44e86c5 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 11 Nov 2016 12:56:07 -0200 Subject: [PATCH 058/201] Check README.rst with rst-lint --- README.rst | 2 +- tox.ini | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 6a5179ed5..5b2d329e0 100644 --- a/README.rst +++ b/README.rst @@ -89,7 +89,7 @@ Please use the `GitHub issue tracker `_ page for fixes and enhancements of each version. +Consult the `Changelog `__ page for fixes and enhancements of each version. License diff --git a/tox.ini b/tox.ini index bbf300ce3..76b92aa53 100644 --- a/tox.ini +++ b/tox.ini @@ -42,8 +42,6 @@ deps=pytest-xdist>=1.13 commands= pytest -n3 -rfsxX --runpytest=subprocess {posargs:testing} -[testenv:genscript] -commands= pytest --genscript=pytest1 [testenv:linting] basepython = python2.7 @@ -54,7 +52,7 @@ deps = commands = check-manifest flake8 pytest.py _pytest testing - rst-lint CHANGELOG.rst HOWTORELEASE.rst + rst-lint CHANGELOG.rst HOWTORELEASE.rst README.rst [testenv:py27-xdist] deps=pytest-xdist>=1.13 From 6c8c1da428816cb0abcb39cbdd9c8f74f1841b63 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 11 Nov 2016 16:34:52 +0100 Subject: [PATCH 059/201] add pygments dependency because of rst-lint --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 76b92aa53..17fe0e3e4 100644 --- a/tox.ini +++ b/tox.ini @@ -47,6 +47,8 @@ commands= basepython = python2.7 deps = flake8 + # pygments required by rst-lint + pygments restructuredtext_lint check-manifest commands = From 3e01e83390950331a4e208c4cf9e165b50772223 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 11 Nov 2016 18:20:02 -0200 Subject: [PATCH 060/201] Bump version to 3.0.5.dev --- CHANGELOG.rst | 14 ++++++++++++++ _pytest/__init__.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 178e5406f..02a66079b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,17 @@ +3.0.5.dev0 +========== + +* + +* + +* + +* + +* + + 3.0.4 ===== diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 97cf2527b..15043e71c 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.4' +__version__ = '3.0.5.dev0' From 1519b38af08cdb93b8e84563be7fc9cdb7fc6b79 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 11 Nov 2016 19:03:18 -0200 Subject: [PATCH 061/201] Allow failure of py35-trial on Travis Related to #1989 --- .travis.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c36a298c..bbc03d856 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,13 +22,17 @@ env: - TESTENV=py27-trial - TESTENV=py35-pexpect - TESTENV=py35-xdist - # Disable py35-trial temporarily: #1989 - #- TESTENV=py35-trial + - TESTENV=py35-trial - TESTENV=py27-nobyte - TESTENV=doctesting - TESTENV=freeze - TESTENV=docs +matrix: + allow_failures: + # py35-trial failing on Linux: #1989 + - env: TESTENV=py35-trial + script: tox --recreate -e $TESTENV notifications: From 98caeedd9e22d12184bbef4910650d3e2b1f9dd9 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 11 Nov 2016 19:17:14 -0200 Subject: [PATCH 062/201] Allow failure of pypy on AppVeyor Related to #1963 --- appveyor.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index cd95611cb..64c9d6018 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,10 +8,15 @@ environment: matrix: # create multiple jobs to execute a set of tox runs on each; this is to workaround having # builds timing out in AppVeyor - # pypy is disabled until #1963 gets fixed - TOXENV: "linting,py26,py27,py33,py34,py35" - TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial" - TOXENV: "py27-nobyte,doctesting,freeze,docs" + - TOXENV: "pypy" + +matrix: + allow_failures: + # pypy is disabled until #1963 gets fixed + - TOXENV: "pypy" install: - echo Installed Pythons @@ -21,10 +26,10 @@ install: # choco install returns non-zero, because choco install python.pypy is too # noisy) # pypy is disabled until #1963 gets fixed - #- choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) - #- set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy - #- echo PyPy installed - #- pypy --version + - choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) + - set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy + - echo PyPy installed + - pypy --version - C:\Python35\python -m pip install tox From 351395b7ea3607424110815e0eff6fd34166fc68 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 11 Nov 2016 17:31:36 -0200 Subject: [PATCH 063/201] Use a wrapper script to bypass check-manifest if not under git Related to comment in #2051 --- MANIFEST.in | 2 ++ scripts/check-manifest.py | 21 +++++++++++++++++++++ tox.ini | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 scripts/check-manifest.py diff --git a/MANIFEST.in b/MANIFEST.in index 0c5bfd552..24b4cfc9b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,6 +9,8 @@ include HOWTORELEASE.rst include tox.ini include setup.py +recursive-include scripts *.py + include .coveragerc recursive-include bench *.py diff --git a/scripts/check-manifest.py b/scripts/check-manifest.py new file mode 100644 index 000000000..5911a84fe --- /dev/null +++ b/scripts/check-manifest.py @@ -0,0 +1,21 @@ +""" +Script used by tox.ini to check the manifest file if we are under version control, or skip the +check altogether if not. + +"check-manifest" will needs a vcs to work, which is not available when testing the package +instead of the source code (with ``devpi test`` for example). +""" + +from __future__ import print_function + +import os +import subprocess +import sys + + +if os.path.isdir('.git'): + sys.exit(subprocess.call('check-manifest', shell=True)) +else: + print('No .git directory found, skipping checking the manifest file') + sys.exit(0) + diff --git a/tox.ini b/tox.ini index 17fe0e3e4..efa3ad2f1 100644 --- a/tox.ini +++ b/tox.ini @@ -52,7 +52,7 @@ deps = restructuredtext_lint check-manifest commands = - check-manifest + {envpython} scripts/check-manifest.py flake8 pytest.py _pytest testing rst-lint CHANGELOG.rst HOWTORELEASE.rst README.rst From c169c883d359026a970b71262dd941c72a344ac0 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 12 Nov 2016 11:50:22 -0200 Subject: [PATCH 064/201] Use one job for each tox env on AppVeyor Some time ago when we first added support for testing pytest on AppVeyor, jobs in a build would not start immediately one after the other, as if AppVeyor would schedule jobs from other builds (projects) in its VMs. So it made sense at the time to reduce the number of jobs. I have noticed in other projects that this behavior has changed, and jobs in a build now start one after the other. Having a separate list then improves visibility when the build fails, because we can see at a glance the failing(s) tox environment(s). --- appveyor.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 64c9d6018..b761e0352 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,17 +6,23 @@ environment: # https://www.appveyor.com/docs/build-configuration#secure-variables matrix: - # create multiple jobs to execute a set of tox runs on each; this is to workaround having - # builds timing out in AppVeyor - - TOXENV: "linting,py26,py27,py33,py34,py35" - - TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial" - - TOXENV: "py27-nobyte,doctesting,freeze,docs" + - TOXENV: "linting" + - TOXENV: "py26" + - TOXENV: "py27" + - TOXENV: "py33" + - TOXENV: "py34" + - TOXENV: "py35" - TOXENV: "pypy" - -matrix: - allow_failures: - # pypy is disabled until #1963 gets fixed - - 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" install: - echo Installed Pythons From ec69514eb2be687f751e3a7a18d96e3e29d44c16 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 12 Nov 2016 12:29:40 -0200 Subject: [PATCH 065/201] Only install pypy on AppVeyor for "pypy" tox-env --- MANIFEST.in | 1 + appveyor.yml | 10 ++-------- scripts/install-pypy.bat | 6 ++++++ 3 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 scripts/install-pypy.bat diff --git a/MANIFEST.in b/MANIFEST.in index 24b4cfc9b..c57cbd911 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -10,6 +10,7 @@ include tox.ini include setup.py recursive-include scripts *.py +recursive-include scripts *.bat include .coveragerc diff --git a/appveyor.yml b/appveyor.yml index b761e0352..7192ec06f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,6 +6,7 @@ environment: # https://www.appveyor.com/docs/build-configuration#secure-variables matrix: + # note: please use "tox --listenvs" to populate the build matrix below - TOXENV: "linting" - TOXENV: "py26" - TOXENV: "py27" @@ -28,14 +29,7 @@ install: - echo Installed Pythons - dir c:\Python* - # install pypy using choco (redirect to a file and write to console in case - # choco install returns non-zero, because choco install python.pypy is too - # noisy) - # pypy is disabled until #1963 gets fixed - - choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) - - set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy - - echo PyPy installed - - pypy --version + - if "%TOXENV%" == "pypy" scripts\install-pypy.bat - C:\Python35\python -m pip install tox diff --git a/scripts/install-pypy.bat b/scripts/install-pypy.bat new file mode 100644 index 000000000..8012ea46a --- /dev/null +++ b/scripts/install-pypy.bat @@ -0,0 +1,6 @@ +REM install pypy using choco +REM redirect to a file because choco install python.pypy is too noisy. If the command fails, write output to console +choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) +set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy +echo PyPy installed +pypy --version From 50328f47db986c5c66813b2ae3654207919aad1c Mon Sep 17 00:00:00 2001 From: Igor Starikov Date: Sun, 13 Nov 2016 18:04:39 +0700 Subject: [PATCH 066/201] Docs: Added pytest promotional talk in Russian --- doc/en/talks.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/en/talks.rst b/doc/en/talks.rst index 46188bbe7..c35fba0b0 100644 --- a/doc/en/talks.rst +++ b/doc/en/talks.rst @@ -11,6 +11,9 @@ Talks and Tutorials Talks and blog postings --------------------------------------------- +- `Pythonic testing, Igor Starikov (Russian, PyNsk, November 2016) + `_. + - `pytest - Rapid Simple Testing, Florian Bruhin, Swiss Python Summit 2016 `_. From 0ba930a11d2448b3a21cdbae5274268c09ddf715 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Tue, 15 Nov 2016 23:05:58 +0100 Subject: [PATCH 067/201] Fix spelling mistakes Signed-off-by: Sebastian Ramacher --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 02a66079b..60875f4c4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -36,10 +36,10 @@ Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. * Report teardown output on test failure (`#442`_). - Thanks `@matclab`_ or the PR. + Thanks `@matclab`_ for the PR. * Fix teardown error message in generated xUnit XML. - Thanks `@gdyuldin`_ or the PR. + Thanks `@gdyuldin`_ for the PR. * Properly handle exceptions in ``multiprocessing`` tasks (`#1984`_). Thanks `@adborden`_ for the report and `@nicoddemus`_ for the PR. From 06bb61bbe31829955b36451829fdb9b4ffedc65b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 20 Nov 2016 11:56:15 -0500 Subject: [PATCH 068/201] Don't fail if imp can't find the source for a .pyc file. #2038 --- AUTHORS | 1 + CHANGELOG.rst | 7 ++++++- _pytest/assertion/rewrite.py | 7 ++++++- testing/test_assertrewrite.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6de0a112b..8cc6824cd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -101,6 +101,7 @@ Michael Birtwell Michael Droettboom Michael Seifert Mike Lundy +Ned Batchelder Nicolas Delaby Oleg Pidsadnyi Oliver Bestwalter diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 60875f4c4..b87302e8c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,12 +5,17 @@ * -* +* Cope gracefully with a .pyc file with no matching .py file (`#2038`_). Thanks + `@nedbat`_. * * +.. _@nedbat: https://github.com/nedbat + +.. _#2038: https://github.com/pytest-dev/pytest/issues/2038 + 3.0.4 ===== diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 6b4c1f483..9136c3867 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -80,7 +80,12 @@ class AssertionRewritingHook(object): tp = desc[2] if tp == imp.PY_COMPILED: if hasattr(imp, "source_from_cache"): - fn = imp.source_from_cache(fn) + try: + fn = imp.source_from_cache(fn) + except ValueError: + # Python 3 doesn't like orphaned but still-importable + # .pyc files. + fn = fn[:-1] else: fn = fn[:-1] elif tp != imp.PY_SOURCE: diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index e72266a18..ded11cbb4 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1,7 +1,10 @@ +import glob import os +import py_compile import stat import sys import zipfile + import py import pytest @@ -480,6 +483,31 @@ def test_rewritten(): monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1") assert testdir.runpytest_subprocess().ret == 0 + def test_orphaned_pyc_file(self, testdir): + if sys.version_info < (3, 0) and hasattr(sys, 'pypy_version_info'): + pytest.skip("pypy2 doesn't run orphaned pyc files") + + testdir.makepyfile(""" + import orphan + def test_it(): + assert orphan.value == 17 + """) + testdir.makepyfile(orphan=""" + value = 17 + """) + py_compile.compile("orphan.py") + os.remove("orphan.py") + + # Python 3 puts the .pyc files in a __pycache__ directory, and will + # not import from there without source. It will import a .pyc from + # the source location though. + if not os.path.exists("orphan.pyc"): + pycs = glob.glob("__pycache__/orphan.*.pyc") + assert len(pycs) == 1 + os.rename(pycs[0], "orphan.pyc") + + assert testdir.runpytest().ret == 0 + @pytest.mark.skipif('"__pypy__" in sys.modules') def test_pyc_vs_pyo(self, testdir, monkeypatch): testdir.makepyfile(""" From 1eb5a690d4c416962b6ccf46618367f68e54ea89 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 20 Nov 2016 18:59:15 -0200 Subject: [PATCH 069/201] Fix flake8 E305 and E306 errors These errors started to appear with flake8-3.1.1, while they don't appear with version 3.1.0 (weird). --- _pytest/_argcomplete.py | 1 + _pytest/_code/code.py | 2 + _pytest/_code/source.py | 3 ++ _pytest/assertion/__init__.py | 2 + _pytest/assertion/rewrite.py | 1 + _pytest/capture.py | 1 + _pytest/config.py | 6 +++ _pytest/debugging.py | 2 + _pytest/fixtures.py | 2 + _pytest/helpconfig.py | 2 + _pytest/junitxml.py | 1 + _pytest/mark.py | 2 + _pytest/pastebin.py | 6 +++ _pytest/pytester.py | 8 +++ _pytest/python.py | 3 ++ _pytest/runner.py | 7 +++ _pytest/skipping.py | 4 ++ _pytest/tmpdir.py | 1 + _pytest/unittest.py | 2 + testing/code/test_code.py | 5 ++ testing/code/test_excinfo.py | 23 ++++++++- testing/python/collect.py | 6 +++ testing/python/fixture.py | 10 ++++ testing/python/integration.py | 10 ++++ testing/python/metafunc.py | 12 +++++ testing/test_assertion.py | 3 ++ testing/test_assertrewrite.py | 97 +++++++++++++++++++++++++++++++++++ testing/test_collection.py | 5 ++ testing/test_config.py | 25 +++++++++ testing/test_conftest.py | 2 + testing/test_mark.py | 21 +++++++- testing/test_nose.py | 4 ++ testing/test_parseopt.py | 5 +- testing/test_pastebin.py | 2 + testing/test_pdb.py | 2 + testing/test_pluginmanager.py | 4 ++ testing/test_pytester.py | 4 ++ testing/test_runner.py | 10 ++++ tox.ini | 1 + 39 files changed, 303 insertions(+), 4 deletions(-) diff --git a/_pytest/_argcomplete.py b/_pytest/_argcomplete.py index 955855a96..3ab679d8b 100644 --- a/_pytest/_argcomplete.py +++ b/_pytest/_argcomplete.py @@ -87,6 +87,7 @@ class FastFilesCompleter: completion.append(x[prefix_dir:]) return completion + if os.environ.get('_ARGCOMPLETE'): try: import argcomplete.completers diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index 5b4237939..616d5c431 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -343,6 +343,7 @@ class Traceback(list): l.append(entry.frame.f_locals) return None + co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2', '?', 'eval') @@ -846,6 +847,7 @@ def getrawcode(obj, trycall=True): return x return obj + if sys.version_info[:2] >= (3, 5): # RecursionError introduced in 3.5 def is_recursion_error(excinfo): return excinfo.errisinstance(RecursionError) # noqa diff --git a/_pytest/_code/source.py b/_pytest/_code/source.py index 846e3cced..522150b55 100644 --- a/_pytest/_code/source.py +++ b/_pytest/_code/source.py @@ -265,6 +265,7 @@ def findsource(obj): source.lines = [line.rstrip() for line in sourcelines] return source, lineno + def getsource(obj, **kwargs): import _pytest._code obj = _pytest._code.getrawcode(obj) @@ -275,6 +276,7 @@ def getsource(obj, **kwargs): assert isinstance(strsrc, str) return Source(strsrc, **kwargs) + def deindent(lines, offset=None): if offset is None: for line in lines: @@ -288,6 +290,7 @@ def deindent(lines, offset=None): if offset == 0: return list(lines) newlines = [] + def readline_generator(lines): for line in lines: yield line + '\n' diff --git a/_pytest/assertion/__init__.py b/_pytest/assertion/__init__.py index fd1ebe2c1..18cb7d32c 100644 --- a/_pytest/assertion/__init__.py +++ b/_pytest/assertion/__init__.py @@ -80,10 +80,12 @@ def install_importhook(config): config._assertstate.hook = hook = rewrite.AssertionRewritingHook(config) sys.meta_path.insert(0, hook) config._assertstate.trace('installed rewrite import hook') + def undo(): hook = config._assertstate.hook if hook is not None and hook in sys.meta_path: sys.meta_path.remove(hook) + config.add_cleanup(undo) return hook diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 6b4c1f483..c2098936d 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -276,6 +276,7 @@ def _write_pyc(state, co, source_stat, pyc): fp.close() return True + RN = "\r\n".encode("utf-8") N = "\n".encode("utf-8") diff --git a/_pytest/capture.py b/_pytest/capture.py index 9f60db6ac..eea81ca18 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -152,6 +152,7 @@ class CaptureManager: item.add_report_section(when, "stdout", out) item.add_report_section(when, "stderr", err) + error_capsysfderror = "cannot use capsys and capfd at the same time" diff --git a/_pytest/config.py b/_pytest/config.py index 5df198e21..bd7a03aa8 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -65,9 +65,11 @@ def main(args=None, plugins=None): class cmdline: # compatibility namespace main = staticmethod(main) + class UsageError(Exception): """ error in pytest usage or invocation""" + _preinit = [] default_plugins = ( @@ -818,9 +820,11 @@ class Notset: def __repr__(self): return "" + notset = Notset() FILE_OR_DIR = 'file_or_dir' + class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ @@ -843,9 +847,11 @@ class Config(object): self._warn = self.pluginmanager._warn self.pluginmanager.register(self, "pytestconfig") self._configured = False + def do_setns(dic): import pytest setns(pytest, dic) + self.hook.pytest_namespace.call_historic(do_setns, {}) self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser)) diff --git a/_pytest/debugging.py b/_pytest/debugging.py index 299b05028..d96170bd8 100644 --- a/_pytest/debugging.py +++ b/_pytest/debugging.py @@ -31,10 +31,12 @@ def pytest_configure(config): pytestPDB._pdb_cls = pdb_cls old = (pdb.set_trace, pytestPDB._pluginmanager) + def fin(): pdb.set_trace, pytestPDB._pluginmanager = old pytestPDB._config = None pytestPDB._pdb_cls = pdb.Pdb + pdb.set_trace = pytest.set_trace pytestPDB._pluginmanager = config.pluginmanager pytestPDB._config = config diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index 3f08b7c6d..28bcd4d8d 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -32,11 +32,13 @@ scope2props["function"] = scope2props["instance"] + ("function", "keywords") def scopeproperty(name=None, doc=None): def decoratescope(func): scopename = name or func.__name__ + def provide(self): if func.__name__ in scope2props[self.scope]: return func(self) raise AttributeError("%s not available in %s-scoped context" % ( scopename, self.scope)) + return property(provide, None, None, func.__doc__) return decoratescope diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py index 538a763ca..dd161275b 100644 --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -41,12 +41,14 @@ def pytest_cmdline_parse(): config.trace.root.setwriter(debugfile.write) undo_tracing = config.pluginmanager.enable_tracing() sys.stderr.write("writing pytestdebug information to %s\n" % path) + def unset_tracing(): debugfile.close() sys.stderr.write("wrote pytestdebug information to %s\n" % debugfile.name) config.trace.root.setwriter(None) undo_tracing() + config.add_cleanup(unset_tracing) def pytest_cmdline_main(config): diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py index 97d0675a6..4b9103949 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -27,6 +27,7 @@ else: class Junit(py.xml.Namespace): pass + # We need to get the subset of the invalid unicode ranges according to # XML 1.0 which are valid in this python build. Hence we calculate # this dynamically instead of hardcoding it. The spec range of valid diff --git a/_pytest/mark.py b/_pytest/mark.py index 640c4e61c..357a60492 100644 --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -54,6 +54,8 @@ def pytest_cmdline_main(config): tw.line() config._ensure_unconfigure() return 0 + + pytest_cmdline_main.tryfirst = True diff --git a/_pytest/pastebin.py b/_pytest/pastebin.py index 4ec62d022..9f1cf9063 100644 --- a/_pytest/pastebin.py +++ b/_pytest/pastebin.py @@ -11,6 +11,7 @@ def pytest_addoption(parser): choices=['failed', 'all'], help="send failed|all info to bpaste.net pastebin service.") + @pytest.hookimpl(trylast=True) def pytest_configure(config): import py @@ -23,13 +24,16 @@ def pytest_configure(config): # pastebin file will be utf-8 encoded binary file config._pastebinfile = tempfile.TemporaryFile('w+b') oldwrite = tr._tw.write + def tee_write(s, **kwargs): oldwrite(s, **kwargs) if py.builtin._istext(s): s = s.encode('utf-8') config._pastebinfile.write(s) + tr._tw.write = tee_write + def pytest_unconfigure(config): if hasattr(config, '_pastebinfile'): # get terminal contents and delete file @@ -45,6 +49,7 @@ def pytest_unconfigure(config): pastebinurl = create_new_paste(sessionlog) tr.write_line("pastebin session-log: %s\n" % pastebinurl) + def create_new_paste(contents): """ Creates a new paste using bpaste.net service. @@ -72,6 +77,7 @@ def create_new_paste(contents): else: return 'bad response: ' + response + def pytest_terminal_summary(terminalreporter): import _pytest.config if terminalreporter.config.option.pastebin != "failed": diff --git a/_pytest/pytester.py b/_pytest/pytester.py index a8bb39794..8aa5c0c4f 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -479,10 +479,12 @@ class Testdir: for name, value in items: p = self.tmpdir.join(name).new(ext=ext) source = Source(value) + def my_totext(s, encoding="utf-8"): if py.builtin._isbytes(s): s = py.builtin._totext(s, encoding=encoding) return s + source_unicode = "\n".join([my_totext(line) for line in source.lines]) source = py.builtin._totext(source_unicode) content = source.strip().encode("utf-8") # + "\n" @@ -692,12 +694,15 @@ class Testdir: # warning which will trigger to say they can no longer be # re-written, which is fine as they are already re-written. orig_warn = AssertionRewritingHook._warn_already_imported + def revert(): AssertionRewritingHook._warn_already_imported = orig_warn + self.request.addfinalizer(revert) AssertionRewritingHook._warn_already_imported = lambda *a: None rec = [] + class Collect: def pytest_configure(x, config): rec.append(self.make_hook_recorder(config.pluginmanager)) @@ -732,10 +737,13 @@ class Testdir: try: reprec = self.inline_run(*args, **kwargs) except SystemExit as e: + class reprec: ret = e.args[0] + except Exception: traceback.print_exc() + class reprec: ret = 3 finally: diff --git a/_pytest/python.py b/_pytest/python.py index 18432c1e7..88c65b1ce 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -214,9 +214,12 @@ class PyobjMixin(PyobjContext): if obj is None: self._obj = obj = self._getobj() return obj + def fset(self, value): self._obj = value + return property(fget, fset, None, "underlying python object") + obj = obj() def _getobj(self): diff --git a/_pytest/runner.py b/_pytest/runner.py index d1a155415..eb29e7370 100644 --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -515,8 +515,10 @@ def exit(msg): __tracebackhide__ = True raise Exit(msg) + exit.Exception = Exit + def skip(msg=""): """ skip an executing test with the given message. Note: it's usually better to use the pytest.mark.skipif marker to declare a test to be @@ -525,8 +527,11 @@ def skip(msg=""): """ __tracebackhide__ = True raise Skipped(msg=msg) + + skip.Exception = Skipped + def fail(msg="", pytrace=True): """ explicitly fail an currently-executing test with the given Message. @@ -535,6 +540,8 @@ def fail(msg="", pytrace=True): """ __tracebackhide__ = True raise Failed(msg=msg, pytrace=pytrace) + + fail.Exception = Failed diff --git a/_pytest/skipping.py b/_pytest/skipping.py index 2f000b7b9..a8eaea98a 100644 --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -25,8 +25,10 @@ def pytest_configure(config): if config.option.runxfail: old = pytest.xfail config._cleanup.append(lambda: setattr(pytest, "xfail", old)) + def nop(*args, **kwargs): pass + nop.Exception = XFailed setattr(pytest, "xfail", nop) @@ -65,6 +67,8 @@ def xfail(reason=""): """ xfail an executing test or setup functions with the given reason.""" __tracebackhide__ = True raise XFailed(reason) + + xfail.Exception = XFailed diff --git a/_pytest/tmpdir.py b/_pytest/tmpdir.py index 5c0802508..28a6b0636 100644 --- a/_pytest/tmpdir.py +++ b/_pytest/tmpdir.py @@ -81,6 +81,7 @@ def get_user(): except (ImportError, KeyError): return None + # backward compatibility TempdirHandler = TempdirFactory diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 4355efe70..73224010b 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -186,6 +186,7 @@ def pytest_runtest_protocol(item): ut = sys.modules['twisted.python.failure'] Failure__init__ = ut.Failure.__init__ check_testcase_implements_trial_reporter() + def excstore(self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None): if exc_value is None: @@ -199,6 +200,7 @@ def pytest_runtest_protocol(item): captureVars=captureVars) except TypeError: Failure__init__(self, exc_value, exc_type, exc_tb) + ut.Failure.__init__ = excstore yield ut.Failure.__init__ = Failure__init__ diff --git a/testing/code/test_code.py b/testing/code/test_code.py index 6f1d9d3cc..ad9db6d2e 100644 --- a/testing/code/test_code.py +++ b/testing/code/test_code.py @@ -24,6 +24,7 @@ def test_code_with_class(): pass pytest.raises(TypeError, "_pytest._code.Code(A)") + if True: def x(): pass @@ -68,8 +69,10 @@ def test_code_from_func(): def test_unicode_handling(): value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8') + def f(): raise Exception(value) + excinfo = pytest.raises(Exception, f) str(excinfo) if sys.version_info[0] < 3: @@ -79,8 +82,10 @@ def test_unicode_handling(): @pytest.mark.skipif(sys.version_info[0] >= 3, reason='python 2 only issue') def test_unicode_handling_syntax_error(): value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8') + def f(): raise SyntaxError('invalid syntax', (None, 1, 3, value)) + excinfo = pytest.raises(Exception, f) str(excinfo) if sys.version_info[0] < 3: diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 3aae9c71c..c72b87428 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -56,8 +56,10 @@ def test_excinfo_simple(): def test_excinfo_getstatement(): def g(): raise ValueError + def f(): g() + try: f() except ValueError: @@ -168,11 +170,13 @@ class TestTraceback_f_g_h: # raise ValueError # + def g(): # __tracebackhide__ = tracebackhide f() # + def h(): # g() @@ -214,15 +218,18 @@ class TestTraceback_f_g_h: def test_traceback_no_recursion_index(self): def do_stuff(): raise RuntimeError + def reraise_me(): import sys exc, val, tb = sys.exc_info() py.builtin._reraise(exc, val, tb) + def f(n): try: do_stuff() except: reraise_me() + excinfo = pytest.raises(RuntimeError, f, 8) traceback = excinfo.traceback recindex = traceback.recursionindex() @@ -245,17 +252,18 @@ class TestTraceback_f_g_h: excinfo = pytest.raises(ValueError, fail) assert excinfo.traceback.recursionindex() is None - - def test_traceback_getcrashentry(self): def i(): __tracebackhide__ = True raise ValueError + def h(): i() + def g(): __tracebackhide__ = True h() + def f(): g() @@ -271,6 +279,7 @@ class TestTraceback_f_g_h: def g(): __tracebackhide__ = True raise ValueError + def f(): __tracebackhide__ = True g() @@ -465,11 +474,13 @@ raise ValueError() class FakeCode(object): class raw: co_filename = '?' + path = '?' firstlineno = 5 def fullsource(self): return None + fullsource = property(fullsource) class FakeFrame(object): @@ -491,17 +502,21 @@ raise ValueError() class FakeExcinfo(_pytest._code.ExceptionInfo): typename = "Foo" value = Exception() + def __init__(self): pass def exconly(self, tryshort): return "EXC" + def errisinstance(self, cls): return False excinfo = FakeExcinfo() + class FakeRawTB(object): tb_next = None + tb = FakeRawTB() excinfo.traceback = Traceback(tb) @@ -719,8 +734,10 @@ raise ValueError() excinfo = pytest.raises(ValueError, mod.entry) p = FormattedExcinfo() + def raiseos(): raise OSError(2) + monkeypatch.setattr(py.std.os, 'getcwd', raiseos) assert p._makepath(__file__) == __file__ p.repr_traceback(excinfo) @@ -789,9 +806,11 @@ raise ValueError() def test_reprexcinfo_unicode(self): from _pytest._code.code import TerminalRepr + class MyRepr(TerminalRepr): def toterminal(self, tw): tw.line(py.builtin._totext("я", "utf-8")) + x = py.builtin._totext(MyRepr()) assert x == py.builtin._totext("я", "utf-8") diff --git a/testing/python/collect.py b/testing/python/collect.py index 2913b11a4..1e69f2da9 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -383,10 +383,13 @@ class TestFunction: config = testdir.parseconfigure() session = testdir.Session(config) session._fixturemanager = FixtureManager(session) + def func1(): pass + def func2(): pass + f1 = pytest.Function(name="name", parent=session, config=config, args=(1,), callobj=func1) assert f1 == f1 @@ -547,12 +550,15 @@ class TestFunction: def test_pyfunc_call(self, testdir): item = testdir.getitem("def test_func(): raise ValueError") config = item.config + class MyPlugin1: def pytest_pyfunc_call(self, pyfuncitem): raise ValueError + class MyPlugin2: def pytest_pyfunc_call(self, pyfuncitem): return True + config.pluginmanager.register(MyPlugin1()) config.pluginmanager.register(MyPlugin2()) config.hook.pytest_runtest_setup(item=item) diff --git a/testing/python/fixture.py b/testing/python/fixture.py index d6b7840c6..be99ed833 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -10,15 +10,20 @@ from _pytest import fixtures def test_getfuncargnames(): def f(): pass assert not fixtures.getfuncargnames(f) + def g(arg): pass assert fixtures.getfuncargnames(g) == ('arg',) + def h(arg1, arg2="hello"): pass assert fixtures.getfuncargnames(h) == ('arg1',) + def h(arg1, arg2, arg3="hello"): pass assert fixtures.getfuncargnames(h) == ('arg1', 'arg2') + class A: def f(self, arg1, arg2="hello"): pass + assert fixtures.getfuncargnames(A().f) == ('arg1',) if sys.version_info < (3,0): assert fixtures.getfuncargnames(A.f) == ('arg1',) @@ -869,8 +874,10 @@ class TestRequestCachedSetup: item1 = testdir.getitem("def test_func(): pass") req1 = fixtures.FixtureRequest(item1) l = ["hello", "world"] + def setup(): return l.pop() + ret1 = req1.cached_setup(setup, extrakey=1) ret2 = req1.cached_setup(setup, extrakey=2) assert ret2 == "hello" @@ -884,10 +891,13 @@ class TestRequestCachedSetup: item1 = testdir.getitem("def test_func(): pass") req1 = fixtures.FixtureRequest(item1) l = [] + def setup(): l.append("setup") + def teardown(val): l.append("teardown") + req1.cached_setup(setup, teardown, scope="function") assert l == ['setup'] # artificial call of finalizer diff --git a/testing/python/integration.py b/testing/python/integration.py index 237becd6f..6697342ea 100644 --- a/testing/python/integration.py +++ b/testing/python/integration.py @@ -63,10 +63,12 @@ class TestOEJSKITSpecials: def test_wrapped_getfslineno(): def func(): pass + def wrap(f): func.__wrapped__ = f func.patchings = ["qwe"] return func + @wrap def wrapped_func(x, y, z): pass @@ -77,28 +79,36 @@ def test_wrapped_getfslineno(): class TestMockDecoration: def test_wrapped_getfuncargnames(self): from _pytest.compat import getfuncargnames + def wrap(f): + def func(): pass + func.__wrapped__ = f return func + @wrap def f(x): pass + l = getfuncargnames(f) assert l == ("x",) def test_wrapped_getfuncargnames_patching(self): from _pytest.compat import getfuncargnames + def wrap(f): def func(): pass func.__wrapped__ = f func.patchings = ["qwe"] return func + @wrap def f(x, y, z): pass + l = getfuncargnames(f) assert l == ("y", "z") diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 9d71df20a..a7e1d5699 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -20,8 +20,10 @@ class TestMetafunc: # initiliazation class FixtureInfo: name2fixturedefs = None + def __init__(self, names): self.names_closure = names + names = fixtures.getfuncargnames(func) fixtureinfo = FixtureInfo(names) return python.Metafunc(func, fixtureinfo, None) @@ -65,7 +67,9 @@ class TestMetafunc: def test_addcall_param(self): def func(arg1): pass metafunc = self.Metafunc(func) + class obj: pass + metafunc.addcall(param=obj) metafunc.addcall(param=obj) metafunc.addcall(param=1) @@ -76,8 +80,11 @@ class TestMetafunc: def test_addcall_funcargs(self): def func(x): pass + metafunc = self.Metafunc(func) + class obj: pass + metafunc.addcall(funcargs={"x": 2}) metafunc.addcall(funcargs={"x": 3}) pytest.raises(pytest.fail.Exception, "metafunc.addcall({'xyz': 0})") @@ -142,8 +149,10 @@ class TestMetafunc: def test_parametrize_with_userobjects(self): def func(x, y): pass metafunc = self.Metafunc(func) + class A: pass + metafunc.parametrize("x", [A(), A()]) metafunc.parametrize("y", list("ab")) assert metafunc._calls[0].id == "x0-a" @@ -254,6 +263,7 @@ class TestMetafunc: @pytest.mark.issue351 def test_idmaker_idfn(self): from _pytest.python import idmaker + def ids(val): if isinstance(val, Exception): return repr(val) @@ -270,6 +280,7 @@ class TestMetafunc: @pytest.mark.issue351 def test_idmaker_idfn_unique_names(self): from _pytest.python import idmaker + def ids(val): return 'a' @@ -285,6 +296,7 @@ class TestMetafunc: @pytest.mark.issue351 def test_idmaker_idfn_exception(self): from _pytest.python import idmaker + def ids(val): raise Exception("bad code") diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 48cd26f02..c63f26b9c 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -12,12 +12,15 @@ PY3 = sys.version_info >= (3, 0) @pytest.fixture def mock_config(): + class Config(object): verbose = False + def getoption(self, name): if name == 'verbose': return self.verbose raise KeyError('Not mocked out: %s' % name) + return Config() diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index e72266a18..483d80b3d 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -104,20 +104,29 @@ class TestAssertionRewrite: def f(): assert False assert getmsg(f) == "assert False" + def f(): f = False assert f + assert getmsg(f) == "assert False" + def f(): assert a_global # noqa + assert getmsg(f, {"a_global" : False}) == "assert False" + def f(): assert sys == 42 + assert getmsg(f, {"sys" : sys}) == "assert sys == 42" + def f(): assert cls == 42 # noqa + class X(object): pass + assert getmsg(f, {"cls" : X}) == "assert cls == 42" def test_assert_already_has_message(self): @@ -190,78 +199,110 @@ class TestAssertionRewrite: def f(): f = g = False assert f and g + assert getmsg(f) == "assert (False)" + def f(): f = True g = False assert f and g + assert getmsg(f) == "assert (True and False)" + def f(): f = False g = True assert f and g + assert getmsg(f) == "assert (False)" + def f(): f = g = False assert f or g + assert getmsg(f) == "assert (False or False)" + def f(): f = g = False assert not f and not g + getmsg(f, must_pass=True) + def x(): return False + def f(): assert x() and x() + assert getmsg(f, {"x" : x}) == """assert (False) + where False = x()""" + def f(): assert False or x() + assert getmsg(f, {"x" : x}) == """assert (False or False) + where False = x()""" + def f(): assert 1 in {} and 2 in {} + assert getmsg(f) == "assert (1 in {})" + def f(): x = 1 y = 2 assert x in {1 : None} and y in {} + assert getmsg(f) == "assert (1 in {1: None} and 2 in {})" + def f(): f = True g = False assert f or g + getmsg(f, must_pass=True) + def f(): f = g = h = lambda: True assert f() and g() and h() + getmsg(f, must_pass=True) def test_short_circut_evaluation(self): def f(): assert True or explode # noqa + getmsg(f, must_pass=True) + def f(): x = 1 assert x == 1 or x == 2 + getmsg(f, must_pass=True) def test_unary_op(self): def f(): x = True assert not x + assert getmsg(f) == "assert not True" + def f(): x = 0 assert ~x + 1 + assert getmsg(f) == "assert (~0 + 1)" + def f(): x = 3 assert -x + x + assert getmsg(f) == "assert (-3 + 3)" + def f(): x = 0 assert +x + x + assert getmsg(f) == "assert (+0 + 0)" def test_binary_op(self): @@ -269,7 +310,9 @@ class TestAssertionRewrite: x = 1 y = -1 assert x + y + assert getmsg(f) == "assert (1 + -1)" + def f(): assert not 5 % 4 assert getmsg(f) == "assert not (5 % 4)" @@ -277,7 +320,9 @@ class TestAssertionRewrite: def test_boolop_percent(self): def f(): assert 3 % 2 and False + assert getmsg(f) == "assert ((3 % 2) and False)" + def f(): assert False or 4 % 2 assert getmsg(f) == "assert (False or (4 % 2))" @@ -298,113 +343,159 @@ class TestAssertionRewrite: def test_call(self): def g(a=42, *args, **kwargs): return False + ns = {"g" : g} + def f(): assert g() + assert getmsg(f, ns) == """assert False + where False = g()""" + def f(): assert g(1) + assert getmsg(f, ns) == """assert False + where False = g(1)""" + def f(): assert g(1, 2) + assert getmsg(f, ns) == """assert False + where False = g(1, 2)""" + def f(): assert g(1, g=42) + assert getmsg(f, ns) == """assert False + where False = g(1, g=42)""" + def f(): assert g(1, 3, g=23) + assert getmsg(f, ns) == """assert False + where False = g(1, 3, g=23)""" + def f(): seq = [1, 2, 3] assert g(*seq) + assert getmsg(f, ns) == """assert False + where False = g(*[1, 2, 3])""" + def f(): x = "a" assert g(**{x : 2}) + assert getmsg(f, ns) == """assert False + where False = g(**{'a': 2})""" def test_attribute(self): class X(object): g = 3 + ns = {"x" : X} + def f(): assert not x.g # noqa + assert getmsg(f, ns) == """assert not 3 + where 3 = x.g""" + def f(): x.a = False # noqa assert x.a # noqa + assert getmsg(f, ns) == """assert False + where False = x.a""" def test_comparisons(self): + def f(): a, b = range(2) assert b < a + assert getmsg(f) == """assert 1 < 0""" + def f(): a, b, c = range(3) assert a > b > c + assert getmsg(f) == """assert 0 > 1""" + def f(): a, b, c = range(3) assert a < b > c + assert getmsg(f) == """assert 1 > 2""" + def f(): a, b, c = range(3) assert a < b <= c + getmsg(f, must_pass=True) + def f(): a, b, c = range(3) assert a < b assert b < c + getmsg(f, must_pass=True) def test_len(self): + def f(): l = list(range(10)) assert len(l) == 11 + assert getmsg(f).startswith("""assert 10 == 11 + where 10 = len([""") def test_custom_reprcompare(self, monkeypatch): def my_reprcompare(op, left, right): return "42" + monkeypatch.setattr(util, "_reprcompare", my_reprcompare) + def f(): assert 42 < 3 + assert getmsg(f) == "assert 42" + def my_reprcompare(op, left, right): return "%s %s %s" % (left, op, right) + monkeypatch.setattr(util, "_reprcompare", my_reprcompare) + def f(): assert 1 < 3 < 5 <= 4 < 7 + assert getmsg(f) == "assert 5 <= 4" def test_assert_raising_nonzero_in_comparison(self): def f(): class A(object): + def __nonzero__(self): raise ValueError(42) + def __lt__(self, other): return A() + def __repr__(self): return "" + def myany(x): return False + assert myany(A() < 0) + assert " < 0" in getmsg(f) def test_formatchar(self): def f(): assert "%test" == "test" + assert getmsg(f).startswith("assert '%test' == 'test'") def test_custom_repr(self): @@ -414,8 +505,10 @@ class TestAssertionRewrite: def __repr__(self): return "\n{ \n~ \n}" + f = Foo() assert 0 == f.a + assert r"where 1 = \n{ \n~ \n}.a" in util._format_lines([getmsg(f)])[0] @@ -527,8 +620,10 @@ def test_rewritten(): def test_rewrite_warning(self, pytestconfig, monkeypatch): hook = AssertionRewritingHook(pytestconfig) warnings = [] + def mywarn(code, msg): warnings.append((code, msg)) + monkeypatch.setattr(hook.config, 'warn', mywarn) hook.mark_rewrite('_pytest') assert '_pytest' in warnings[0][1] @@ -642,10 +737,12 @@ class TestAssertionRewriteHookDetails(object): source_path = tmpdir.ensure("source.py") pycpath = tmpdir.join("pyc").strpath assert _write_pyc(state, [1], source_path.stat(), pycpath) + def open(*args): e = IOError() e.errno = 10 raise e + monkeypatch.setattr(b, "open", open) assert not _write_pyc(state, [1], source_path.stat(), pycpath) diff --git a/testing/test_collection.py b/testing/test_collection.py index 71a64c3c9..9cf4de895 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -150,11 +150,13 @@ class TestCollectFS: class TestCollectPluginHookRelay: def test_pytest_collect_file(self, testdir): wascalled = [] + class Plugin: def pytest_collect_file(self, path, parent): if not path.basename.startswith("."): # Ignore hidden files, e.g. .testmondata. wascalled.append(path) + testdir.makefile(".abc", "xyz") pytest.main([testdir.tmpdir], plugins=[Plugin()]) assert len(wascalled) == 1 @@ -162,15 +164,18 @@ class TestCollectPluginHookRelay: def test_pytest_collect_directory(self, testdir): wascalled = [] + class Plugin: def pytest_collect_directory(self, path, parent): wascalled.append(path.basename) + testdir.mkdir("hello") testdir.mkdir("world") pytest.main(testdir.tmpdir, plugins=[Plugin()]) assert "hello" in wascalled assert "world" in wascalled + class TestPrunetraceback: def test_custom_repr_failure(self, testdir): diff --git a/testing/test_config.py b/testing/test_config.py index 83e8f4e6a..75a806c4a 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -373,23 +373,31 @@ def test_options_on_small_file_do_not_blow_up(testdir): ['--traceconfig'], ['-v'], ['-v', '-v']): runfiletest(opts + [path]) + def test_preparse_ordering_with_setuptools(testdir, monkeypatch): pkg_resources = pytest.importorskip("pkg_resources") + def my_iter(name): assert name == "pytest11" + class Dist: project_name = 'spam' version = '1.0' + def _get_metadata(self, name): return ['foo.txt,sha256=abc,123'] + class EntryPoint: name = "mytestplugin" dist = Dist() + def load(self): class PseudoPlugin: x = 42 return PseudoPlugin() + return iter([EntryPoint()]) + monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) testdir.makeconftest(""" pytest_plugins = "mytestplugin", @@ -402,18 +410,24 @@ def test_preparse_ordering_with_setuptools(testdir, monkeypatch): def test_setuptools_importerror_issue1479(testdir, monkeypatch): pkg_resources = pytest.importorskip("pkg_resources") + def my_iter(name): assert name == "pytest11" + class Dist: project_name = 'spam' version = '1.0' + def _get_metadata(self, name): return ['foo.txt,sha256=abc,123'] + class EntryPoint: name = "mytestplugin" dist = Dist() + def load(self): raise ImportError("Don't hide me!") + return iter([EntryPoint()]) monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) @@ -423,19 +437,26 @@ def test_setuptools_importerror_issue1479(testdir, monkeypatch): def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch): pkg_resources = pytest.importorskip("pkg_resources") + def my_iter(name): assert name == "pytest11" + class Dist: project_name = 'spam' version = '1.0' + def _get_metadata(self, name): return ['foo.txt,sha256=abc,123'] + class EntryPoint: name = "mytestplugin" dist = Dist() + def load(self): assert 0, "should not arrive here" + return iter([EntryPoint()]) + monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) config = testdir.parseconfig("-p", "no:mytestplugin") plugin = config.pluginmanager.getplugin("mytestplugin") @@ -503,9 +524,11 @@ def test_notify_exception(testdir, capfd): config.notify_exception(excinfo) out, err = capfd.readouterr() assert "ValueError" in err + class A: def pytest_internalerror(self, excrepr): return True + config.pluginmanager.register(A()) config.notify_exception(excinfo) out, err = capfd.readouterr() @@ -515,9 +538,11 @@ def test_notify_exception(testdir, capfd): def test_load_initial_conftest_last_ordering(testdir): from _pytest.config import get_config pm = get_config().pluginmanager + class My: def pytest_load_initial_conftests(self): pass + m = My() pm.register(m) hc = pm.hook.pytest_load_initial_conftests diff --git a/testing/test_conftest.py b/testing/test_conftest.py index 377283eb9..6dce13859 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -200,8 +200,10 @@ def test_conftest_import_order(testdir, monkeypatch): sub = testdir.mkdir("sub") ct2 = sub.join("conftest.py") ct2.write("") + def impct(p): return p + conftest = PytestPluginManager() conftest._confcutdir = testdir.tmpdir monkeypatch.setattr(conftest, '_importconftest', impct) diff --git a/testing/test_mark.py b/testing/test_mark.py index e0bf3c3c8..a4430b4c8 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -23,15 +23,19 @@ class TestMark: def test_pytest_mark_bare(self): mark = Mark() + def f(): pass + mark.hello(f) assert f.hello def test_pytest_mark_keywords(self): mark = Mark() + def f(): pass + mark.world(x=3, y=4)(f) assert f.world assert f.world.kwargs['x'] == 3 @@ -39,8 +43,10 @@ class TestMark: def test_apply_multiple_and_merge(self): mark = Mark() + def f(): pass + mark.world mark.world(x=3)(f) assert f.world.kwargs['x'] == 3 @@ -53,33 +59,43 @@ class TestMark: def test_pytest_mark_positional(self): mark = Mark() + def f(): pass + mark.world("hello")(f) assert f.world.args[0] == "hello" mark.world("world")(f) def test_pytest_mark_positional_func_and_keyword(self): mark = Mark() + def f(): raise Exception + m = mark.world(f, omega="hello") + def g(): pass + assert m(g) == g assert g.world.args[0] is f assert g.world.kwargs["omega"] == "hello" def test_pytest_mark_reuse(self): mark = Mark() + def f(): pass + w = mark.some w("hello", reason="123")(f) assert f.some.args[0] == "hello" assert f.some.kwargs['reason'] == "123" + def g(): pass + w("world", reason2="456")(g) assert g.some.args[0] == "world" assert 'reason' not in g.some.kwargs @@ -610,11 +626,12 @@ class TestFunctional: def test_1(parameter): assert True """) - reprec = testdir.inline_run() reprec.assertoutcome(skipped=1) + class TestKeywordSelection: + def test_select_simple(self, testdir): file_test = testdir.makepyfile(""" def test_one(): @@ -623,6 +640,7 @@ class TestKeywordSelection: def test_method_one(self): assert 42 == 43 """) + def check(keyword, name): reprec = testdir.inline_run("-s", "-k", keyword, file_test) passed, skipped, failed = reprec.listoutcomes() @@ -709,6 +727,7 @@ class TestKeywordSelection: p = testdir.makepyfile(""" def test_one(): assert 1 """) + def assert_test_is_not_selected(keyword): reprec = testdir.inline_run("-k", keyword, p) passed, skipped, failed = reprec.countoutcomes() diff --git a/testing/test_nose.py b/testing/test_nose.py index a5162381e..f54246111 100644 --- a/testing/test_nose.py +++ b/testing/test_nose.py @@ -25,18 +25,22 @@ def test_nose_setup(testdir): def test_setup_func_with_setup_decorator(): from _pytest.nose import call_optional l = [] + class A: @pytest.fixture(autouse=True) def f(self): l.append(1) + call_optional(A(), "f") assert not l def test_setup_func_not_callable(): from _pytest.nose import call_optional + class A: f = 1 + call_optional(A(), "f") def test_nose_setup_func(testdir): diff --git a/testing/test_parseopt.py b/testing/test_parseopt.py index fc9ded488..e933dbb8d 100644 --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -138,7 +138,10 @@ class TestParser: def test_parse_setoption(self, parser): parser.addoption("--hello", dest="hello", action="store") parser.addoption("--world", dest="world", default=42) - class A: pass + + class A: + pass + option = A() args = parser.parse_setoption(['--hello', 'world'], option) assert option.hello == "world" diff --git a/testing/test_pastebin.py b/testing/test_pastebin.py index 03570a5c7..8123424ca 100644 --- a/testing/test_pastebin.py +++ b/testing/test_pastebin.py @@ -84,8 +84,10 @@ class TestPaste: function that connects to bpaste service. """ calls = [] + def mocked(url, data): calls.append((url, data)) + class DummyFile: def read(self): # part of html of a normal response diff --git a/testing/test_pdb.py b/testing/test_pdb.py index b22f5128e..df58dad87 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -19,8 +19,10 @@ class TestPDB: def pdblist(self, request): monkeypatch = request.getfixturevalue("monkeypatch") pdblist = [] + def mypdb(*args): pdblist.append(args) + plugin = request.config.pluginmanager.getplugin('debugging') monkeypatch.setattr(plugin, 'post_mortem', mypdb) return pdblist diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index e61c84247..d636102f7 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -83,6 +83,7 @@ class TestPytestPluginInteractions: def test_configure(self, testdir): config = testdir.parseconfig() l = [] + class A: def pytest_configure(self, config): l.append(self) @@ -102,13 +103,16 @@ class TestPytestPluginInteractions: def test_hook_tracing(self): pytestpm = get_config().pluginmanager # fully initialized with plugins saveindent = [] + class api1: def pytest_plugin_registered(self): saveindent.append(pytestpm.trace.root.indent) + class api2: def pytest_plugin_registered(self): saveindent.append(pytestpm.trace.root.indent) raise ValueError() + l = [] pytestpm.trace.root.setwriter(l.append) undo = pytestpm.enable_tracing() diff --git a/testing/test_pytester.py b/testing/test_pytester.py index 65660afdf..14548808c 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -11,6 +11,7 @@ def test_make_hook_recorder(testdir): assert not recorder.getfailures() pytest.xfail("internal reportrecorder tests need refactoring") + class rep: excinfo = None passed = False @@ -80,10 +81,13 @@ def make_holder(): "x" apimod = type(os)('api') + def pytest_xyz(arg): "x" + def pytest_xyz_noarg(): "x" + apimod.pytest_xyz = pytest_xyz apimod.pytest_xyz_noarg = pytest_xyz_noarg return apiclass, apimod diff --git a/testing/test_runner.py b/testing/test_runner.py index e88a548d7..727defa92 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -38,9 +38,13 @@ class TestSetupState: def test_teardown_multiple_one_fails(self, testdir): r = [] + def fin1(): r.append('fin1') + def fin2(): raise Exception('oops') + def fin3(): r.append('fin3') + item = testdir.getitem("def test_func(): pass") ss = runner.SetupState() ss.addfinalizer(fin1, item) @@ -55,7 +59,9 @@ class TestSetupState: # Ensure the first exception is the one which is re-raised. # Ideally both would be reported however. def fin1(): raise Exception('oops1') + def fin2(): raise Exception('oops2') + item = testdir.getitem("def test_func(): pass") ss = runner.SetupState() ss.addfinalizer(fin1, item) @@ -527,8 +533,10 @@ def test_exception_printing_skip(): def test_importorskip(monkeypatch): importorskip = pytest.importorskip + def f(): importorskip("asdlkj") + try: sys = importorskip("sys") # noqa assert sys == py.std.sys @@ -643,11 +651,13 @@ def test_makereport_getsource_dynamic_code(testdir, monkeypatch): """Test that exception in dynamically generated code doesn't break getting the source line.""" import inspect original_findsource = inspect.findsource + def findsource(obj, *args, **kwargs): # Can be triggered by dynamically created functions if obj.__name__ == 'foo': raise IndexError() return original_findsource(obj, *args, **kwargs) + monkeypatch.setattr(inspect, 'findsource', findsource) testdir.makepyfile(""" diff --git a/tox.ini b/tox.ini index efa3ad2f1..c2f866f26 100644 --- a/tox.ini +++ b/tox.ini @@ -175,3 +175,4 @@ norecursedirs = .tox ja .hg cx_freeze_source [flake8] ignore =E401,E225,E261,E128,E124,E301,E302,E121,E303,W391,E501,E231,E126,E701,E265,E241,E251,E226,E101,W191,E131,E203,E122,E123,E271,E712,E222,E127,E125,E221,W292,E111,E113,E293,E262,W293,E129,E702,E201,E272,E202,E704,E731,E402 +exclude = _pytest/vendored_packages/pluggy.py From 984d4ce5ec31d0d0d8771c7e5ab3f639182c9025 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 20 Nov 2016 19:12:42 -0200 Subject: [PATCH 070/201] Fix test_excinfo_getstatement that broke because of whitespace changes --- testing/code/test_excinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index c72b87428..23b0a985e 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -64,7 +64,7 @@ def test_excinfo_getstatement(): f() except ValueError: excinfo = _pytest._code.ExceptionInfo() - linenumbers = [_pytest._code.getrawcode(f).co_firstlineno - 1 + 3, + linenumbers = [_pytest._code.getrawcode(f).co_firstlineno - 1 + 4, _pytest._code.getrawcode(f).co_firstlineno - 1 + 1, _pytest._code.getrawcode(g).co_firstlineno - 1 + 1, ] l = list(excinfo.traceback) From 632c4d5daffb5908fdb4ae5a67adf8b2f2d5938a Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 21 Nov 2016 10:17:23 -0500 Subject: [PATCH 071/201] Remove an accidental double space --- _pytest/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/config.py b/_pytest/config.py index 5df198e21..f478b1b67 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -594,7 +594,7 @@ class Argument: if typ == 'choice': warnings.warn( 'type argument to addoption() is a string %r.' - ' For parsearg this is optional and when supplied ' + ' For parsearg this is optional and when supplied' ' should be a type.' ' (options: %s)' % (typ, names), DeprecationWarning, From 629d8e9fd62999ffbb80fcb8881c1c88e51d345f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 23 Nov 2016 09:47:36 -0200 Subject: [PATCH 072/201] Show an error if --confcutdir is not a valid directory Fixes #2078 --- CHANGELOG.rst | 6 +++++- _pytest/config.py | 6 +++++- testing/test_config.py | 9 +++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b87302e8c..eeb41a648 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,7 +3,10 @@ * -* +* An error message is now displayed if ``--confcutdir`` is not a valid directory, avoiding + subtle bugs (`#2078`_). + Thanks `@nicoddemus`_ for the PR. + * Cope gracefully with a .pyc file with no matching .py file (`#2038`_). Thanks `@nedbat`_. @@ -15,6 +18,7 @@ .. _@nedbat: https://github.com/nedbat .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 +.. _#2078: https://github.com/pytest-dev/pytest/issues/2078 3.0.4 diff --git a/_pytest/config.py b/_pytest/config.py index ab5e1b994..61123f6ac 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -996,6 +996,7 @@ class Config(object): "(are you using python -O?)\n") def _preparse(self, args, addopts=True): + import pytest self._initini(args) if addopts: args[:] = shlex.split(os.environ.get('PYTEST_ADDOPTS', '')) + args @@ -1007,7 +1008,10 @@ class Config(object): self.pluginmanager.load_setuptools_entrypoints(entrypoint_name) self.pluginmanager.consider_env() self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy()) - if self.known_args_namespace.confcutdir is None and self.inifile: + confcutdir = self.known_args_namespace.confcutdir + if confcutdir and not os.path.isdir(confcutdir): + raise pytest.UsageError('--confcutdir must be a directory, given: {0}'.format(confcutdir)) + if confcutdir is None and self.inifile: confcutdir = py.path.local(self.inifile).dirname self.known_args_namespace.confcutdir = confcutdir try: diff --git a/testing/test_config.py b/testing/test_config.py index 75a806c4a..1567dd27c 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -294,6 +294,15 @@ class TestConfigAPI: assert len(l) == 2 assert l == ["456", "123"] + def test_confcutdir_check_isdir(self, testdir): + """Give an error if --confcutdir is not a valid directory (#2078)""" + with pytest.raises(pytest.UsageError): + testdir.parseconfig('--confcutdir', testdir.tmpdir.join('file').ensure(file=1)) + with pytest.raises(pytest.UsageError): + testdir.parseconfig('--confcutdir', testdir.tmpdir.join('inexistant')) + config = testdir.parseconfig('--confcutdir', testdir.tmpdir.join('dir').ensure(dir=1)) + assert config.getoption('confcutdir') == str(testdir.tmpdir.join('dir')) + class TestConfigFromdictargs: def test_basic_behavior(self): From 33c0b06fdf989d8df63dc68ba5336ecad2eadd30 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 24 Nov 2016 15:27:38 -0200 Subject: [PATCH 073/201] Fix error in approx's repr with complex numbers Fix #2082 --- CHANGELOG.rst | 6 ++++++ _pytest/python.py | 3 +++ testing/python/approx.py | 1 + 3 files changed, 10 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index eeb41a648..f97ff3787 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,10 @@ subtle bugs (`#2078`_). Thanks `@nicoddemus`_ for the PR. +* Fix error message using ``approx`` with complex numbers (`#2082`_). + Thanks `@adler-j`_ for the report and `@nicoddemus`_ for the PR. + +* * Cope gracefully with a .pyc file with no matching .py file (`#2038`_). Thanks `@nedbat`_. @@ -15,10 +19,12 @@ * +.. _@adler-j: https://github.com/adler-j .. _@nedbat: https://github.com/nedbat .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 +.. _#2082: https://github.com/pytest-dev/pytest/issues/2082 3.0.4 diff --git a/_pytest/python.py b/_pytest/python.py index 88c65b1ce..76cf4bd64 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1419,6 +1419,9 @@ class ApproxNonIterable(object): self.rel = rel def __repr__(self): + if isinstance(self.expected, complex): + return str(self.expected) + # Infinities aren't compared using tolerances, so don't show a # tolerance. if math.isinf(self.expected): diff --git a/testing/python/approx.py b/testing/python/approx.py index 2720c573f..d6bb1f9cf 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -28,6 +28,7 @@ class TestApprox: print(approx(inf)) print(approx(1.0, rel=nan)) print(approx(1.0, rel=inf)) + print(approx(1.0j, rel=inf)) def test_operator_overloading(self): assert 1 == approx(1, rel=1e-6, abs=1e-12) From 8763590eefe7d1e5e2668bcb4a057f726f5e4a0e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 24 Nov 2016 16:08:51 -0200 Subject: [PATCH 074/201] Only execute "coveralls" toxenv on master once Just noticed that the "coveralls" env was being execute after each env. This was introduced by mistake in #2056 --- appveyor.yml | 9 ++++----- scripts/call-tox.bat | 8 ++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 scripts/call-tox.bat diff --git a/appveyor.yml b/appveyor.yml index 7192ec06f..a42aa16dc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,6 +6,8 @@ environment: # https://www.appveyor.com/docs/build-configuration#secure-variables matrix: + # coveralls is not in the default env list + - TOXENV: "coveralls" # note: please use "tox --listenvs" to populate the build matrix below - TOXENV: "linting" - TOXENV: "py26" @@ -29,14 +31,11 @@ install: - echo Installed Pythons - dir c:\Python* - - if "%TOXENV%" == "pypy" scripts\install-pypy.bat + - if "%TOXENV%" == "pypy" call scripts\install-pypy.bat - C:\Python35\python -m pip install tox build: false # Not a C# project, build stuff at the test step instead. test_script: - - C:\Python35\python -m tox - # coveralls is not in tox's envlist, plus for PRs the secure variable - # is not defined so we have to check for it - - if defined COVERALLS_REPO_TOKEN C:\Python35\python -m tox -e coveralls + - call scripts\call-tox.bat diff --git a/scripts/call-tox.bat b/scripts/call-tox.bat new file mode 100644 index 000000000..3ca9eb6d7 --- /dev/null +++ b/scripts/call-tox.bat @@ -0,0 +1,8 @@ +REM skip "coveralls" run in PRs or forks +if "%TOXENV%" == "coveralls" ( + if not defined COVERALLS_REPO_TOKEN ( + echo skipping coveralls run because COVERALLS_REPO_TOKEN is not defined + exit /b 0 + ) +) +C:\Python35\python -m tox From c1b83cdeea9763635bc182ab7f8c94aae3d4c4ad Mon Sep 17 00:00:00 2001 From: Duncan Betts Date: Sat, 26 Nov 2016 10:47:15 +0000 Subject: [PATCH 075/201] Add hint of Issue #478 to error text --- AUTHORS | 1 + CHANGELOG.rst | 4 +++- _pytest/main.py | 5 ++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 8cc6824cd..e966139be 100644 --- a/AUTHORS +++ b/AUTHORS @@ -44,6 +44,7 @@ David Mohr David Vierra Diego Russo Dmitry Dygalo +Duncan Betts Edison Gustavo Muenz Edoardo Batini Eduardo Schettino diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f97ff3787..40797c30c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,7 @@ 3.0.5.dev0 ========== -* +* Add hint to error message hinting possible missing __init__.py (`#478`_). Thanks `@DuncanBetts`_. * An error message is now displayed if ``--confcutdir`` is not a valid directory, avoiding subtle bugs (`#2078`_). @@ -20,8 +20,10 @@ * .. _@adler-j: https://github.com/adler-j +.. _@DuncanBetts: https://github.com/DuncanBetts .. _@nedbat: https://github.com/nedbat +.. _#478: https://github.com/pytest-dev/pytest/issues/478 .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 .. _#2082: https://github.com/pytest-dev/pytest/issues/2082 diff --git a/_pytest/main.py b/_pytest/main.py index 5771a1699..dd0775501 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -704,10 +704,9 @@ class Session(FSCollector): path = self.config.invocation_dir.join(relpath, abs=True) if not path.check(): if self.config.option.pyargs: - msg = "file or package not found: " + raise pytest.UsageError("file or package not found: " + arg + " (missing __init__.py?)") else: - msg = "file not found: " - raise pytest.UsageError(msg + arg) + raise pytest.UsageError("file not found: " + arg) parts[0] = path return parts From 2e6a58ab6981ce5bed1becf5239951654166ccbb Mon Sep 17 00:00:00 2001 From: Ana Vojnovic Date: Sat, 26 Nov 2016 15:04:52 +0100 Subject: [PATCH 076/201] Clarify test discovery docs. --- doc/en/goodpractices.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 2a5d4d7c8..d1e3e66fd 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -16,10 +16,12 @@ Conventions for Python test discovery * If no arguments are specified then collection starts from :confval:`testpaths` (if configured) or the current directory. Alternatively, command line arguments can be used in any combination of directories, file names or node ids. -* recurse into directories, unless they match :confval:`norecursedirs` -* ``test_*.py`` or ``*_test.py`` files, imported by their `test package name`_. -* ``Test`` prefixed test classes (without an ``__init__`` method) -* ``test_`` prefixed test functions or methods are test items +* Recurse into directories, unless they match :confval:`norecursedirs`. +* In those directories, search for ``test_*.py`` or ``*_test.py`` files, imported by their `test package name`_. +* From those files, collect test items: + + * ``test_`` prefixed test functions or methods outside of class + * ``test_`` prefixed test functions or methods inside ``Test`` prefixed test classes (without an ``__init__`` method) For examples of how to customize your test discovery :doc:`example/pythoncollection`. From 61205701981d9d27e0bd0209f2bf577156eb01d5 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 26 Nov 2016 14:49:31 -0200 Subject: [PATCH 077/201] Pin setuptools to < 29 because of AppVeyor failures Related to pypa/setuptools#861 Remove the pin when we have a new setuptools release --- tox.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index c2f866f26..f0c8e93d4 100644 --- a/tox.ini +++ b/tox.ini @@ -117,7 +117,10 @@ commands= basepython = python usedevelop=True skipsdist=True -deps=PyYAML +deps= + PyYAML + # pinning setuptools because of AppVeyor failures, see pypa/setuptools#861 + setuptools<29.0.0 commands= pytest -rfsxX doc/en pytest --doctest-modules {toxinidir}/_pytest From 1aa5bfea11e00ebc1e288f5ad818d937c03caef4 Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Sat, 26 Nov 2016 12:25:42 +0100 Subject: [PATCH 078/201] Add `:ref:` targets to `recwarn.rst`. --- AUTHORS | 1 + CHANGELOG.rst | 5 +++++ doc/en/recwarn.rst | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/AUTHORS b/AUTHORS index e966139be..d8fb8f703 100644 --- a/AUTHORS +++ b/AUTHORS @@ -83,6 +83,7 @@ Kevin Cox Lee Kamentsky Lev Maximov Lukas Bednar +Luke Murphy Maciek Fijalkowski Maho Marc Schlaich diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 40797c30c..8fb7b1589 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,9 @@ * Add hint to error message hinting possible missing __init__.py (`#478`_). Thanks `@DuncanBetts`_. +* Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. + Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR. + * An error message is now displayed if ``--confcutdir`` is not a valid directory, avoiding subtle bugs (`#2078`_). Thanks `@nicoddemus`_ for the PR. @@ -19,6 +22,8 @@ * +.. _@dupuy: https://bitbucket.org/dupuy/ +.. _@lwm: https://github.com/lwm .. _@adler-j: https://github.com/adler-j .. _@DuncanBetts: https://github.com/DuncanBetts .. _@nedbat: https://github.com/nedbat diff --git a/doc/en/recwarn.rst b/doc/en/recwarn.rst index 735006016..7bb193c99 100644 --- a/doc/en/recwarn.rst +++ b/doc/en/recwarn.rst @@ -1,8 +1,12 @@ +.. _`asserting warnings`: + .. _assertwarnings: Asserting Warnings ===================================================== +.. _`asserting warnings with the warns function`: + .. _warns: Asserting warnings with the warns function @@ -46,6 +50,8 @@ Alternatively, you can examine raised warnings in detail using the ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated differently; see :ref:`ensuring_function_triggers`. +.. _`recording warnings`: + .. _recwarn: Recording warnings @@ -96,6 +102,8 @@ class of the warning. The ``message`` is the warning itself; calling ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated differently; see :ref:`ensuring_function_triggers`. +.. _`ensuring a function triggers a deprecation warning`: + .. _ensuring_function_triggers: Ensuring a function triggers a deprecation warning From 6c5475660afadd66a8ab46c415e45e2839d3d581 Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Sat, 26 Nov 2016 18:47:26 +0100 Subject: [PATCH 079/201] Add test case for #595. This new test proves that reports do not capture stdout by default when skipped. --- testing/test_junitxml.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 85e49e451..443b8111b 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -249,6 +249,18 @@ class TestPython: snode = tnode.find_first_by_tag("skipped") snode.assert_attr(type="pytest.skip", message="hello25", ) + def test_mark_skip_doesnt_capture_output(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.skip(reason="foo") + def test_skip(): + print("bar!") + """) + result, dom = runandparse(testdir) + assert result.ret == 0 + node_xml = dom.find_first_by_tag("testsuite").toxml() + assert "bar!" not in node_xml + def test_classname_instance(self, testdir): testdir.makepyfile(""" class TestClass: From 0aa891543d4b3961e600f2f153f57bdff4f3963f Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Sat, 26 Nov 2016 18:57:51 +0100 Subject: [PATCH 080/201] Add documentation building note. --- CONTRIBUTING.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 19b31c7f4..71dc04d91 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -79,6 +79,16 @@ Pytest could always use more documentation. What exactly is needed? You can also edit documentation files directly in the GitHub web interface, without using a local copy. This can be convenient for small fixes. +.. note:: + Build the documentation locally with the following command: + + .. code:: bash + + $ tox -e docs + + The built documentation should be available in the ``doc/en/_build/``. + + Where 'en' refers to the documentation language. .. _submitplugin: From 5566b3ccb6949623137e693da570176fa56a8cf0 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 27 Nov 2016 03:26:35 -0200 Subject: [PATCH 081/201] Remove setuptools pin now that upstream has been fixed Related to pypa/setuptools#861 --- tox.ini | 2 -- 1 file changed, 2 deletions(-) diff --git a/tox.ini b/tox.ini index f0c8e93d4..f3494e8be 100644 --- a/tox.ini +++ b/tox.ini @@ -119,8 +119,6 @@ usedevelop=True skipsdist=True deps= PyYAML - # pinning setuptools because of AppVeyor failures, see pypa/setuptools#861 - setuptools<29.0.0 commands= pytest -rfsxX doc/en pytest --doctest-modules {toxinidir}/_pytest From b38fad4b82123b392409fe78be01db2f39c7985b Mon Sep 17 00:00:00 2001 From: nmundar Date: Sat, 26 Nov 2016 12:22:58 +0100 Subject: [PATCH 082/201] Add compatproperty deprecation warning. --- _pytest/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_pytest/main.py b/_pytest/main.py index dd0775501..33d7ef432 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -190,7 +190,9 @@ class FSHookProxy: def compatproperty(name): def fget(self): - # deprecated - use pytest.name + import warnings + warnings.warn("compatproperty is deprecated. Use pytest.name", + PendingDeprecationWarning, stacklevel=2) return getattr(pytest, name) return property(fget) From 0e6ad8e59f7ee25860c2cf4626d26f2dabd37ef5 Mon Sep 17 00:00:00 2001 From: nmundar Date: Sat, 26 Nov 2016 12:36:32 +0100 Subject: [PATCH 083/201] update CHANGELOG and AUTHORS --- AUTHORS | 1 + CHANGELOG.rst | 3 +++ 2 files changed, 4 insertions(+) diff --git a/AUTHORS b/AUTHORS index d8fb8f703..8c7cb19ce 100644 --- a/AUTHORS +++ b/AUTHORS @@ -104,6 +104,7 @@ Michael Droettboom Michael Seifert Mike Lundy Ned Batchelder +Neven Mundar Nicolas Delaby Oleg Pidsadnyi Oliver Bestwalter diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8fb7b1589..1820e083a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,9 @@ * Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR. +* Using ``pytest.main.compatproperty`` is now issuing deprecation warning. + Thanks `@nmundar` for the PR. + * An error message is now displayed if ``--confcutdir`` is not a valid directory, avoiding subtle bugs (`#2078`_). Thanks `@nicoddemus`_ for the PR. From 0a30f072e65da60f284af399e55c2ec897afb9cd Mon Sep 17 00:00:00 2001 From: nmundar Date: Sat, 26 Nov 2016 21:37:43 +0100 Subject: [PATCH 084/201] Show name argment in compatproperty deprecation message --- _pytest/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/main.py b/_pytest/main.py index 33d7ef432..2b5b12875 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -191,7 +191,7 @@ class FSHookProxy: def compatproperty(name): def fget(self): import warnings - warnings.warn("compatproperty is deprecated. Use pytest.name", + warnings.warn("This usage is deprecated, please use pytest.{0} instead".format(name), PendingDeprecationWarning, stacklevel=2) return getattr(pytest, name) From 2d7197926a8a2bb1cb8aebbe1fcb86e99837cad8 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 27 Nov 2016 14:19:29 -0200 Subject: [PATCH 085/201] Improve CHANGELOG entry for #2034 --- CHANGELOG.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1820e083a..77b67ddbb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,13 +1,14 @@ 3.0.5.dev0 ========== -* Add hint to error message hinting possible missing __init__.py (`#478`_). Thanks `@DuncanBetts`_. +* Add hint to error message hinting possible missing ``__init__.py`` (`#478`_). Thanks `@DuncanBetts`_. * Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR. -* Using ``pytest.main.compatproperty`` is now issuing deprecation warning. - Thanks `@nmundar` for the PR. +* Using ``item.Function``, ``item.Module``, etc., is now issuing deprecation warnings, prefer + ``pytest.Function``, ``pytest.Module``, etc., instead (`#2034`_). + Thanks `@nmundar`_ for the PR. * An error message is now displayed if ``--confcutdir`` is not a valid directory, avoiding subtle bugs (`#2078`_). @@ -30,8 +31,10 @@ .. _@adler-j: https://github.com/adler-j .. _@DuncanBetts: https://github.com/DuncanBetts .. _@nedbat: https://github.com/nedbat +.. _@nmundar: https://github.com/nmundar .. _#478: https://github.com/pytest-dev/pytest/issues/478 +.. _#2034: https://github.com/pytest-dev/pytest/issues/2034 .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 .. _#2082: https://github.com/pytest-dev/pytest/issues/2082 From 788e394c935ef9f24ce1ef9035dbc570c17fe0ed Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 27 Nov 2016 14:45:52 -0200 Subject: [PATCH 086/201] Use "inc" instead of "func" in the snipped on README and doc index "inc" reads better, also fixed the line separators so they have the same size --- README.rst | 16 ++++++++-------- doc/en/index.rst | 26 ++++++++++++-------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/README.rst b/README.rst index 5b2d329e0..d5650af65 100644 --- a/README.rst +++ b/README.rst @@ -24,31 +24,31 @@ An example of a simple test: .. code-block:: python # content of test_sample.py - def func(x): + def inc(x): return x + 1 def test_answer(): - assert func(3) == 5 + assert inc(3) == 5 To execute it:: $ pytest - ======= test session starts ======== + ============================= test session starts ============================= collected 1 items test_sample.py F - ======= FAILURES ======== - _______ test_answer ________ + ================================== FAILURES =================================== + _________________________________ test_answer _________________________________ def test_answer(): - > assert func(3) == 5 + > assert inc(3) == 5 E assert 4 == 5 - E + where 4 = func(3) + E + where 4 = inc(3) test_sample.py:5: AssertionError - ======= 1 failed in 0.12 seconds ======== + ========================== 1 failed in 0.04 seconds =========================== Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started `_ for more examples. diff --git a/doc/en/index.rst b/doc/en/index.rst index aadabf222..67b13d3e3 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -14,33 +14,31 @@ An example of a simple test: .. code-block:: python # content of test_sample.py - def func(x): + def inc(x): return x + 1 def test_answer(): - assert func(3) == 5 + assert inc(3) == 5 To execute it:: $ pytest - ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 - rootdir: $REGENDOC_TMPDIR, inifile: + ============================= test session starts ============================= collected 1 items - + test_sample.py F - - ======= FAILURES ======== - _______ test_answer ________ - + + ================================== FAILURES =================================== + _________________________________ test_answer _________________________________ + def test_answer(): - > assert func(3) == 5 + > assert inc(3) == 5 E assert 4 == 5 - E + where 4 = func(3) - + E + where 4 = inc(3) + test_sample.py:5: AssertionError - ======= 1 failed in 0.12 seconds ======== + ========================== 1 failed in 0.04 seconds =========================== Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See :ref:`Getting Started ` for more examples. From 4e1609b12eb1a44b0fc8519de458362d7fd8cdf2 Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Mon, 28 Nov 2016 00:55:49 +0100 Subject: [PATCH 087/201] Add `type` validation. Argparse driven argument type validation is added for the `--junit-xml` and `--confcutdir` arguments. The commit partially reverts #2080. Closes #2089. --- CHANGELOG.rst | 8 ++++---- _pytest/config.py | 27 +++++++++++++++++++++++---- _pytest/junitxml.py | 3 +++ _pytest/main.py | 4 +++- testing/test_junitxml.py | 4 ++++ 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 77b67ddbb..4025eb24b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,9 @@ 3.0.5.dev0 ========== +* Now ``--confcutdir`` and ``--junit-xml`` are properly validated if they are directories + and filenames, respectively (`#2089`_ and `#2078`_). Thanks to `@lwm`_ for the PR. + * Add hint to error message hinting possible missing ``__init__.py`` (`#478`_). Thanks `@DuncanBetts`_. * Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. @@ -10,10 +13,6 @@ ``pytest.Function``, ``pytest.Module``, etc., instead (`#2034`_). Thanks `@nmundar`_ for the PR. -* An error message is now displayed if ``--confcutdir`` is not a valid directory, avoiding - subtle bugs (`#2078`_). - Thanks `@nicoddemus`_ for the PR. - * Fix error message using ``approx`` with complex numbers (`#2082`_). Thanks `@adler-j`_ for the report and `@nicoddemus`_ for the PR. @@ -33,6 +32,7 @@ .. _@nedbat: https://github.com/nedbat .. _@nmundar: https://github.com/nmundar +.. _#2089: https://github.com/pytest-dev/pytest/issues/2089 .. _#478: https://github.com/pytest-dev/pytest/issues/478 .. _#2034: https://github.com/pytest-dev/pytest/issues/2034 .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 diff --git a/_pytest/config.py b/_pytest/config.py index 61123f6ac..4eed5ace1 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -70,6 +70,28 @@ class UsageError(Exception): """ error in pytest usage or invocation""" +def filename_arg(path, optname): + """ Argparse type validator for filename arguments. + + :path: path of filename + :optname: name of the option + """ + if os.path.isdir(path): + raise UsageError("{0} must be a filename, given: {1}".format(optname, path)) + return path + + +def directory_arg(path, optname): + """Argparse type validator for directory arguments. + + :path: path of directory + :optname: name of the option + """ + if not os.path.isdir(path): + raise UsageError("{0} must be a directory, given: {1}".format(optname, path)) + return path + + _preinit = [] default_plugins = ( @@ -996,7 +1018,6 @@ class Config(object): "(are you using python -O?)\n") def _preparse(self, args, addopts=True): - import pytest self._initini(args) if addopts: args[:] = shlex.split(os.environ.get('PYTEST_ADDOPTS', '')) + args @@ -1009,9 +1030,7 @@ class Config(object): self.pluginmanager.consider_env() self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy()) confcutdir = self.known_args_namespace.confcutdir - if confcutdir and not os.path.isdir(confcutdir): - raise pytest.UsageError('--confcutdir must be a directory, given: {0}'.format(confcutdir)) - if confcutdir is None and self.inifile: + if self.known_args_namespace.confcutdir is None and self.inifile: confcutdir = py.path.local(self.inifile).dirname self.known_args_namespace.confcutdir = confcutdir try: diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py index 4b9103949..317382e63 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -8,12 +8,14 @@ Based on initial code from Ross Lawley. # Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/ # src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd +import functools import py import os import re import sys import time import pytest +from _pytest.config import filename_arg # Python 2.X and 3.X compatibility if sys.version_info[0] < 3: @@ -214,6 +216,7 @@ def pytest_addoption(parser): action="store", dest="xmlpath", metavar="path", + type=functools.partial(filename_arg, optname="--junitxml"), default=None, help="create junit-xml style report file at given path.") group.addoption( diff --git a/_pytest/main.py b/_pytest/main.py index 2b5b12875..2562df3af 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -1,4 +1,5 @@ """ core implementation of testing process: init, session, runtest loop. """ +import functools import os import sys @@ -11,6 +12,7 @@ try: except ImportError: from UserDict import DictMixin as MappingMixin +from _pytest.config import directory_arg from _pytest.runner import collect_one_node tracebackcutdir = py.path.local(_pytest.__file__).dirpath() @@ -58,7 +60,7 @@ def pytest_addoption(parser): # when changing this to --conf-cut-dir, config.py Conftest.setinitial # needs upgrading as well group.addoption('--confcutdir', dest="confcutdir", default=None, - metavar="dir", + metavar="dir", type=functools.partial(directory_arg, optname="--confcutdir"), help="only load conftest.py's relative to specified dir.") group.addoption('--noconftest', action="store_true", dest="noconftest", default=False, diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 443b8111b..abbc9cd33 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -715,6 +715,10 @@ def test_logxml_makedir(testdir): assert result.ret == 0 assert testdir.tmpdir.join("path/to/results.xml").check() +def test_logxml_check_isdir(testdir): + """Give an error if --junit-xml is a directory (#2089)""" + result = testdir.runpytest("--junit-xml=.") + result.stderr.fnmatch_lines(["*--junitxml must be a filename*"]) def test_escaped_parametrized_names_xml(testdir): testdir.makepyfile(""" From 6473c3d87e9cbcbf39976ee98a56bf620e848249 Mon Sep 17 00:00:00 2001 From: Duncan Betts Date: Mon, 28 Nov 2016 14:27:12 +0000 Subject: [PATCH 088/201] Improved description of functionality for Issue #687 --- CHANGELOG.rst | 3 +++ doc/en/fixture.rst | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 77b67ddbb..300812383 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,8 @@ * Add hint to error message hinting possible missing ``__init__.py`` (`#478`_). Thanks `@DuncanBetts`_. +* More accurately describe when fixture finalization occurs in documentation (`#687`_). Thanks `@DuncanBetts`_. + * Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR. @@ -34,6 +36,7 @@ .. _@nmundar: https://github.com/nmundar .. _#478: https://github.com/pytest-dev/pytest/issues/478 +.. _#687: https://github.com/pytest-dev/pytest/issues/687 .. _#2034: https://github.com/pytest-dev/pytest/issues/2034 .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index b0595bc9d..510a4edf9 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -318,8 +318,7 @@ the ``with`` statement ends. request.addfinalizer(fin) return smtp # provide the fixture value - The ``fin`` function will execute when the last test using - the fixture in the module has finished execution. + The ``fin`` function will execute when the last test in the module has finished execution. This method is still fully supported, but ``yield`` is recommended from 2.10 onward because it is considered simpler and better describes the natural code flow. From 40cffacadc05ef652782d99409b99fa4ed8c7bc0 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 28 Nov 2016 21:33:15 +0100 Subject: [PATCH 089/201] minor: fix grammar with help for --setup-{only,show} --- _pytest/setuponly.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_pytest/setuponly.py b/_pytest/setuponly.py index 0ecdbc2bd..1752c575f 100644 --- a/_pytest/setuponly.py +++ b/_pytest/setuponly.py @@ -5,9 +5,9 @@ import sys def pytest_addoption(parser): group = parser.getgroup("debugconfig") group.addoption('--setuponly', '--setup-only', action="store_true", - help="only setup fixtures, don't execute the tests.") + help="only setup fixtures, do not execute tests.") group.addoption('--setupshow', '--setup-show', action="store_true", - help="show setup fixtures while executing the tests.") + help="show setup of fixtures while executing tests.") @pytest.hookimpl(hookwrapper=True) From f8d195253e1d7a63c7783585e5f4412908455322 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 30 Nov 2016 22:23:02 -0200 Subject: [PATCH 090/201] Remove support code for earlier Python 3 version in Source.compile This code leaves None in sys.modules as a side effect but is no longer needed in the Python 3 versions we support. Fix #2103 --- CHANGELOG.rst | 6 +++++- _pytest/_code/source.py | 8 -------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4e0c2f9c1..460ecc573 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,10 @@ * Fix error message using ``approx`` with complex numbers (`#2082`_). Thanks `@adler-j`_ for the report and `@nicoddemus`_ for the PR. -* +* Remove internal code meant to support earlier Python 3 versions that produced the side effect + of leaving ``None`` in ``sys.modules`` when expressions were evaluated by pytest (for example passing a condition + as a string to ``pytest.mark.skipif``)(`#2103`_). + Thanks `@jaraco`_ for the report and `@nicoddemus`_ for the PR. * Cope gracefully with a .pyc file with no matching .py file (`#2038`_). Thanks `@nedbat`_. @@ -41,6 +44,7 @@ .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 .. _#2082: https://github.com/pytest-dev/pytest/issues/2082 +.. _#2103: https://github.com/pytest-dev/pytest/issues/2103 3.0.4 diff --git a/_pytest/_code/source.py b/_pytest/_code/source.py index 522150b55..f69d045b5 100644 --- a/_pytest/_code/source.py +++ b/_pytest/_code/source.py @@ -192,14 +192,6 @@ class Source(object): if flag & _AST_FLAG: return co lines = [(x + "\n") for x in self.lines] - if sys.version_info[0] >= 3: - # XXX py3's inspect.getsourcefile() checks for a module - # and a pep302 __loader__ ... we don't have a module - # at code compile-time so we need to fake it here - m = ModuleType("_pycodecompile_pseudo_module") - py.std.inspect.modulesbyfile[filename] = None - py.std.sys.modules[None] = m - m.__loader__ = 1 py.std.linecache.cache[filename] = (1, None, lines, filename) return co From 30f0152ae6abecd911a0db87d137466af1cd39f9 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 30 Nov 2016 22:34:02 -0200 Subject: [PATCH 091/201] Remove unused import --- _pytest/_code/source.py | 1 - 1 file changed, 1 deletion(-) diff --git a/_pytest/_code/source.py b/_pytest/_code/source.py index f69d045b5..fcec0f5ca 100644 --- a/_pytest/_code/source.py +++ b/_pytest/_code/source.py @@ -4,7 +4,6 @@ from bisect import bisect_right import sys import inspect, tokenize import py -from types import ModuleType cpy_compile = compile try: From c856537e7163b657f8ff32021ab5cb3f2991435f Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Thu, 1 Dec 2016 13:20:42 +0100 Subject: [PATCH 092/201] Add warning for incorrect passing args to `-o`. --- CHANGELOG.rst | 6 ++++++ _pytest/config.py | 5 ++++- _pytest/helpconfig.py | 2 +- testing/test_config.py | 10 +++++++++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 460ecc573..dd9de9687 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,10 @@ 3.0.5.dev0 ========== +* Add warning when not passing ``option=value`` correctly to ``-o/--override-ini`` (`#2105`_). + Also improved the help documentation. Thanks to `@mbukatov`_ for the report and + `@lwm`_ for the PR. + * Now ``--confcutdir`` and ``--junit-xml`` are properly validated if they are directories and filenames, respectively (`#2089`_ and `#2078`_). Thanks to `@lwm`_ for the PR. @@ -30,6 +34,7 @@ * +.. _@mbukatov: https://github.com/mbukatov .. _@dupuy: https://bitbucket.org/dupuy/ .. _@lwm: https://github.com/lwm .. _@adler-j: https://github.com/adler-j @@ -45,6 +50,7 @@ .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 .. _#2082: https://github.com/pytest-dev/pytest/issues/2082 .. _#2103: https://github.com/pytest-dev/pytest/issues/2103 +.. _#2105: https://github.com/pytest-dev/pytest/issues/2105 3.0.4 diff --git a/_pytest/config.py b/_pytest/config.py index 4eed5ace1..fe386ed0b 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1149,7 +1149,10 @@ class Config(object): if self.getoption("override_ini", None): for ini_config_list in self.option.override_ini: for ini_config in ini_config_list: - (key, user_ini_value) = ini_config.split("=", 1) + 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 diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py index dd161275b..6e66b11c4 100644 --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -23,7 +23,7 @@ def pytest_addoption(parser): group._addoption( '-o', '--override-ini', nargs='*', dest="override_ini", action="append", - help="override config option, e.g. `-o xfail_strict=True`.") + help="override config option with option=value style, e.g. `-o xfail_strict=True`.") @pytest.hookimpl(hookwrapper=True) diff --git a/testing/test_config.py b/testing/test_config.py index 1567dd27c..21ceab1e2 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -83,7 +83,7 @@ class TestParseIni: """) result = testdir.inline_run("--confcutdir=.") assert result.ret == 0 - + class TestConfigCmdlineParsing: def test_parsing_again_fails(self, testdir): config = testdir.parseconfig() @@ -732,6 +732,14 @@ class TestOverrideIniArgs: "ini3:True", "ini4:False"]) + def test_override_ini_usage_error_bad_style(self, testdir): + testdir.makeini(""" + [pytest] + xdist_strict=False + """) + result = testdir.runpytest("--override-ini", 'xdist_strict True', "-s") + result.stderr.fnmatch_lines(["*ERROR* *expects option=value*"]) + def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch): monkeypatch.chdir(str(tmpdir)) a = tmpdir.mkdir("a") From bc0f7e62430a3dba644303b4d966c166c84e86e2 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 1 Dec 2016 15:50:08 -0200 Subject: [PATCH 093/201] Fix false-positive assert rewrite warnings when using 'pytest_plugins' pytest would emit false positive warnings about assertion-rewrite when a module appears multiple times in plugins which depend on other plugins using the 'pytest_plugins' mechanism --- CHANGELOG.rst | 4 ++++ _pytest/assertion/rewrite.py | 9 ++++----- testing/test_assertrewrite.py | 13 +++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dd9de9687..48ea722bf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -22,6 +22,10 @@ * Fix error message using ``approx`` with complex numbers (`#2082`_). Thanks `@adler-j`_ for the report and `@nicoddemus`_ for the PR. +* Fixed false-positives warnings from assertion rewrite hook for modules imported more than + once by the ``pytest_plugins`` mechanism. + Thanks `@nicoddemus`_ for the PR. + * Remove internal code meant to support earlier Python 3 versions that produced the side effect of leaving ``None`` in ``sys.modules`` when expressions were evaluated by pytest (for example passing a condition as a string to ``pytest.mark.skipif``)(`#2103`_). diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 9ad08391c..abf5b491f 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -186,16 +186,15 @@ class AssertionRewritingHook(object): """ already_imported = set(names).intersection(set(sys.modules)) if already_imported: - for name in names: + for name in already_imported: if name not in self._rewritten_names: - self._warn_already_imported(already_imported) + self._warn_already_imported(name) self._must_rewrite.update(names) - def _warn_already_imported(self, names): + def _warn_already_imported(self, name): self.config.warn( 'P1', - 'Modules are already imported so can not be re-written: %s' % - ','.join(names)) + 'Module already imported so can not be re-written: %s' % name) def load_module(self, name): # If there is an existing module object named 'fullname' in diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 5f36d4a6b..8e26cdb1b 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -682,6 +682,19 @@ def test_rewritten(): hook.mark_rewrite('test_remember_rewritten_modules') assert warnings == [] + def test_rewrite_warning_using_pytest_plugins(self, testdir, monkeypatch): + testdir.makepyfile(**{ + 'conftest.py': "pytest_plugins = ['core', 'gui', 'sci']", + 'core.py': "", + 'gui.py': "pytest_plugins = ['core', 'sci']", + 'sci.py': "pytest_plugins = ['core']", + 'test_rewrite_warning_pytest_plugins.py': "def test(): pass", + }) + testdir.chdir() + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines(['*= 1 passed in *=*']) + assert 'pytest-warning summary' not in result.stdout.str() + class TestAssertionRewriteHookDetails(object): def test_loader_is_package_false_for_module(self, testdir): From 81528ea81f84937c2364b4fc1108d219b7b4ec61 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 21 Nov 2016 12:50:21 -0200 Subject: [PATCH 094/201] Remove hook proxy cache Fix #2016 --- CHANGELOG.rst | 6 ++++++ _pytest/main.py | 30 ++++++++++++------------------ _pytest/pytester.py | 1 + testing/test_conftest.py | 25 +++++++++++++++++++++++++ testing/test_pluginmanager.py | 22 +++++++++++++++++++++- 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 48ea722bf..c4a5b5144 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,10 @@ once by the ``pytest_plugins`` mechanism. Thanks `@nicoddemus`_ for the PR. +* Remove an internal cache which could cause hooks from ``conftest.py`` files in + sub-directories to be called in other directories incorrectly (`#2016`_). + Thanks `@d-b-w`_ for the report and `@nicoddemus`_ for the PR. + * Remove internal code meant to support earlier Python 3 versions that produced the side effect of leaving ``None`` in ``sys.modules`` when expressions were evaluated by pytest (for example passing a condition as a string to ``pytest.mark.skipif``)(`#2103`_). @@ -40,6 +44,7 @@ .. _@mbukatov: https://github.com/mbukatov .. _@dupuy: https://bitbucket.org/dupuy/ +.. _@d-b-w: https://bitbucket.org/d-b-w/ .. _@lwm: https://github.com/lwm .. _@adler-j: https://github.com/adler-j .. _@DuncanBetts: https://github.com/DuncanBetts @@ -49,6 +54,7 @@ .. _#2089: https://github.com/pytest-dev/pytest/issues/2089 .. _#478: https://github.com/pytest-dev/pytest/issues/478 .. _#687: https://github.com/pytest-dev/pytest/issues/687 +.. _#2016: https://github.com/pytest-dev/pytest/issues/2016 .. _#2034: https://github.com/pytest-dev/pytest/issues/2034 .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 diff --git a/_pytest/main.py b/_pytest/main.py index 2562df3af..52876c12a 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -539,7 +539,6 @@ class Session(FSCollector): def __init__(self, config): FSCollector.__init__(self, config.rootdir, parent=None, config=config, session=self) - self._fs2hookproxy = {} self.testsfailed = 0 self.testscollected = 0 self.shouldstop = False @@ -570,23 +569,18 @@ class Session(FSCollector): return path in self._initialpaths def gethookproxy(self, fspath): - try: - return self._fs2hookproxy[fspath] - except KeyError: - # check if we have the common case of running - # hooks with all conftest.py filesall conftest.py - pm = self.config.pluginmanager - my_conftestmodules = pm._getconftestmodules(fspath) - remove_mods = pm._conftest_plugins.difference(my_conftestmodules) - if remove_mods: - # one or more conftests are not in use at this fspath - proxy = FSHookProxy(fspath, pm, remove_mods) - else: - # all plugis are active for this fspath - proxy = self.config.hook - - self._fs2hookproxy[fspath] = proxy - return proxy + # check if we have the common case of running + # hooks with all conftest.py filesall conftest.py + pm = self.config.pluginmanager + my_conftestmodules = pm._getconftestmodules(fspath) + remove_mods = pm._conftest_plugins.difference(my_conftestmodules) + if remove_mods: + # one or more conftests are not in use at this fspath + proxy = FSHookProxy(fspath, pm, remove_mods) + else: + # all plugis are active for this fspath + proxy = self.config.hook + return proxy def perform_collect(self, args=None, genitems=True): hook = self.config.hook diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 8aa5c0c4f..17ff529a6 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -478,6 +478,7 @@ class Testdir: ret = None for name, value in items: p = self.tmpdir.join(name).new(ext=ext) + p.dirpath().ensure_dir() source = Source(value) def my_totext(s, encoding="utf-8"): diff --git a/testing/test_conftest.py b/testing/test_conftest.py index 6dce13859..c0fa74701 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -423,3 +423,28 @@ def test_conftest_exception_handling(testdir): res = testdir.runpytest() assert res.ret == 4 assert 'raise ValueError()' in [line.strip() for line in res.errlines] + + +def test_hook_proxy(testdir): + """Session's gethookproxy() would cache conftests incorrectly (#2016). + It was decided to remove the cache altogether. + """ + testdir.makepyfile(**{ + 'root/demo-0/test_foo1.py': "def test1(): pass", + + 'root/demo-a/test_foo2.py': "def test1(): pass", + 'root/demo-a/conftest.py': """ + def pytest_ignore_collect(path, config): + return True + """, + + 'root/demo-b/test_foo3.py': "def test1(): pass", + 'root/demo-c/test_foo4.py': "def test1(): pass", + }) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*test_foo1.py*', + '*test_foo3.py*', + '*test_foo4.py*', + '*3 passed*', + ]) diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index d636102f7..45ad321a3 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -4,7 +4,8 @@ import py import os from _pytest.config import get_config, PytestPluginManager -from _pytest.main import EXIT_NOTESTSCOLLECTED +from _pytest.main import EXIT_NOTESTSCOLLECTED, Session + @pytest.fixture def pytestpm(): @@ -133,6 +134,25 @@ class TestPytestPluginInteractions: finally: undo() + def test_hook_proxy(self, testdir): + """Test the gethookproxy function(#2016)""" + config = testdir.parseconfig() + session = Session(config) + testdir.makepyfile(**{ + 'tests/conftest.py': '', + 'tests/subdir/conftest.py': '', + }) + + conftest1 = testdir.tmpdir.join('tests/conftest.py') + conftest2 = testdir.tmpdir.join('tests/subdir/conftest.py') + + config.pluginmanager._importconftest(conftest1) + ihook_a = session.gethookproxy(testdir.tmpdir.join('tests')) + assert ihook_a is not None + config.pluginmanager._importconftest(conftest2) + ihook_b = session.gethookproxy(testdir.tmpdir.join('tests')) + assert ihook_a is not ihook_b + def test_warn_on_deprecated_multicall(self, pytestpm): warnings = [] From 7480342710ea7b1389811c5316a70457070d8baf Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 2 Dec 2016 09:22:47 -0200 Subject: [PATCH 095/201] Fix typo in docstring of register_assert_rewrite --- _pytest/assertion/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/assertion/__init__.py b/_pytest/assertion/__init__.py index 18cb7d32c..3f14a7ae7 100644 --- a/_pytest/assertion/__init__.py +++ b/_pytest/assertion/__init__.py @@ -29,7 +29,7 @@ def pytest_namespace(): def register_assert_rewrite(*names): - """Register a module name to be rewritten on import. + """Register one or more module names to be rewritten on import. This function will make sure that this module or all modules inside the package will get their assert statements rewritten. From 1f0401ab620e66416e3293c980274cd81a80eefb Mon Sep 17 00:00:00 2001 From: Ismail Date: Fri, 2 Dec 2016 15:09:38 +0000 Subject: [PATCH 096/201] Fix minor typo --- doc/en/goodpractices.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index d1e3e66fd..43b15a077 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -127,7 +127,7 @@ required configurations. The reason for this somewhat evolved importing technique is that in larger projects multiple test modules might import from each other and thus deriving a canonical import name helps - to avoid surprises such as a test modules getting imported twice. + to avoid surprises such as a test module getting imported twice. .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv From 57c44899164c3ff7a521886eb43906c48ba3ef1f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 2 Dec 2016 19:28:45 -0200 Subject: [PATCH 097/201] Use a simple ``+-`` ASCII string in the string representation of pytest.approx In Python 2 Fix #2111 --- CHANGELOG.rst | 21 +++++++++++++------- _pytest/python.py | 10 ++-------- testing/python/approx.py | 41 ++++++++++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c4a5b5144..8776726f2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,11 @@ * Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR. +* In Python 2, use a simple ``+-`` ASCII string in the string representation of ``pytest.approx`` (for example ``"4 +- 4.0e-06"``) + because it is brittle to handle that in different contexts and representations internally in pytest + which can result in bugs such as `#2111`_. In Python 3, the representation still uses ``±`` (for example ``4 ± 4.0e-06``). + Thanks `@kerrick-lyft`_ for the report and `@nicoddemus`_ for the PR. + * Using ``item.Function``, ``item.Module``, etc., is now issuing deprecation warnings, prefer ``pytest.Function``, ``pytest.Module``, etc., instead (`#2034`_). Thanks `@nmundar`_ for the PR. @@ -42,25 +47,27 @@ * -.. _@mbukatov: https://github.com/mbukatov -.. _@dupuy: https://bitbucket.org/dupuy/ -.. _@d-b-w: https://bitbucket.org/d-b-w/ -.. _@lwm: https://github.com/lwm .. _@adler-j: https://github.com/adler-j +.. _@d-b-w: https://bitbucket.org/d-b-w/ .. _@DuncanBetts: https://github.com/DuncanBetts +.. _@dupuy: https://bitbucket.org/dupuy/ +.. _@kerrick-lyft: https://github.com/kerrick-lyft +.. _@lwm: https://github.com/lwm +.. _@mbukatov: https://github.com/mbukatov .. _@nedbat: https://github.com/nedbat .. _@nmundar: https://github.com/nmundar -.. _#2089: https://github.com/pytest-dev/pytest/issues/2089 -.. _#478: https://github.com/pytest-dev/pytest/issues/478 -.. _#687: https://github.com/pytest-dev/pytest/issues/687 .. _#2016: https://github.com/pytest-dev/pytest/issues/2016 .. _#2034: https://github.com/pytest-dev/pytest/issues/2034 .. _#2038: https://github.com/pytest-dev/pytest/issues/2038 .. _#2078: https://github.com/pytest-dev/pytest/issues/2078 .. _#2082: https://github.com/pytest-dev/pytest/issues/2082 +.. _#2089: https://github.com/pytest-dev/pytest/issues/2089 .. _#2103: https://github.com/pytest-dev/pytest/issues/2103 .. _#2105: https://github.com/pytest-dev/pytest/issues/2105 +.. _#2111: https://github.com/pytest-dev/pytest/issues/2111 +.. _#478: https://github.com/pytest-dev/pytest/issues/478 +.. _#687: https://github.com/pytest-dev/pytest/issues/687 3.0.4 diff --git a/_pytest/python.py b/_pytest/python.py index 76cf4bd64..e46f2f1bc 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1434,16 +1434,10 @@ class ApproxNonIterable(object): except ValueError: vetted_tolerance = '???' - plus_minus = u'{0} \u00b1 {1}'.format(self.expected, vetted_tolerance) - - # In python2, __repr__() must return a string (i.e. not a unicode - # object). In python3, __repr__() must return a unicode object - # (although now strings are unicode objects and bytes are what - # strings were). if sys.version_info[0] == 2: - return plus_minus.encode('utf-8') + return '{0} +- {1}'.format(self.expected, vetted_tolerance) else: - return plus_minus + return u'{0} \u00b1 {1}'.format(self.expected, vetted_tolerance) def __eq__(self, actual): # Short-circuit exact equality. diff --git a/testing/python/approx.py b/testing/python/approx.py index d6bb1f9cf..fc1cbf9ab 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -1,5 +1,5 @@ # encoding: utf-8 - +import sys import pytest import doctest @@ -9,6 +9,7 @@ from decimal import Decimal from fractions import Fraction inf, nan = float('inf'), float('nan') + class MyDocTestRunner(doctest.DocTestRunner): def __init__(self): @@ -22,13 +23,17 @@ class MyDocTestRunner(doctest.DocTestRunner): class TestApprox: def test_repr_string(self): - # Just make sure the Unicode handling doesn't raise any exceptions. - print(approx(1.0)) - print(approx([1.0, 2.0, 3.0])) - print(approx(inf)) - print(approx(1.0, rel=nan)) - print(approx(1.0, rel=inf)) - print(approx(1.0j, rel=inf)) + # for some reason in Python 2.6 it is not displaying the tolerance representation correctly + plus_minus = u'\u00b1' if sys.version_info[0] > 2 else u'+-' + tol1, tol2, infr = '1.0e-06', '2.0e-06', 'inf' + if sys.version_info[:2] == (2, 6): + tol1, tol2, infr = '???', '???', '???' + assert repr(approx(1.0)) == '1.0 {pm} {tol1}'.format(pm=plus_minus, tol1=tol1) + assert repr(approx([1.0, 2.0])) == '1.0 {pm} {tol1}, 2.0 {pm} {tol2}'.format(pm=plus_minus, tol1=tol1, tol2=tol2) + assert repr(approx(inf)) == 'inf' + assert repr(approx(1.0, rel=nan)) == '1.0 {pm} ???'.format(pm=plus_minus) + assert repr(approx(1.0, rel=inf)) == '1.0 {pm} {infr}'.format(pm=plus_minus, infr=infr) + assert repr(approx(1.0j, rel=inf)) == '1j' def test_operator_overloading(self): assert 1 == approx(1, rel=1e-6, abs=1e-12) @@ -285,3 +290,23 @@ class TestApprox: runner = MyDocTestRunner() runner.run(test) + def test_unicode_plus_minus(self, testdir): + """ + Comparing approx instances inside lists should not produce an error in the detailed diff. + Integration test for issue #2111. + """ + testdir.makepyfile(""" + import pytest + def test_foo(): + assert [3] == [pytest.approx(4)] + """) + expected = '4.0e-06' + # for some reason in Python 2.6 it is not displaying the tolerance representation correctly + if sys.version_info[:2] == (2, 6): + expected = '???' + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*At index 0 diff: 3 != 4 * {0}'.format(expected), + '=* 1 failed in *=', + ]) + From 0febd855e1ad121c179389d1c012601b44ec7114 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 5 Dec 2016 10:06:58 -0200 Subject: [PATCH 098/201] Bump version to 3.0.5 --- _pytest/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 15043e71c..be20d3d41 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.5.dev0' +__version__ = '3.0.5' From 833acb9d3c24602a8ababa53bb24b9edc5be40ab Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 5 Dec 2016 10:07:37 -0200 Subject: [PATCH 099/201] Finalize CHANGELOG for 3.0.5 --- CHANGELOG.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8776726f2..cfcb012f2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,5 @@ -3.0.5.dev0 -========== +3.0.5 +===== * Add warning when not passing ``option=value`` correctly to ``-o/--override-ini`` (`#2105`_). Also improved the help documentation. Thanks to `@mbukatov`_ for the report and @@ -43,10 +43,6 @@ * Cope gracefully with a .pyc file with no matching .py file (`#2038`_). Thanks `@nedbat`_. -* - -* - .. _@adler-j: https://github.com/adler-j .. _@d-b-w: https://bitbucket.org/d-b-w/ .. _@DuncanBetts: https://github.com/DuncanBetts From 31f114e51f0e6eed208bfd95188790170544a610 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 5 Dec 2016 10:19:27 -0200 Subject: [PATCH 100/201] Add release announcement for 3.0.5 --- doc/en/announce/index.rst | 1 + doc/en/announce/release-3.0.5.rst | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 doc/en/announce/release-3.0.5.rst diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index a1bf7bed7..44b29cae1 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-3.0.5 release-3.0.4 release-3.0.3 release-3.0.2 diff --git a/doc/en/announce/release-3.0.5.rst b/doc/en/announce/release-3.0.5.rst new file mode 100644 index 000000000..3e2419d7e --- /dev/null +++ b/doc/en/announce/release-3.0.5.rst @@ -0,0 +1,27 @@ +pytest-3.0.5 +============ + +pytest 3.0.5 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Ana Vojnovic +* Bruno Oliveira +* Daniel Hahler +* Duncan Betts +* Igor Starikov +* Ismail +* Luke Murphy +* Ned Batchelder +* Ronny Pfannschmidt +* Sebastian Ramacher +* nmundar + +Happy testing, +The pytest Development Team From f592c7746a53999f52df46db764b31d9fbb987f9 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 5 Dec 2016 07:22:06 -0500 Subject: [PATCH 101/201] Regendocs for 3.0.5 --- doc/en/assert.rst | 4 ++-- doc/en/cache.rst | 6 +++--- doc/en/capture.rst | 2 +- doc/en/doctest.rst | 2 +- doc/en/example/markers.rst | 28 ++++++++++++++-------------- doc/en/example/nonpython.rst | 6 +++--- doc/en/example/parametrize.rst | 12 ++++++------ doc/en/example/pythoncollection.rst | 6 +++--- doc/en/example/reportingdemo.rst | 4 ++-- doc/en/example/simple.rst | 22 +++++++++++----------- doc/en/fixture.rst | 10 +++++----- doc/en/getting-started.rst | 4 ++-- doc/en/index.rst | 18 ++++++++++-------- doc/en/parametrize.rst | 4 ++-- doc/en/skipping.rst | 2 +- doc/en/tmpdir.rst | 2 +- doc/en/unittest.rst | 2 +- 17 files changed, 68 insertions(+), 66 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index 675dece57..f898391df 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -26,7 +26,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -170,7 +170,7 @@ if you run this module:: $ pytest test_assert2.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/cache.rst b/doc/en/cache.rst index 4baae4c96..dc1f91286 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -80,7 +80,7 @@ If you then run it with ``--lf``:: $ pytest --lf ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 run-last-failure: rerun last 2 failures rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -122,7 +122,7 @@ of ``FF`` and dots):: $ pytest --ff ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 run-last-failure: rerun last 2 failures first rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -227,7 +227,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: cachedir: $REGENDOC_TMPDIR/.cache ------------------------------- cache values ------------------------------- diff --git a/doc/en/capture.rst b/doc/en/capture.rst index 454655d7e..7ee73b992 100644 --- a/doc/en/capture.rst +++ b/doc/en/capture.rst @@ -64,7 +64,7 @@ of the failing function and hide the other one:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/doctest.rst b/doc/en/doctest.rst index 5a1122515..513d9aed9 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, 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 2f5f29e0d..7e48e6f2e 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -31,7 +31,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -45,7 +45,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -66,7 +66,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 5 items @@ -79,7 +79,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -92,7 +92,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items @@ -130,7 +130,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -144,7 +144,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -160,7 +160,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -352,7 +352,7 @@ the test needs:: $ pytest -E stage2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -364,7 +364,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -485,7 +485,7 @@ then you will see two test 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -499,7 +499,7 @@ Note that if you specify a platform via the marker-command line option like this $ pytest -m linux2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -551,7 +551,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -573,7 +573,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items diff --git a/doc/en/example/nonpython.rst b/doc/en/example/nonpython.rst index e0670aeba..817e5693f 100644 --- a/doc/en/example/nonpython.rst +++ b/doc/en/example/nonpython.rst @@ -27,7 +27,7 @@ now execute the test specification:: nonpython $ pytest test_simple.yml ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collected 2 items @@ -59,7 +59,7 @@ consulted when reporting in ``verbose`` mode:: nonpython $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR/nonpython, inifile: collecting ... collected 2 items @@ -81,7 +81,7 @@ interesting to just look at the collection tree:: nonpython $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, 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 fee2b6dcc..dac070c84 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -130,7 +130,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 6 items @@ -181,7 +181,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -194,7 +194,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -259,7 +259,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -320,7 +320,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -447,7 +447,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index f1e9a976d..3fa8834bd 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, 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 061097cc3..0817458ad 100644 --- a/doc/en/example/reportingdemo.rst +++ b/doc/en/example/reportingdemo.rst @@ -11,7 +11,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/assertion, inifile: collected 42 items @@ -359,7 +359,7 @@ get on the terminal - we are working on that):: > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1204>:1: ValueError + <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1207>:1: ValueError _______ TestRaises.test_raises_doesnt ________ self = diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 032f83c08..3dd6fe92e 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -113,7 +113,7 @@ directory with the above conftest.py:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -164,7 +164,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -178,7 +178,7 @@ Or run it including the ``slow`` marked test:: $ pytest --runslow ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -302,7 +302,7 @@ which will add the string to the test header accordingly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 project deps: mylib-1.1 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -327,7 +327,7 @@ which will add info only when run with "--v":: $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache info1: did you know that ... did you? @@ -340,7 +340,7 @@ and nothing when run plainly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -374,7 +374,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -440,7 +440,7 @@ If we run this:: $ pytest -rx ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -519,7 +519,7 @@ We can run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 7 items @@ -627,7 +627,7 @@ and run them:: $ pytest test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -721,7 +721,7 @@ and run it:: $ pytest -s test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 510a4edf9..07a85e9b3 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -70,7 +70,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -188,7 +188,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -519,7 +519,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 11 items @@ -572,7 +572,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 2 items @@ -641,7 +641,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index a3e21e54a..e398e4db5 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.4, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py + This is pytest version 3.0.5, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py .. _`simpletest`: @@ -46,7 +46,7 @@ That's it. You can execute the test function now:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/index.rst b/doc/en/index.rst index 67b13d3e3..ce1618e66 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -24,21 +24,23 @@ An example of a simple test: To execute it:: $ pytest - ============================= test session starts ============================= + ======= test session starts ======== + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items - + test_sample.py F - - ================================== FAILURES =================================== - _________________________________ test_answer _________________________________ - + + ======= FAILURES ======== + _______ test_answer ________ + def test_answer(): > assert inc(3) == 5 E assert 4 == 5 E + where 4 = inc(3) - + test_sample.py:5: AssertionError - ========================== 1 failed in 0.04 seconds =========================== + ======= 1 failed in 0.12 seconds ======== Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See :ref:`Getting Started ` for more examples. diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index 5cfedac8c..052d0e72e 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -55,7 +55,7 @@ them in turn:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -103,7 +103,7 @@ Let's run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index a024b43a4..afa33444e 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -224,7 +224,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/example, inifile: collected 7 items diff --git a/doc/en/tmpdir.rst b/doc/en/tmpdir.rst index 3287ff30f..56e4190c5 100644 --- a/doc/en/tmpdir.rst +++ b/doc/en/tmpdir.rst @@ -29,7 +29,7 @@ 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.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 0bc0209e7..179347eb9 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -100,7 +100,7 @@ the ``self.db`` values in the traceback:: $ pytest test_unittest_db.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items From 3a0a1d2de3ae1cfded8adaec9dcd9b9a6864cc9d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 5 Dec 2016 12:51:00 -0200 Subject: [PATCH 102/201] Bump version to 3.0.6.dev0 --- CHANGELOG.rst | 15 +++++++++++++++ _pytest/__init__.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cfcb012f2..d49214e3f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,18 @@ +3.0.6.dev0 +========== + +* + +* + +* + +* + +* + + + 3.0.5 ===== diff --git a/_pytest/__init__.py b/_pytest/__init__.py index be20d3d41..8546ff02b 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.5' +__version__ = '3.0.6.dev0' From 8afca5d0fa56953f6bceff0fbfa1969feb04a134 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 5 Dec 2016 17:21:01 -0200 Subject: [PATCH 103/201] Add release dates to CHANGELOG entry Fix #721 --- CHANGELOG.rst | 252 +++++++++++++++++++++++++------------------------- 1 file changed, 126 insertions(+), 126 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d49214e3f..707253958 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,5 @@ -3.0.6.dev0 -========== +3.0.6.dev0 (unreleased) +======================= * @@ -13,8 +13,8 @@ -3.0.5 -===== +3.0.5 (2016-12-05) +================== * Add warning when not passing ``option=value`` correctly to ``-o/--override-ini`` (`#2105`_). Also improved the help documentation. Thanks to `@mbukatov`_ for the report and @@ -81,8 +81,8 @@ .. _#687: https://github.com/pytest-dev/pytest/issues/687 -3.0.4 -===== +3.0.4 (2016-11-09) +================== * Import errors when collecting test modules now display the full traceback (`#1976`_). Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. @@ -135,8 +135,8 @@ .. _#1649: https://github.com/pytest-dev/pytest/issues/1649 -3.0.3 -===== +3.0.3 (2016-09-28) +================== * The ``ids`` argument to ``parametrize`` again accepts ``unicode`` strings in Python 2 (`#1905`_). @@ -174,8 +174,8 @@ -3.0.2 -===== +3.0.2 (2016-09-01) +================== * Improve error message when passing non-string ids to ``pytest.mark.parametrize`` (`#1857`_). Thanks `@okken`_ for the report and `@nicoddemus`_ for the PR. @@ -214,8 +214,8 @@ .. _#1898: https://github.com/pytest-dev/pytest/issues/1898 -3.0.1 -===== +3.0.1 (2016-08-23) +================== * Fix regression when ``importorskip`` is used at module level (`#1822`_). Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR. @@ -240,8 +240,8 @@ .. _#1849: https://github.com/pytest-dev/pytest/issues/1849 -3.0.0 -===== +3.0.0 (2016-08-18) +================== **Incompatible changes** @@ -666,8 +666,8 @@ time or change existing behaviors in order to make them less surprising/more use .. _@matthiasha: https://github.com/matthiasha -2.9.2 -===== +2.9.2 (2016-05-31) +================== **Bug Fixes** @@ -705,8 +705,8 @@ time or change existing behaviors in order to make them less surprising/more use .. _@astraw38: https://github.com/astraw38 -2.9.1 -===== +2.9.1 (2016-03-17) +================== **Bug Fixes** @@ -741,8 +741,8 @@ time or change existing behaviors in order to make them less surprising/more use .. _@asottile: https://github.com/asottile -2.9.0 -===== +2.9.0 (2016-02-29) +================== **New Features** @@ -862,13 +862,13 @@ time or change existing behaviors in order to make them less surprising/more use .. _@pquentin: https://github.com/pquentin .. _@ioggstream: https://github.com/ioggstream -2.8.7 -===== +2.8.7 (2016-01-24) +================== - fix #1338: use predictable object resolution for monkeypatch -2.8.6 -===== +2.8.6 (2016-01-21) +================== - fix #1259: allow for double nodeids in junitxml, this was a regression failing plugins combinations @@ -899,8 +899,8 @@ time or change existing behaviors in order to make them less surprising/more use Thanks Georgy Dyuldin for the PR. -2.8.5 -===== +2.8.5 (2015-12-11) +================== - fix #1243: fixed issue where class attributes injected during collection could break pytest. PR by Alexei Kozlenok, thanks Ronny Pfannschmidt and Bruno Oliveira for the review and help. @@ -913,8 +913,8 @@ time or change existing behaviors in order to make them less surprising/more use Bruno Oliveira for the PR. -2.8.4 -===== +2.8.4 (2015-12-06) +================== - fix #1190: ``deprecated_call()`` now works when the deprecated function has been already called by another test in the same @@ -937,8 +937,8 @@ time or change existing behaviors in order to make them less surprising/more use - a number of documentation modernizations wrt good practices. Thanks Bruno Oliveira for the PR. -2.8.3 -===== +2.8.3 (2015-11-18) +================== - fix #1169: add __name__ attribute to testcases in TestCaseFunction to support the @unittest.skip decorator on functions and methods. @@ -965,8 +965,8 @@ time or change existing behaviors in order to make them less surprising/more use system integrity protection (thanks Florian) -2.8.2 -===== +2.8.2 (2015-10-07) +================== - fix #1085: proper handling of encoding errors when passing encoded byte strings to pytest.parametrize in Python 2. @@ -985,8 +985,8 @@ time or change existing behaviors in order to make them less surprising/more use Thanks Sergey B Kirpichev and Vital Kudzelka for contributing and Bruno Oliveira for the PR. -2.8.1 -===== +2.8.1 (2015-09-29) +================== - fix #1034: Add missing nodeid on pytest_logwarning call in addhook. Thanks Simon Gomizelj for the PR. @@ -1032,8 +1032,8 @@ time or change existing behaviors in order to make them less surprising/more use - fix issue 1029: transform errors when writing cache values into pytest-warnings -2.8.0 -===== +2.8.0 (2015-09-18) +================== - new ``--lf`` and ``-ff`` options to run only the last failing tests or "failing tests first" from the last run. This functionality is provided @@ -1222,8 +1222,8 @@ time or change existing behaviors in order to make them less surprising/more use properly used to discover ``rootdir`` and ``ini`` files. Thanks Peter Lauri for the report and Bruno Oliveira for the PR. -2.7.3 (compared to 2.7.2) -============================= +2.7.3 (2015-09-15) +================== - Allow 'dev', 'rc', or other non-integer version strings in ``importorskip``. Thanks to Eric Hunsberger for the PR. @@ -1265,8 +1265,8 @@ time or change existing behaviors in order to make them less surprising/more use directories created by this fixture (defaults to $TEMP/pytest-$USER). Thanks Bruno Oliveira for the PR. -2.7.2 (compared to 2.7.1) -============================= +2.7.2 (2015-06-23) +================== - fix issue767: pytest.raises value attribute does not contain the exception instance on Python 2.6. Thanks Eric Siegerman for providing the test @@ -1294,8 +1294,8 @@ time or change existing behaviors in order to make them less surprising/more use which has a refined algorithm for traceback generation. -2.7.1 (compared to 2.7.0) -============================= +2.7.1 (2015-05-19) +================== - fix issue731: do not get confused by the braces which may be present and unbalanced in an object's repr while collapsing False @@ -1327,8 +1327,8 @@ time or change existing behaviors in order to make them less surprising/more use - reintroduced _pytest fixture of the pytester plugin which is used at least by pytest-xdist. -2.7.0 (compared to 2.6.4) -============================= +2.7.0 (2015-03-26) +================== - fix issue435: make reload() work when assert rewriting is active. Thanks Daniel Hahler. @@ -1397,8 +1397,8 @@ time or change existing behaviors in order to make them less surprising/more use ``sys.last_traceback`` are set, so that a user can inspect the error via postmortem debugging (almarklein). -2.6.4 -===== +2.6.4 (2014-10-24) +================== - Improve assertion failure reporting on iterables, by using ndiff and pprint. @@ -1426,8 +1426,8 @@ time or change existing behaviors in order to make them less surprising/more use - fix issue614: fixed pastebin support. -2.6.3 -===== +2.6.3 (2014-09-24) +================== - fix issue575: xunit-xml was reporting collection errors as failures instead of errors, thanks Oleg Sinyavskiy. @@ -1453,8 +1453,8 @@ time or change existing behaviors in order to make them less surprising/more use - check xfail/skip also with non-python function test items. Thanks Floris Bruynooghe. -2.6.2 -===== +2.6.2 (2014-09-05) +================== - Added function pytest.freeze_includes(), which makes it easy to embed pytest into executables using tools like cx_freeze. @@ -1482,8 +1482,8 @@ time or change existing behaviors in order to make them less surprising/more use replace the py.test introspection message but are shown in addition to them. -2.6.1 -===== +2.6.1 (2014-08-07) +================== - No longer show line numbers in the --verbose output, the output is now purely the nodeid. The line number is still shown in failure reports. @@ -1619,8 +1619,8 @@ time or change existing behaviors in order to make them less surprising/more use in monkeypatch plugin. Improves output in documentation. -2.5.2 -===== +2.5.2 (2014-01-29) +================== - fix issue409 -- better interoperate with cx_freeze by not trying to import from collections.abc which causes problems @@ -1647,8 +1647,8 @@ time or change existing behaviors in order to make them less surprising/more use - make capfd/capsys.capture private, its unused and shouldnt be exposed -2.5.1 -===== +2.5.1 (2013-12-17) +================== - merge new documentation styling PR from Tobias Bieniek. @@ -1668,8 +1668,8 @@ time or change existing behaviors in order to make them less surprising/more use -2.5.0 -===== +2.5.0 (2013-12-12) +================== - dropped python2.5 from automated release testing of pytest itself which means it's probably going to break soon (but still works @@ -1804,8 +1804,8 @@ time or change existing behaviors in order to make them less surprising/more use - fix verbose reporting for @mock'd test functions -2.4.2 -===== +2.4.2 (2013-10-04) +================== - on Windows require colorama and a newer py lib so that py.io.TerminalWriter() now uses colorama instead of its own ctypes hacks. (fixes issue365) @@ -1835,8 +1835,8 @@ time or change existing behaviors in order to make them less surprising/more use - add pluginmanager.do_configure(config) as a link to config.do_configure() for plugin-compatibility -2.4.1 -===== +2.4.1 (2013-10-02) +================== - When using parser.addoption() unicode arguments to the "type" keyword should also be converted to the respective types. @@ -2020,8 +2020,8 @@ Bug fixes: ".section(title)" and ".line(msg)" methods to print extra information at the end of a test run. -2.3.5 -===== +2.3.5 (2013-04-30) +================== - fix issue169: respect --tb=style with setup/teardown errors as well. @@ -2085,8 +2085,8 @@ Bug fixes: - fix issue266 - accept unicode in MarkEvaluator expressions -2.3.4 -===== +2.3.4 (2012-11-20) +================== - yielded test functions will now have autouse-fixtures active but cannot accept fixtures as funcargs - it's anyway recommended to @@ -2105,8 +2105,8 @@ Bug fixes: need to write as -k "TestClass and test_method" to match a certain method in a certain test class. -2.3.3 -===== +2.3.3 (2012-11-06) +================== - fix issue214 - parse modules that contain special objects like e. g. flask's request object which blows up on getattr access if no request @@ -2137,8 +2137,8 @@ Bug fixes: - fix issue127 - improve documentation for pytest_addoption() and add a ``config.getoption(name)`` helper function for consistency. -2.3.2 -===== +2.3.2 (2012-10-25) +================== - fix issue208 and fix issue29 use new py version to avoid long pauses when printing tracebacks in long modules @@ -2170,8 +2170,8 @@ Bug fixes: - add tox.ini to pytest distribution so that ignore-dirs and others config bits are properly distributed for maintainers who run pytest-own tests -2.3.1 -===== +2.3.1 (2012-10-20) +================== - fix issue202 - fix regression: using "self" from fixture functions now works as expected (it's the same "self" instance that a test method @@ -2183,8 +2183,8 @@ Bug fixes: - link to web pages from --markers output which provides help for pytest.mark.* usage. -2.3.0 -===== +2.3.0 (2012-10-19) +================== - fix issue202 - better automatic names for parametrized test functions - fix issue139 - introduce @pytest.fixture which allows direct scoping @@ -2262,8 +2262,8 @@ Bug fixes: - py.test -vv will show all of assert comparisations instead of truncating -2.2.4 -===== +2.2.4 (2012-05-22) +================== - fix error message for rewritten assertions involving the % operator - fix issue 126: correctly match all invalid xml characters for junitxml @@ -2279,13 +2279,13 @@ Bug fixes: - fix issue #144: better mangle test ids to junitxml classnames - upgrade distribute_setup.py to 0.6.27 -2.2.3 -===== +2.2.3 (2012-02-05) +================== - fix uploaded package to only include neccesary files -2.2.2 -===== +2.2.2 (2012-02-05) +================== - fix issue101: wrong args to unittest.TestCase test function now produce better output @@ -2304,8 +2304,8 @@ Bug fixes: - allow adding of attributes to test reports such that it also works with distributed testing (no upgrade of pytest-xdist needed) -2.2.1 -===== +2.2.1 (2011-12-16) +================== - fix issue99 (in pytest and py) internallerrors with resultlog now produce better output - fixed by normalizing pytest_internalerror @@ -2321,8 +2321,8 @@ Bug fixes: - fix collection crash due to unknown-source collected items, thanks to Ralf Schmitt (fixed by depending on a more recent pylib) -2.2.0 -===== +2.2.0 (2011-11-18) +================== - fix issue90: introduce eager tearing down of test items so that teardown function are called earlier. @@ -2356,8 +2356,8 @@ Bug fixes: - simplify junitxml output code by relying on py.xml - add support for skip properties on unittest classes and functions -2.1.3 -===== +2.1.3 (2011-10-18) +================== - fix issue79: assertion rewriting failed on some comparisons in boolops - correctly handle zero length arguments (a la pytest '') @@ -2365,8 +2365,8 @@ Bug fixes: - fix issue75 / skipping test failure on jython - fix issue77 / Allow assertrepr_compare hook to apply to a subset of tests -2.1.2 -===== +2.1.2 (2011-09-24) +================== - fix assertion rewriting on files with windows newlines on some Python versions - refine test discovery by package/module name (--pyargs), thanks Florian Mayer @@ -2388,8 +2388,8 @@ Bug fixes: - fix issue61: assertion rewriting on boolean operations with 3 or more operands - you can now build a man page with "cd doc ; make man" -2.1.0 -===== +2.1.0 (2011-07-09) +================== - fix issue53 call nosestyle setup functions with correct ordering - fix issue58 and issue59: new assertion code fixes @@ -2408,8 +2408,8 @@ Bug fixes: - report KeyboardInterrupt even if interrupted during session startup - fix issue 35 - provide PDF doc version and download link from index page -2.0.3 -===== +2.0.3 (2011-05-11) +================== - fix issue38: nicer tracebacks on calls to hooks, particularly early configure/sessionstart ones @@ -2428,8 +2428,8 @@ Bug fixes: - fix issue37: avoid invalid characters in junitxml's output -2.0.2 -===== +2.0.2 (2011-03-09) +================== - tackle issue32 - speed up test runs of very quick test functions by reducing the relative overhead @@ -2480,8 +2480,8 @@ Bug fixes: - avoid std unittest assertion helper code in tracebacks (thanks Ronny) -2.0.1 -===== +2.0.1 (2011-02-07) +================== - refine and unify initial capturing so that it works nicely even if the logging module is used on an early-loaded conftest.py @@ -2529,8 +2529,8 @@ Bug fixes: parametraization remains the "pytest_generate_tests" mechanism, see the docs. -2.0.0 -===== +2.0.0 (2010-11-25) +================== - pytest-2.0 is now its own package and depends on pylib-2.0 - new ability: python -m pytest / python -m pytest.main ability @@ -2574,8 +2574,8 @@ Bug fixes: - add ability to use "class" level for cached_setup helper - fix strangeness: mark.* objects are now immutable, create new instances -1.3.4 -===== +1.3.4 (2010-09-14) +================== - fix issue111: improve install documentation for windows - fix issue119: fix custom collectability of __init__.py as a module @@ -2583,8 +2583,8 @@ Bug fixes: - fix issue115: unify internal exception passthrough/catching/GeneratorExit - fix issue118: new --tb=native for presenting cpython-standard exceptions -1.3.3 -===== +1.3.3 (2010-07-30) +================== - fix issue113: assertion representation problem with triple-quoted strings (and possibly other cases) @@ -2598,8 +2598,8 @@ Bug fixes: (thanks Armin Ronacher for reporting) - remove trailing whitespace in all py/text distribution files -1.3.2 -===== +1.3.2 (2010-07-08) +================== **New features** @@ -2671,8 +2671,8 @@ Bug fixes: - fix homedir detection on Windows - ship distribute_setup.py version 0.6.13 -1.3.1 -===== +1.3.1 (2010-05-25) +================== **New features** @@ -2741,8 +2741,8 @@ Bug fixes: (and internally be more careful when presenting unexpected byte sequences) -1.3.0 -===== +1.3.0 (2010-05-05) +================== - deprecate --report option in favour of a new shorter and easier to remember -r option: it takes a string argument consisting of any @@ -2806,8 +2806,8 @@ Bug fixes: - added links to the new capturelog and coverage plugins -1.2.0 -===== +1.2.0 (2010-01-18) +================== - refined usage and options for "py.cleanup":: @@ -2845,8 +2845,8 @@ Bug fixes: - fix plugin links -1.1.1 -===== +1.1.1 (2009-11-24) +================== - moved dist/looponfailing from py.test core into a new separately released pytest-xdist plugin. @@ -2929,8 +2929,8 @@ Bug fixes: - fix docs, fix internal bin/ script generation -1.1.0 -===== +1.1.0 (2009-11-05) +================== - introduce automatic plugin registration via 'pytest11' entrypoints via setuptools' pkg_resources.iter_entry_points @@ -3033,16 +3033,16 @@ Bug fixes: * simplified internal localpath implementation -1.0.2 -===== +1.0.2 (2009-08-27) +================== * fixing packaging issues, triggered by fedora redhat packaging, also added doc, examples and contrib dirs to the tarball. * added a documentation link to the new django plugin. -1.0.1 -===== +1.0.1 (2009-08-19) +================== * added a 'pytest_nose' plugin which handles nose.SkipTest, nose-style function/method/generator setup/teardown and @@ -3075,14 +3075,14 @@ Bug fixes: * simplified multicall mechanism and plugin architecture, renamed some internal methods and argnames -1.0.0 -===== +1.0.0 (2009-08-04) +================== * more terse reporting try to show filesystem path relatively to current dir * improve xfail output a bit -1.0.0b9 -======= +1.0.0b9 (2009-07-31) +==================== * cleanly handle and report final teardown of test setup @@ -3115,8 +3115,8 @@ Bug fixes: * item.repr_failure(excinfo) instead of item.repr_failure(excinfo, outerr) -1.0.0b8 -======= +1.0.0b8 (2009-07-22) +==================== * pytest_unittest-plugin is now enabled by default @@ -3169,8 +3169,8 @@ Bug fixes: * make __name__ == "__channelexec__" for remote_exec code -1.0.0b3 -======= +1.0.0b3 (2009-06-19) +==================== * plugin classes are removed: one now defines hooks directly in conftest.py or global pytest_*.py From 9c285dfc1d1c79f71a532e8618a8eb9b443f9df8 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Tue, 6 Dec 2016 09:13:25 +0100 Subject: [PATCH 104/201] fix #2118 - rework Node._getcustomclass and Node compat properties --- CHANGELOG.rst | 4 +++- _pytest/main.py | 47 ++++++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d49214e3f..ff6efb7ef 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,9 @@ 3.0.6.dev0 ========== -* +* fix issue #2118 - protect against internal deprecationerrors by changing the code path of Node._getcustomclass. + This also turns a internal deprecation into a real deprecation. + Thanks to `@nicoddemus`_ for the report and `@RonnyPfannschmidt`_ for the PR. * diff --git a/_pytest/main.py b/_pytest/main.py index 52876c12a..905b35d83 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -3,6 +3,8 @@ import functools import os import sys +import warnings + import _pytest import _pytest._code import py @@ -190,14 +192,21 @@ class FSHookProxy: self.__dict__[name] = x return x -def compatproperty(name): - def fget(self): - import warnings - warnings.warn("This usage is deprecated, please use pytest.{0} instead".format(name), - PendingDeprecationWarning, stacklevel=2) - return getattr(pytest, name) +class _CompatProperty(object): + def __init__(self, name): + self.name = name + + def __get__(self, obj, owner): + if obj is None: + return self + + warnings.warn( + "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format( + name=self.name, owner=type(owner).__name__), + PendingDeprecationWarning, stacklevel=2) + return getattr(pytest, self.name) + - return property(fget) class NodeKeywords(MappingMixin): def __init__(self, node): @@ -269,19 +278,23 @@ class Node(object): """ fspath sensitive hook proxy used to call pytest hooks""" return self.session.gethookproxy(self.fspath) - Module = compatproperty("Module") - Class = compatproperty("Class") - Instance = compatproperty("Instance") - Function = compatproperty("Function") - File = compatproperty("File") - Item = compatproperty("Item") + Module = _CompatProperty("Module") + Class = _CompatProperty("Class") + Instance = _CompatProperty("Instance") + Function = _CompatProperty("Function") + File = _CompatProperty("File") + Item = _CompatProperty("Item") def _getcustomclass(self, name): - cls = getattr(self, name) - if cls != getattr(pytest, name): - py.log._apiwarn("2.0", "use of node.%s is deprecated, " + maybe_compatprop = getattr(type(self), name) + if isinstance(maybe_compatprop, _CompatProperty): + return getattr(pytest, name) + else: + cls = getattr(self, name) + + warnings.warn("use of node.%s is deprecated, " "use pytest_pycollect_makeitem(...) to create custom " - "collection nodes" % name) + "collection nodes" % name, category=DeprecationWarning) return cls def __repr__(self): From f42a954cb3ced2dad27fd973d8316b2191cc55fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Hellstr=C3=B6m?= Date: Tue, 29 Nov 2016 10:25:57 +0100 Subject: [PATCH 105/201] Also update yield teardown for Issue #687 --- doc/en/fixture.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 07a85e9b3..bbc4a95c4 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -257,8 +257,9 @@ the code after the *yield* statement serves as the teardown code.:: print("teardown smtp") smtp.close() -The ``print`` and ``smtp.close()`` statements will execute when the last test using -the fixture in the module has finished execution, regardless of the exception status of the tests. +The ``print`` and ``smtp.close()`` statements will execute when the last test in +the module has finished execution, regardless of the exception status of the +tests. Let's execute it:: From 81c9bdcd0b6a0853e1883d797b93636488665340 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 10 Dec 2016 16:55:04 -0200 Subject: [PATCH 106/201] Mention that Python also adds CWD to sys.path using python -m --- doc/en/usage.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/en/usage.rst b/doc/en/usage.rst index ef63a8e06..4f01081ce 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -16,8 +16,8 @@ You can invoke testing through the Python interpreter from the command line:: python -m pytest [...] -This is equivalent to invoking the command line script ``pytest [...]`` -directly. +This is almost equivalent to invoking the command line script ``pytest [...]`` +directly, except that python will also add the current directory to ``sys.path``. Getting help on version, option names, environment variables -------------------------------------------------------------- From 3a59acf69f0121302bcddd34f71fcd74b966ce7c Mon Sep 17 00:00:00 2001 From: Dmitry Malinovsky Date: Sun, 11 Dec 2016 21:59:11 +0600 Subject: [PATCH 107/201] Use inspect to properly detect generators. Fixes #2129 --- _pytest/compat.py | 15 ++++++++++----- testing/conftest.py | 7 +++++++ testing/test_compat.py | 12 ++++++++++++ testing/test_compat_3.py | 15 +++++++++++++++ testing/test_compat_35.py | 12 ++++++++++++ 5 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 testing/conftest.py create mode 100644 testing/test_compat.py create mode 100644 testing/test_compat_3.py create mode 100644 testing/test_compat_35.py diff --git a/_pytest/compat.py b/_pytest/compat.py index 51fc3bc5c..7a3d0af81 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -19,6 +19,12 @@ except ImportError: # pragma: no cover # Only available in Python 3.4+ or as a backport enum = None +try: + import asyncio +except ImportError: # pragma: no cover + # Only available in Python 3.4+ or as a backport + asyncio = None + _PY3 = sys.version_info > (3, 0) _PY2 = not _PY3 @@ -42,11 +48,10 @@ REGEX_TYPE = type(re.compile('')) def is_generator(func): - try: - return _pytest._code.getrawcode(func).co_flags & 32 # generator function - except AttributeError: # builtin functions have no bytecode - # assume them to not be generators - return False + genfunc = inspect.isgeneratorfunction(func) + if asyncio is not None: + return genfunc and not asyncio.iscoroutinefunction(func) + return genfunc def getlocation(function, curdir): diff --git a/testing/conftest.py b/testing/conftest.py new file mode 100644 index 000000000..76a314837 --- /dev/null +++ b/testing/conftest.py @@ -0,0 +1,7 @@ +import sys + +collect_ignore = [] +if sys.version_info[0] < 3: + collect_ignore.append("test_compat_3.py") +if sys.version_info < (3, 5): + collect_ignore.append("test_compat_35.py") diff --git a/testing/test_compat.py b/testing/test_compat.py new file mode 100644 index 000000000..185fc3bd6 --- /dev/null +++ b/testing/test_compat.py @@ -0,0 +1,12 @@ +from _pytest.compat import is_generator + + +def test_is_generator(): + def zap(): + yield + + def foo(): + pass + + assert is_generator(zap) + assert not is_generator(foo) diff --git a/testing/test_compat_3.py b/testing/test_compat_3.py new file mode 100644 index 000000000..a1ee0e6f1 --- /dev/null +++ b/testing/test_compat_3.py @@ -0,0 +1,15 @@ +import pytest +from _pytest.compat import is_generator +try: + import asyncio +except ImportError: + asyncio = None + + +@pytest.mark.skipif(asyncio is None, reason='asyncio is not installed') +def test_is_generator(): + @asyncio.coroutine + def baz(): + yield from [1,2,3] + + assert not is_generator(baz) diff --git a/testing/test_compat_35.py b/testing/test_compat_35.py new file mode 100644 index 000000000..93eecc920 --- /dev/null +++ b/testing/test_compat_35.py @@ -0,0 +1,12 @@ +from _pytest.compat import is_generator + + +def test_is_generator_py35(): + async def foo(): + await foo() + + async def bar(): + pass + + assert not is_generator(foo) + assert not is_generator(bar) From 45eb9b566c318b529219263936a8592cb4c26a88 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 13 Dec 2016 21:28:07 -0200 Subject: [PATCH 108/201] Move compat tests to a single file using testdir This avoids having to resort to skipping modules in conftest.py file and avoids flake8 errors --- testing/conftest.py | 7 ------- testing/test_compat.py | 37 +++++++++++++++++++++++++++++++++++++ testing/test_compat_3.py | 15 --------------- testing/test_compat_35.py | 12 ------------ 4 files changed, 37 insertions(+), 34 deletions(-) delete mode 100644 testing/conftest.py delete mode 100644 testing/test_compat_3.py delete mode 100644 testing/test_compat_35.py diff --git a/testing/conftest.py b/testing/conftest.py deleted file mode 100644 index 76a314837..000000000 --- a/testing/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import sys - -collect_ignore = [] -if sys.version_info[0] < 3: - collect_ignore.append("test_compat_3.py") -if sys.version_info < (3, 5): - collect_ignore.append("test_compat_35.py") diff --git a/testing/test_compat.py b/testing/test_compat.py index 185fc3bd6..d704bb807 100644 --- a/testing/test_compat.py +++ b/testing/test_compat.py @@ -1,3 +1,6 @@ +import sys + +import pytest from _pytest.compat import is_generator @@ -10,3 +13,37 @@ def test_is_generator(): assert is_generator(zap) assert not is_generator(foo) + + +def test_is_generator_asyncio(testdir): + pytest.importorskip('asyncio') + testdir.makepyfile(""" + from _pytest.compat import is_generator + import asyncio + @asyncio.coroutine + def baz(): + yield from [1,2,3] + + def test_is_generator_asyncio(): + assert not is_generator(baz) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*1 passed*']) + + +@pytest.mark.skipif(sys.version_info < (3, 5), reason='async syntax available in Python 3.5+') +def test_is_generator_async_syntax(testdir): + testdir.makepyfile(""" + from _pytest.compat import is_generator + def test_is_generator_py35(): + async def foo(): + await foo() + + async def bar(): + pass + + assert not is_generator(foo) + assert not is_generator(bar) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*1 passed*']) diff --git a/testing/test_compat_3.py b/testing/test_compat_3.py deleted file mode 100644 index a1ee0e6f1..000000000 --- a/testing/test_compat_3.py +++ /dev/null @@ -1,15 +0,0 @@ -import pytest -from _pytest.compat import is_generator -try: - import asyncio -except ImportError: - asyncio = None - - -@pytest.mark.skipif(asyncio is None, reason='asyncio is not installed') -def test_is_generator(): - @asyncio.coroutine - def baz(): - yield from [1,2,3] - - assert not is_generator(baz) diff --git a/testing/test_compat_35.py b/testing/test_compat_35.py deleted file mode 100644 index 93eecc920..000000000 --- a/testing/test_compat_35.py +++ /dev/null @@ -1,12 +0,0 @@ -from _pytest.compat import is_generator - - -def test_is_generator_py35(): - async def foo(): - await foo() - - async def bar(): - pass - - assert not is_generator(foo) - assert not is_generator(bar) From 1312b83866709611aaa9d9d22e3161dfd9b8d244 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 13 Dec 2016 21:33:01 -0200 Subject: [PATCH 109/201] Add CHANGELOG entry for #2129 --- CHANGELOG.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 707253958..3bb525c1e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,7 +3,8 @@ * -* +* pytest no longer recognizes coroutine functions as yield tests (`#2129`_). + Thanks to `@malinoff`_ for the PR. * @@ -12,6 +13,9 @@ * +.. _@malinoff: https://github.com/malinoff + +.. _#2129: https://github.com/pytest-dev/pytest/issues/2129 3.0.5 (2016-12-05) ================== From caee5ce489e4f7058154bea1b4bc371bd384af20 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 13 Dec 2016 21:54:20 -0200 Subject: [PATCH 110/201] Avoid importing asyncio directly because that in turn initializes logging (#8) --- _pytest/compat.py | 19 +++++++++++-------- testing/test_compat.py | 5 +++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/_pytest/compat.py b/_pytest/compat.py index 7a3d0af81..dc3e69545 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -19,11 +19,6 @@ except ImportError: # pragma: no cover # Only available in Python 3.4+ or as a backport enum = None -try: - import asyncio -except ImportError: # pragma: no cover - # Only available in Python 3.4+ or as a backport - asyncio = None _PY3 = sys.version_info > (3, 0) _PY2 = not _PY3 @@ -49,9 +44,17 @@ REGEX_TYPE = type(re.compile('')) def is_generator(func): genfunc = inspect.isgeneratorfunction(func) - if asyncio is not None: - return genfunc and not asyncio.iscoroutinefunction(func) - return genfunc + return genfunc and not iscoroutinefunction(func) + + +def iscoroutinefunction(func): + """Return True if func is a decorated coroutine function. + + Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly, + which in turns also initializes the "logging" module as side-effect (see issue #8). + """ + return (getattr(func, '_is_coroutine', False) or + (hasattr(inspect, 'iscoroutinefunction') and inspect.iscoroutinefunction(func))) def getlocation(function, curdir): diff --git a/testing/test_compat.py b/testing/test_compat.py index d704bb807..1fdd07e29 100644 --- a/testing/test_compat.py +++ b/testing/test_compat.py @@ -15,8 +15,8 @@ def test_is_generator(): assert not is_generator(foo) +@pytest.mark.skipif(sys.version_info < (3, 4), reason='asyncio available in Python 3.4+') def test_is_generator_asyncio(testdir): - pytest.importorskip('asyncio') testdir.makepyfile(""" from _pytest.compat import is_generator import asyncio @@ -27,7 +27,8 @@ def test_is_generator_asyncio(testdir): def test_is_generator_asyncio(): assert not is_generator(baz) """) - result = testdir.runpytest() + # avoid importing asyncio into pytest's own process, which in turn imports logging (#8) + result = testdir.runpytest_subprocess() result.stdout.fnmatch_lines(['*1 passed*']) From 3f5edc705a336cf7a40dd1117065e9a413d27847 Mon Sep 17 00:00:00 2001 From: Stefan Scherfke Date: Mon, 19 Dec 2016 13:22:25 +0100 Subject: [PATCH 111/201] Explicitly add setuptools to install_requires Setuptools is used in `_pytest/config.py` but was not explicitly listed as requirement. This led to an error when creating a Conda package for pytest since setuptools is not necessarily installed by default in Conda envs. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cdcf3b3bb..f03ab9c40 100644 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ def has_environment_marker_support(): def main(): - install_requires = ['py>=1.4.29'] # pluggy is vendored in _pytest.vendored_packages + install_requires = ['py>=1.4.29', 'setuptools'] # pluggy is vendored in _pytest.vendored_packages extras_require = {} if has_environment_marker_support(): extras_require[':python_version=="2.6"'] = ['argparse'] From f94189b48b7a50ad51f9b40c6f26a93ccc9565fb Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Tue, 20 Dec 2016 01:48:32 +0100 Subject: [PATCH 112/201] Fix wrong fixture name. Closes #2143. --- doc/en/fixture.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index bbc4a95c4..9bc4f6084 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -1002,7 +1002,7 @@ Given the tests file structure is: @pytest.mark.parametrize('username', ['directly-overridden-username-other']) def test_username_other(other_username): - assert username == 'other-directly-overridden-username-other' + assert other_username == 'other-directly-overridden-username-other' In the example above, a fixture value is overridden by the test parameter value. Note that the value of the fixture can be overridden this way even if the test doesn't use it directly (doesn't mention it in the function prototype). From c5f0b751f48d1c44e74d14e7d89772b825ffa332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Tue, 20 Dec 2016 13:36:57 +0100 Subject: [PATCH 113/201] Improve error message when pytest.warns fail The error message contains the expected type of warnings and the warnings that were captured. Add tests. --- _pytest/recwarn.py | 5 ++++- testing/test_recwarn.py | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/_pytest/recwarn.py b/_pytest/recwarn.py index 87823bfbc..d66f87e72 100644 --- a/_pytest/recwarn.py +++ b/_pytest/recwarn.py @@ -223,4 +223,7 @@ class WarningsChecker(WarningsRecorder): if self.expected_warning is not None: if not any(r.category in self.expected_warning for r in self): __tracebackhide__ = True - pytest.fail("DID NOT WARN") + pytest.fail("DID NOT WARN. No warnings of type {0} was emitted. " + "The list of emitted warnings is: {1}.".format( + self.expected_warning, + [each.message for each in self])) diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 87e5846c2..0f3bf6a14 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -1,4 +1,5 @@ import warnings +import re import py import pytest from _pytest.recwarn import WarningsRecorder @@ -114,7 +115,7 @@ class TestDeprecatedCall(object): with pytest.raises(pytest.fail.Exception) as ex: with pytest.deprecated_call(): self.dep(1) - assert str(ex.value) == "DID NOT WARN" + assert str(ex.value).startswith("DID NOT WARN") def test_deprecated_call_as_context_manager(self): with pytest.deprecated_call(): @@ -185,17 +186,39 @@ class TestWarns(object): with pytest.warns(RuntimeWarning): warnings.warn("runtime", RuntimeWarning) - with pytest.raises(pytest.fail.Exception): - with pytest.warns(RuntimeWarning): - warnings.warn("user", UserWarning) - - with pytest.raises(pytest.fail.Exception): - with pytest.warns(UserWarning): - warnings.warn("runtime", RuntimeWarning) - with pytest.warns(UserWarning): warnings.warn("user", UserWarning) + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(RuntimeWarning): + warnings.warn("user", UserWarning) + excinfo.match(r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) was emitted. " + r"The list of emitted warnings is: \[UserWarning\('user',\)\].") + + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(UserWarning): + warnings.warn("runtime", RuntimeWarning) + excinfo.match(r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. " + r"The list of emitted warnings is: \[RuntimeWarning\('runtime',\)\].") + + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(UserWarning): + pass + excinfo.match(r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. " + r"The list of emitted warnings is: \[\].") + + warning_classes = (UserWarning, FutureWarning) + with pytest.raises(pytest.fail.Exception) as excinfo: + with pytest.warns(warning_classes) as warninfo: + warnings.warn("runtime", RuntimeWarning) + warnings.warn("import", ImportWarning) + + message_template = ("DID NOT WARN. No warnings of type {0} was emitted. " + "The list of emitted warnings is: {1}.") + 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) From bfada968d3d1947523a6cf70f59d44620a9505c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= Date: Tue, 20 Dec 2016 14:36:10 +0100 Subject: [PATCH 114/201] Update AUTHORS and CHANGELOG.rst following contribution guidelines --- AUTHORS | 1 + CHANGELOG.rst | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 8c7cb19ce..8c6fa1b5d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -82,6 +82,7 @@ Katarzyna Jachim Kevin Cox Lee Kamentsky Lev Maximov +Loic Esteve Lukas Bednar Luke Murphy Maciek Fijalkowski diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 707253958..847d27c51 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,12 +5,17 @@ * -* +* Improve error message when pytest.warns fails (`#2150`_). The type(s) of the + expected warnings and the list of caught warnings is added to the + error message. Thanks `@lesteve`_ for the PR. * * +.. _@lesteve: https://github.com/lesteve + +.. _#2150: https://github.com/pytest-dev/pytest/issues/2150 3.0.5 (2016-12-05) From f7a1d369c35cf2716d84751b4132bfc90c68a162 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 26 Dec 2016 21:47:50 -0200 Subject: [PATCH 115/201] Allow trial environments to fail on CI for now While I agree this is *far* from ideal, IMHO It is better to ignore them for now otherwise we hamper contributors with unrelated errors. We should fix this before the next release. #1989 --- .travis.yml | 3 ++- appveyor.yml | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bbc03d856..a7b84194e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,8 @@ env: matrix: allow_failures: - # py35-trial failing on Linux: #1989 + # see #1989 + - env: TESTENV=py27-trial - env: TESTENV=py35-trial script: tox --recreate -e $TESTENV diff --git a/appveyor.yml b/appveyor.yml index a42aa16dc..c82b81ce9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,6 +27,12 @@ environment: - TOXENV: "freeze" - TOXENV: "docs" +matrix: + allow_failures: + # see #1989 + - TOXENV: "py27-trial" + - TOXENV: "py35-trial" + install: - echo Installed Pythons - dir c:\Python* From 0bb8a4a36d8b32f17d6e0cf8aebe9c4a92a99cfa Mon Sep 17 00:00:00 2001 From: Andreas Pelme Date: Tue, 20 Dec 2016 11:22:18 +0100 Subject: [PATCH 116/201] Fixed #2148 - parse directory names properly when args contains ::. This commit also improves readbility in get_dirs_from_args by using self documenting local functions. get_dirs_from_args also now only returns directories that actually exists, and not files to avoid confusion. This commit also removes redundant checks in get_common_ancestor that was already performed in get_dirs_from_args.. --- CHANGELOG.rst | 6 +++++- _pytest/config.py | 47 ++++++++++++++++++++++++++++-------------- testing/test_config.py | 23 +++++++++++++++++++++ 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 847d27c51..6ad73d0c2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,13 +9,17 @@ expected warnings and the list of caught warnings is added to the error message. Thanks `@lesteve`_ for the PR. -* +* Specifying tests with colons like ``test_foo.py::test_bar`` for tests in + subdirectories with ini configuration files now uses the correct ini file + (`#2148`_). Thanks `@pelme`_. * .. _@lesteve: https://github.com/lesteve +.. _@pelme: https://github.com/pelme .. _#2150: https://github.com/pytest-dev/pytest/issues/2150 +.. _#2148: https://github.com/pytest-dev/pytest/issues/2148 3.0.5 (2016-12-05) diff --git a/_pytest/config.py b/_pytest/config.py index fe386ed0b..55326447e 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1228,25 +1228,20 @@ def getcfg(args, warnfunc=None): return None, None, None -def get_common_ancestor(args): - # args are what we get after early command line parsing (usually - # strings, but can be py.path.local objects as well) +def get_common_ancestor(paths): common_ancestor = None - for arg in args: - if str(arg)[0] == "-": - continue - p = py.path.local(arg) - if not p.exists(): + for path in paths: + if not path.exists(): continue if common_ancestor is None: - common_ancestor = p + common_ancestor = path else: - if p.relto(common_ancestor) or p == common_ancestor: + if path.relto(common_ancestor) or path == common_ancestor: continue - elif common_ancestor.relto(p): - common_ancestor = p + elif common_ancestor.relto(path): + common_ancestor = path else: - shared = p.common(common_ancestor) + shared = path.common(common_ancestor) if shared is not None: common_ancestor = shared if common_ancestor is None: @@ -1257,9 +1252,29 @@ def get_common_ancestor(args): def get_dirs_from_args(args): - return [d for d in (py.path.local(x) for x in args - if not str(x).startswith("-")) - if d.exists()] + def is_option(x): + return str(x).startswith('-') + + def get_file_part_from_node_id(x): + return str(x).split('::')[0] + + def get_dir_from_path(path): + if path.isdir(): + return path + return py.path.local(path.dirname) + + # These look like paths but may not exist + possible_paths = ( + py.path.local(get_file_part_from_node_id(arg)) + for arg in args + if not is_option(arg) + ) + + return [ + get_dir_from_path(path) + for path in possible_paths + if path.exists() + ] def determine_setup(inifile, args, warnfunc=None): diff --git a/testing/test_config.py b/testing/test_config.py index 21ceab1e2..6bc867737 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -527,6 +527,29 @@ def test_toolongargs_issue224(testdir): result = testdir.runpytest("-m", "hello" * 500) assert result.ret == EXIT_NOTESTSCOLLECTED +def test_config_in_subdirectory_colon_command_line_issue2148(testdir): + conftest_source = ''' + def pytest_addoption(parser): + parser.addini('foo', 'foo') + ''' + + testdir.makefile('.ini', **{ + 'pytest': '[pytest]\nfoo = root', + 'subdir/pytest': '[pytest]\nfoo = subdir', + }) + + testdir.makepyfile(**{ + 'conftest': conftest_source, + 'subdir/conftest': conftest_source, + 'subdir/test_foo': ''' + def test_foo(pytestconfig): + assert pytestconfig.getini('foo') == 'subdir' + '''}) + + result = testdir.runpytest('subdir/test_foo.py::test_foo') + assert result.ret == 0 + + def test_notify_exception(testdir, capfd): config = testdir.parseconfig() excinfo = pytest.raises(ValueError, "raise ValueError(1)") From 1680eeb3a3cf13892c5fae59a9d251727370df39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 13 Dec 2016 13:49:44 +0100 Subject: [PATCH 117/201] Tests: Check for ModuleNotFoundError on Python 3.6+ Those tests originally checked for ImportError. Since Python 3.6 ModuleNotFoundError is raised in this context instead, the tests didn't work as they are text based (so exception inheritance does not save the day). Fixes https://github.com/pytest-dev/pytest/issues/2132 --- testing/test_doctest.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/testing/test_doctest.py b/testing/test_doctest.py index 4ea2cc58e..196a5670e 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -4,6 +4,10 @@ import _pytest._code from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile import pytest +PY36 = sys.version_info[:2] >= (3, 6) +MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError' + + class TestDoctests: def test_collect_testtextfile(self, testdir): @@ -211,8 +215,8 @@ class TestDoctests: # doctest is never executed because of error during hello.py collection result.stdout.fnmatch_lines([ "*>>> import asdals*", - "*UNEXPECTED*ImportError*", - "ImportError: No module named *asdal*", + "*UNEXPECTED*{e}*".format(e=MODULE_NOT_FOUND_ERROR), + "{e}: No module named *asdal*".format(e=MODULE_NOT_FOUND_ERROR), ]) def test_doctest_unex_importerror_with_module(self, testdir): @@ -227,7 +231,7 @@ class TestDoctests: # doctest is never executed because of error during hello.py collection result.stdout.fnmatch_lines([ "*ERROR collecting hello.py*", - "*ImportError: No module named *asdals*", + "*{e}: No module named *asdals*".format(e=MODULE_NOT_FOUND_ERROR), "*Interrupted: 1 errors during collection*", ]) From 6b24ce2a9d618bbda2c2f1dd70c8d7f43c474473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 13 Dec 2016 15:16:06 +0100 Subject: [PATCH 118/201] Test Python 3.6 on Travis CI Partial fix for https://github.com/pytest-dev/pytest/issues/2134 --- .travis.yml | 3 +++ tox.ini | 1 + 2 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index bbc03d856..c4699ec4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,9 @@ matrix: allow_failures: # py35-trial failing on Linux: #1989 - env: TESTENV=py35-trial + include: + - env: TESTENV=py36 + python: '3.6-dev' script: tox --recreate -e $TESTENV diff --git a/tox.ini b/tox.ini index f3494e8be..a5dec3fdc 100644 --- a/tox.ini +++ b/tox.ini @@ -9,6 +9,7 @@ envlist= py33 py34 py35 + py36 pypy {py27,py35}-{pexpect,xdist,trial} py27-nobyte From 515fb099957286b6c692d0fb95b789dbfcae6b0a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 27 Dec 2016 22:01:22 -0200 Subject: [PATCH 119/201] Move module error compatibility code to _pytest.compat --- _pytest/compat.py | 3 +++ testing/test_doctest.py | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/_pytest/compat.py b/_pytest/compat.py index 51fc3bc5c..8f4d0a8e6 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -26,6 +26,9 @@ _PY2 = not _PY3 NoneType = type(None) NOTSET = object() +PY36 = sys.version_info[:2] >= (3, 6) +MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError' + if hasattr(inspect, 'signature'): def _format_args(func): return str(inspect.signature(func)) diff --git a/testing/test_doctest.py b/testing/test_doctest.py index 196a5670e..faf75ef33 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -1,12 +1,10 @@ # encoding: utf-8 import sys import _pytest._code +from _pytest.compat import MODULE_NOT_FOUND_ERROR from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile import pytest -PY36 = sys.version_info[:2] >= (3, 6) -MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError' - class TestDoctests: From 7592c5b491ac83c3c2be1b580a3a6afde469114e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 27 Dec 2016 23:20:34 -0200 Subject: [PATCH 120/201] Sort issues and user references in CHANGELOG --- CHANGELOG.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fff42ce3b..9d0b80ecf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,14 +17,13 @@ * .. _@lesteve: https://github.com/lesteve +.. _@malinoff: https://github.com/malinoff .. _@pelme: https://github.com/pelme -.. _#2150: https://github.com/pytest-dev/pytest/issues/2150 -.. _#2148: https://github.com/pytest-dev/pytest/issues/2148 - -.. _@malinoff: https://github.com/malinoff - .. _#2129: https://github.com/pytest-dev/pytest/issues/2129 +.. _#2148: https://github.com/pytest-dev/pytest/issues/2148 +.. _#2150: https://github.com/pytest-dev/pytest/issues/2150 + 3.0.5 (2016-12-05) ================== From 03a7a2cd3ed855a8ee0af260aba236818bbcacaf Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Sat, 31 Dec 2016 18:54:47 +0100 Subject: [PATCH 121/201] Fix typos --- CHANGELOG.rst | 50 ++++++++++++++--------------- doc/en/announce/release-2.0.2.rst | 4 +-- doc/en/announce/release-2.0.3.rst | 4 +-- doc/en/announce/release-2.2.1.rst | 2 +- doc/en/announce/release-2.2.4.rst | 2 +- doc/en/announce/release-2.3.0.rst | 4 +-- doc/en/announce/release-2.3.2.rst | 2 +- doc/en/announce/release-2.3.3.rst | 6 ++-- doc/en/announce/release-2.3.5.rst | 8 ++--- doc/en/announce/release-2.4.0.rst | 4 +-- doc/en/announce/release-2.5.0.rst | 4 +-- doc/en/announce/release-2.5.2.rst | 2 +- doc/en/announce/release-2.6.3.rst | 2 +- doc/en/announce/release-2.7.1.rst | 2 +- doc/en/announce/release-2.9.2.rst | 2 +- doc/en/cache.rst | 2 +- doc/en/conf.py | 2 +- doc/en/example/markers.rst | 4 +-- doc/en/example/pythoncollection.rst | 2 +- doc/en/example/simple.rst | 6 ++-- doc/en/funcarg_compare.rst | 2 +- doc/en/monkeypatch.rst | 4 +-- doc/en/projects.rst | 2 +- doc/en/skipping.rst | 2 +- doc/en/test/plugin/xdist.rst | 2 +- doc/en/usage.rst | 4 +-- doc/en/writing_plugins.rst | 4 +-- 27 files changed, 67 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9d0b80ecf..7c3df0327 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -690,7 +690,7 @@ time or change existing behaviors in order to make them less surprising/more use Thanks `@astraw38`_ for reporting the issue (`#1496`_) and `@tomviner`_ for PR the (`#1524`_). -* Fix win32 path issue when puttinging custom config file with absolute path +* Fix win32 path issue when putting custom config file with absolute path in ``pytest.main("-c your_absolute_path")``. * Fix maximum recursion depth detection when raised error class is not aware @@ -1022,7 +1022,7 @@ time or change existing behaviors in order to make them less surprising/more use - (experimental) adapt more SEMVER style versioning and change meaning of master branch in git repo: "master" branch now keeps the bugfixes, changes - aimed for micro releases. "features" branch will only be be released + aimed for micro releases. "features" branch will only be released with minor or major pytest releases. - Fix issue #766 by removing documentation references to distutils. @@ -1156,7 +1156,7 @@ time or change existing behaviors in order to make them less surprising/more use - new option ``--import-mode`` to allow to change test module importing behaviour to append to sys.path instead of prepending. This better allows - to run test modules against installated versions of a package even if the + to run test modules against installed versions of a package even if the package under test has the same import root. In this example:: testing/__init__.py @@ -1314,7 +1314,7 @@ time or change existing behaviors in order to make them less surprising/more use explanations. Thanks Carl Meyer for the report and test case. - fix issue553: properly handling inspect.getsourcelines failures in - FixtureLookupError which would lead to to an internal error, + FixtureLookupError which would lead to an internal error, obfuscating the original problem. Thanks talljosh for initial diagnose/patch and Bruno Oliveira for final patch. @@ -1457,7 +1457,7 @@ time or change existing behaviors in order to make them less surprising/more use - fix conftest related fixture visibility issue: when running with a CWD outside of a test package pytest would get fixture discovery wrong. - Thanks to Wolfgang Schnerring for figuring out a reproducable example. + Thanks to Wolfgang Schnerring for figuring out a reproducible example. - Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the timeout when interactively entering pdb). Thanks Wolfgang Schnerring. @@ -1656,7 +1656,7 @@ time or change existing behaviors in order to make them less surprising/more use - fix issue429: comparing byte strings with non-ascii chars in assert expressions now work better. Thanks Floris Bruynooghe. -- make capfd/capsys.capture private, its unused and shouldnt be exposed +- make capfd/capsys.capture private, its unused and shouldn't be exposed 2.5.1 (2013-12-17) @@ -1713,7 +1713,7 @@ time or change existing behaviors in order to make them less surprising/more use to problems for more than >966 non-function scoped parameters). - fix issue290 - there is preliminary support now for parametrizing - with repeated same values (sometimes useful to to test if calling + with repeated same values (sometimes useful to test if calling a second time works as with the first time). - close issue240 - document precisely how pytest module importing @@ -1927,7 +1927,7 @@ new features: - fix issue322: tearDownClass is not run if setUpClass failed. Thanks Mathieu Agopian for the initial fix. Also make all of pytest/nose - finalizer mimick the same generic behaviour: if a setupX exists and + finalizer mimic the same generic behaviour: if a setupX exists and fails, don't run teardownX. This internally introduces a new method "node.addfinalizer()" helper which can only be called during the setup phase of a node. @@ -2046,11 +2046,11 @@ Bug fixes: (thanks Adam Goucher) - Issue 265 - integrate nose setup/teardown with setupstate - so it doesnt try to teardown if it did not setup + so it doesn't try to teardown if it did not setup -- issue 271 - dont write junitxml on slave nodes +- issue 271 - don't write junitxml on slave nodes -- Issue 274 - dont try to show full doctest example +- Issue 274 - don't try to show full doctest example when doctest does not know the example location - issue 280 - disable assertion rewriting on buggy CPython 2.6.0 @@ -2086,7 +2086,7 @@ Bug fixes: - allow to specify prefixes starting with "_" when customizing python_functions test discovery. (thanks Graham Horler) -- improve PYTEST_DEBUG tracing output by puting +- improve PYTEST_DEBUG tracing output by putting extra data on a new lines with additional indent - ensure OutcomeExceptions like skip/fail have initialized exception attributes @@ -2135,7 +2135,7 @@ Bug fixes: - fix issue209 - reintroduce python2.4 support by depending on newer pylib which re-introduced statement-finding for pre-AST interpreters -- nose support: only call setup if its a callable, thanks Andrew +- nose support: only call setup if it's a callable, thanks Andrew Taumoefolau - fix issue219 - add py2.4-3.3 classifiers to TROVE list @@ -2231,7 +2231,7 @@ Bug fixes: - fix issue128: show captured output when capsys/capfd are used -- fix issue179: propperly show the dependency chain of factories +- fix issue179: properly show the dependency chain of factories - pluginmanager.register(...) now raises ValueError if the plugin has been already registered or the name is taken @@ -2272,7 +2272,7 @@ Bug fixes: - don't show deselected reason line if there is none - - py.test -vv will show all of assert comparisations instead of truncating + - py.test -vv will show all of assert comparisons instead of truncating 2.2.4 (2012-05-22) ================== @@ -2283,7 +2283,7 @@ Bug fixes: - fix issue with unittest: now @unittest.expectedFailure markers should be processed correctly (you can also use @pytest.mark markers) - document integration with the extended distribute/setuptools test commands -- fix issue 140: propperly get the real functions +- fix issue 140: properly get the real functions of bound classmethods for setup/teardown_class - fix issue #141: switch from the deceased paste.pocoo.org to bpaste.net - fix issue #143: call unconfigure/sessionfinish always when @@ -2294,7 +2294,7 @@ Bug fixes: 2.2.3 (2012-02-05) ================== -- fix uploaded package to only include neccesary files +- fix uploaded package to only include necessary files 2.2.2 (2012-02-05) ================== @@ -2435,7 +2435,7 @@ Bug fixes: - don't require zlib (and other libs) for genscript plugin without --genscript actually being used. -- speed up skips (by not doing a full traceback represenation +- speed up skips (by not doing a full traceback representation internally) - fix issue37: avoid invalid characters in junitxml's output @@ -2483,9 +2483,9 @@ Bug fixes: this. - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular - thanks to Laura Creighton who also revieved parts of the documentation. + thanks to Laura Creighton who also reviewed parts of the documentation. -- fix slighly wrong output of verbose progress reporting for classes +- fix slightly wrong output of verbose progress reporting for classes (thanks Amaury) - more precise (avoiding of) deprecation warnings for node.Class|Function accesses @@ -2546,7 +2546,7 @@ Bug fixes: - pytest-2.0 is now its own package and depends on pylib-2.0 - new ability: python -m pytest / python -m pytest.main ability -- new python invcation: pytest.main(args, plugins) to load +- new python invocation: pytest.main(args, plugins) to load some custom plugins early. - try harder to run unittest test suites in a more compatible manner by deferring setup/teardown semantics to the unittest package. @@ -2785,7 +2785,7 @@ Bug fixes: - extend and refine xfail mechanism: ``@py.test.mark.xfail(run=False)`` do not run the decorated test ``@py.test.mark.xfail(reason="...")`` prints the reason string in xfail summaries - specifiying ``--runxfail`` on command line virtually ignores xfail markers + specifying ``--runxfail`` on command line virtually ignores xfail markers - expose (previously internal) commonly useful methods: py.io.get_terminal_with() -> return terminal width @@ -3010,7 +3010,7 @@ Bug fixes: * add the ability to specify a path for py.lookup to search in -* fix a funcarg cached_setup bug probably only occuring +* fix a funcarg cached_setup bug probably only occurring in distributed testing and "module" scope with teardown. * many fixes and changes for making the code base python3 compatible, @@ -3276,10 +3276,10 @@ serve as a reference for developers. * fixed issue with 2.5 type representations in py.test [45483, 45484] * made that internal reporting issues displaying is done atomically in py.test [45518] -* made that non-existing files are igored by the py.lookup script [45519] +* made that non-existing files are ignored by the py.lookup script [45519] * improved exception name creation in py.test [45535] * made that less threads are used in execnet [merge in 45539] -* removed lock required for atomical reporting issue displaying in py.test +* removed lock required for atomic reporting issue displaying in py.test [45545] * removed globals from execnet [45541, 45547] * refactored cleanup mechanics, made that setDaemon is set to 1 to make atexit diff --git a/doc/en/announce/release-2.0.2.rst b/doc/en/announce/release-2.0.2.rst index 733a9f7bd..f1f44f34f 100644 --- a/doc/en/announce/release-2.0.2.rst +++ b/doc/en/announce/release-2.0.2.rst @@ -63,9 +63,9 @@ Changes between 2.0.1 and 2.0.2 this. - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular - thanks to Laura Creighton who also revieved parts of the documentation. + thanks to Laura Creighton who also reviewed parts of the documentation. -- fix slighly wrong output of verbose progress reporting for classes +- fix slightly wrong output of verbose progress reporting for classes (thanks Amaury) - more precise (avoiding of) deprecation warnings for node.Class|Function accesses diff --git a/doc/en/announce/release-2.0.3.rst b/doc/en/announce/release-2.0.3.rst index ed746e851..9bbfdaab3 100644 --- a/doc/en/announce/release-2.0.3.rst +++ b/doc/en/announce/release-2.0.3.rst @@ -13,7 +13,7 @@ If you want to install or upgrade pytest, just type one of:: easy_install -U pytest There also is a bugfix release 1.6 of pytest-xdist, the plugin -that enables seemless distributed and "looponfail" testing for Python. +that enables seamless distributed and "looponfail" testing for Python. best, holger krekel @@ -33,7 +33,7 @@ Changes between 2.0.2 and 2.0.3 - don't require zlib (and other libs) for genscript plugin without --genscript actually being used. -- speed up skips (by not doing a full traceback represenation +- speed up skips (by not doing a full traceback representation internally) - fix issue37: avoid invalid characters in junitxml's output diff --git a/doc/en/announce/release-2.2.1.rst b/doc/en/announce/release-2.2.1.rst index f9764634c..5d28bcb01 100644 --- a/doc/en/announce/release-2.2.1.rst +++ b/doc/en/announce/release-2.2.1.rst @@ -2,7 +2,7 @@ pytest-2.2.1: bug fixes, perfect teardowns =========================================================================== -pytest-2.2.1 is a minor backward-compatible release of the the py.test +pytest-2.2.1 is a minor backward-compatible release of the py.test testing tool. It contains bug fixes and little improvements, including documentation fixes. If you are using the distributed testing pluginmake sure to upgrade it to pytest-xdist-1.8. diff --git a/doc/en/announce/release-2.2.4.rst b/doc/en/announce/release-2.2.4.rst index 8720bdb28..67f0feb27 100644 --- a/doc/en/announce/release-2.2.4.rst +++ b/doc/en/announce/release-2.2.4.rst @@ -29,7 +29,7 @@ Changes between 2.2.3 and 2.2.4 - fix issue with unittest: now @unittest.expectedFailure markers should be processed correctly (you can also use @pytest.mark markers) - document integration with the extended distribute/setuptools test commands -- fix issue 140: propperly get the real functions +- fix issue 140: properly get the real functions of bound classmethods for setup/teardown_class - fix issue #141: switch from the deceased paste.pocoo.org to bpaste.net - fix issue #143: call unconfigure/sessionfinish always when diff --git a/doc/en/announce/release-2.3.0.rst b/doc/en/announce/release-2.3.0.rst index 54fe3961f..f863aad0a 100644 --- a/doc/en/announce/release-2.3.0.rst +++ b/doc/en/announce/release-2.3.0.rst @@ -89,7 +89,7 @@ Changes between 2.2.4 and 2.3.0 - fix issue128: show captured output when capsys/capfd are used -- fix issue179: propperly show the dependency chain of factories +- fix issue179: properly show the dependency chain of factories - pluginmanager.register(...) now raises ValueError if the plugin has been already registered or the name is taken @@ -130,5 +130,5 @@ Changes between 2.2.4 and 2.3.0 - don't show deselected reason line if there is none - - py.test -vv will show all of assert comparisations instead of truncating + - py.test -vv will show all of assert comparisons instead of truncating diff --git a/doc/en/announce/release-2.3.2.rst b/doc/en/announce/release-2.3.2.rst index 948b374d4..75312b429 100644 --- a/doc/en/announce/release-2.3.2.rst +++ b/doc/en/announce/release-2.3.2.rst @@ -1,7 +1,7 @@ pytest-2.3.2: some fixes and more traceback-printing speed =========================================================================== -pytest-2.3.2 is a another stabilization release: +pytest-2.3.2 is another stabilization release: - issue 205: fixes a regression with conftest detection - issue 208/29: fixes traceback-printing speed in some bad cases diff --git a/doc/en/announce/release-2.3.3.rst b/doc/en/announce/release-2.3.3.rst index 1d7c7027b..3a48b6ac4 100644 --- a/doc/en/announce/release-2.3.3.rst +++ b/doc/en/announce/release-2.3.3.rst @@ -1,7 +1,7 @@ -pytest-2.3.3: integration fixes, py24 suport, ``*/**`` shown in traceback +pytest-2.3.3: integration fixes, py24 support, ``*/**`` shown in traceback =========================================================================== -pytest-2.3.3 is a another stabilization release of the py.test tool +pytest-2.3.3 is another stabilization release of the py.test tool which offers uebersimple assertions, scalable fixture mechanisms and deep customization for testing with Python. Particularly, this release provides: @@ -46,7 +46,7 @@ Changes between 2.3.2 and 2.3.3 - fix issue209 - reintroduce python2.4 support by depending on newer pylib which re-introduced statement-finding for pre-AST interpreters -- nose support: only call setup if its a callable, thanks Andrew +- nose support: only call setup if it's a callable, thanks Andrew Taumoefolau - fix issue219 - add py2.4-3.3 classifiers to TROVE list diff --git a/doc/en/announce/release-2.3.5.rst b/doc/en/announce/release-2.3.5.rst index c4e91e0e6..112399ef3 100644 --- a/doc/en/announce/release-2.3.5.rst +++ b/doc/en/announce/release-2.3.5.rst @@ -44,11 +44,11 @@ Changes between 2.3.4 and 2.3.5 (thanks Adam Goucher) - Issue 265 - integrate nose setup/teardown with setupstate - so it doesnt try to teardown if it did not setup + so it doesn't try to teardown if it did not setup -- issue 271 - dont write junitxml on slave nodes +- issue 271 - don't write junitxml on slave nodes -- Issue 274 - dont try to show full doctest example +- Issue 274 - don't try to show full doctest example when doctest does not know the example location - issue 280 - disable assertion rewriting on buggy CPython 2.6.0 @@ -84,7 +84,7 @@ Changes between 2.3.4 and 2.3.5 - allow to specify prefixes starting with "_" when customizing python_functions test discovery. (thanks Graham Horler) -- improve PYTEST_DEBUG tracing output by puting +- improve PYTEST_DEBUG tracing output by putting extra data on a new lines with additional indent - ensure OutcomeExceptions like skip/fail have initialized exception attributes diff --git a/doc/en/announce/release-2.4.0.rst b/doc/en/announce/release-2.4.0.rst index 88130c481..be3aaedb0 100644 --- a/doc/en/announce/release-2.4.0.rst +++ b/doc/en/announce/release-2.4.0.rst @@ -36,7 +36,7 @@ a full list of details. A few feature highlights: - reporting: color the last line red or green depending if failures/errors occurred or everything passed. -The documentation has been updated to accomodate the changes, +The documentation has been updated to accommodate the changes, see `http://pytest.org `_ To install or upgrade pytest:: @@ -118,7 +118,7 @@ new features: - fix issue322: tearDownClass is not run if setUpClass failed. Thanks Mathieu Agopian for the initial fix. Also make all of pytest/nose - finalizer mimick the same generic behaviour: if a setupX exists and + finalizer mimic the same generic behaviour: if a setupX exists and fails, don't run teardownX. This internally introduces a new method "node.addfinalizer()" helper which can only be called during the setup phase of a node. diff --git a/doc/en/announce/release-2.5.0.rst b/doc/en/announce/release-2.5.0.rst index b8f28d6fd..b04a825cd 100644 --- a/doc/en/announce/release-2.5.0.rst +++ b/doc/en/announce/release-2.5.0.rst @@ -70,7 +70,7 @@ holger krekel to problems for more than >966 non-function scoped parameters). - fix issue290 - there is preliminary support now for parametrizing - with repeated same values (sometimes useful to to test if calling + with repeated same values (sometimes useful to test if calling a second time works as with the first time). - close issue240 - document precisely how pytest module importing @@ -149,7 +149,7 @@ holger krekel would not work correctly because pytest assumes @pytest.mark.some gets a function to be decorated already. We now at least detect if this - arg is an lambda and thus the example will work. Thanks Alex Gaynor + arg is a lambda and thus the example will work. Thanks Alex Gaynor for bringing it up. - xfail a test on pypy that checks wrong encoding/ascii (pypy does diff --git a/doc/en/announce/release-2.5.2.rst b/doc/en/announce/release-2.5.2.rst index 9308ffdd6..d5cfca2db 100644 --- a/doc/en/announce/release-2.5.2.rst +++ b/doc/en/announce/release-2.5.2.rst @@ -60,5 +60,5 @@ holger krekel - fix issue429: comparing byte strings with non-ascii chars in assert expressions now work better. Thanks Floris Bruynooghe. -- make capfd/capsys.capture private, its unused and shouldnt be exposed +- make capfd/capsys.capture private, its unused and shouldn't be exposed diff --git a/doc/en/announce/release-2.6.3.rst b/doc/en/announce/release-2.6.3.rst index c1d0ad278..ee0d2692c 100644 --- a/doc/en/announce/release-2.6.3.rst +++ b/doc/en/announce/release-2.6.3.rst @@ -42,7 +42,7 @@ Changes 2.6.3 - fix conftest related fixture visibility issue: when running with a CWD outside of a test package pytest would get fixture discovery wrong. - Thanks to Wolfgang Schnerring for figuring out a reproducable example. + Thanks to Wolfgang Schnerring for figuring out a reproducible example. - Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the timeout when interactively entering pdb). Thanks Wolfgang Schnerring. diff --git a/doc/en/announce/release-2.7.1.rst b/doc/en/announce/release-2.7.1.rst index cd37cad0c..fdc71eebb 100644 --- a/doc/en/announce/release-2.7.1.rst +++ b/doc/en/announce/release-2.7.1.rst @@ -32,7 +32,7 @@ The py.test Development Team explanations. Thanks Carl Meyer for the report and test case. - fix issue553: properly handling inspect.getsourcelines failures in - FixtureLookupError which would lead to to an internal error, + FixtureLookupError which would lead to an internal error, obfuscating the original problem. Thanks talljosh for initial diagnose/patch and Bruno Oliveira for final patch. diff --git a/doc/en/announce/release-2.9.2.rst b/doc/en/announce/release-2.9.2.rst index b71ae85dd..8f274cdf3 100644 --- a/doc/en/announce/release-2.9.2.rst +++ b/doc/en/announce/release-2.9.2.rst @@ -46,7 +46,7 @@ The py.test Development Team Thanks `@astraw38`_ for reporting the issue (`#1496`_) and `@tomviner`_ for PR the (`#1524`_). -* Fix win32 path issue when puttinging custom config file with absolute path +* Fix win32 path issue when putting custom config file with absolute path in ``pytest.main("-c your_absolute_path")``. * Fix maximum recursion depth detection when raised error class is not aware diff --git a/doc/en/cache.rst b/doc/en/cache.rst index dc1f91286..b1a7b3796 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -246,7 +246,7 @@ by adding the ``--cache-clear`` option like this:: pytest --cache-clear -This is recommended for invocations from Continous Integration +This is recommended for invocations from Continuous Integration servers where isolation and correctness is more important than speed. diff --git a/doc/en/conf.py b/doc/en/conf.py index f3b8d7d1e..40f1e4165 100644 --- a/doc/en/conf.py +++ b/doc/en/conf.py @@ -303,7 +303,7 @@ texinfo_documents = [ ('Holger Krekel@*Benjamin Peterson@*Ronny Pfannschmidt@*' 'Floris Bruynooghe@*others'), 'pytest', - 'simple powerful testing with Pytho', + 'simple powerful testing with Python', 'Programming', 1), ] diff --git a/doc/en/example/markers.rst b/doc/en/example/markers.rst index 7e48e6f2e..99b09fa57 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -205,7 +205,7 @@ You can ask which markers exist for your test suite - the list includes our just @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @@ -381,7 +381,7 @@ The ``--markers`` option always gives you a list of available markers:: @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index 3fa8834bd..7dc531100 100644 --- a/doc/en/example/pythoncollection.rst +++ b/doc/en/example/pythoncollection.rst @@ -95,7 +95,7 @@ the :confval:`python_files`, :confval:`python_classes` and :confval:`python_functions` configuration options. Example:: # content of pytest.ini - # can also be defined in in tox.ini or setup.cfg file, although the section + # can also be defined in tox.ini or setup.cfg file, although the section # name in setup.cfg files should be "tool:pytest" [pytest] python_files=check_*.py diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 3dd6fe92e..623ff33cc 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -476,7 +476,7 @@ concept. It's however recommended to have explicit fixture references in your tests or test classes rather than relying on implicitly executing setup/teardown functions, especially if they are far away from the actual tests. -Here is a an example for making a ``db`` fixture available in a directory: +Here is an example for making a ``db`` fixture available in a directory: .. code-block:: python @@ -585,7 +585,7 @@ environment you can implement a hook that gets called when the test "report" object is about to be created. Here we write out all failing test calls and also access a fixture (if it was used by the test) in case you want to query/look at it during your post processing. In our -case we just write some informations out to a ``failures`` file: +case we just write some information out to a ``failures`` file: .. code-block:: python @@ -678,7 +678,7 @@ here is a little example implemented via a local plugin: outcome = yield rep = outcome.get_result() - # set an report attribute for each phase of a call, which can + # set a report attribute for each phase of a call, which can # be "setup", "call", "teardown" setattr(item, "rep_" + rep.when, rep) diff --git a/doc/en/funcarg_compare.rst b/doc/en/funcarg_compare.rst index 88a34215f..3d121b944 100644 --- a/doc/en/funcarg_compare.rst +++ b/doc/en/funcarg_compare.rst @@ -97,7 +97,7 @@ sets. pytest-2.3 introduces a decorator for use on the factory itself:: ... # use request.param Here the factory will be invoked twice (with the respective "mysql" -and "pg" values set as ``request.param`` attributes) and and all of +and "pg" values set as ``request.param`` attributes) and all of the tests requiring "db" will run twice as well. The "mysql" and "pg" values will also be used for reporting the test-invocation variants. diff --git a/doc/en/monkeypatch.rst b/doc/en/monkeypatch.rst index 806e910bd..0c07b2f44 100644 --- a/doc/en/monkeypatch.rst +++ b/doc/en/monkeypatch.rst @@ -35,7 +35,7 @@ patch this function before calling into a function which uses it:: assert x == '/abc/.ssh' Here our test function monkeypatches ``os.path.expanduser`` and -then calls into an function that calls it. After the test function +then calls into a function that calls it. After the test function finishes the ``os.path.expanduser`` modification will be undone. example: preventing "requests" from remote operations @@ -60,7 +60,7 @@ so that any attempts within tests to create http requests will fail. Be advised that it is not recommended to patch builtin functions such as ``open``, ``compile``, etc., because it might break pytest's internals. If that's unavoidable, passing ``--tb=native``, ``--assert=plain`` and ``--capture=no`` might - help althought there's no guarantee. + help although there's no guarantee. Method reference of the monkeypatch fixture diff --git a/doc/en/projects.rst b/doc/en/projects.rst index fa7a2f29a..a2edbf68f 100644 --- a/doc/en/projects.rst +++ b/doc/en/projects.rst @@ -58,7 +58,7 @@ Here are some examples of projects using ``pytest`` (please send notes via :ref: * `katcp `_ Telescope communication protocol over Twisted * `kss plugin timer `_ * `pyudev `_ a pure Python binding to the Linux library libudev -* `pytest-localserver `_ a plugin for pytest that provides a httpserver and smtpserver +* `pytest-localserver `_ a plugin for pytest that provides an httpserver and smtpserver * `pytest-monkeyplus `_ a plugin that extends monkeypatch These projects help integrate ``pytest`` into other Python frameworks: diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index afa33444e..b142738c9 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -2,7 +2,7 @@ .. _skipping: -Skip and xfail: dealing with tests that can not succeed +Skip and xfail: dealing with tests that cannot succeed ===================================================================== If you have test functions that cannot be run on certain platforms diff --git a/doc/en/test/plugin/xdist.rst b/doc/en/test/plugin/xdist.rst index 79440998b..506d240ae 100644 --- a/doc/en/test/plugin/xdist.rst +++ b/doc/en/test/plugin/xdist.rst @@ -71,7 +71,7 @@ you can ad-hoc distribute your tests by typing:: pytest -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg This will synchronize your ``mypkg`` package directory -to an remote ssh account and then locally collect tests +to a remote ssh account and then locally collect tests and send them to remote places for execution. You can specify multiple ``--rsyncdir`` directories diff --git a/doc/en/usage.rst b/doc/en/usage.rst index 4f01081ce..15b3d71b0 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -49,7 +49,7 @@ Several test run options:: # will select TestMyClass.test_something # but not TestMyClass.test_method_simple pytest test_mod.py::test_func # only run tests that match the "node ID", - # e.g "test_mod.py::test_func" will select + # e.g. "test_mod.py::test_func" will select # only test_func in test_mod.py pytest test_mod.py::TestClass::test_method # run a single method in # a single class @@ -76,7 +76,7 @@ Examples for modifying traceback printing:: The ``--full-trace`` causes very long traces to be printed on error (longer than ``--tb=long``). It also ensures that a stack trace is printed on -**KeyboardInterrrupt** (Ctrl+C). +**KeyboardInterrupt** (Ctrl+C). This is very useful if the tests are taking too long and you interrupt them with Ctrl+C to find out where the tests are *hanging*. By default no output will be shown (because KeyboardInterrupt is caught by pytest). By using this diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index 8a46648cd..b4ff7f8eb 100644 --- a/doc/en/writing_plugins.rst +++ b/doc/en/writing_plugins.rst @@ -250,8 +250,8 @@ which will import the specified module as a ``pytest`` plugin. 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 -imported already, it it was already imported at the time the -``pytest_plugins`` statement is processed a warning will result and +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 can either call :func:`pytest.register_assert_rewrite` yourself before the module is imported, or you can arrange the code to delay the From 3d18c9c1c6e58e30da97e74fc79efb91f1aae24e Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sun, 18 Dec 2016 21:30:00 +0000 Subject: [PATCH 122/201] '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 123/201] 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 124/201] 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 ef903460b1670a59db54cc47976a79b059062252 Mon Sep 17 00:00:00 2001 From: Peter Heatwole Date: Mon, 2 Jan 2017 14:07:41 -0800 Subject: [PATCH 125/201] Fix broken links --- doc/en/fixture.rst | 2 +- doc/en/goodpractices.rst | 2 +- doc/en/writing_plugins.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 9bc4f6084..201ad4863 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -11,7 +11,7 @@ pytest fixtures: explicit, modular, scalable .. _`xUnit`: http://en.wikipedia.org/wiki/XUnit .. _`purpose of test fixtures`: http://en.wikipedia.org/wiki/Test_fixture#Software -.. _`Dependency injection`: http://en.wikipedia.org/wiki/Dependency_injection#Definition +.. _`Dependency injection`: http://en.wikipedia.org/wiki/Dependency_injection The `purpose of test fixtures`_ is to provide a fixed baseline upon which tests can reliably and repeatedly execute. pytest fixtures diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 43b15a077..48f80a9e2 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -147,7 +147,7 @@ dependencies are isolated from the system Python installation. If you frequently release code and want to make sure that your actual package passes all tests you may want to look into `tox`_, the virtualenv test automation tool and its `pytest support -`_. +`_. Tox helps you to setup virtualenv environments with pre-defined dependencies and then executing a pre-configured test command with options. It will run tests against the installed package and not diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index b4ff7f8eb..770f81e46 100644 --- a/doc/en/writing_plugins.rst +++ b/doc/en/writing_plugins.rst @@ -172,7 +172,7 @@ If a package is installed this way, ``pytest`` will load .. note:: Make sure to include ``Framework :: Pytest`` in your list of - `PyPI classifiers `_ + `PyPI classifiers `_ to make it easy for users to find your plugin. From 6d81c684ccdf502e5e76c04d63e3229e1e5188a2 Mon Sep 17 00:00:00 2001 From: Jeff Widman Date: Wed, 4 Jan 2017 05:31:44 -0800 Subject: [PATCH 126/201] Switch monkeypatch fixture to yield syntax --- AUTHORS | 1 + _pytest/monkeypatch.py | 6 +++--- testing/test_monkeypatch.py | 14 ++++---------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/AUTHORS b/AUTHORS index 8c6fa1b5d..e3bbdc5d1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -71,6 +71,7 @@ Janne Vanhala Jason R. Coombs Javier Domingo Cansino Javier Romero +Jeff Widman John Towler Jon Sonesen Jordan Guymon diff --git a/_pytest/monkeypatch.py b/_pytest/monkeypatch.py index 852e72bed..2651cf044 100644 --- a/_pytest/monkeypatch.py +++ b/_pytest/monkeypatch.py @@ -11,7 +11,7 @@ RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$") @pytest.fixture -def monkeypatch(request): +def monkeypatch(): """The returned ``monkeypatch`` fixture provides these helper methods to modify objects, dictionaries or os.environ:: @@ -30,8 +30,8 @@ def monkeypatch(request): will be raised if the set/deletion operation has no target. """ mpatch = MonkeyPatch() - request.addfinalizer(mpatch.undo) - return mpatch + yield mpatch + mpatch.undo() def resolve(name): diff --git a/testing/test_monkeypatch.py b/testing/test_monkeypatch.py index 3fcd20f32..9d02e2cc0 100644 --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -7,16 +7,12 @@ from _pytest.monkeypatch import MonkeyPatch @pytest.fixture -def mp(request): +def mp(): cwd = os.getcwd() sys_path = list(sys.path) - - def cleanup(): - sys.path[:] = sys_path - os.chdir(cwd) - - request.addfinalizer(cleanup) - return MonkeyPatch() + yield MonkeyPatch() + sys.path[:] = sys_path + os.chdir(cwd) def test_setattr(): @@ -329,5 +325,3 @@ def test_issue1338_name_resolving(): monkeypatch.delattr('requests.sessions.Session.request') finally: monkeypatch.undo() - - From 7559400183de8d1d8df2521193be36c80e23c164 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 5 Jan 2017 19:18:03 -0200 Subject: [PATCH 127/201] Add py36 to test on AppVeyor Fix #2134 --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index c82b81ce9..aa28e4db8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,6 +15,7 @@ environment: - TOXENV: "py33" - TOXENV: "py34" - TOXENV: "py35" + - TOXENV: "py36" - TOXENV: "pypy" - TOXENV: "py27-pexpect" - TOXENV: "py27-xdist" From aa82db9fe286ef709645151f11df8ec451a21c18 Mon Sep 17 00:00:00 2001 From: Philippe Ombredanne Date: Tue, 10 Jan 2017 19:25:57 +0100 Subject: [PATCH 128/201] Ensure the LICENSE is included in built wheels Otherwise it is not included by default as wheels do not honor the MANIFEST.in Signed-off-by: Philippe Ombredanne --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index 1ab4fd059..f3299af5b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,5 +9,8 @@ upload-dir = doc/en/build/html [bdist_wheel] universal = 1 +[metadata] +license_file = LICENSE + [devpi:upload] formats = sdist.tgz,bdist_wheel From e18b2a427a803a3e89b4dc88e6c904e32f20eb09 Mon Sep 17 00:00:00 2001 From: Eli Boyarski Date: Wed, 11 Jan 2017 16:49:09 +0200 Subject: [PATCH 129/201] Fail assert_outcomes() on missing terminal report Currently if the terminal report of testdir.runpytest() is missing, assert_outcomes() on its output fails because parseoutcomes() returns an unexpected value (None). It's better to fail parseoutcomes() directly. --- AUTHORS | 1 + CHANGELOG.rst | 4 ++++ _pytest/pytester.py | 1 + testing/test_pytester.py | 7 +++++++ 4 files changed, 13 insertions(+) diff --git a/AUTHORS b/AUTHORS index e3bbdc5d1..acf715cde 100644 --- a/AUTHORS +++ b/AUTHORS @@ -141,3 +141,4 @@ Tyler Goodlet Vasily Kuznetsov Wouter van Ackooy Xuecong Liao +Eli Boyarski diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7c3df0327..f2248ca20 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,11 +14,15 @@ subdirectories with ini configuration files now uses the correct ini file (`#2148`_). Thanks `@pelme`_. +* Fail ``testdir.runpytest().assert_outcomes()`` explicitly if the pytest + terminal output it relies on is missing. Thanks to `@eli-b`_ for the PR. + * .. _@lesteve: https://github.com/lesteve .. _@malinoff: https://github.com/malinoff .. _@pelme: https://github.com/pelme +.. _@eli-b: https://github.com/eli-b .. _#2129: https://github.com/pytest-dev/pytest/issues/2129 .. _#2148: https://github.com/pytest-dev/pytest/issues/2148 diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 17ff529a6..de7899173 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -367,6 +367,7 @@ class RunResult: for num, cat in outcomes: d[cat] = int(num) return d + raise ValueError("Pytest terminal report not found") def assert_outcomes(self, passed=0, skipped=0, failed=0): """ assert that the specified outcomes appear with the respective diff --git a/testing/test_pytester.py b/testing/test_pytester.py index 14548808c..49cf43a3e 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -124,3 +124,10 @@ def test_inline_run_clean_modules(testdir): test_mod.write("def test_foo(): assert False") result2 = testdir.inline_run(str(test_mod)) assert result2.ret == EXIT_TESTSFAILED + +def test_assert_outcomes_after_pytest_erro(testdir): + testdir.makepyfile("def test_foo(): assert True") + + result = testdir.runpytest('--unexpected-argument') + with pytest.raises(ValueError, message="Pytest terminal report not found"): + result.assert_outcomes(passed=0) From 043aadeaf2467d7b4c263ba339fe1daea3ac8ae5 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 11 Jan 2017 17:11:56 -0200 Subject: [PATCH 130/201] Consider plugins loaded by PYTEST_PLUGINS for assertion rewrite Fix #2185 --- CHANGELOG.rst | 5 +++++ _pytest/config.py | 7 +++++-- testing/test_assertrewrite.py | 18 +++++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7c3df0327..bb5c5e6a6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,10 @@ * pytest no longer recognizes coroutine functions as yield tests (`#2129`_). Thanks to `@malinoff`_ for the PR. +* Plugins loaded by the ``PYTEST_PLUGINS`` environment variable are now automatically + considered for assertion rewriting (`#2185`_). + Thanks `@nicoddemus`_ for the PR. + * Improve error message when pytest.warns fails (`#2150`_). The type(s) of the expected warnings and the list of caught warnings is added to the error message. Thanks `@lesteve`_ for the PR. @@ -23,6 +27,7 @@ .. _#2129: https://github.com/pytest-dev/pytest/issues/2129 .. _#2148: https://github.com/pytest-dev/pytest/issues/2148 .. _#2150: https://github.com/pytest-dev/pytest/issues/2150 +.. _#2185: https://github.com/pytest-dev/pytest/issues/2185 3.0.5 (2016-12-05) diff --git a/_pytest/config.py b/_pytest/config.py index 55326447e..9aa465954 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -399,13 +399,15 @@ class PytestPluginManager(PluginManager): self.consider_module(conftestmodule) def consider_env(self): - self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS")) + specs = os.environ.get("PYTEST_PLUGINS") + if specs: + plugins = specs.split(',') + self._import_plugin_specs(plugins) def consider_module(self, mod): plugins = getattr(mod, 'pytest_plugins', []) if isinstance(plugins, str): plugins = [plugins] - self.rewrite_hook.mark_rewrite(*plugins) self._import_plugin_specs(plugins) def _import_plugin_specs(self, spec): @@ -427,6 +429,7 @@ class PytestPluginManager(PluginManager): importspec = "_pytest." + modname else: importspec = modname + self.rewrite_hook.mark_rewrite(modname) try: __import__(importspec) except ImportError as e: diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 8e26cdb1b..fdf674f25 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -682,7 +682,7 @@ def test_rewritten(): hook.mark_rewrite('test_remember_rewritten_modules') assert warnings == [] - def test_rewrite_warning_using_pytest_plugins(self, testdir, monkeypatch): + def test_rewrite_warning_using_pytest_plugins(self, testdir): testdir.makepyfile(**{ 'conftest.py': "pytest_plugins = ['core', 'gui', 'sci']", 'core.py': "", @@ -695,6 +695,22 @@ def test_rewritten(): result.stdout.fnmatch_lines(['*= 1 passed in *=*']) assert 'pytest-warning summary' not in result.stdout.str() + def test_rewrite_warning_using_pytest_plugins_env_var(self, testdir, monkeypatch): + monkeypatch.setenv('PYTEST_PLUGINS', 'plugin') + testdir.makepyfile(**{ + 'plugin.py': "", + 'test_rewrite_warning_using_pytest_plugins_env_var.py': """ + import plugin + pytest_plugins = ['plugin'] + def test(): + pass + """, + }) + testdir.chdir() + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines(['*= 1 passed in *=*']) + assert 'pytest-warning summary' not in result.stdout.str() + class TestAssertionRewriteHookDetails(object): def test_loader_is_package_false_for_module(self, testdir): From 7cd7c283ddde7c45ad1b97372948ff6ba2f0aaa4 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 12 Jan 2017 14:23:09 -0200 Subject: [PATCH 131/201] Refactor plugin specs handling into an isolated function --- _pytest/config.py | 38 ++++++++++++++++++++++++-------------- testing/test_config.py | 15 +++++++++++++++ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/_pytest/config.py b/_pytest/config.py index 9aa465954..8578e8aaa 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -399,30 +399,22 @@ class PytestPluginManager(PluginManager): self.consider_module(conftestmodule) def consider_env(self): - specs = os.environ.get("PYTEST_PLUGINS") - if specs: - plugins = specs.split(',') - self._import_plugin_specs(plugins) + self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS")) def consider_module(self, mod): - plugins = getattr(mod, 'pytest_plugins', []) - if isinstance(plugins, str): - plugins = [plugins] - self._import_plugin_specs(plugins) + self._import_plugin_specs(getattr(mod, 'pytest_plugins', [])) def _import_plugin_specs(self, spec): - if spec: - if isinstance(spec, str): - spec = spec.split(",") - for import_spec in spec: - self.import_plugin(import_spec) + plugins = _get_plugin_specs_as_list(spec) + for import_spec in plugins: + self.import_plugin(import_spec) def import_plugin(self, modname): # most often modname refers to builtin modules, e.g. "pytester", # "terminal" or "capture". Those plugins are registered under their # basename for historic purposes but must be imported with the # _pytest prefix. - assert isinstance(modname, str) + assert isinstance(modname, str), "module name as string required, got %r" % modname if self.get_plugin(modname) is not None: return if modname in builtin_plugins: @@ -450,6 +442,24 @@ class PytestPluginManager(PluginManager): self.consider_module(mod) +def _get_plugin_specs_as_list(specs): + """ + Parses a list of "plugin specs" and returns a list of plugin names. + + Plugin specs can be given as a list of strings separated by "," or already as a list/tuple in + which case it is returned as a list. Specs can also be `None` in which case an + empty list is returned. + """ + if specs is not None: + if isinstance(specs, str): + specs = specs.split(',') if specs else [] + if not isinstance(specs, (list, tuple)): + raise UsageError("Plugin specs must be a ','-separated string or a " + "list/tuple of strings for plugin names. Given: %r" % specs) + return list(specs) + return [] + + class Parser: """ Parser for command line arguments and ini-file values. diff --git a/testing/test_config.py b/testing/test_config.py index 6bc867737..e6aa423e8 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -587,6 +587,21 @@ def test_load_initial_conftest_last_ordering(testdir): assert [x.function.__module__ for x in l] == expected +def test_get_plugin_specs_as_list(): + from _pytest.config import _get_plugin_specs_as_list + with pytest.raises(pytest.UsageError): + _get_plugin_specs_as_list(set(['foo'])) + with pytest.raises(pytest.UsageError): + _get_plugin_specs_as_list(dict()) + + assert _get_plugin_specs_as_list(None) == [] + assert _get_plugin_specs_as_list('') == [] + assert _get_plugin_specs_as_list('foo') == ['foo'] + assert _get_plugin_specs_as_list('foo,bar') == ['foo', 'bar'] + assert _get_plugin_specs_as_list(['foo', 'bar']) == ['foo', 'bar'] + assert _get_plugin_specs_as_list(('foo', 'bar')) == ['foo', 'bar'] + + class TestWarning: def test_warn_config(self, testdir): testdir.makeconftest(""" From 46a9861d29b1af89caa239b978d6a4717bddce19 Mon Sep 17 00:00:00 2001 From: Rutger Prins Date: Fri, 13 Jan 2017 16:52:02 +0100 Subject: [PATCH 132/201] Remove mention of --assert=reinterp in documentation Related to #1940 --- doc/en/assert.rst | 49 ++++++++++------------------------------------- doc/en/faq.rst | 8 -------- 2 files changed, 10 insertions(+), 47 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index f898391df..b682897e1 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -262,50 +262,20 @@ Advanced assertion introspection .. versionadded:: 2.1 -Reporting details about a failing assertion is achieved either by rewriting -assert statements before they are run or re-evaluating the assert expression and -recording the intermediate values. Which technique is used depends on the -location of the assert, ``pytest`` configuration, and Python version being used -to run ``pytest``. - -By default, ``pytest`` rewrites assert statements in test modules. -Rewritten assert statements put introspection information into the assertion failure message. -``pytest`` only rewrites test modules directly discovered by its test collection process, so -asserts in supporting modules which are not themselves test modules will not be -rewritten. +Reporting details about a failing assertion is achieved by rewriting assert +statements before they are run. Rewritten assert statements put introspection +information into the assertion failure message. ``pytest`` only rewrites test +modules directly discovered by its test collection process, so asserts in +supporting modules which are not themselves test modules will not be rewritten. .. note:: ``pytest`` rewrites test modules on import. It does this by using an import - hook to write a new pyc files. Most of the time this works transparently. + hook to write new pyc files. Most of the time this works transparently. However, if you are messing with import yourself, the import hook may - interfere. If this is the case, simply use ``--assert=reinterp`` or - ``--assert=plain``. Additionally, rewriting will fail silently if it cannot - write new pycs, i.e. in a read-only filesystem or a zipfile. - -If an assert statement has not been rewritten or the Python version is less than -2.6, ``pytest`` falls back on assert reinterpretation. In assert -reinterpretation, ``pytest`` walks the frame of the function containing the -assert statement to discover sub-expression results of the failing assert -statement. You can force ``pytest`` to always use assertion reinterpretation by -passing the ``--assert=reinterp`` option. - -Assert reinterpretation has a caveat not present with assert rewriting: If -evaluating the assert expression has side effects you may get a warning that the -intermediate values could not be determined safely. A common example of this -issue is an assertion which reads from a file:: - - assert f.read() != '...' - -If this assertion fails then the re-evaluation will probably succeed! -This is because ``f.read()`` will return an empty string when it is -called the second time during the re-evaluation. However, it is -easy to rewrite the assertion and avoid any trouble:: - - content = f.read() - assert content != '...' - -All assert introspection can be turned off by passing ``--assert=plain``. + interfere. If this is the case, use ``--assert=plain``. Additionally, + rewriting will fail silently if it cannot write new pycs, i.e. in a read-only + filesystem or a zipfile. For further information, Benjamin Peterson wrote up `Behind the scenes of pytest's new assertion rewriting `_. @@ -318,3 +288,4 @@ For further information, Benjamin Peterson wrote up `Behind the scenes of pytest .. versionchanged:: 3.0 Removes the ``--no-assert`` and``--nomagic`` options. + Removes the ``--assert=reinterp`` option. diff --git a/doc/en/faq.rst b/doc/en/faq.rst index 774998b14..27d74e114 100644 --- a/doc/en/faq.rst +++ b/doc/en/faq.rst @@ -66,14 +66,6 @@ This completely avoids previous issues of confusing assertion-reporting. It also means, that you can use Python's ``-O`` optimization without losing assertions in test modules. -``pytest`` contains a second, mostly obsolete, assert debugging technique -invoked via ``--assert=reinterpret``: When an ``assert`` statement fails, ``pytest`` re-interprets -the expression part to show intermediate values. This technique suffers -from a caveat that the rewriting does not: If your expression has side -effects (better to avoid them anyway!) the intermediate values may not -be the same, confusing the reinterpreter and obfuscating the initial -error (this is also explained at the command line if it happens). - You can also turn off all assertion interaction using the ``--assert=plain`` option. From 61fa91f3d013aad4fae4d2e54a3c04100317307f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 17 Jan 2017 21:09:04 -0200 Subject: [PATCH 133/201] Fix marker example on "linux" platform I cheated a little and updated the example output by hand. :grin: Fix #2200 --- doc/en/example/markers.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/en/example/markers.rst b/doc/en/example/markers.rst index 99b09fa57..b0825ce6e 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -450,7 +450,7 @@ for your particular platform, you could use the following plugin:: import sys import pytest - ALL = set("darwin linux2 win32".split()) + ALL = set("darwin linux win32".split()) def pytest_runtest_setup(item): if isinstance(item, item.Function): @@ -470,7 +470,7 @@ Let's do a little test file to show how this looks like:: def test_if_apple_is_evil(): pass - @pytest.mark.linux2 + @pytest.mark.linux def test_if_linux_works(): pass @@ -481,7 +481,7 @@ Let's do a little test file to show how this looks like:: def test_runs_everywhere(): pass -then you will see two test skipped and two executed tests as expected:: +then you will see two tests skipped and two executed tests as expected:: $ pytest -rs # this option reports skip reasons ======= test session starts ======== @@ -489,15 +489,15 @@ then you will see two test skipped and two executed tests as expected:: rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_plat.py sss. + test_plat.py s.s. ======= short test summary info ======== - SKIP [3] $REGENDOC_TMPDIR/conftest.py:12: cannot run on platform linux + SKIP [2] $REGENDOC_TMPDIR/conftest.py:12: cannot run on platform linux - ======= 1 passed, 3 skipped in 0.12 seconds ======== + ======= 2 passed, 2 skipped in 0.12 seconds ======== Note that if you specify a platform via the marker-command line option like this:: - $ pytest -m linux2 + $ pytest -m linux ======= test session starts ======== platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: @@ -506,7 +506,7 @@ Note that if you specify a platform via the marker-command line option like this test_plat.py s ======= 3 tests deselected ======== - ======= 1 skipped, 3 deselected in 0.12 seconds ======== + ======= 1 passed, 3 deselected in 0.12 seconds ======== then the unmarked-tests will not be run. It is thus a way to restrict the run to the specific tests. From 2574da8d32197d2c82889bd809c931c641c24105 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 19 Jan 2017 20:47:45 -0200 Subject: [PATCH 134/201] Fix pytester internal plugin to work correctly with latest versions of zope.interface Fix #1989 --- .travis.yml | 4 ---- CHANGELOG.rst | 4 ++++ _pytest/pytester.py | 6 +++--- appveyor.yml | 6 ------ 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index f8f127b1a..b2d356e19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,10 +29,6 @@ env: - TESTENV=docs matrix: - allow_failures: - # see #1989 - - env: TESTENV=py27-trial - - env: TESTENV=py35-trial include: - env: TESTENV=py36 python: '3.6-dev' diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bb5c5e6a6..173347d7b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,9 @@ expected warnings and the list of caught warnings is added to the error message. Thanks `@lesteve`_ for the PR. +* Fix ``pytester`` internal plugin to work correctly with latest versions of + ``zope.interface`` (`#1989`_). Thanks `@nicoddemus`_ for the PR. + * Specifying tests with colons like ``test_foo.py::test_bar`` for tests in subdirectories with ini configuration files now uses the correct ini file (`#2148`_). Thanks `@pelme`_. @@ -24,6 +27,7 @@ .. _@malinoff: https://github.com/malinoff .. _@pelme: https://github.com/pelme +.. _#1989: https://github.com/pytest-dev/pytest/issues/1989 .. _#2129: https://github.com/pytest-dev/pytest/issues/2129 .. _#2148: https://github.com/pytest-dev/pytest/issues/2148 .. _#2150: https://github.com/pytest-dev/pytest/issues/2150 diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 17ff529a6..b401c4f23 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -446,9 +446,9 @@ class Testdir: the module is re-imported. """ for name in set(sys.modules).difference(self._savemodulekeys): - # it seems zope.interfaces is keeping some state - # (used by twisted related tests) - if name != "zope.interface": + # zope.interface (used by twisted-related tests) keeps internal + # state and can't be deleted + if not name.startswith("zope.interface"): del sys.modules[name] def make_hook_recorder(self, pluginmanager): diff --git a/appveyor.yml b/appveyor.yml index aa28e4db8..cc72b4b70 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,12 +28,6 @@ environment: - TOXENV: "freeze" - TOXENV: "docs" -matrix: - allow_failures: - # see #1989 - - TOXENV: "py27-trial" - - TOXENV: "py35-trial" - install: - echo Installed Pythons - dir c:\Python* From c477f09177cabaaa1dbddd9d754f44ec9eba7b2a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 19 Jan 2017 21:33:51 -0200 Subject: [PATCH 135/201] Assert statements of the pytester plugin again benefit from assertion rewriting Fix #1920 --- CHANGELOG.rst | 4 ++++ _pytest/config.py | 2 +- testing/test_assertion.py | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bb5c5e6a6..452d50b76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,9 @@ expected warnings and the list of caught warnings is added to the error message. Thanks `@lesteve`_ for the PR. +* Assert statements of the ``pytester`` plugin again benefit from assertion rewriting (`#1920`_). + Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. + * Specifying tests with colons like ``test_foo.py::test_bar`` for tests in subdirectories with ini configuration files now uses the correct ini file (`#2148`_). Thanks `@pelme`_. @@ -24,6 +27,7 @@ .. _@malinoff: https://github.com/malinoff .. _@pelme: https://github.com/pelme +.. _#1920: https://github.com/pytest-dev/pytest/issues/1920 .. _#2129: https://github.com/pytest-dev/pytest/issues/2129 .. _#2148: https://github.com/pytest-dev/pytest/issues/2148 .. _#2150: https://github.com/pytest-dev/pytest/issues/2150 diff --git a/_pytest/config.py b/_pytest/config.py index 8578e8aaa..42d1a118a 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -421,7 +421,7 @@ class PytestPluginManager(PluginManager): importspec = "_pytest." + modname else: importspec = modname - self.rewrite_hook.mark_rewrite(modname) + self.rewrite_hook.mark_rewrite(importspec) try: __import__(importspec) except ImportError as e: diff --git a/testing/test_assertion.py b/testing/test_assertion.py index c63f26b9c..9115d25e2 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -58,6 +58,23 @@ class TestImportHookInstallation: assert 0 result.stdout.fnmatch_lines([expected]) + def test_rewrite_assertions_pytester_plugin(self, testdir): + """ + Assertions in the pytester plugin must also benefit from assertion + rewriting (#1920). + """ + testdir.makepyfile(""" + pytest_plugins = ['pytester'] + def test_dummy_failure(testdir): # how meta! + testdir.makepyfile('def test(): assert 0') + r = testdir.inline_run() + r.assertoutcome(passed=1) + """) + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines([ + '*assert 1 == 0*', + ]) + @pytest.mark.parametrize('mode', ['plain', 'rewrite']) def test_pytest_plugins_rewrite(self, testdir, mode): contents = { From 4082f4024a1ea9333e55a5af3954733e2c200c00 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 11:25:48 +0100 Subject: [PATCH 136/201] comment out compatproperty deprecations todo: reenable in the features branch --- _pytest/main.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/_pytest/main.py b/_pytest/main.py index 905b35d83..0aa97da64 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -200,10 +200,11 @@ class _CompatProperty(object): if obj is None: return self - warnings.warn( - "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format( - name=self.name, owner=type(owner).__name__), - PendingDeprecationWarning, stacklevel=2) + # TODO: reenable in the features branch + # warnings.warn( + # "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format( + # name=self.name, owner=type(owner).__name__), + # PendingDeprecationWarning, stacklevel=2) return getattr(pytest, self.name) @@ -291,10 +292,10 @@ class Node(object): return getattr(pytest, name) else: cls = getattr(self, name) - - warnings.warn("use of node.%s is deprecated, " - "use pytest_pycollect_makeitem(...) to create custom " - "collection nodes" % name, category=DeprecationWarning) + # TODO: reenable in the features branch + # warnings.warn("use of node.%s is deprecated, " + # "use pytest_pycollect_makeitem(...) to create custom " + # "collection nodes" % name, category=DeprecationWarning) return cls def __repr__(self): From 7b4afd89465596d5d003bb250b5e0531d0e5f172 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 12:09:49 +0100 Subject: [PATCH 137/201] remove unused import --- _pytest/main.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/_pytest/main.py b/_pytest/main.py index 0aa97da64..a32352793 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -3,8 +3,6 @@ import functools import os import sys -import warnings - import _pytest import _pytest._code import py From 6a96b464abf6b3c808f918e6c5cc9c795d2416c8 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 15:26:59 +0100 Subject: [PATCH 138/201] update changelog as suggested --- CHANGELOG.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ff6efb7ef..fae302fd3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,10 +1,11 @@ 3.0.6.dev0 ========== -* fix issue #2118 - protect against internal deprecationerrors by changing the code path of Node._getcustomclass. - This also turns a internal deprecation into a real deprecation. +* pytest no longer generates ``PendingDeprecationWarning`` from its own operations, which was introduced by mistake in version ``3.0.5`` (`#2118`_). Thanks to `@nicoddemus`_ for the report and `@RonnyPfannschmidt`_ for the PR. + + * * @@ -14,6 +15,7 @@ * +.. _#2118: https://github.com/pytest-dev/pytest/issues/2118 3.0.5 ===== From 403122281a3a7157e68db27e4778efb5bf848afb Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sun, 22 Jan 2017 11:48:05 +0100 Subject: [PATCH 139/201] fix devpi test for doctesting env due to a devpi bug, we always get a sdist install which in turn triggers the pytest issue #2042 / #726 going for pyargs and a changed folder, it should no longer happen (and will be tested firther after rebasing the release branch) --- tox.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index a5dec3fdc..4be692fc7 100644 --- a/tox.ini +++ b/tox.ini @@ -118,11 +118,13 @@ commands= basepython = python usedevelop=True skipsdist=True +# ensure the given pyargs cant mean anytrhing else +changedir=doc/ deps= PyYAML commands= - pytest -rfsxX doc/en - pytest --doctest-modules {toxinidir}/_pytest + pytest -rfsxX en + pytest --doctest-modules --pyargs _pytest [testenv:regen] changedir=doc/en From 55f21bd2b9f07c55072c1017637587b2fd3bd24e Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 17:55:16 +0100 Subject: [PATCH 140/201] bump version --- CHANGELOG.rst | 4 +--- _pytest/__init__.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6c1161ba7..bf297971d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,11 +1,10 @@ -3.0.6.dev0 (unreleased) +3.0.6 (2017-01-29) ======================= * pytest no longer generates ``PendingDeprecationWarning`` from its own operations, which was introduced by mistake in version ``3.0.5`` (`#2118`_). Thanks to `@nicoddemus`_ for the report and `@RonnyPfannschmidt`_ for the PR. - * pytest no longer recognizes coroutine functions as yield tests (`#2129`_). Thanks to `@malinoff`_ for the PR. @@ -30,7 +29,6 @@ * Fail ``testdir.runpytest().assert_outcomes()`` explicitly if the pytest terminal output it relies on is missing. Thanks to `@eli-b`_ for the PR. -* .. _@lesteve: https://github.com/lesteve .. _@malinoff: https://github.com/malinoff diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 8546ff02b..a4739a613 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.6.dev0' +__version__ = '3.0.6' From 4d0c635252273fa95f9b7aaa70506a1e8f727c8e Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 17:55:35 +0100 Subject: [PATCH 141/201] regendoc --- doc/en/assert.rst | 4 +-- doc/en/cache.rst | 6 ++-- doc/en/capture.rst | 2 +- doc/en/doctest.rst | 2 +- doc/en/example/markers.rst | 34 +++++++++--------- doc/en/example/nonpython.rst | 54 ++++++++++++++--------------- doc/en/example/parametrize.rst | 20 ++++++----- doc/en/example/pythoncollection.rst | 6 ++-- doc/en/example/reportingdemo.rst | 4 +-- doc/en/example/simple.rst | 22 ++++++------ doc/en/fixture.rst | 10 +++--- doc/en/getting-started.rst | 4 +-- doc/en/index.rst | 2 +- doc/en/parametrize.rst | 4 +-- doc/en/skipping.rst | 2 +- doc/en/tmpdir.rst | 2 +- doc/en/unittest.rst | 2 +- 17 files changed, 91 insertions(+), 89 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index b682897e1..d93da178d 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -26,7 +26,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -170,7 +170,7 @@ if you run this module:: $ pytest test_assert2.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/cache.rst b/doc/en/cache.rst index b1a7b3796..3b4703bf5 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -80,7 +80,7 @@ If you then run it with ``--lf``:: $ pytest --lf ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 run-last-failure: rerun last 2 failures rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -122,7 +122,7 @@ of ``FF`` and dots):: $ pytest --ff ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 run-last-failure: rerun last 2 failures first rootdir: $REGENDOC_TMPDIR, inifile: collected 50 items @@ -227,7 +227,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: cachedir: $REGENDOC_TMPDIR/.cache ------------------------------- cache values ------------------------------- diff --git a/doc/en/capture.rst b/doc/en/capture.rst index 7ee73b992..201006637 100644 --- a/doc/en/capture.rst +++ b/doc/en/capture.rst @@ -64,7 +64,7 @@ of the failing function and hide the other one:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/doctest.rst b/doc/en/doctest.rst index 513d9aed9..4cbf92b13 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, 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 b0825ce6e..afa66960b 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -31,7 +31,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -45,7 +45,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -66,7 +66,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 5 items @@ -79,7 +79,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -92,7 +92,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items @@ -130,7 +130,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -144,7 +144,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -160,7 +160,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 4 items @@ -205,7 +205,7 @@ You can ask which markers exist for your test suite - the list includes our just @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @@ -352,7 +352,7 @@ the test needs:: $ pytest -E stage2 ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -364,7 +364,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -381,7 +381,7 @@ The ``--markers`` option always gives you a list of available markers:: @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @@ -485,7 +485,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -499,11 +499,11 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items - test_plat.py s + test_plat.py . ======= 3 tests deselected ======== ======= 1 passed, 3 deselected in 0.12 seconds ======== @@ -551,7 +551,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -573,7 +573,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items diff --git a/doc/en/example/nonpython.rst b/doc/en/example/nonpython.rst index 817e5693f..09daa3808 100644 --- a/doc/en/example/nonpython.rst +++ b/doc/en/example/nonpython.rst @@ -27,18 +27,17 @@ now execute the test specification:: nonpython $ pytest test_simple.yml ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/nonpython, inifile: - collected 2 items + collected 0 items / 1 errors - test_simple.yml F. - - ======= FAILURES ======== - _______ usecase: hello ________ - usecase execution failed - spec failed: 'some': 'other' - no further details known at this point. - ======= 1 failed, 1 passed in 0.12 seconds ======== + ======= ERRORS ======== + _______ ERROR collecting test_simple.yml ________ + conftest.py:11: in collect + import yaml # we need a yaml parser, e.g. PyYAML + E ImportError: No module named 'yaml' + !!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!! + ======= 1 error in 0.12 seconds ======== .. regendoc:wipe @@ -59,20 +58,18 @@ consulted when reporting in ``verbose`` mode:: nonpython $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR/nonpython, inifile: - collecting ... collected 2 items + collecting ... collected 0 items / 1 errors - test_simple.yml::hello FAILED - test_simple.yml::ok PASSED - - ======= FAILURES ======== - _______ usecase: hello ________ - usecase execution failed - spec failed: 'some': 'other' - no further details known at this point. - ======= 1 failed, 1 passed in 0.12 seconds ======== + ======= ERRORS ======== + _______ ERROR collecting test_simple.yml ________ + conftest.py:11: in collect + import yaml # we need a yaml parser, e.g. PyYAML + E ImportError: No module named 'yaml' + !!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!! + ======= 1 error in 0.12 seconds ======== .. regendoc:wipe @@ -81,11 +78,14 @@ interesting to just look at the collection tree:: nonpython $ pytest --collect-only ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/nonpython, inifile: - collected 2 items - - - + collected 0 items / 1 errors - ======= no tests ran in 0.12 seconds ======== + ======= ERRORS ======== + _______ ERROR collecting test_simple.yml ________ + conftest.py:11: in collect + import yaml # we need a yaml parser, e.g. PyYAML + E ImportError: No module named 'yaml' + !!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!! + ======= 1 error in 0.12 seconds ======== diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index dac070c84..cd1b05b86 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -130,7 +130,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 6 items @@ -181,7 +181,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -194,7 +194,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -259,7 +259,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -320,7 +320,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -397,10 +397,12 @@ 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 - sssssssssssssss.........sss.........sss......... + sssssssssssssssssssssssssssssssssssssssssssss... ======= short test summary info ======== - SKIP [21] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.6' not found - 27 passed, 21 skipped in 0.12 seconds + SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python3.4' not found + SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.6' not found + SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.7' not found + 3 passed, 45 skipped in 0.12 seconds Indirect parametrization of optional implementations/imports -------------------------------------------------------------------- @@ -447,7 +449,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index 7dc531100..0d53b0593 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, 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 0817458ad..c586bc250 100644 --- a/doc/en/example/reportingdemo.rst +++ b/doc/en/example/reportingdemo.rst @@ -11,7 +11,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/assertion, inifile: collected 42 items @@ -359,7 +359,7 @@ get on the terminal - we are working on that):: > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1207>:1: ValueError + <0-codegen /home/ronny/Projects/pytest-dev/pytest/_pytest/python.py:1207>:1: ValueError _______ TestRaises.test_raises_doesnt ________ self = diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 623ff33cc..d4b3fba43 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -113,7 +113,7 @@ directory with the above conftest.py:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -164,7 +164,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -178,7 +178,7 @@ Or run it including the ``slow`` marked test:: $ pytest --runslow ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -302,7 +302,7 @@ which will add the string to the test header accordingly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 project deps: mylib-1.1 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -327,7 +327,7 @@ which will add info only when run with "--v":: $ pytest -v ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache info1: did you know that ... did you? @@ -340,7 +340,7 @@ and nothing when run plainly:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 0 items @@ -374,7 +374,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -440,7 +440,7 @@ If we run this:: $ pytest -rx ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 4 items @@ -519,7 +519,7 @@ We can run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 7 items @@ -627,7 +627,7 @@ and run them:: $ pytest test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -721,7 +721,7 @@ and run it:: $ pytest -s test_module.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 201ad4863..0a9000611 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -70,7 +70,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items @@ -188,7 +188,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items @@ -520,7 +520,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + 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 @@ -573,7 +573,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 2 items @@ -642,7 +642,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 8 items diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index e398e4db5..f19f4d0c0 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.5, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py + This is pytest version 3.0.6, imported from /home/ronny/Projects/pytest-dev/pytest/pytest.py .. _`simpletest`: @@ -46,7 +46,7 @@ That's it. You can execute the test function now:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/index.rst b/doc/en/index.rst index ce1618e66..32671ddb2 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -25,7 +25,7 @@ To execute it:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index 052d0e72e..a3499ea3b 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -55,7 +55,7 @@ them in turn:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items @@ -103,7 +103,7 @@ Let's run this:: $ pytest ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 3 items diff --git a/doc/en/skipping.rst b/doc/en/skipping.rst index b142738c9..0a2e18208 100644 --- a/doc/en/skipping.rst +++ b/doc/en/skipping.rst @@ -224,7 +224,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR/example, inifile: collected 7 items diff --git a/doc/en/tmpdir.rst b/doc/en/tmpdir.rst index 56e4190c5..7a23c84de 100644 --- a/doc/en/tmpdir.rst +++ b/doc/en/tmpdir.rst @@ -29,7 +29,7 @@ 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.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 179347eb9..430d5ca55 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -100,7 +100,7 @@ the ``self.db`` values in the traceback:: $ pytest test_unittest_db.py ======= test session starts ======== - platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0 + platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 2 items From 01eaf9db51bc1d7982eb5414902799c365a6909d Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 18:03:06 +0100 Subject: [PATCH 142/201] fix the xfail docstring typo at the actual docstring + regendoc --- _pytest/skipping.py | 2 +- doc/en/example/markers.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/_pytest/skipping.py b/_pytest/skipping.py index a8eaea98a..91a34169f 100644 --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -46,7 +46,7 @@ def pytest_configure(config): ) config.addinivalue_line("markers", "xfail(condition, reason=None, run=True, raises=None, strict=False): " - "mark the the test function as an expected failure if eval(condition) " + "mark the test function as an expected failure if eval(condition) " "has a True value. Optionally specify a reason for better reporting " "and run=False if you don't even want to execute the test function. " "If only specific exception(s) are expected, you can list them in " diff --git a/doc/en/example/markers.rst b/doc/en/example/markers.rst index afa66960b..7dd5c8359 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -205,7 +205,7 @@ You can ask which markers exist for your test suite - the list includes our just @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @@ -381,7 +381,7 @@ The ``--markers`` option always gives you a list of available markers:: @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html + @pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. From 34b898b47e322afc564906574aa9f3bf0956262b Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 18:06:28 +0100 Subject: [PATCH 143/201] generate the release announcement --- doc/en/announce/index.rst | 1 + doc/en/announce/release-3.0.6.rst | 33 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 doc/en/announce/release-3.0.6.rst diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 44b29cae1..5cf8b4dcb 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-3.0.6 release-3.0.5 release-3.0.4 release-3.0.3 diff --git a/doc/en/announce/release-3.0.6.rst b/doc/en/announce/release-3.0.6.rst new file mode 100644 index 000000000..81b893141 --- /dev/null +++ b/doc/en/announce/release-3.0.6.rst @@ -0,0 +1,33 @@ +pytest-3.0.5 +============ + +pytest 3.0.5 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: + +* Andreas Pelme +* Bruno Oliveira +* Dmitry Malinovsky +* Eli Boyarski +* Jakub Wilk +* Jeff Widman +* Loïc Estève +* Luke Murphy +* Miro Hrončok +* Oscar Hellström +* Peter Heatwole +* Philippe Ombredanne +* Ronny Pfannschmidt +* Rutger Prins +* Stefan Scherfke + + +Happy testing, +The pytest Development Team From 449b88c6407f3da139f2b02a3263ac5166af312e Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 18:17:27 +0100 Subject: [PATCH 144/201] rerun regendoc with correct install --- doc/en/example/nonpython.rst | 48 ++++++++++++++++---------------- doc/en/example/parametrize.rst | 2 +- doc/en/example/reportingdemo.rst | 2 +- doc/en/getting-started.rst | 2 +- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/doc/en/example/nonpython.rst b/doc/en/example/nonpython.rst index 09daa3808..6510c861c 100644 --- a/doc/en/example/nonpython.rst +++ b/doc/en/example/nonpython.rst @@ -29,15 +29,16 @@ now execute the test specification:: ======= 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: - collected 0 items / 1 errors + collected 2 items - ======= ERRORS ======== - _______ ERROR collecting test_simple.yml ________ - conftest.py:11: in collect - import yaml # we need a yaml parser, e.g. PyYAML - E ImportError: No module named 'yaml' - !!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!! - ======= 1 error in 0.12 seconds ======== + test_simple.yml F. + + ======= FAILURES ======== + _______ usecase: hello ________ + usecase execution failed + spec failed: 'some': 'other' + no further details known at this point. + ======= 1 failed, 1 passed in 0.12 seconds ======== .. regendoc:wipe @@ -61,15 +62,17 @@ consulted when reporting in ``verbose`` mode:: platform linux -- Python 3.5.2, pytest-3.0.6, py-1.4.33, pluggy-0.4.0 -- $PYTHON_PREFIX/bin/python3.5m cachedir: .cache rootdir: $REGENDOC_TMPDIR/nonpython, inifile: - collecting ... collected 0 items / 1 errors + collecting ... collected 2 items - ======= ERRORS ======== - _______ ERROR collecting test_simple.yml ________ - conftest.py:11: in collect - import yaml # we need a yaml parser, e.g. PyYAML - E ImportError: No module named 'yaml' - !!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!! - ======= 1 error in 0.12 seconds ======== + test_simple.yml::hello FAILED + test_simple.yml::ok PASSED + + ======= FAILURES ======== + _______ usecase: hello ________ + usecase execution failed + spec failed: 'some': 'other' + no further details known at this point. + ======= 1 failed, 1 passed in 0.12 seconds ======== .. regendoc:wipe @@ -80,12 +83,9 @@ interesting to just look at the collection tree:: ======= 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: - collected 0 items / 1 errors + collected 2 items + + + - ======= ERRORS ======== - _______ ERROR collecting test_simple.yml ________ - conftest.py:11: in collect - import yaml # we need a yaml parser, e.g. PyYAML - E ImportError: No module named 'yaml' - !!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!! - ======= 1 error in 0.12 seconds ======== + ======= no tests ran in 0.12 seconds ======== diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index cd1b05b86..609158590 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -399,8 +399,8 @@ Running it results in some skips if we don't have all the python interpreters in . $ pytest -rs -q multipython.py sssssssssssssssssssssssssssssssssssssssssssss... ======= short test summary info ======== - SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python3.4' not found 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 diff --git a/doc/en/example/reportingdemo.rst b/doc/en/example/reportingdemo.rst index c586bc250..141208321 100644 --- a/doc/en/example/reportingdemo.rst +++ b/doc/en/example/reportingdemo.rst @@ -359,7 +359,7 @@ get on the terminal - we are working on that):: > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen /home/ronny/Projects/pytest-dev/pytest/_pytest/python.py:1207>:1: ValueError + <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1207>:1: ValueError _______ TestRaises.test_raises_doesnt ________ self = diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index f19f4d0c0..557e8245d 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 /home/ronny/Projects/pytest-dev/pytest/pytest.py + This is pytest version 3.0.6, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py .. _`simpletest`: From 22da561ae5bcfe57f78889153d3fa3057b56204a Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Fri, 20 Jan 2017 21:56:08 +0100 Subject: [PATCH 145/201] fix copy+paste error, its supposed to be 3.0.6 --- doc/en/announce/release-3.0.6.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/en/announce/release-3.0.6.rst b/doc/en/announce/release-3.0.6.rst index 81b893141..2988b9cb3 100644 --- a/doc/en/announce/release-3.0.6.rst +++ b/doc/en/announce/release-3.0.6.rst @@ -1,7 +1,7 @@ -pytest-3.0.5 +pytest-3.0.6 ============ -pytest 3.0.5 has just been released to PyPI. +pytest 3.0.6 has just been released to PyPI. This is a bug-fix release, being a drop-in replacement. To upgrade:: From 0e64cd045c8477cc81014490ed5e38e5b690a1ea Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sun, 22 Jan 2017 22:14:54 +0100 Subject: [PATCH 146/201] take off author_email after pypi rejects --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index f03ab9c40..d602b7979 100644 --- a/setup.py +++ b/setup.py @@ -68,7 +68,6 @@ def main(): license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others', - author_email='holger at merlinux.eu', entry_points={'console_scripts': ['pytest=pytest:main', 'py.test=pytest:main']}, classifiers=classifiers, From c9f327dc876d190c0e4fed6e7a1b24fdc5b63a89 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sun, 22 Jan 2017 22:21:08 +0100 Subject: [PATCH 147/201] bump version to next dev --- CHANGELOG.rst | 12 ++++++++++++ _pytest/__init__.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bf297971d..223e96f9e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,15 @@ +3.0.7 (unreleased) +======================= + +* + +* + +* + +* + + 3.0.6 (2017-01-29) ======================= diff --git a/_pytest/__init__.py b/_pytest/__init__.py index a4739a613..16616ffb0 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '3.0.6' +__version__ = '3.0.7.dev0' From 839aa963a12c38e258c2e7e8d0068d639110f3e7 Mon Sep 17 00:00:00 2001 From: Victor Uriarte Date: Sun, 22 Jan 2017 16:34:51 -0700 Subject: [PATCH 148/201] Add py36 identifier and order AUTHORS --- AUTHORS | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index acf715cde..c2400f508 100644 --- a/AUTHORS +++ b/AUTHORS @@ -48,6 +48,7 @@ Duncan Betts Edison Gustavo Muenz Edoardo Batini Eduardo Schettino +Eli Boyarski Elizaveta Shashkova Endre Galaczi Eric Hunsberger @@ -139,6 +140,6 @@ Tom Viner Trevor Bekolay Tyler Goodlet Vasily Kuznetsov +Victor Uriarte Wouter van Ackooy Xuecong Liao -Eli Boyarski diff --git a/setup.py b/setup.py index d602b7979..1d0630cd2 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ classifiers = ['Development Status :: 6 - Mature', 'Topic :: Software Development :: Libraries', 'Topic :: Utilities'] + [ ('Programming Language :: Python :: %s' % x) for x in - '2 2.6 2.7 3 3.3 3.4 3.5'.split()] + '2 2.6 2.7 3 3.3 3.4 3.5 3.6'.split()] with open('README.rst') as fd: long_description = fd.read() From 902fd2ff6a4b5081cf2efea810e080d0cf893f7d Mon Sep 17 00:00:00 2001 From: Victor Uriarte Date: Sun, 22 Jan 2017 17:20:15 -0700 Subject: [PATCH 149/201] Add py37-nightly to travis --- .travis.yml | 2 ++ tox.ini | 1 + 2 files changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index b2d356e19..f701302d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,8 @@ matrix: include: - env: TESTENV=py36 python: '3.6-dev' + - env: TESTENV=py37 + python: 'nightly' script: tox --recreate -e $TESTENV diff --git a/tox.ini b/tox.ini index 4be692fc7..e57fabd4b 100644 --- a/tox.ini +++ b/tox.ini @@ -10,6 +10,7 @@ envlist= py34 py35 py36 + py37 pypy {py27,py35}-{pexpect,xdist,trial} py27-nobyte From beb77c1a381ed559e67711bae14cb8528dab13bf Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 23 Jan 2017 13:51:12 -0200 Subject: [PATCH 150/201] Fix release date for 3.0.6 --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 223e96f9e..006c0ed0f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,8 +10,8 @@ * -3.0.6 (2017-01-29) -======================= +3.0.6 (2017-01-22) +================== * pytest no longer generates ``PendingDeprecationWarning`` from its own operations, which was introduced by mistake in version ``3.0.5`` (`#2118`_). Thanks to `@nicoddemus`_ for the report and `@RonnyPfannschmidt`_ for the PR. From d98d122e81324f22938a5791860820be993a29f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Wed, 25 Jan 2017 14:20:38 +0200 Subject: [PATCH 151/201] Discourage users from using this all the time. --- doc/en/unittest.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 430d5ca55..43b6526c7 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -17,6 +17,14 @@ run using ``pytest``. We assume here that you are familiar with writing ``unittest.TestCase`` style tests and rather focus on integration aspects. +Note that this is meant as a provisional way of running your test code +until you fully convert to pytest-style tests. To fully take advantage of +:ref:`fixtures `, :ref:`parametrization ` and +:ref:`hooks ` you should convert (tools like `unittest2pytest +`__ are helpful). +Also, not all 3rd party pluging are expected to work best with +``unittest.TestCase`` style tests. + Usage ------------------------------------------------------------------- @@ -191,12 +199,3 @@ was executed ahead of the ``test_method``. pytest fixtures into unittest suites. And of course you can also start to selectively leave away the ``unittest.TestCase`` subclassing, use plain asserts and get the unlimited pytest feature set. - - -Converting from unittest to pytest ---------------------------------------- - -If you want to convert your unittest testcases to pytest, there are -some helpers like `unittest2pytest -`__, which uses lib2to3 -and introspection for the transformation. From c8032a9bbb18cdbcf7d01303a2a846fbc048b76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Wed, 25 Jan 2017 14:44:07 +0200 Subject: [PATCH 152/201] Fix reference. --- doc/en/unittest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 43b6526c7..1bee0e146 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -20,7 +20,7 @@ integration aspects. Note that this is meant as a provisional way of running your test code until you fully convert to pytest-style tests. To fully take advantage of :ref:`fixtures `, :ref:`parametrization ` and -:ref:`hooks ` you should convert (tools like `unittest2pytest +:ref:`hooks ` you should convert (tools like `unittest2pytest `__ are helpful). Also, not all 3rd party pluging are expected to work best with ``unittest.TestCase`` style tests. From d1c725078a8c2fccfc573772e1944b9fe2a902e6 Mon Sep 17 00:00:00 2001 From: mbyt Date: Mon, 30 Jan 2017 21:20:12 +0100 Subject: [PATCH 153/201] 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 154/201] 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 155/201] 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 156/201] 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 157/201] 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 158/201] 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 159/201] 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 160/201] 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 161/201] 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 162/201] --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 163/201] 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 164/201] 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 165/201] 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 166/201] 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 167/201] 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 168/201] 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 169/201] 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 170/201] 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 171/201] 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 172/201] 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 173/201] 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 5fd010c4c3f53d69bcef396989e52a6cbfa59c4e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 19 Feb 2017 09:02:35 -0800 Subject: [PATCH 174/201] 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 175/201] 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 bb5f200ed7bd75934235e53bc3acfac9c9251c7e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 25 Feb 2017 12:06:51 -0300 Subject: [PATCH 176/201] 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 6a52fe165070dcbeda9b7c5b622975effcab5f40 Mon Sep 17 00:00:00 2001 From: Omer Hadari Date: Sat, 4 Mar 2017 10:26:46 +0200 Subject: [PATCH 177/201] 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 178/201] 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 179/201] 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 180/201] 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 181/201] 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 182/201] 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 183/201] 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 184/201] 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 841f73170751b237a15f64a489988f783da7982d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 9 Mar 2017 20:41:33 -0300 Subject: [PATCH 185/201] Attempt to clarify the confusion regarding __init__ files and unique test names Fix #529 --- doc/en/goodpractices.rst | 85 ++++++++++++++++++---------------------- tox.ini | 2 + 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 48f80a9e2..65c5624fa 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -30,68 +30,58 @@ Within Python modules, ``pytest`` also discovers tests using the standard Choosing a test layout / import rules ------------------------------------------- +------------------------------------- ``pytest`` supports two common test layouts: -* putting tests into an extra directory outside your actual application - code, useful if you have many functional tests or for other reasons - want to keep tests separate from actual application code (often a good - idea):: +Tests outside application code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - setup.py # your setuptools Python package metadata +Putting tests into an extra directory outside your actual application code +might be useful if you have many functional tests or for other reasons want +to keep tests separate from actual application code (often a good idea):: + + setup.py mypkg/ __init__.py - appmodule.py + app.py + view.py tests/ test_app.py + test_view.py ... +This way your tests can run easily against an installed version +of ``mypkg``. -* inlining test directories into your application package, useful if you - have direct relation between (unit-)test and application modules and - want to distribute your tests along with your application:: +Note that using this scheme your test files must have **unique names**, because +``pytest`` will import them as *top-level* modules since there are no packages +to derive a full package name from. - setup.py # your setuptools Python package metadata +Tests as part of application code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inlining test directories into your application package +is useful if you have direct relation between tests and application modules and +want to distribute them along with your application:: + + setup.py mypkg/ __init__.py - appmodule.py - ... + app.py + view.py test/ + __init__.py test_app.py + test_view.py ... -Important notes relating to both schemes: +In this scheme, it is easy to your tests using the ``--pyargs`` option:: -- **make sure that "mypkg" is importable**, for example by typing once:: + pytest --pyargs mypkg - pip install -e . # install package using setup.py in editable mode +``pytest`` will discover where ``mypkg`` is installed and collect tests from there. -- **avoid "__init__.py" files in your test directories**. - This way your tests can run easily against an installed version - of ``mypkg``, independently from the installed package if it contains - the tests or not. - -- With inlined tests you might put ``__init__.py`` into test - directories and make them installable as part of your application. - Using the ``pytest --pyargs mypkg`` invocation pytest will - discover where mypkg is installed and collect tests from there. - With the "external" test you can still distribute tests but they - will not be installed or become importable. - -Typically you can run tests by pointing to test directories or modules:: - - pytest tests/test_app.py # for external test dirs - pytest mypkg/test/test_app.py # for inlined test dirs - pytest mypkg # run tests in all below test directories - pytest # run all tests below current dir - ... - -Because of the above ``editable install`` mode you can change your -source code (both tests and the app) and rerun tests at will. -Once you are done with your work, you can `use tox`_ to make sure -that the package is really correct and tests pass in all -required configurations. .. note:: @@ -144,7 +134,13 @@ for installing your application and any dependencies as well as the ``pytest`` package itself. This ensures your code and dependencies are isolated from the system Python installation. -If you frequently release code and want to make sure that your actual +You can then install your package in "editable" mode:: + + pip install -e . + +which lets you change your source code (both tests and application) and rerun tests at will. + +Once you are done with your work and want to make sure that your actual package passes all tests you may want to look into `tox`_, the virtualenv test automation tool and its `pytest support `_. @@ -154,11 +150,6 @@ options. It will run tests against the installed package and not against your source code checkout, helping to detect packaging glitches. -Continuous integration services such as Jenkins_ can make use of the -``--junitxml=PATH`` option to create a JUnitXML file and generate reports (e.g. -by publishing the results in a nice format with the `Jenkins xUnit Plugin -`_). - Integrating with setuptools / ``python setup.py test`` / ``pytest-runner`` -------------------------------------------------------------------------- diff --git a/tox.ini b/tox.ini index 1b9fb9f5a..a47fc5132 100644 --- a/tox.ini +++ b/tox.ini @@ -106,6 +106,8 @@ commands= pytest -ra {posargs:testing/test_unittest.py} [testenv:docs] +skipsdist=True +usedevelop=True basepython=python changedir=doc/en deps= From 581857aab631b2a5a17232b3a332dd44b832e689 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 9 Mar 2017 20:46:22 -0300 Subject: [PATCH 186/201] Fix typo --- doc/en/goodpractices.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 65c5624fa..5f6ea710b 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -76,7 +76,7 @@ want to distribute them along with your application:: test_view.py ... -In this scheme, it is easy to your tests using the ``--pyargs`` option:: +In this scheme, it is easy to your run tests using the ``--pyargs`` option:: pytest --pyargs mypkg From b1ab2ca963b776fb145f71e49f2186e2b4c02618 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 13 Mar 2017 18:37:49 -0400 Subject: [PATCH 187/201] 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 188/201] 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 90c934e25ed378bd517da9039dfed65c1ea570ba Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 13 Mar 2017 18:59:15 -0400 Subject: [PATCH 189/201] 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 190/201] 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 4a9348324d414f4f7a68b8a096a9ff960101aa1f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 07:59:01 -0300 Subject: [PATCH 191/201] Add more information to test-layout docs as discussed during PR --- doc/en/goodpractices.rst | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 5f6ea710b..ff71f1c9c 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -56,7 +56,44 @@ of ``mypkg``. Note that using this scheme your test files must have **unique names**, because ``pytest`` will import them as *top-level* modules since there are no packages -to derive a full package name from. +to derive a full package name from. In other words, the test files in the example above will +be imported as ``test_app`` and ``test_view`` top-level modules by adding ``tests/`` to +``sys.path``. + +If you need to have test modules with the same name, you might add ``__init__.py`` files to your +``tests`` folder and subfolders, changing them to packages:: + + mypkg/ + ... + tests/ + __init__.py + foo/ + __init__.py + test_view.py + bar/ + __init__.py + test_view.py + +Now pytest will load the modules as ``tests.foo.test_view`` and ``tests.bar.test_view``, allowing +you to have modules with the same name. But now this introduces a subtle problem: in order to load +the test modules from the ``tests`` directory, pytest prepends the root of the repository to +``sys.path``, which adds the side-effect that now ``mypkg`` is also importable. +This is problematic if you are using a tool like `tox`_ to test your package in a virtual environment, +because you want to test the *installed* version of your package, not the local code from the repository. + +There are a couple of solutions to this: + +* Do not add the ``tests/__init__.py`` file. This will cause your test modules to be loaded as + ``foo.test_view`` and ``bar.test_view``, which is usually fine and avoids having the root of + the repository being added to the ``PYTHONPATH``. + +* Add ``addopts=--import-mode=append`` to your ``pytest.ini`` file. This will cause ``pytest`` to + load your modules by *appending* the root directory instead of prepending. + +* Alternatively, consider using the ``src`` layout explained in detail in this excellent + `blog post by Ionel Cristian Mărieș `_ + which prevents a lot of the pitfalls described here. + Tests as part of application code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From fa15ae754500916eb5226adb1efaaf95f0ce4618 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 18:07:44 -0300 Subject: [PATCH 192/201] 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' From 272aba98e2009aaa37841594691ff88cb866b7d3 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 18:39:02 -0300 Subject: [PATCH 193/201] Mention the src layout as recommended practice --- doc/en/goodpractices.rst | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index ff71f1c9c..c17fabbc9 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -63,6 +63,7 @@ be imported as ``test_app`` and ``test_view`` top-level modules by adding ``test If you need to have test modules with the same name, you might add ``__init__.py`` files to your ``tests`` folder and subfolders, changing them to packages:: + setup.py mypkg/ ... tests/ @@ -81,19 +82,27 @@ the test modules from the ``tests`` directory, pytest prepends the root of the r This is problematic if you are using a tool like `tox`_ to test your package in a virtual environment, because you want to test the *installed* version of your package, not the local code from the repository. -There are a couple of solutions to this: +In this situation, it is **strongly** suggested to use a ``src`` layout where application root package resides in a +sub-directory of your root:: -* Do not add the ``tests/__init__.py`` file. This will cause your test modules to be loaded as - ``foo.test_view`` and ``bar.test_view``, which is usually fine and avoids having the root of - the repository being added to the ``PYTHONPATH``. + setup.py + src/ + mypkg/ + __init__.py + app.py + view.py + tests/ + __init__.py + foo/ + __init__.py + test_view.py + bar/ + __init__.py + test_view.py -* Add ``addopts=--import-mode=append`` to your ``pytest.ini`` file. This will cause ``pytest`` to - load your modules by *appending* the root directory instead of prepending. - -* Alternatively, consider using the ``src`` layout explained in detail in this excellent - `blog post by Ionel Cristian Mărieș `_ - which prevents a lot of the pitfalls described here. +This layout prevents a lot of common pitfalls and has many benefits, which are better explained in this excellent +`blog post by Ionel Cristian Mărieș `_. Tests as part of application code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,6 +128,8 @@ In this scheme, it is easy to your run tests using the ``--pyargs`` option:: ``pytest`` will discover where ``mypkg`` is installed and collect tests from there. +Note that this layout also works in conjunction with the ``src`` layout mentioned in the previous section. + .. note:: From dc6890709e19567219cc35a561a07dc8cd5d611c Mon Sep 17 00:00:00 2001 From: Xander Johnson Date: Tue, 14 Mar 2017 12:45:56 -0700 Subject: [PATCH 194/201] Change ValueError to io.UnsupportedOperation in capture.py. Resolves issue #2276 --- _pytest/capture.py | 3 ++- testing/test_capture.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/_pytest/capture.py b/_pytest/capture.py index eea81ca18..07ec662b6 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -13,6 +13,7 @@ import py import pytest from py.io import TextIO +from io import UnsupportedOperation unicode = py.builtin.text patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} @@ -448,7 +449,7 @@ class DontReadFromInput: __iter__ = read def fileno(self): - raise ValueError("redirected Stdin is pseudofile, has no fileno()") + raise UnsupportedOperation("redirected Stdin is pseudofile, has no fileno()") def isatty(self): return False diff --git a/testing/test_capture.py b/testing/test_capture.py index 763e28315..978e67b7e 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -4,6 +4,7 @@ from __future__ import with_statement import pickle import os import sys +from io import UnsupportedOperation import _pytest._code import py @@ -658,7 +659,7 @@ def test_dontreadfrominput(): pytest.raises(IOError, f.read) pytest.raises(IOError, f.readlines) pytest.raises(IOError, iter, f) - pytest.raises(ValueError, f.fileno) + pytest.raises(UnsupportedOperation, f.fileno) f.close() # just for completeness From 9062fbb9cc0aae758f97f90d26cffa56cc8bf5be Mon Sep 17 00:00:00 2001 From: Xander Johnson Date: Tue, 14 Mar 2017 12:52:37 -0700 Subject: [PATCH 195/201] Add AUTHORS & CHANGELOG --- AUTHORS | 1 + CHANGELOG.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/AUTHORS b/AUTHORS index ce19f1f21..063593dd6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,7 @@ Contributors include:: Abdeali JK Abhijeet Kasurde Ahn Ki-Wook +Alexander Johnson Alexei Kozlenok Anatoly Bubenkoff Andreas Zeidler diff --git a/CHANGELOG.rst b/CHANGELOG.rst index beb0542be..7aceb200c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,9 @@ 3.0.7 (2017-03-14) ================== +* Change capture.py's DontReadFromInput class to throw io.UnsupportedOperation errors rather + than ValueErrors in the fileno method (`#2276`). + Thanks `@metasyn` for the PR. * Fix issue in assertion rewriting breaking due to modules silently discarding other modules when importing fails @@ -58,6 +61,7 @@ .. _@kkoukiou: https://github.com/KKoukiou .. _@omerhadari: https://github.com/omerhadari .. _@fbjorn: https://github.com/fbjorn +.. _@metasyn: https://github.com/metasyn .. _#2248: https://github.com/pytest-dev/pytest/issues/2248 .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 @@ -66,6 +70,7 @@ .. _#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 +.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ From aad4946fb665269a7771cc3ae6eb67a7392e8306 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 18:58:28 -0300 Subject: [PATCH 196/201] Move CHANGELOG entry for #2276 to 3.0.8 --- CHANGELOG.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7aceb200c..c2e4e9ce7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,9 @@ 3.0.8 (unreleased) ================== -* +* Change capture.py's ``DontReadFromInput`` class to throw ``io.UnsupportedOperation`` errors rather + than ValueErrors in the ``fileno`` method (`#2276`_). + Thanks `@metasyn`_ for the PR. * @@ -12,16 +14,19 @@ * +.. _@metasyn: https://github.com/metasyn + + +.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 + + 3.0.7 (2017-03-14) ================== -* Change capture.py's DontReadFromInput class to throw io.UnsupportedOperation errors rather - than ValueErrors in the fileno method (`#2276`). - Thanks `@metasyn` for the PR. * Fix issue in assertion rewriting breaking due to modules silently discarding other modules when importing fails - Notably, importing the `anydbm` module is fixed. (`#2248`_). + Notably, importing the ``anydbm`` module is fixed. (`#2248`_). Thanks `@pfhayes`_ for the PR. * junitxml: Fix problematic case where system-out tag occured twice per testcase @@ -61,7 +66,6 @@ .. _@kkoukiou: https://github.com/KKoukiou .. _@omerhadari: https://github.com/omerhadari .. _@fbjorn: https://github.com/fbjorn -.. _@metasyn: https://github.com/metasyn .. _#2248: https://github.com/pytest-dev/pytest/issues/2248 .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 @@ -70,7 +74,6 @@ .. _#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 -.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ From d58bc146459ae295256bbcf324c08eced354a086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Adamczak?= Date: Sun, 19 Mar 2017 18:34:43 +0000 Subject: [PATCH 197/201] Added 'Possible exit codes' section to docs (#2239) --- doc/en/usage.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/en/usage.rst b/doc/en/usage.rst index a6fd4892e..8cc682787 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -19,6 +19,18 @@ You can invoke testing through the Python interpreter from the command line:: This is almost equivalent to invoking the command line script ``pytest [...]`` directly, except that python will also add the current directory to ``sys.path``. +Possible exit codes +-------------------------------------------------------------- + +Running ``pytest`` can result in six different exit codes: + +:Exit code 0: All tests were collected and passed successfully +:Exit code 1: Tests were collected and run but some of the tests failed +:Exit code 2: Test execution was interrupted by the user +:Exit code 3: Internal error happened while executing tests +:Exit code 4: pytest command line usage error +:Exit code 5: No tests were collected + Getting help on version, option names, environment variables -------------------------------------------------------------- From 8b57aaf94410f664d8b5bb2d952943a44d581067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Adamczak?= Date: Sun, 19 Mar 2017 18:38:41 +0000 Subject: [PATCH 198/201] =?UTF-8?q?Added=20'Pawe=C5=82=20Adamczak'=20to=20?= =?UTF-8?q?AUTHORS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 063593dd6..025a3c8f6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -117,6 +117,7 @@ Oliver Bestwalter Omar Kohl Omer Hadari Patrick Hayes +Paweł Adamczak Pieter Mulder Piotr Banaszkiewicz Punyashloka Biswal From 58ac4faf0c6338439f9b8335709a6bc216d7cd1c Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 29 Mar 2017 14:38:14 -0300 Subject: [PATCH 199/201] Fix exception formatting while importing test modules Fix #2336 --- CHANGELOG.rst | 9 +++++++-- _pytest/compat.py | 2 ++ _pytest/python.py | 4 ++-- testing/python/collect.py | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c2e4e9ce7..78d7501fb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,8 +5,11 @@ than ValueErrors in the ``fileno`` method (`#2276`_). Thanks `@metasyn`_ for the PR. -* - +* Fix exception formatting while importing modules when the exception message + contains non-ascii characters (`#2336`_). + Thanks `@fabioz`_ for the report and `@nicoddemus`_ for the PR. + + * * @@ -14,10 +17,12 @@ * +.. _@fabioz: https://github.com/fabioz .. _@metasyn: https://github.com/metasyn .. _#2276: https://github.com/pytest-dev/pytest/issues/2276 +.. _#2336: https://github.com/pytest-dev/pytest/issues/2336 3.0.7 (2017-03-14) diff --git a/_pytest/compat.py b/_pytest/compat.py index d278b89cd..cc2954bff 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -237,5 +237,7 @@ else: try: return str(v) except UnicodeError: + if not isinstance(v, unicode): + v = unicode(v) errors = 'replace' return v.encode('ascii', errors) diff --git a/_pytest/python.py b/_pytest/python.py index 3e865e9df..59492bc41 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -19,7 +19,7 @@ from _pytest.compat import ( isclass, isfunction, is_generator, _escape_strings, REGEX_TYPE, STRING_TYPES, NoneType, NOTSET, get_real_func, getfslineno, safe_getattr, - getlocation, enum, + safe_str, getlocation, enum, ) cutdir1 = py.path.local(pluggy.__file__.rstrip("oc")) @@ -437,7 +437,7 @@ class Module(pytest.File, PyCollector): if self.config.getoption('verbose') < 2: exc_info.traceback = exc_info.traceback.filter(filter_traceback) exc_repr = exc_info.getrepr(style='short') if exc_info.traceback else exc_info.exconly() - formatted_tb = py._builtin._totext(exc_repr) + formatted_tb = safe_str(exc_repr) raise self.CollectError( "ImportError while importing test module '{fspath}'.\n" "Hint: make sure your test modules/packages have valid Python names.\n" diff --git a/testing/python/collect.py b/testing/python/collect.py index cce934ddc..d0e490832 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -105,6 +105,23 @@ class TestModule: assert name not in stdout + def test_show_traceback_import_error_unicode(self, testdir): + """Check test modules collected which raise ImportError with unicode messages + are handled properly (#2336). + """ + testdir.makepyfile(u""" + # -*- coding: utf-8 -*- + raise ImportError(u'Something bad happened ☺') + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "ImportError while importing test module*", + "Traceback:", + "*raise ImportError*Something bad happened*", + ]) + assert result.ret == 2 + + class TestClass: def test_class_with_init_warning(self, testdir): testdir.makepyfile(""" From a542ed48a23cfbc526a1876ec135d4e43b37a38f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 29 Mar 2017 15:18:41 -0300 Subject: [PATCH 200/201] Convert using utf-8 instead of ascii in safe_str() This way we don't lose information and the returned string is ascii-compatible anyway --- _pytest/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/compat.py b/_pytest/compat.py index cc2954bff..4f2013dac 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -240,4 +240,4 @@ else: if not isinstance(v, unicode): v = unicode(v) errors = 'replace' - return v.encode('ascii', errors) + return v.encode('utf-8', errors) From 44a3db3dc668b28fa3892b3cd9fb2e14aa2d7c21 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Apr 2017 18:02:49 -0300 Subject: [PATCH 201/201] Pin sphinx to 1.4 when generating docs to workaround search issues on RTD Fix #2302 --- doc/en/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/en/requirements.txt diff --git a/doc/en/requirements.txt b/doc/en/requirements.txt new file mode 100644 index 000000000..72bb60a81 --- /dev/null +++ b/doc/en/requirements.txt @@ -0,0 +1,3 @@ +# pinning sphinx to 1.4.* due to search issues with rtd: +# https://github.com/rtfd/readthedocs-sphinx-ext/issues/25 +sphinx ==1.4.*