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

View File

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

View File

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

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('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>

View File

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

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

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

View File

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

View File

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

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

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
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`:

View File

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

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

View File

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

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
* `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>`_

View File

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

View File

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

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`_
*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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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