Merge remote-tracking branch 'upstream/master'

This commit is contained in:
helloocc 2019-07-24 23:35:22 +08:00
commit 28343bdcbd
32 changed files with 285 additions and 113 deletions

View File

@ -5,13 +5,11 @@ repos:
hooks: hooks:
- id: black - id: black
args: [--safe, --quiet] args: [--safe, --quiet]
language_version: python3
- repo: https://github.com/asottile/blacken-docs - repo: https://github.com/asottile/blacken-docs
rev: v1.0.0 rev: v1.0.0
hooks: hooks:
- id: blacken-docs - id: blacken-docs
additional_dependencies: [black==19.3b0] additional_dependencies: [black==19.3b0]
language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.2.3 rev: v2.2.3
hooks: hooks:

View File

@ -1,6 +1,6 @@
================= =========
Changelog history Changelog
================= =========
Versions follow `Semantic Versioning <https://semver.org/>`_ (``<major>.<minor>.<patch>``). Versions follow `Semantic Versioning <https://semver.org/>`_ (``<major>.<minor>.<patch>``).
@ -90,6 +90,24 @@ Removals
- `#5412 <https://github.com/pytest-dev/pytest/issues/5412>`_: ``ExceptionInfo`` objects (returned by ``pytest.raises``) now have the same ``str`` representation as ``repr``, which - `#5412 <https://github.com/pytest-dev/pytest/issues/5412>`_: ``ExceptionInfo`` objects (returned by ``pytest.raises``) now have the same ``str`` representation as ``repr``, which
avoids some confusion when users use ``print(e)`` to inspect the object. avoids some confusion when users use ``print(e)`` to inspect the object.
This means code like:
.. code-block:: python
with pytest.raises(SomeException) as e:
...
assert "some message" in str(e)
Needs to be changed to:
.. code-block:: python
with pytest.raises(SomeException) as e:
...
assert "some message" in str(e.value)
Deprecations Deprecations
@ -2173,10 +2191,10 @@ Features
design. This introduces new ``Node.iter_markers(name)`` and design. This introduces new ``Node.iter_markers(name)`` and
``Node.get_closest_marker(name)`` APIs. Users are **strongly encouraged** to ``Node.get_closest_marker(name)`` APIs. Users are **strongly encouraged** to
read the `reasons for the revamp in the docs read the `reasons for the revamp in the docs
<https://docs.pytest.org/en/latest/mark.html#marker-revamp-and-iteration>`_, <https://docs.pytest.org/en/latest/historical-notes.html#marker-revamp-and-iteration>`_,
or jump over to details about `updating existing code to use the new APIs or jump over to details about `updating existing code to use the new APIs
<https://docs.pytest.org/en/latest/mark.html#updating-code>`_. (`#3317 <https://docs.pytest.org/en/latest/historical-notes.html#updating-code>`_.
<https://github.com/pytest-dev/pytest/issues/3317>`_) (`#3317 <https://github.com/pytest-dev/pytest/issues/3317>`_)
- Now when ``@pytest.fixture`` is applied more than once to the same function a - Now when ``@pytest.fixture`` is applied more than once to the same function a
``ValueError`` is raised. This buggy behavior would cause surprising problems ``ValueError`` is raised. This buggy behavior would cause surprising problems
@ -2582,10 +2600,10 @@ Features
<https://github.com/pytest-dev/pytest/issues/3038>`_) <https://github.com/pytest-dev/pytest/issues/3038>`_)
- New `pytest_runtest_logfinish - New `pytest_runtest_logfinish
<https://docs.pytest.org/en/latest/writing_plugins.html#_pytest.hookspec.pytest_runtest_logfinish>`_ <https://docs.pytest.org/en/latest/reference.html#_pytest.hookspec.pytest_runtest_logfinish>`_
hook which is called when a test item has finished executing, analogous to hook which is called when a test item has finished executing, analogous to
`pytest_runtest_logstart `pytest_runtest_logstart
<https://docs.pytest.org/en/latest/writing_plugins.html#_pytest.hookspec.pytest_runtest_start>`_. <https://docs.pytest.org/en/latest/reference.html#_pytest.hookspec.pytest_runtest_logstart>`_.
(`#3101 <https://github.com/pytest-dev/pytest/issues/3101>`_) (`#3101 <https://github.com/pytest-dev/pytest/issues/3101>`_)
- Improve performance when collecting tests using many fixtures. (`#3107 - Improve performance when collecting tests using many fixtures. (`#3107
@ -3575,7 +3593,7 @@ Bug Fixes
Thanks `@sirex`_ for the report and `@nicoddemus`_ for the PR. Thanks `@sirex`_ for the report and `@nicoddemus`_ for the PR.
* Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). * Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_).
Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. Thanks to `@nicoddemus`_ for the PR.
* Fix internal errors when an unprintable ``AssertionError`` is raised inside a test. * Fix internal errors when an unprintable ``AssertionError`` is raised inside a test.
Thanks `@omerhadari`_ for the PR. Thanks `@omerhadari`_ for the PR.
@ -3706,7 +3724,7 @@ Bug Fixes
.. _@syre: https://github.com/syre .. _@syre: https://github.com/syre
.. _@adler-j: https://github.com/adler-j .. _@adler-j: https://github.com/adler-j
.. _@d-b-w: https://bitbucket.org/d-b-w/ .. _@d-b-w: https://github.com/d-b-w
.. _@DuncanBetts: https://github.com/DuncanBetts .. _@DuncanBetts: https://github.com/DuncanBetts
.. _@dupuy: https://bitbucket.org/dupuy/ .. _@dupuy: https://bitbucket.org/dupuy/
.. _@kerrick-lyft: https://github.com/kerrick-lyft .. _@kerrick-lyft: https://github.com/kerrick-lyft
@ -3766,7 +3784,7 @@ Bug Fixes
.. _@adborden: https://github.com/adborden .. _@adborden: https://github.com/adborden
.. _@cwitty: https://github.com/cwitty .. _@cwitty: https://github.com/cwitty
.. _@d_b_w: https://github.com/d_b_w .. _@d_b_w: https://github.com/d-b-w
.. _@gdyuldin: https://github.com/gdyuldin .. _@gdyuldin: https://github.com/gdyuldin
.. _@matclab: https://github.com/matclab .. _@matclab: https://github.com/matclab
.. _@MSeifert04: https://github.com/MSeifert04 .. _@MSeifert04: https://github.com/MSeifert04
@ -3801,7 +3819,7 @@ Bug Fixes
Thanks `@axil`_ for the PR. Thanks `@axil`_ for the PR.
* Explain a bad scope value passed to ``@fixture`` declarations or * Explain a bad scope value passed to ``@fixture`` declarations or
a ``MetaFunc.parametrize()`` call. Thanks `@tgoodlet`_ for the PR. a ``MetaFunc.parametrize()`` call.
* This version includes ``pluggy-0.4.0``, which correctly handles * This version includes ``pluggy-0.4.0``, which correctly handles
``VersionConflict`` errors in plugins (`#704`_). ``VersionConflict`` errors in plugins (`#704`_).
@ -3811,7 +3829,6 @@ Bug Fixes
.. _@philpep: https://github.com/philpep .. _@philpep: https://github.com/philpep
.. _@raquel-ucl: https://github.com/raquel-ucl .. _@raquel-ucl: https://github.com/raquel-ucl
.. _@axil: https://github.com/axil .. _@axil: https://github.com/axil
.. _@tgoodlet: https://github.com/tgoodlet
.. _@vlad-dragos: https://github.com/vlad-dragos .. _@vlad-dragos: https://github.com/vlad-dragos
.. _#1853: https://github.com/pytest-dev/pytest/issues/1853 .. _#1853: https://github.com/pytest-dev/pytest/issues/1853
@ -4157,7 +4174,7 @@ time or change existing behaviors in order to make them less surprising/more use
* Updated docstrings with a more uniform style. * Updated docstrings with a more uniform style.
* Add stderr write for ``pytest.exit(msg)`` during startup. Previously the message was never shown. * Add stderr write for ``pytest.exit(msg)`` during startup. Previously the message was never shown.
Thanks `@BeyondEvil`_ for reporting `#1210`_. Thanks to `@JonathonSonesen`_ and Thanks `@BeyondEvil`_ for reporting `#1210`_. Thanks to `@jgsonesen`_ and
`@tomviner`_ for the PR. `@tomviner`_ for the PR.
* No longer display the incorrect test deselection reason (`#1372`_). * No longer display the incorrect test deselection reason (`#1372`_).
@ -4205,7 +4222,7 @@ time or change existing behaviors in order to make them less surprising/more use
Thanks to `@Stranger6667`_ for the PR. Thanks to `@Stranger6667`_ for the PR.
* Fixed the total tests tally in junit xml output (`#1798`_). * Fixed the total tests tally in junit xml output (`#1798`_).
Thanks to `@cryporchild`_ for the PR. Thanks to `@cboelsen`_ for the PR.
* Fixed off-by-one error with lines from ``request.node.warn``. * Fixed off-by-one error with lines from ``request.node.warn``.
Thanks to `@blueyed`_ for the PR. Thanks to `@blueyed`_ for the PR.
@ -4278,7 +4295,7 @@ time or change existing behaviors in order to make them less surprising/more use
.. _@BeyondEvil: https://github.com/BeyondEvil .. _@BeyondEvil: https://github.com/BeyondEvil
.. _@blueyed: https://github.com/blueyed .. _@blueyed: https://github.com/blueyed
.. _@ceridwen: https://github.com/ceridwen .. _@ceridwen: https://github.com/ceridwen
.. _@cryporchild: https://github.com/cryporchild .. _@cboelsen: https://github.com/cboelsen
.. _@csaftoiu: https://github.com/csaftoiu .. _@csaftoiu: https://github.com/csaftoiu
.. _@d6e: https://github.com/d6e .. _@d6e: https://github.com/d6e
.. _@davehunt: https://github.com/davehunt .. _@davehunt: https://github.com/davehunt
@ -4289,7 +4306,7 @@ time or change existing behaviors in order to make them less surprising/more use
.. _@gprasad84: https://github.com/gprasad84 .. _@gprasad84: https://github.com/gprasad84
.. _@graingert: https://github.com/graingert .. _@graingert: https://github.com/graingert
.. _@hartym: https://github.com/hartym .. _@hartym: https://github.com/hartym
.. _@JonathonSonesen: https://github.com/JonathonSonesen .. _@jgsonesen: https://github.com/jgsonesen
.. _@kalekundert: https://github.com/kalekundert .. _@kalekundert: https://github.com/kalekundert
.. _@kvas-it: https://github.com/kvas-it .. _@kvas-it: https://github.com/kvas-it
.. _@marscher: https://github.com/marscher .. _@marscher: https://github.com/marscher
@ -4426,7 +4443,7 @@ time or change existing behaviors in order to make them less surprising/more use
**Changes** **Changes**
* **Important**: `py.code <https://pylib.readthedocs.io/en/latest/code.html>`_ has been * **Important**: `py.code <https://pylib.readthedocs.io/en/stable/code.html>`_ has been
merged into the ``pytest`` repository as ``pytest._code``. This decision merged into the ``pytest`` repository as ``pytest._code``. This decision
was made because ``py.code`` had very few uses outside ``pytest`` and the was made because ``py.code`` had very few uses outside ``pytest`` and the
fact that it was in a different repository made it difficult to fix bugs on fact that it was in a different repository made it difficult to fix bugs on

