diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fce7978c4..c9940674d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -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:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index c4ab6f1bd..811f7475d 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,6 @@
-=================
-Changelog history
-=================
+=========
+Changelog
+=========
Versions follow `Semantic Versioning `_ (``..``).
@@ -90,6 +90,24 @@ Removals
- `#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
- `_,
+ `_,
or jump over to details about `updating existing code to use the new APIs
- `_. (`#3317
- `_)
+ `_.
+ (`#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
`_)
- New `pytest_runtest_logfinish
- `_
+ `_
hook which is called when a test item has finished executing, analogous to
`pytest_runtest_logstart
- `_.
+ `_.
(`#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 `_ has been
+* **Important**: `py.code `_ 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
diff --git a/README.rst b/README.rst
index 9739a1bda..301e49538 100644
--- a/README.rst
+++ b/README.rst
@@ -111,13 +111,13 @@ Consult the `Changelog `__ 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
diff --git a/changelog/5606.bugfix.rst b/changelog/5606.bugfix.rst
new file mode 100644
index 000000000..82332ba99
--- /dev/null
+++ b/changelog/5606.bugfix.rst
@@ -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.
diff --git a/changelog/5634.bugfix.rst b/changelog/5634.bugfix.rst
new file mode 100644
index 000000000..a2a282f93
--- /dev/null
+++ b/changelog/5634.bugfix.rst
@@ -0,0 +1,2 @@
+``pytest.exit`` is now correctly handled in ``unittest`` cases.
+This makes ``unittest`` cases handle ``quit`` from pytest's pdb correctly.
diff --git a/changelog/5650.bugfix.rst b/changelog/5650.bugfix.rst
new file mode 100644
index 000000000..db57a40b9
--- /dev/null
+++ b/changelog/5650.bugfix.rst
@@ -0,0 +1 @@
+Improved output when parsing an ini configuration file fails.
diff --git a/doc/en/_templates/globaltoc.html b/doc/en/_templates/globaltoc.html
index 39cebb968..50c2239e5 100644
--- a/doc/en/_templates/globaltoc.html
+++ b/doc/en/_templates/globaltoc.html
@@ -4,7 +4,7 @@
Home
Install
Contents
- Reference
+ API Reference
Examples
Customize
Changelog
diff --git a/doc/en/_themes/flask/static/flasky.css_t b/doc/en/_themes/flask/static/flasky.css_t
index ad23acf28..108c85401 100644
--- a/doc/en/_themes/flask/static/flasky.css_t
+++ b/doc/en/_themes/flask/static/flasky.css_t
@@ -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) {
diff --git a/doc/en/adopt.rst b/doc/en/adopt.rst
index 710f431be..e3c0477bc 100644
--- a/doc/en/adopt.rst
+++ b/doc/en/adopt.rst
@@ -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
diff --git a/doc/en/announce/release-2.1.0.rst b/doc/en/announce/release-2.1.0.rst
index 831548ac2..2a2181d97 100644
--- a/doc/en/announce/release-2.1.0.rst
+++ b/doc/en/announce/release-2.1.0.rst
@@ -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.
diff --git a/doc/en/announce/release-2.9.0.rst b/doc/en/announce/release-2.9.0.rst
index c079fdf6b..05d9a394f 100644
--- a/doc/en/announce/release-2.9.0.rst
+++ b/doc/en/announce/release-2.9.0.rst
@@ -75,7 +75,7 @@ The py.test Development Team
**Changes**
-* **Important**: `py.code `_ has been
+* **Important**: `py.code `_ 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 `_.
+ `pylib `_.
* ``pytest_enter_pdb`` now optionally receives the pytest config object.
Thanks `@nicoddemus`_ for the PR.
diff --git a/doc/en/announce/release-2.9.2.rst b/doc/en/announce/release-2.9.2.rst
index 8f274cdf3..b007a6d99 100644
--- a/doc/en/announce/release-2.9.2.rst
+++ b/doc/en/announce/release-2.9.2.rst
@@ -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
diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst
index 0a5ba8358..3dff2c559 100644
--- a/doc/en/example/parametrize.rst
+++ b/doc/en/example/parametrize.rst
@@ -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:
diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst
index d6c7bfd4d..40493e66f 100644
--- a/doc/en/fixture.rst
+++ b/doc/en/fixture.rst
@@ -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`:
diff --git a/doc/en/flaky.rst b/doc/en/flaky.rst
index 8e340316e..0f0eecab0 100644
--- a/doc/en/flaky.rst
+++ b/doc/en/flaky.rst
@@ -122,4 +122,4 @@ Resources
* Google:
* `Flaky Tests at Google and How We Mitigate Them `_ by John Micco, 2016
- * `Where do Google's flaky tests come from? `_ by Jeff Listfield, 2017
+ * `Where do Google's flaky tests come from? `_ by Jeff Listfield, 2017
diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst
index 750de086e..c313f3849 100644
--- a/doc/en/getting-started.rst
+++ b/doc/en/getting-started.rst
@@ -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 `_ to request arbitrary resources, like a unique temporary directory::
+``pytest`` provides `Builtin fixtures/function arguments `_ to request arbitrary resources, like a unique temporary directory::
# content of test_tmpdir.py
def test_needsfiles(tmpdir):
diff --git a/doc/en/links.inc b/doc/en/links.inc
index 1b7cbd05b..7c5e8d88c 100644
--- a/doc/en/links.inc
+++ b/doc/en/links.inc
@@ -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/
diff --git a/doc/en/projects.rst b/doc/en/projects.rst
index 606e9d47c..226358596 100644
--- a/doc/en/projects.rst
+++ b/doc/en/projects.rst
@@ -28,7 +28,6 @@ Here are some examples of projects using ``pytest`` (please send notes via :ref:
* `sentry `_, realtime app-maintenance and exception tracking
* `Astropy `_ and `affiliated packages `_
* `tox `_, virtualenv/Hudson integration tool
-* `PIDA `_ framework for integrated development
* `PyPM `_ ActiveState's package manager
* `Fom `_ a fluid object mapper for FluidDB
* `applib `_ cross-platform utilities
@@ -37,8 +36,7 @@ Here are some examples of projects using ``pytest`` (please send notes via :ref:
* `mwlib `_ mediawiki parser and utility library
* `The Translate Toolkit `_ for localization and conversion
* `execnet `_ rapid multi-Python deployment
-* `pylib `_ cross-platform path, IO, dynamic code library
-* `Pacha `_ configuration management in five minutes
+* `pylib `_ cross-platform path, IO, dynamic code library
* `bbfreeze `_ create standalone executables from Python scripts
* `pdb++ `_ a fancier version of PDB
* `py-s3fuse `_ Amazon S3 FUSE based filesystem
@@ -77,7 +75,7 @@ Some organisations using pytest
* `Tandberg `_
* `Shootq `_
* `Stups department of Heinrich Heine University Duesseldorf `_
-* `cellzome `_
+* cellzome
* `Open End, Gothenborg `_
* `Laboratory of Bioinformatics, Warsaw `_
* `merlinux, Germany `_
diff --git a/doc/en/reference.rst b/doc/en/reference.rst
index 5abb01f50..afbef6b1e 100644
--- a/doc/en/reference.rst
+++ b/doc/en/reference.rst
@@ -1,5 +1,5 @@
-Reference
-=========
+API Reference
+=============
This page contains the full reference to pytest's API.
diff --git a/doc/en/talks.rst b/doc/en/talks.rst
index 20b6e5b09..f66192817 100644
--- a/doc/en/talks.rst
+++ b/doc/en/talks.rst
@@ -4,9 +4,8 @@ Talks and Tutorials
.. sidebar:: Next Open Trainings
- - `Training at Europython 2019 `_, 8th July 2019, Basel, Switzerland.
-
- `Training at Workshoptage 2019 `_ (German), 10th September 2019, Rapperswil, Switzerland.
+ - `3 day hands-on workshop covering pytest, tox and devpi: "Professional Testing with Python" `_ (English), October 21 - 23, 2019, Leipzig, Germany.
.. _`funcargs`: funcargs.html
diff --git a/doc/en/warnings.rst b/doc/en/warnings.rst
index c2b256bb3..382f15928 100644
--- a/doc/en/warnings.rst
+++ b/doc/en/warnings.rst
@@ -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
diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst
index 4bbc1afce..67a8fcecf 100644
--- a/doc/en/writing_plugins.rst
+++ b/doc/en/writing_plugins.rst
@@ -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 `_
+ `PyPI classifiers `_
to make it easy for users to find your plugin.
diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py
index d238061b4..52ffc36bc 100644
--- a/src/_pytest/compat.py
+++ b/src/_pytest/compat.py
@@ -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):
diff --git a/src/_pytest/config/findpaths.py b/src/_pytest/config/findpaths.py
index fa2024470..3f91bbd07 100644
--- a/src/_pytest/config/findpaths.py
+++ b/src/_pytest/config/findpaths.py
@@ -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
diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py
index 0887d6b9c..2fb6ad851 100644
--- a/src/_pytest/mark/structures.py
+++ b/src/_pytest/mark/structures.py
@@ -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 `.
- 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
diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py
index cbd833946..bd0f4d59f 100644
--- a/src/_pytest/python_api.py
+++ b/src/_pytest/python_api.py
@@ -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 ` for a workaround.
diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py
index 216266979..337490d13 100644
--- a/src/_pytest/unittest.py
+++ b/src/_pytest/unittest.py
@@ -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):
diff --git a/testing/python/integration.py b/testing/python/integration.py
index 0b87fea33..73419eef4 100644
--- a/testing/python/integration.py
+++ b/testing/python/integration.py
@@ -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(
diff --git a/testing/test_config.py b/testing/test_config.py
index ff993e401..c1a58848a 100644
--- a/testing/test_config.py
+++ b/testing/test_config.py
@@ -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")
diff --git a/testing/test_pytester.py b/testing/test_pytester.py
index 37b63f31a..ba3135f65 100644
--- a/testing/test_pytester.py
+++ b/testing/test_pytester.py
@@ -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(
diff --git a/testing/test_unittest.py b/testing/test_unittest.py
index 2467ddd39..ec5f92e18 100644
--- a/testing/test_unittest.py
+++ b/testing/test_unittest.py
@@ -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 *"])
diff --git a/tox.ini b/tox.ini
index 95c49db04..52d400524 100644
--- a/tox.ini
+++ b/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