Merge branch 'master' into merge-master-features

This commit is contained in:
Bruno Oliveira 2016-11-11 18:56:53 -02:00
commit efc54b2e56
47 changed files with 469 additions and 177 deletions

View File

@ -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

View File

@ -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

View File

@ -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)::

View File

@ -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

View File

@ -89,7 +89,7 @@ Please use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issue
Changelog
---------
Consult the `Changelog <http://docs.pytest.org/en/latest/changelog.html>`_ page for fixes and enhancements of each version.
Consult the `Changelog <http://docs.pytest.org/en/latest/changelog.html>`__ page for fixes and enhancements of each version.
License

View File

@ -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 "<ExceptionInfo %s tblen=%d>" % (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

View File

@ -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):

View File

@ -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):

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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":

View File

@ -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

View File

@ -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

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2
release-3.0.4
release-3.0.3
release-3.0.2
release-3.0.1

View File

@ -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

View File

@ -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

View File

@ -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 -------------------------------

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
<YamlFile 'test_simple.yml'>

View File

@ -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
<Module 'test_time.py'>
@ -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
<Module 'test_scenarios.py'>
@ -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
<Module 'test_backends.py'>
@ -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
<Module 'test_indirect_list.py'>
@ -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

View File

@ -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
<Module 'check_myapp.py'>
@ -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
<Module 'CWD/pythoncollection.py'>
@ -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

View File

@ -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 = <failure_demo.TestRaises object at 0xdeadbeef>

View File

@ -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

View File

@ -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 <smtplib.SMTP object at 0xdeadbeef> (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 <smtplib.SMTP object at 0xdeadbeef>
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
<Module 'test_anothersmtp.py'>
@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -4,7 +4,7 @@ Talks and Tutorials
.. sidebar:: Next Open Trainings
`professional testing with pytest and tox <http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, 27-29th June 2016, Freiburg, Germany
`pytest workshop <http://www.meetup.com/Python-Django-User-Group-Bern/events/235151115/>`_, 8th December 2016, Bern, Switzerland
.. _`funcargs`: funcargs.html

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,3 +0,0 @@
sphinx==1.2.3
regendoc
pyyaml

View File

@ -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:])

View File

@ -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,

View File

@ -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"])

View File

@ -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

View File

@ -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("")

View File

@ -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):

View File

@ -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

View File

@ -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 """)

View File

@ -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("""

View File

@ -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("""

42
tox.ini
View File

@ -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}