View File

@ -111,13 +111,13 @@ Consult the `Changelog <https://docs.pytest.org/en/latest/changelog.html>`__ pag
Support pytest Support pytest
-------------- --------------
You can support pytest by obtaining a `Tideflift subscription`_. You can support pytest by obtaining a `Tidelift subscription`_.
Tidelift gives software development teams a single source for purchasing and maintaining their software, Tidelift gives software development teams a single source for purchasing and maintaining their software,
with professional grade assurances from the experts who know it best, while seamlessly integrating with existing tools. with professional grade assurances from the experts who know it best, while seamlessly integrating with existing tools.
.. _`Tideflift subscription`: https://tidelift.com/subscription/pkg/pypi-pytest?utm_source=pypi-pytest&utm_medium=referral&utm_campaign=readme .. _`Tidelift subscription`: https://tidelift.com/subscription/pkg/pypi-pytest?utm_source=pypi-pytest&utm_medium=referral&utm_campaign=readme
Security Security

View File

@ -0,0 +1,2 @@
Fixed internal error when test functions were patched with objects that cannot be compared
for truth values against others, like ``numpy`` arrays.

View File

@ -0,0 +1,2 @@
``pytest.exit`` is now correctly handled in ``unittest`` cases.
This makes ``unittest`` cases handle ``quit`` from pytest's pdb correctly.

