diff --git a/AUTHORS b/AUTHORS index ca41d0ac1..b19a850fb 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 @@ -90,6 +91,7 @@ Markus Unterwaditzer Martijn Faassen Martin K. Scherer Martin Prusse +Mathieu Clabaut Matt Bachmann Matt Duck Matt Williams @@ -98,6 +100,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 b16f2c2cd..b0b2701c2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,31 +41,74 @@ Changes .. _#2013: https://github.com/pytest-dev/pytest/issues/2013 -3.0.4.dev -========= +3.0.5.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. -* 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`_). Thanks `@nicoddemus`_ for the PR. -* +* 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 + 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. + +* 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. + +* 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. +.. _@adborden: https://github.com/adborden .. _@cwitty: https://github.com/cwitty +.. _@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 .. _#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 @@ -439,7 +482,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/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..0c5bfd552 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -11,22 +11,23 @@ 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 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/install.ps1 exclude appveyor.yml -exclude appveyor +exclude .travis.yml +prune .github 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/_pytest/_code/code.py b/_pytest/_code/code.py index 30e12940b..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)) @@ -623,16 +624,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/_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/_pytest/junitxml.py b/_pytest/junitxml.py index 88e4f5282..ce882394c 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -158,8 +158,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/_pytest/pytester.py b/_pytest/pytester.py index da8996a04..641c7c31f 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -1008,8 +1008,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/_pytest/python.py b/_pytest/python.py index db345fe27..3a35ce5ae 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1106,7 +1106,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:: @@ -1117,19 +1119,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:: @@ -1228,7 +1232,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/_pytest/recwarn.py b/_pytest/recwarn.py index 0f6f93571..0591c342b 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/_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/_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/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/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 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/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 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 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/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, 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/python/raises.py b/testing/python/raises.py index aee3715f1..08edd5c6a 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): @@ -88,3 +90,31 @@ class TestRaises: assert e.msg == message else: assert False, "Expected pytest.raises.Exception" + + @pytest.mark.parametrize('method', ['function', 'with']) + def test_raises_cyclic_reference(self, method): + """ + Ensure pytest.raises does not leave a reference cycle (#1965). + """ + import gc + + class T(object): + def __call__(self): + raise ValueError + + t = T() + if method == 'function': + pytest.raises(ValueError, t) + else: + with pytest.raises(ValueError): + t() + + # 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 + diff --git a/testing/test_assertion.py b/testing/test_assertion.py index c6afab014..b917b3c3c 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -757,6 +757,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("") 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): diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 382d7c137..f4455a081 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 diff --git a/testing/test_pdb.py b/testing/test_pdb.py index f164f9691..b63670ab4 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -1,4 +1,5 @@ import sys +import platform import _pytest._code import pytest @@ -96,6 +97,12 @@ 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 platform.system() == 'Darwin': + return if child.isalive(): child.wait() @@ -115,8 +122,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(""" @@ -131,8 +137,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(""" @@ -150,8 +155,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(""" @@ -163,8 +167,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(""" @@ -176,8 +179,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(""" @@ -197,8 +199,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(""" @@ -213,8 +214,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(""" @@ -229,8 +229,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(""" @@ -249,8 +248,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(""" @@ -269,8 +267,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(""" @@ -296,8 +293,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(""" @@ -308,7 +304,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(""" @@ -322,7 +318,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 """) @@ -351,8 +347,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, custom_pdb_calls): p1 = testdir.makepyfile("""xxx """) 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(""" 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(""" diff --git a/tox.ini b/tox.ini index ca55e7813..17fe0e3e4 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} @@ -33,15 +42,19 @@ deps=pytest-xdist>=1.13 commands= pytest -n3 -rfsxX --runpytest=subprocess {posargs:testing} -[testenv:genscript] -commands= pytest --genscript=pytest1 [testenv:linting] basepython = python2.7 -deps = flake8 +deps = + flake8 + # pygments required by rst-lint + pygments restructuredtext_lint -commands = flake8 pytest.py _pytest testing - rst-lint CHANGELOG.rst HOWTORELEASE.rst + check-manifest +commands = + check-manifest + flake8 pytest.py _pytest testing + rst-lint CHANGELOG.rst HOWTORELEASE.rst README.rst [testenv:py27-xdist] deps=pytest-xdist>=1.13 @@ -90,10 +103,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 +115,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 +151,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}