Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
28343bdcbd
|
@ -5,13 +5,11 @@ repos:
|
|||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
language_version: python3
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v1.0.0
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==19.3b0]
|
||||
language_version: python3
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.2.3
|
||||
hooks:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
=================
|
||||
Changelog history
|
||||
=================
|
||||
=========
|
||||
Changelog
|
||||
=========
|
||||
|
||||
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
|
||||
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
|
||||
|
@ -2173,10 +2191,10 @@ Features
|
|||
design. This introduces new ``Node.iter_markers(name)`` and
|
||||
``Node.get_closest_marker(name)`` APIs. Users are **strongly encouraged** to
|
||||
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
|
||||
<https://docs.pytest.org/en/latest/mark.html#updating-code>`_. (`#3317
|
||||
<https://github.com/pytest-dev/pytest/issues/3317>`_)
|
||||
<https://docs.pytest.org/en/latest/historical-notes.html#updating-code>`_.
|
||||
(`#3317 <https://github.com/pytest-dev/pytest/issues/3317>`_)
|
||||
|
||||
- Now when ``@pytest.fixture`` is applied more than once to the same function a
|
||||
``ValueError`` is raised. This buggy behavior would cause surprising problems
|
||||
|
@ -2582,10 +2600,10 @@ Features
|
|||
<https://github.com/pytest-dev/pytest/issues/3038>`_)
|
||||
|
||||
- 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
|
||||
`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>`_)
|
||||
|
||||
- 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.
|
||||
|
||||
* 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.
|
||||
Thanks `@omerhadari`_ for the PR.
|
||||
|
@ -3706,7 +3724,7 @@ Bug Fixes
|
|||
|
||||
.. _@syre: https://github.com/syre
|
||||
.. _@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
|
||||
.. _@dupuy: https://bitbucket.org/dupuy/
|
||||
.. _@kerrick-lyft: https://github.com/kerrick-lyft
|
||||
|
@ -3766,7 +3784,7 @@ Bug Fixes
|
|||
|
||||
.. _@adborden: https://github.com/adborden
|
||||
.. _@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
|
||||
.. _@matclab: https://github.com/matclab
|
||||
.. _@MSeifert04: https://github.com/MSeifert04
|
||||
|
@ -3801,7 +3819,7 @@ Bug Fixes
|
|||
Thanks `@axil`_ for the PR.
|
||||
|
||||
* 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
|
||||
``VersionConflict`` errors in plugins (`#704`_).
|
||||
|
@ -3811,7 +3829,6 @@ Bug Fixes
|
|||
.. _@philpep: https://github.com/philpep
|
||||
.. _@raquel-ucl: https://github.com/raquel-ucl
|
||||
.. _@axil: https://github.com/axil
|
||||
.. _@tgoodlet: https://github.com/tgoodlet
|
||||
.. _@vlad-dragos: https://github.com/vlad-dragos
|
||||
|
||||
.. _#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.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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``.
|
||||
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
|
||||
.. _@blueyed: https://github.com/blueyed
|
||||
.. _@ceridwen: https://github.com/ceridwen
|
||||
.. _@cryporchild: https://github.com/cryporchild
|
||||
.. _@cboelsen: https://github.com/cboelsen
|
||||
.. _@csaftoiu: https://github.com/csaftoiu
|
||||
.. _@d6e: https://github.com/d6e
|
||||
.. _@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
|
||||
.. _@graingert: https://github.com/graingert
|
||||
.. _@hartym: https://github.com/hartym
|
||||
.. _@JonathonSonesen: https://github.com/JonathonSonesen
|
||||
.. _@jgsonesen: https://github.com/jgsonesen
|
||||
.. _@kalekundert: https://github.com/kalekundert
|
||||
.. _@kvas-it: https://github.com/kvas-it
|
||||
.. _@marscher: https://github.com/marscher
|
||||
|
@ -4426,7 +4443,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
|||
|
||||
**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
|
||||
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
|
||||
|
|
|
@ -111,13 +111,13 @@ Consult the `Changelog <https://docs.pytest.org/en/latest/changelog.html>`__ pag
|
|||
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,
|
||||
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
|
||||
|
|
|
@ -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.
|
|
@ -0,0 +1,2 @@
|
|||
``pytest.exit`` is now correctly handled in ``unittest`` cases.
|
||||
This makes ``unittest`` cases handle ``quit`` from pytest's pdb correctly.
|
|
@ -0,0 +1 @@
|
|||
Improved output when parsing an ini configuration file fails.
|
|
@ -4,7 +4,7 @@
|
|||
<li><a href="{{ pathto('index') }}">Home</a></li>
|
||||
<li><a href="{{ pathto('getting-started') }}">Install</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('customize') }}">Customize</a></li>
|
||||
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
|
||||
|
|
|
@ -424,12 +424,56 @@ a:hover tt {
|
|||
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 {
|
||||
/* separate code elements in the reference section */
|
||||
border-top: 1px solid #ccc;
|
||||
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) {
|
||||
|
||||
|
|
|
@ -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)
|
||||
- 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
|
||||
-----------------------------------------
|
||||
|
@ -40,11 +38,9 @@ The ideal partner project
|
|||
- has the support of the core development team, in trying out pytest adoption
|
||||
- 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"?
|
||||
-----------------------------------------
|
||||
|
@ -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.
|
||||
|
||||
.. _`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
|
||||
.. _`setUp/tearDown methods`: xunit_setup.html
|
||||
.. _fixtures: fixture.html
|
||||
.. _markers: markers.html
|
||||
.. _markers: mark.html
|
||||
.. _distributed: xdist.html
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
or python optimization ("-OO") options. This is achieved by rewriting
|
||||
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,
|
||||
merlinux GmbH.
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ The py.test Development Team
|
|||
|
||||
**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
|
||||
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
|
||||
|
@ -88,7 +88,7 @@ The py.test Development Team
|
|||
**experimental**, so you definitely should not import it explicitly!
|
||||
|
||||
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.
|
||||
Thanks `@nicoddemus`_ for the PR.
|
||||
|
|
|
@ -66,8 +66,8 @@ The py.test Development Team
|
|||
|
||||
.. _#510: https://github.com/pytest-dev/pytest/issues/510
|
||||
.. _#1506: https://github.com/pytest-dev/pytest/pull/1506
|
||||
.. _#1496: https://github.com/pytest-dev/pytest/issue/1496
|
||||
.. _#1524: https://github.com/pytest-dev/pytest/issue/1524
|
||||
.. _#1496: https://github.com/pytest-dev/pytest/issues/1496
|
||||
.. _#1524: https://github.com/pytest-dev/pytest/pull/1524
|
||||
|
||||
.. _@astraw38: https://github.com/astraw38
|
||||
.. _@hackebrot: https://github.com/hackebrot
|
||||
|
|
|
@ -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
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
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[basic_2+4] PASSED [ 66%]
|
||||
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:
|
||||
|
||||
|
|
|
@ -378,6 +378,34 @@ The ``smtp_connection`` connection will be closed after the test finished
|
|||
execution because the ``smtp_connection`` object automatically closes when
|
||||
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
|
||||
*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
|
||||
|
||||
|
||||
Here's the ``equipments`` fixture changed to use ``addfinalizer`` for cleanup:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of test_yield3.py
|
||||
|
||||
import contextlib
|
||||
import functools
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def connect(port):
|
||||
... # create connection
|
||||
yield
|
||||
... # close connection
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def equipments(request):
|
||||
r = []
|
||||
for port in ("C1", "C3", "C28"):
|
||||
cm = connect(port)
|
||||
equip = cm.__enter__()
|
||||
request.addfinalizer(functools.partial(cm.__exit__, None, None, None))
|
||||
r.append(equip)
|
||||
return r
|
||||
|
||||
|
||||
Both ``yield`` and ``addfinalizer`` methods work similarly by calling their code after the test
|
||||
ends, but ``addfinalizer`` has two key differences over ``yield``:
|
||||
|
||||
1. It is possible to register multiple finalizer functions.
|
||||
|
||||
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
|
||||
def equipments(request):
|
||||
r = []
|
||||
for port in ('C1', 'C3', 'C28'):
|
||||
equip = connect(port)
|
||||
request.addfinalizer(equip.disconnect)
|
||||
r.append(equip)
|
||||
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
|
||||
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`:
|
||||
|
|
|
@ -122,4 +122,4 @@ Resources
|
|||
* 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
|
||||
* `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
|
||||
|
|
|
@ -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
|
||||
--------------------------------------------------------------
|
||||
|
||||
``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
|
||||
def test_needsfiles(tmpdir):
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
.. _`distribute docs`:
|
||||
.. _`distribute`: https://pypi.org/project/distribute/
|
||||
.. _`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/
|
||||
.. _hudson: http://hudson-ci.org/
|
||||
.. _jenkins: http://jenkins-ci.org/
|
||||
|
|
|
@ -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
|
||||
* `Astropy <http://www.astropy.org/>`_ and `affiliated packages <http://www.astropy.org/affiliated/index.html>`_
|
||||
* `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
|
||||
* `Fom <http://packages.python.org/Fom/>`_ a fluid object mapper for FluidDB
|
||||
* `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
|
||||
* `The Translate Toolkit <http://translate.sourceforge.net/wiki/toolkit/index>`_ for localization and conversion
|
||||
* `execnet <http://codespeak.net/execnet>`_ rapid multi-Python deployment
|
||||
* `pylib <https://py.readthedocs.io>`_ cross-platform path, IO, dynamic code library
|
||||
* `Pacha <http://pacha.cafepais.com/>`_ configuration management in five minutes
|
||||
* `pylib <https://pylib.readthedocs.io/en/stable/>`_ cross-platform path, IO, dynamic code library
|
||||
* `bbfreeze <https://pypi.org/project/bbfreeze/>`_ create standalone executables from Python scripts
|
||||
* `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
|
||||
|
@ -77,7 +75,7 @@ Some organisations using pytest
|
|||
* `Tandberg <http://www.tandberg.com/>`_
|
||||
* `Shootq <http://web.shootq.com/>`_
|
||||
* `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>`_
|
||||
* `Laboratory of Bioinformatics, Warsaw <http://genesilico.pl/>`_
|
||||
* `merlinux, Germany <http://merlinux.eu>`_
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Reference
|
||||
=========
|
||||
API Reference
|
||||
=============
|
||||
|
||||
This page contains the full reference to pytest's API.
|
||||
|
||||
|
|
|
@ -4,9 +4,8 @@ Talks and Tutorials
|
|||
|
||||
.. 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.
|
||||
- `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
|
||||
|
||||
|
|
|
@ -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`_
|
||||
*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
|
||||
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ If a package is installed this way, ``pytest`` will load
|
|||
.. note::
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
@ -64,13 +64,18 @@ def num_mock_patch_args(function):
|
|||
patchings = getattr(function, "patchings", None)
|
||||
if not patchings:
|
||||
return 0
|
||||
mock_modules = [sys.modules.get("mock"), sys.modules.get("unittest.mock")]
|
||||
if any(mock_modules):
|
||||
sentinels = [m.DEFAULT for m in mock_modules if m is not None]
|
||||
return len(
|
||||
[p for p in patchings if not p.attribute_name and p.new in sentinels]
|
||||
)
|
||||
return len(patchings)
|
||||
|
||||
mock_sentinel = getattr(sys.modules.get("mock"), "DEFAULT", object())
|
||||
ut_mock_sentinel = getattr(sys.modules.get("unittest.mock"), "DEFAULT", object())
|
||||
|
||||
return len(
|
||||
[
|
||||
p
|
||||
for p in patchings
|
||||
if not p.attribute_name
|
||||
and (p.new is mock_sentinel or p.new is ut_mock_sentinel)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def getfuncargnames(function, is_method=False, cls=None):
|
||||
|
|
|
@ -32,7 +32,11 @@ def getcfg(args, config=None):
|
|||
for inibasename in inibasenames:
|
||||
p = base.join(inibasename)
|
||||
if exists(p):
|
||||
iniconfig = py.iniconfig.IniConfig(p)
|
||||
try:
|
||||
iniconfig = py.iniconfig.IniConfig(p)
|
||||
except py.iniconfig.ParseError as exc:
|
||||
raise UsageError(str(exc))
|
||||
|
||||
if (
|
||||
inibasename == "setup.cfg"
|
||||
and "tool:pytest" in iniconfig.sections
|
||||
|
|
|
@ -179,9 +179,7 @@ class Mark:
|
|||
@attr.s
|
||||
class MarkDecorator:
|
||||
""" A decorator for test functions and test classes. When applied
|
||||
it will create :class:`MarkInfo` objects which may be
|
||||
:ref:`retrieved by hooks as item keywords <excontrolskip>`.
|
||||
MarkDecorator instances are often created like this::
|
||||
it will create :class:`Mark` objects which are often created like this::
|
||||
|
||||
mark1 = pytest.mark.NAME # simple MarkDecorator
|
||||
mark2 = pytest.mark.NAME(name1=value) # parametrized MarkDecorator
|
||||
|
@ -193,17 +191,18 @@ class MarkDecorator:
|
|||
pass
|
||||
|
||||
When a MarkDecorator instance is called it does the following:
|
||||
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
|
||||
gets applied automatically to all test cases found in that class.
|
||||
2. If called with a single function as its only positional argument and
|
||||
no additional keyword arguments, it attaches a MarkInfo object to the
|
||||
function, containing all the arguments already stored internally in
|
||||
the MarkDecorator.
|
||||
3. When called in any other case, it performs a 'fake construction' call,
|
||||
i.e. it returns a new MarkDecorator instance with the original
|
||||
MarkDecorator's content updated with the arguments passed to this
|
||||
call.
|
||||
|
||||
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
|
||||
gets applied automatically to all test cases found in that class.
|
||||
2. If called with a single function as its only positional argument and
|
||||
no additional keyword arguments, it attaches a MarkInfo object to the
|
||||
function, containing all the arguments already stored internally in
|
||||
the MarkDecorator.
|
||||
3. When called in any other case, it performs a 'fake construction' call,
|
||||
i.e. it returns a new MarkDecorator instance with the original
|
||||
MarkDecorator's content updated with the arguments passed to this
|
||||
call.
|
||||
|
||||
Note: The rules above prevent MarkDecorator objects from storing only a
|
||||
single function or class reference as their positional argument with no
|
||||
|
|
|
@ -542,7 +542,7 @@ def raises(expected_exception, *args, **kwargs):
|
|||
string that may contain `special characters`__, the pattern can
|
||||
first be escaped with ``re.escape``.
|
||||
|
||||
__ https://docs.python.org/3/library/re.html#regular-expression-syntax
|
||||
__ https://docs.python.org/3/library/re.html#regular-expression-syntax
|
||||
|
||||
:kwparam message: **(deprecated since 4.1)** if specified, provides a custom failure message
|
||||
if the exception is not raised. See :ref:`the deprecation docs <raises message deprecated>` for a workaround.
|
||||
|
|
|
@ -6,6 +6,7 @@ import _pytest._code
|
|||
import pytest
|
||||
from _pytest.compat import getimfunc
|
||||
from _pytest.config import hookimpl
|
||||
from _pytest.outcomes import exit
|
||||
from _pytest.outcomes import fail
|
||||
from _pytest.outcomes import skip
|
||||
from _pytest.outcomes import xfail
|
||||
|
@ -153,6 +154,11 @@ class TestCaseFunction(Function):
|
|||
self.__dict__.setdefault("_excinfo", []).append(excinfo)
|
||||
|
||||
def addError(self, testcase, rawexcinfo):
|
||||
try:
|
||||
if isinstance(rawexcinfo[1], exit.Exception):
|
||||
exit(rawexcinfo[1].msg)
|
||||
except TypeError:
|
||||
pass
|
||||
self._addexcinfo(rawexcinfo)
|
||||
|
||||
def addFailure(self, testcase, rawexcinfo):
|
||||
|
|
|
@ -104,21 +104,15 @@ class TestMockDecoration:
|
|||
values = getfuncargnames(f)
|
||||
assert values == ("x",)
|
||||
|
||||
@pytest.mark.xfail(
|
||||
strict=False, reason="getfuncargnames breaks if mock is imported"
|
||||
)
|
||||
def test_wrapped_getfuncargnames_patching(self):
|
||||
def test_getfuncargnames_patching(self):
|
||||
from _pytest.compat import getfuncargnames
|
||||
from unittest.mock import patch
|
||||
|
||||
def wrap(f):
|
||||
def func():
|
||||
class T:
|
||||
def original(self, x, y, z):
|
||||
pass
|
||||
|
||||
func.__wrapped__ = f
|
||||
func.patchings = ["qwe"]
|
||||
return func
|
||||
|
||||
@wrap
|
||||
@patch.object(T, "original")
|
||||
def f(x, y, z):
|
||||
pass
|
||||
|
||||
|
@ -126,7 +120,6 @@ class TestMockDecoration:
|
|||
assert values == ("y", "z")
|
||||
|
||||
def test_unittest_mock(self, testdir):
|
||||
pytest.importorskip("unittest.mock")
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import unittest.mock
|
||||
|
@ -142,7 +135,6 @@ class TestMockDecoration:
|
|||
reprec.assertoutcome(passed=1)
|
||||
|
||||
def test_unittest_mock_and_fixture(self, testdir):
|
||||
pytest.importorskip("unittest.mock")
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import os.path
|
||||
|
@ -164,7 +156,6 @@ class TestMockDecoration:
|
|||
reprec.assertoutcome(passed=1)
|
||||
|
||||
def test_unittest_mock_and_pypi_mock(self, testdir):
|
||||
pytest.importorskip("unittest.mock")
|
||||
pytest.importorskip("mock", "1.0.1")
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
|
@ -187,6 +178,34 @@ class TestMockDecoration:
|
|||
reprec = testdir.inline_run()
|
||||
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):
|
||||
pytest.importorskip("mock", "1.0.1")
|
||||
testdir.makepyfile(
|
||||
|
|
|
@ -122,6 +122,12 @@ class TestParseIni:
|
|||
config = testdir.parseconfigure(sub)
|
||||
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")
|
||||
def test_confcutdir(self, testdir):
|
||||
sub = testdir.mkdir("sub")
|
||||
|
|
|
@ -231,8 +231,8 @@ class TestInlineRunModulesCleanup:
|
|||
):
|
||||
spy_factory = self.spy_factory()
|
||||
monkeypatch.setattr(pytester, "SysModulesSnapshot", spy_factory)
|
||||
original = dict(sys.modules)
|
||||
testdir.syspathinsert()
|
||||
original = dict(sys.modules)
|
||||
testdir.makepyfile(import1="# you son of a silly person")
|
||||
testdir.makepyfile(import2="# my hovercraft is full of eels")
|
||||
test_mod = testdir.makepyfile(
|
||||
|
|
|
@ -1050,3 +1050,39 @@ def test_setup_inheritance_skipping(testdir, test_name, expected_outcome):
|
|||
testdir.copy_example("unittest/{}".format(test_name))
|
||||
result = testdir.runpytest()
|
||||
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 *"])
|
||||
|
|
8
tox.ini
8
tox.ini
|
@ -133,10 +133,8 @@ filterwarnings =
|
|||
ignore::pytest.RemovedInPytest4Warning
|
||||
default:Using or importing the ABCs:DeprecationWarning:unittest2.*
|
||||
ignore:Module already imported so cannot be rewritten:pytest.PytestWarning
|
||||
# produced by path.local
|
||||
ignore:bad escape.*:DeprecationWarning:re
|
||||
# produced by path.readlines
|
||||
ignore:.*U.*mode is deprecated:DeprecationWarning
|
||||
# produced by python3.6/site.py itself (3.6.7 on Travis, could not trigger it with 3.6.8).
|
||||
ignore:.*U.*mode is deprecated:DeprecationWarning:(?!(pytest|_pytest))
|
||||
# produced by pytest-xdist
|
||||
ignore:.*type argument to addoption.*:DeprecationWarning
|
||||
# produced by python >=3.5 on execnet (pytest-xdist)
|
||||
|
@ -144,6 +142,8 @@ filterwarnings =
|
|||
# pytest's own futurewarnings
|
||||
ignore::pytest.PytestExperimentalApiWarning
|
||||
# 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
|
||||
# ignore use of unregistered marks, because we use many to test the implementation
|
||||
ignore::_pytest.warning_types.PytestUnknownMarkWarning
|
||||
|
|
Loading…
Reference in New Issue