View File

@ -0,0 +1 @@
Improved output when parsing an ini configuration file fails.

View File

@ -4,7 +4,7 @@
<li><a href="{{ pathto('index') }}">Home</a></li> <li><a href="{{ pathto('index') }}">Home</a></li>
<li><a href="{{ pathto('getting-started') }}">Install</a></li> <li><a href="{{ pathto('getting-started') }}">Install</a></li>
<li><a href="{{ pathto('contents') }}">Contents</a></li> <li><a href="{{ pathto('contents') }}">Contents</a></li>
<li><a href="{{ pathto('reference') }}">Reference</a></li> <li><a href="{{ pathto('reference') }}">API Reference</a></li>
<li><a href="{{ pathto('example/index') }}">Examples</a></li> <li><a href="{{ pathto('example/index') }}">Examples</a></li>
<li><a href="{{ pathto('customize') }}">Customize</a></li> <li><a href="{{ pathto('customize') }}">Customize</a></li>
<li><a href="{{ pathto('changelog') }}">Changelog</a></li> <li><a href="{{ pathto('changelog') }}">Changelog</a></li>

View File

@ -424,12 +424,56 @@ a:hover tt {
background: #EEE; background: #EEE;
} }
#reference div.section h2 {
/* separate code elements in the reference section */
border-top: 2px solid #ccc;
padding-top: 0.5em;
}
#reference div.section h3 { #reference div.section h3 {
/* separate code elements in the reference section */ /* separate code elements in the reference section */
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
padding-top: 0.5em; padding-top: 0.5em;
} }
dl.class, dl.function {
margin-top: 1em;
margin-bottom: 1em;
}
dl.class > dd {
border-left: 3px solid #ccc;
margin-left: 0px;
padding-left: 30px;
}
dl.field-list {
flex-direction: column;
}
dl.field-list dd {
padding-left: 4em;
border-left: 3px solid #ccc;
margin-bottom: 0.5em;
}
dl.field-list dd > ul {
list-style: none;
padding-left: 0px;
}
dl.field-list dd > ul > li li :first-child {
text-indent: 0;
}
dl.field-list dd > ul > li :first-child {
text-indent: -2em;
padding-left: 0px;
}
dl.field-list dd > p:first-child {
text-indent: -2em;
}
@media screen and (max-width: 870px) { @media screen and (max-width: 870px) {

View File

@ -24,11 +24,9 @@ The ideal pytest helper
- feels confident in using pytest (e.g. has explored command line options, knows how to write parametrized tests, has an idea about conftest contents) - feels confident in using pytest (e.g. has explored command line options, knows how to write parametrized tests, has an idea about conftest contents)
- does not need to be an expert in every aspect! - does not need to be an expert in every aspect!
`Pytest helpers, sign up here`_! (preferably in February, hard deadline 22 March) Pytest helpers, sign up here! (preferably in February, hard deadline 22 March)
.. _`Pytest helpers, sign up here`: http://goo.gl/forms/nxqAhqWt1P
The ideal partner project The ideal partner project
----------------------------------------- -----------------------------------------
@ -40,11 +38,9 @@ The ideal partner project
- has the support of the core development team, in trying out pytest adoption - has the support of the core development team, in trying out pytest adoption
- has no tests... or 100% test coverage... or somewhere in between! - has no tests... or 100% test coverage... or somewhere in between!
`Partner projects, sign up here`_! (by 22 March) Partner projects, sign up here! (by 22 March)
.. _`Partner projects, sign up here`: http://goo.gl/forms/ZGyqlHiwk3
What does it mean to "adopt pytest"? What does it mean to "adopt pytest"?
----------------------------------------- -----------------------------------------
@ -68,11 +64,11 @@ Progressive success might look like:
It may be after the month is up, the partner project decides that pytest is not right for it. That's okay - hopefully the pytest team will also learn something about its weaknesses or deficiencies. It may be after the month is up, the partner project decides that pytest is not right for it. That's okay - hopefully the pytest team will also learn something about its weaknesses or deficiencies.
.. _`nose and unittest`: faq.html#how-does-pytest-relate-to-nose-and-unittest .. _`nose and unittest`: faq.html#how-does-pytest-relate-to-nose-and-unittest
.. _assert: asserts.html .. _assert: assert.html
.. _pycmd: https://bitbucket.org/hpk42/pycmd/overview .. _pycmd: https://bitbucket.org/hpk42/pycmd/overview
.. _`setUp/tearDown methods`: xunit_setup.html .. _`setUp/tearDown methods`: xunit_setup.html
.. _fixtures: fixture.html .. _fixtures: fixture.html
.. _markers: markers.html .. _markers: mark.html
.. _distributed: xdist.html .. _distributed: xdist.html

View File

@ -12,7 +12,7 @@ courtesy of Benjamin Peterson. You can now safely use ``assert``
statements in test modules without having to worry about side effects statements in test modules without having to worry about side effects
or python optimization ("-OO") options. This is achieved by rewriting or python optimization ("-OO") options. This is achieved by rewriting
assert statements in test modules upon import, using a PEP302 hook. assert statements in test modules upon import, using a PEP302 hook.
See http://pytest.org/assert.html#advanced-assertion-introspection for See https://docs.pytest.org/en/latest/assert.html for
detailed information. The work has been partly sponsored by my company, detailed information. The work has been partly sponsored by my company,
merlinux GmbH. merlinux GmbH.

View File

@ -75,7 +75,7 @@ The py.test Development Team
**Changes** **Changes**
* **Important**: `py.code <https://pylib.readthedocs.io/en/latest/code.html>`_ has been * **Important**: `py.code <https://pylib.readthedocs.io/en/stable/code.html>`_ has been
merged into the ``pytest`` repository as ``pytest._code``. This decision merged into the ``pytest`` repository as ``pytest._code``. This decision
was made because ``py.code`` had very few uses outside ``pytest`` and the was made because ``py.code`` had very few uses outside ``pytest`` and the
fact that it was in a different repository made it difficult to fix bugs on fact that it was in a different repository made it difficult to fix bugs on
@ -88,7 +88,7 @@ The py.test Development Team
**experimental**, so you definitely should not import it explicitly! **experimental**, so you definitely should not import it explicitly!
Please note that the original ``py.code`` is still available in Please note that the original ``py.code`` is still available in
`pylib <https://pylib.readthedocs.io>`_. `pylib <https://pylib.readthedocs.io/en/stable/>`_.
* ``pytest_enter_pdb`` now optionally receives the pytest config object. * ``pytest_enter_pdb`` now optionally receives the pytest config object.
Thanks `@nicoddemus`_ for the PR. Thanks `@nicoddemus`_ for the PR.

View File

@ -66,8 +66,8 @@ The py.test Development Team
.. _#510: https://github.com/pytest-dev/pytest/issues/510 .. _#510: https://github.com/pytest-dev/pytest/issues/510
.. _#1506: https://github.com/pytest-dev/pytest/pull/1506 .. _#1506: https://github.com/pytest-dev/pytest/pull/1506
.. _#1496: https://github.com/pytest-dev/pytest/issue/1496 .. _#1496: https://github.com/pytest-dev/pytest/issues/1496
.. _#1524: https://github.com/pytest-dev/pytest/issue/1524 .. _#1524: https://github.com/pytest-dev/pytest/pull/1524
.. _@astraw38: https://github.com/astraw38 .. _@astraw38: https://github.com/astraw38
.. _@hackebrot: https://github.com/hackebrot .. _@hackebrot: https://github.com/hackebrot

View File

@ -552,13 +552,13 @@ Then run ``pytest`` with verbose mode and with only the ``basic`` marker:
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: $PYTHON_PREFIX/.pytest_cache cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR rootdir: $REGENDOC_TMPDIR
collecting ... collected 17 items / 14 deselected / 3 selected collecting ... collected 18 items / 15 deselected / 3 selected
test_pytest_param_example.py::test_eval[1+7-8] PASSED [ 33%] test_pytest_param_example.py::test_eval[1+7-8] PASSED [ 33%]
test_pytest_param_example.py::test_eval[basic_2+4] PASSED [ 66%] test_pytest_param_example.py::test_eval[basic_2+4] PASSED [ 66%]
test_pytest_param_example.py::test_eval[basic_6*9] XFAIL [100%] test_pytest_param_example.py::test_eval[basic_6*9] XFAIL [100%]
============ 2 passed, 14 deselected, 1 xfailed in 0.12 seconds ============ ============ 2 passed, 15 deselected, 1 xfailed in 0.12 seconds ============
As the result: As the result:

View File

@ -378,6 +378,34 @@ The ``smtp_connection`` connection will be closed after the test finished
execution because the ``smtp_connection`` object automatically closes when execution because the ``smtp_connection`` object automatically closes when
the ``with`` statement ends. the ``with`` statement ends.
Using the contextlib.ExitStack context manager finalizers will always be called
regardless if the fixture *setup* code raises an exception. This is handy to properly
close all resources created by a fixture even if one of them fails to be created/acquired:
.. code-block:: python
# content of test_yield3.py
import contextlib
import pytest
@contextlib.contextmanager
def connect(port):
... # create connection
yield
... # close connection
@pytest.fixture
def equipments():
with contextlib.ExitStack() as stack:
yield [stack.enter_context(connect(port)) for port in ("C1", "C3", "C28")]
In the example above, if ``"C28"`` fails with an exception, ``"C1"`` and ``"C3"`` will still
be properly closed.
Note that if an exception happens during the *setup* code (before the ``yield`` keyword), the Note that if an exception happens during the *setup* code (before the ``yield`` keyword), the
*teardown* code (after the ``yield``) will not be called. *teardown* code (after the ``yield``) will not be called.
@ -406,27 +434,39 @@ Here's the ``smtp_connection`` fixture changed to use ``addfinalizer`` for clean
return smtp_connection # provide the fixture value return smtp_connection # provide the fixture value
Both ``yield`` and ``addfinalizer`` methods work similarly by calling their code after the test Here's the ``equipments`` fixture changed to use ``addfinalizer`` for cleanup:
ends, but ``addfinalizer`` has two key differences over ``yield``:
1. It is possible to register multiple finalizer functions. .. code-block:: python
# content of test_yield3.py
import contextlib
import functools
import pytest
@contextlib.contextmanager
def connect(port):
... # create connection
yield
... # close connection
2. Finalizers will always be called regardless if the fixture *setup* code raises an exception.
This is handy to properly close all resources created by a fixture even if one of them
fails to be created/acquired::
@pytest.fixture @pytest.fixture
def equipments(request): def equipments(request):
r = [] r = []
for port in ('C1', 'C3', 'C28'): for port in ("C1", "C3", "C28"):
equip = connect(port) cm = connect(port)
request.addfinalizer(equip.disconnect) equip = cm.__enter__()
request.addfinalizer(functools.partial(cm.__exit__, None, None, None))
r.append(equip) r.append(equip)
return r return r
In the example above, if ``"C28"`` fails with an exception, ``"C1"`` and ``"C3"`` will still
be properly closed. Of course, if an exception happens before the finalize function is Both ``yield`` and ``addfinalizer`` methods work similarly by calling their code after the test
registered then it will not be executed. ends. Of course, if an exception happens before the finalize function is registered then it
will not be executed.
.. _`request-context`: .. _`request-context`:

View File

@ -122,4 +122,4 @@ Resources
* Google: * Google:
* `Flaky Tests at Google and How We Mitigate Them <https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html>`_ by John Micco, 2016 * `Flaky Tests at Google and How We Mitigate Them <https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html>`_ by John Micco, 2016
* `Where do Google's flaky tests come from? <https://docs.google.com/document/d/1mZ0-Kc97DI_F3tf_GBW_NB_aqka-P1jVOsFfufxqUUM/edit#heading=h.ec0r4fypsleh>`_ by Jeff Listfield, 2017 * `Where do Google's flaky tests come from? <https://testing.googleblog.com/2017/04/where-do-our-flaky-tests-come-from.html>`_ by Jeff Listfield, 2017

View File

@ -142,7 +142,7 @@ The first test passed and the second failed. You can easily see the intermediate
Request a unique temporary directory for functional tests Request a unique temporary directory for functional tests
-------------------------------------------------------------- --------------------------------------------------------------
``pytest`` provides `Builtin fixtures/function arguments <https://docs.pytest.org/en/latest/builtin.html#builtinfixtures>`_ to request arbitrary resources, like a unique temporary directory:: ``pytest`` provides `Builtin fixtures/function arguments <https://docs.pytest.org/en/latest/builtin.html>`_ to request arbitrary resources, like a unique temporary directory::
# content of test_tmpdir.py # content of test_tmpdir.py
def test_needsfiles(tmpdir): def test_needsfiles(tmpdir):

View File

@ -14,7 +14,7 @@
.. _`distribute docs`: .. _`distribute docs`:
.. _`distribute`: https://pypi.org/project/distribute/ .. _`distribute`: https://pypi.org/project/distribute/
.. _`pip`: https://pypi.org/project/pip/ .. _`pip`: https://pypi.org/project/pip/
.. _`venv`: https://docs.python.org/3/library/venv.html/ .. _`venv`: https://docs.python.org/3/library/venv.html
.. _`virtualenv`: https://pypi.org/project/virtualenv/ .. _`virtualenv`: https://pypi.org/project/virtualenv/
.. _hudson: http://hudson-ci.org/ .. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/ .. _jenkins: http://jenkins-ci.org/

View File

@ -28,7 +28,6 @@ Here are some examples of projects using ``pytest`` (please send notes via :ref:
* `sentry <https://getsentry.com/welcome/>`_, realtime app-maintenance and exception tracking * `sentry <https://getsentry.com/welcome/>`_, realtime app-maintenance and exception tracking
* `Astropy <http://www.astropy.org/>`_ and `affiliated packages <http://www.astropy.org/affiliated/index.html>`_ * `Astropy <http://www.astropy.org/>`_ and `affiliated packages <http://www.astropy.org/affiliated/index.html>`_
* `tox <http://testrun.org/tox>`_, virtualenv/Hudson integration tool * `tox <http://testrun.org/tox>`_, virtualenv/Hudson integration tool
* `PIDA <http://pida.co.uk>`_ framework for integrated development
* `PyPM <http://code.activestate.com/pypm/>`_ ActiveState's package manager * `PyPM <http://code.activestate.com/pypm/>`_ ActiveState's package manager
* `Fom <http://packages.python.org/Fom/>`_ a fluid object mapper for FluidDB * `Fom <http://packages.python.org/Fom/>`_ a fluid object mapper for FluidDB
* `applib <https://github.com/ActiveState/applib>`_ cross-platform utilities * `applib <https://github.com/ActiveState/applib>`_ cross-platform utilities
@ -37,8 +36,7 @@ Here are some examples of projects using ``pytest`` (please send notes via :ref:
* `mwlib <https://pypi.org/project/mwlib/>`_ mediawiki parser and utility library * `mwlib <https://pypi.org/project/mwlib/>`_ mediawiki parser and utility library
* `The Translate Toolkit <http://translate.sourceforge.net/wiki/toolkit/index>`_ for localization and conversion * `The Translate Toolkit <http://translate.sourceforge.net/wiki/toolkit/index>`_ for localization and conversion
* `execnet <http://codespeak.net/execnet>`_ rapid multi-Python deployment * `execnet <http://codespeak.net/execnet>`_ rapid multi-Python deployment
* `pylib <https://py.readthedocs.io>`_ cross-platform path, IO, dynamic code library * `pylib <https://pylib.readthedocs.io/en/stable/>`_ cross-platform path, IO, dynamic code library
* `Pacha <http://pacha.cafepais.com/>`_ configuration management in five minutes
* `bbfreeze <https://pypi.org/project/bbfreeze/>`_ create standalone executables from Python scripts * `bbfreeze <https://pypi.org/project/bbfreeze/>`_ create standalone executables from Python scripts
* `pdb++ <http://bitbucket.org/antocuni/pdb>`_ a fancier version of PDB * `pdb++ <http://bitbucket.org/antocuni/pdb>`_ a fancier version of PDB
* `py-s3fuse <http://code.google.com/p/py-s3fuse/>`_ Amazon S3 FUSE based filesystem * `py-s3fuse <http://code.google.com/p/py-s3fuse/>`_ Amazon S3 FUSE based filesystem
@ -77,7 +75,7 @@ Some organisations using pytest
* `Tandberg <http://www.tandberg.com/>`_ * `Tandberg <http://www.tandberg.com/>`_
* `Shootq <http://web.shootq.com/>`_ * `Shootq <http://web.shootq.com/>`_
* `Stups department of Heinrich Heine University Duesseldorf <http://www.stups.uni-duesseldorf.de/projects.php>`_ * `Stups department of Heinrich Heine University Duesseldorf <http://www.stups.uni-duesseldorf.de/projects.php>`_
* `cellzome <http://www.cellzome.com/>`_ * cellzome
* `Open End, Gothenborg <http://www.openend.se>`_ * `Open End, Gothenborg <http://www.openend.se>`_
* `Laboratory of Bioinformatics, Warsaw <http://genesilico.pl/>`_ * `Laboratory of Bioinformatics, Warsaw <http://genesilico.pl/>`_
* `merlinux, Germany <http://merlinux.eu>`_ * `merlinux, Germany <http://merlinux.eu>`_

View File

@ -1,5 +1,5 @@
Reference API Reference
========= =============
This page contains the full reference to pytest's API. This page contains the full reference to pytest's API.

View File

@ -4,9 +4,8 @@ Talks and Tutorials
.. sidebar:: Next Open Trainings .. sidebar:: Next Open Trainings
- `Training at Europython 2019 <https://ep2019.europython.eu/talks/94WEnsY-introduction-to-pytest/>`_, 8th July 2019, Basel, Switzerland.
- `Training at Workshoptage 2019 <https://workshoptage.ch/workshops/2019/test-driven-development-fuer-python-mit-pytest/>`_ (German), 10th September 2019, Rapperswil, Switzerland. - `Training at Workshoptage 2019 <https://workshoptage.ch/workshops/2019/test-driven-development-fuer-python-mit-pytest/>`_ (German), 10th September 2019, Rapperswil, Switzerland.
- `3 day hands-on workshop covering pytest, tox and devpi: "Professional Testing with Python" <https://python-academy.com/courses/specialtopics/python_course_testing.html>`_ (English), October 21 - 23, 2019, Leipzig, Germany.
.. _`funcargs`: funcargs.html .. _`funcargs`: funcargs.html

View File

@ -127,7 +127,7 @@ decorator or to all tests in a module by setting the ``pytestmark`` variable:
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_ *Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
*plugin.* *plugin.*
.. _`-W option`: https://docs.python.org/3/using/cmdline.html?highlight=#cmdoption-W .. _`-W option`: https://docs.python.org/3/using/cmdline.html#cmdoption-w
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter .. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings .. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings

View File

@ -164,7 +164,7 @@ If a package is installed this way, ``pytest`` will load
.. note:: .. note::
Make sure to include ``Framework :: Pytest`` in your list of Make sure to include ``Framework :: Pytest`` in your list of
`PyPI classifiers <https://python-packaging-user-guide.readthedocs.io/distributing/#classifiers>`_ `PyPI classifiers <https://pypi.org/classifiers/>`_
to make it easy for users to find your plugin. to make it easy for users to find your plugin.

View File

@ -64,13 +64,18 @@ def num_mock_patch_args(function):
patchings = getattr(function, "patchings", None) patchings = getattr(function, "patchings", None)
if not patchings: if not patchings:
return 0 return 0
mock_modules = [sys.modules.get("mock"), sys.modules.get("unittest.mock")]
if any(mock_modules): mock_sentinel = getattr(sys.modules.get("mock"), "DEFAULT", object())
sentinels = [m.DEFAULT for m in mock_modules if m is not None] ut_mock_sentinel = getattr(sys.modules.get("unittest.mock"), "DEFAULT", object())
return len( return len(
[p for p in patchings if not p.attribute_name and p.new in sentinels] [
p
for p in patchings
if not p.attribute_name
and (p.new is mock_sentinel or p.new is ut_mock_sentinel)
]
) )
return len(patchings)
def getfuncargnames(function, is_method=False, cls=None): def getfuncargnames(function, is_method=False, cls=None):

View File

@ -32,7 +32,11 @@ def getcfg(args, config=None):
for inibasename in inibasenames: for inibasename in inibasenames:
p = base.join(inibasename) p = base.join(inibasename)
if exists(p): if exists(p):
try:
iniconfig = py.iniconfig.IniConfig(p) iniconfig = py.iniconfig.IniConfig(p)
except py.iniconfig.ParseError as exc:
raise UsageError(str(exc))
if ( if (
inibasename == "setup.cfg" inibasename == "setup.cfg"
and "tool:pytest" in iniconfig.sections and "tool:pytest" in iniconfig.sections

View File

@ -179,9 +179,7 @@ class Mark:
@attr.s @attr.s
class MarkDecorator: class MarkDecorator:
""" A decorator for test functions and test classes. When applied """ A decorator for test functions and test classes. When applied
it will create :class:`MarkInfo` objects which may be it will create :class:`Mark` objects which are often created like this::
:ref:`retrieved by hooks as item keywords <excontrolskip>`.
MarkDecorator instances are often created like this::
mark1 = pytest.mark.NAME # simple MarkDecorator mark1 = pytest.mark.NAME # simple MarkDecorator
mark2 = pytest.mark.NAME(name1=value) # parametrized MarkDecorator mark2 = pytest.mark.NAME(name1=value) # parametrized MarkDecorator
@ -193,6 +191,7 @@ class MarkDecorator:
pass pass
When a MarkDecorator instance is called it does the following: When a MarkDecorator instance is called it does the following:
1. If called with a single class as its only positional argument and no 1. If called with a single class as its only positional argument and no
additional keyword arguments, it attaches itself to the class so it additional keyword arguments, it attaches itself to the class so it
gets applied automatically to all test cases found in that class. gets applied automatically to all test cases found in that class.

View File

@ -6,6 +6,7 @@ import _pytest._code
import pytest import pytest
from _pytest.compat import getimfunc from _pytest.compat import getimfunc
from _pytest.config import hookimpl from _pytest.config import hookimpl
from _pytest.outcomes import exit
from _pytest.outcomes import fail from _pytest.outcomes import fail
from _pytest.outcomes import skip from _pytest.outcomes import skip
from _pytest.outcomes import xfail from _pytest.outcomes import xfail
@ -153,6 +154,11 @@ class TestCaseFunction(Function):
self.__dict__.setdefault("_excinfo", []).append(excinfo) self.__dict__.setdefault("_excinfo", []).append(excinfo)
def addError(self, testcase, rawexcinfo): def addError(self, testcase, rawexcinfo):
try:
if isinstance(rawexcinfo[1], exit.Exception):
exit(rawexcinfo[1].msg)
except TypeError:
pass
self._addexcinfo(rawexcinfo) self._addexcinfo(rawexcinfo)
def addFailure(self, testcase, rawexcinfo): def addFailure(self, testcase, rawexcinfo):

View File

@ -104,21 +104,15 @@ class TestMockDecoration:
values = getfuncargnames(f) values = getfuncargnames(f)
assert values == ("x",) assert values == ("x",)
@pytest.mark.xfail( def test_getfuncargnames_patching(self):
strict=False, reason="getfuncargnames breaks if mock is imported"
)
def test_wrapped_getfuncargnames_patching(self):
from _pytest.compat import getfuncargnames from _pytest.compat import getfuncargnames
from unittest.mock import patch
def wrap(f): class T:
def func(): def original(self, x, y, z):
pass pass
func.__wrapped__ = f @patch.object(T, "original")
func.patchings = ["qwe"]
return func
@wrap
def f(x, y, z): def f(x, y, z):
pass pass
@ -126,7 +120,6 @@ class TestMockDecoration:
assert values == ("y", "z") assert values == ("y", "z")
def test_unittest_mock(self, testdir): def test_unittest_mock(self, testdir):
pytest.importorskip("unittest.mock")
testdir.makepyfile( testdir.makepyfile(
""" """
import unittest.mock import unittest.mock
@ -142,7 +135,6 @@ class TestMockDecoration:
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
def test_unittest_mock_and_fixture(self, testdir): def test_unittest_mock_and_fixture(self, testdir):
pytest.importorskip("unittest.mock")
testdir.makepyfile( testdir.makepyfile(
""" """
import os.path import os.path
@ -164,7 +156,6 @@ class TestMockDecoration:
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
def test_unittest_mock_and_pypi_mock(self, testdir): def test_unittest_mock_and_pypi_mock(self, testdir):
pytest.importorskip("unittest.mock")
pytest.importorskip("mock", "1.0.1") pytest.importorskip("mock", "1.0.1")
testdir.makepyfile( testdir.makepyfile(
""" """
@ -187,6 +178,34 @@ class TestMockDecoration:
reprec = testdir.inline_run() reprec = testdir.inline_run()
reprec.assertoutcome(passed=2) reprec.assertoutcome(passed=2)
def test_mock_sentinel_check_against_numpy_like(self, testdir):
"""Ensure our function that detects mock arguments compares against sentinels using
identity to circumvent objects which can't be compared with equality against others
in a truth context, like with numpy arrays (#5606).
"""
testdir.makepyfile(
dummy="""
class NumpyLike:
def __init__(self, value):
self.value = value
def __eq__(self, other):
raise ValueError("like numpy, cannot compare against others for truth")
FOO = NumpyLike(10)
"""
)
testdir.makepyfile(
"""
from unittest.mock import patch
import dummy
class Test(object):
@patch("dummy.FOO", new=dummy.NumpyLike(50))
def test_hello(self):
assert dummy.FOO.value == 50
"""
)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_mock(self, testdir): def test_mock(self, testdir):
pytest.importorskip("mock", "1.0.1") pytest.importorskip("mock", "1.0.1")
testdir.makepyfile( testdir.makepyfile(

View File

@ -122,6 +122,12 @@ class TestParseIni:
config = testdir.parseconfigure(sub) config = testdir.parseconfigure(sub)
assert config.getini("minversion") == "2.0" assert config.getini("minversion") == "2.0"
def test_ini_parse_error(self, testdir):
testdir.tmpdir.join("pytest.ini").write("addopts = -x")
result = testdir.runpytest()
assert result.ret != 0
result.stderr.fnmatch_lines(["ERROR: *pytest.ini:1: no section header defined"])
@pytest.mark.xfail(reason="probably not needed") @pytest.mark.xfail(reason="probably not needed")
def test_confcutdir(self, testdir): def test_confcutdir(self, testdir):
sub = testdir.mkdir("sub") sub = testdir.mkdir("sub")

View File

@ -231,8 +231,8 @@ class TestInlineRunModulesCleanup:
): ):
spy_factory = self.spy_factory() spy_factory = self.spy_factory()
monkeypatch.setattr(pytester, "SysModulesSnapshot", spy_factory) monkeypatch.setattr(pytester, "SysModulesSnapshot", spy_factory)
original = dict(sys.modules)
testdir.syspathinsert() testdir.syspathinsert()
original = dict(sys.modules)
testdir.makepyfile(import1="# you son of a silly person") testdir.makepyfile(import1="# you son of a silly person")
testdir.makepyfile(import2="# my hovercraft is full of eels") testdir.makepyfile(import2="# my hovercraft is full of eels")
test_mod = testdir.makepyfile( test_mod = testdir.makepyfile(

View File

@ -1050,3 +1050,39 @@ def test_setup_inheritance_skipping(testdir, test_name, expected_outcome):
testdir.copy_example("unittest/{}".format(test_name)) testdir.copy_example("unittest/{}".format(test_name))
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines(["* {} in *".format(expected_outcome)]) result.stdout.fnmatch_lines(["* {} in *".format(expected_outcome)])
def test_BdbQuit(testdir):
testdir.makepyfile(
test_foo="""
import unittest
class MyTestCase(unittest.TestCase):
def test_bdbquit(self):
import bdb
raise bdb.BdbQuit()
def test_should_not_run(self):
pass
"""
)
reprec = testdir.inline_run()
reprec.assertoutcome(failed=1, passed=1)
def test_exit_outcome(testdir):
testdir.makepyfile(
test_foo="""
import pytest
import unittest
class MyTestCase(unittest.TestCase):
def test_exit_outcome(self):
pytest.exit("pytest_exit called")
def test_should_not_run(self):
pass
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*Exit: pytest_exit called*", "*= no tests ran in *"])

View File

@ -133,10 +133,8 @@ filterwarnings =
ignore::pytest.RemovedInPytest4Warning ignore::pytest.RemovedInPytest4Warning
default:Using or importing the ABCs:DeprecationWarning:unittest2.* default:Using or importing the ABCs:DeprecationWarning:unittest2.*
ignore:Module already imported so cannot be rewritten:pytest.PytestWarning ignore:Module already imported so cannot be rewritten:pytest.PytestWarning
# produced by path.local # produced by python3.6/site.py itself (3.6.7 on Travis, could not trigger it with 3.6.8).
ignore:bad escape.*:DeprecationWarning:re ignore:.*U.*mode is deprecated:DeprecationWarning:(?!(pytest|_pytest))
# produced by path.readlines
ignore:.*U.*mode is deprecated:DeprecationWarning
# produced by pytest-xdist # produced by pytest-xdist
ignore:.*type argument to addoption.*:DeprecationWarning ignore:.*type argument to addoption.*:DeprecationWarning
# produced by python >=3.5 on execnet (pytest-xdist) # produced by python >=3.5 on execnet (pytest-xdist)
@ -144,6 +142,8 @@ filterwarnings =
# pytest's own futurewarnings # pytest's own futurewarnings
ignore::pytest.PytestExperimentalApiWarning ignore::pytest.PytestExperimentalApiWarning
# Do not cause SyntaxError for invalid escape sequences in py37. # Do not cause SyntaxError for invalid escape sequences in py37.
# Those are caught/handled by pyupgrade, and not easy to filter with the
# module being the filename (with .py removed).
default:invalid escape sequence:DeprecationWarning default:invalid escape sequence:DeprecationWarning
# ignore use of unregistered marks, because we use many to test the implementation # ignore use of unregistered marks, because we use many to test the implementation
ignore::_pytest.warning_types.PytestUnknownMarkWarning ignore::_pytest.warning_types.PytestUnknownMarkWarning