Merge remote-tracking branch 'upstream/master' into merge-master-into-features
This commit is contained in:
commit
1101a20408
6
AUTHORS
6
AUTHORS
|
@ -10,6 +10,7 @@ Ahn Ki-Wook
|
||||||
Alan Velasco
|
Alan Velasco
|
||||||
Alexander Johnson
|
Alexander Johnson
|
||||||
Alexei Kozlenok
|
Alexei Kozlenok
|
||||||
|
Allan Feldman
|
||||||
Anatoly Bubenkoff
|
Anatoly Bubenkoff
|
||||||
Anders Hovmöller
|
Anders Hovmöller
|
||||||
Andras Tim
|
Andras Tim
|
||||||
|
@ -94,6 +95,7 @@ Hui Wang (coldnight)
|
||||||
Ian Bicking
|
Ian Bicking
|
||||||
Ian Lesperance
|
Ian Lesperance
|
||||||
Ionuț Turturică
|
Ionuț Turturică
|
||||||
|
Iwan Briquemont
|
||||||
Jaap Broekhuizen
|
Jaap Broekhuizen
|
||||||
Jan Balster
|
Jan Balster
|
||||||
Janne Vanhala
|
Janne Vanhala
|
||||||
|
@ -179,6 +181,7 @@ Raphael Pierzina
|
||||||
Raquel Alegre
|
Raquel Alegre
|
||||||
Ravi Chandra
|
Ravi Chandra
|
||||||
Roberto Polli
|
Roberto Polli
|
||||||
|
Roland Puntaier
|
||||||
Romain Dorgueil
|
Romain Dorgueil
|
||||||
Roman Bolshakov
|
Roman Bolshakov
|
||||||
Ronny Pfannschmidt
|
Ronny Pfannschmidt
|
||||||
|
@ -223,6 +226,5 @@ Wim Glenn
|
||||||
Wouter van Ackooy
|
Wouter van Ackooy
|
||||||
Xuan Luong
|
Xuan Luong
|
||||||
Xuecong Liao
|
Xuecong Liao
|
||||||
|
Zac Hatfield-Dodds
|
||||||
Zoltán Máté
|
Zoltán Máté
|
||||||
Roland Puntaier
|
|
||||||
Allan Feldman
|
|
||||||
|
|
|
@ -18,6 +18,58 @@ with advance notice in the **Deprecations** section of releases.
|
||||||
|
|
||||||
.. towncrier release notes start
|
.. towncrier release notes start
|
||||||
|
|
||||||
|
pytest 3.8.2 (2018-10-02)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Deprecations and Removals
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- `#4036 <https://github.com/pytest-dev/pytest/issues/4036>`_: The ``item`` parameter of ``pytest_warning_captured`` hook is now documented as deprecated. We realized only after
|
||||||
|
the ``3.8`` release that this parameter is incompatible with ``pytest-xdist``.
|
||||||
|
|
||||||
|
Our policy is to not deprecate features during bugfix releases, but in this case we believe it makes sense as we are
|
||||||
|
only documenting it as deprecated, without issuing warnings which might potentially break test suites. This will get
|
||||||
|
the word out that hook implementers should not use this parameter at all.
|
||||||
|
|
||||||
|
In a future release ``item`` will always be ``None`` and will emit a proper warning when a hook implementation
|
||||||
|
makes use of it.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `#3539 <https://github.com/pytest-dev/pytest/issues/3539>`_: Fix reload on assertion rewritten modules.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4034 <https://github.com/pytest-dev/pytest/issues/4034>`_: The ``.user_properties`` attribute of ``TestReport`` objects is a list
|
||||||
|
of (name, value) tuples, but could sometimes be instantiated as a tuple
|
||||||
|
of tuples. It is now always a list.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4039 <https://github.com/pytest-dev/pytest/issues/4039>`_: No longer issue warnings about using ``pytest_plugins`` in non-top-level directories when using ``--pyargs``: the
|
||||||
|
current ``--pyargs`` mechanism is not reliable and might give false negatives.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4040 <https://github.com/pytest-dev/pytest/issues/4040>`_: Exclude empty reports for passed tests when ``-rP`` option is used.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4051 <https://github.com/pytest-dev/pytest/issues/4051>`_: Improve error message when an invalid Python expression is passed to the ``-m`` option.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4056 <https://github.com/pytest-dev/pytest/issues/4056>`_: ``MonkeyPatch.setenv`` and ``MonkeyPatch.delenv`` issue a warning if the environment variable name is not ``str`` on Python 2.
|
||||||
|
|
||||||
|
In Python 2, adding ``unicode`` keys to ``os.environ`` causes problems with ``subprocess`` (and possible other modules),
|
||||||
|
making this a subtle bug specially susceptible when used with ``from __future__ import unicode_literals``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Improved Documentation
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- `#3928 <https://github.com/pytest-dev/pytest/issues/3928>`_: Add possible values for fixture scope to docs.
|
||||||
|
|
||||||
|
|
||||||
pytest 3.8.1 (2018-09-22)
|
pytest 3.8.1 (2018-09-22)
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ Release announcements
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|
||||||
|
release-3.8.2
|
||||||
release-3.8.1
|
release-3.8.1
|
||||||
release-3.8.0
|
release-3.8.0
|
||||||
release-3.7.4
|
release-3.7.4
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
pytest-3.8.2
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
pytest 3.8.2 has just been released to PyPI.
|
||||||
|
|
||||||
|
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||||
|
|
||||||
|
pip install --upgrade pytest
|
||||||
|
|
||||||
|
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
|
||||||
|
|
||||||
|
Thanks to all who contributed to this release, among them:
|
||||||
|
|
||||||
|
* Ankit Goel
|
||||||
|
* Anthony Sottile
|
||||||
|
* Bruno Oliveira
|
||||||
|
* Daniel Hahler
|
||||||
|
* Denis Otkidach
|
||||||
|
* Harry Percival
|
||||||
|
* Jeffrey Rackauckas
|
||||||
|
* Jose Carlos Menezes
|
||||||
|
* Ronny Pfannschmidt
|
||||||
|
* Zac-HD
|
||||||
|
* iwanb
|
||||||
|
|
||||||
|
|
||||||
|
Happy testing,
|
||||||
|
The pytest Development Team
|
|
@ -264,8 +264,12 @@ Advanced assertion introspection
|
||||||
Reporting details about a failing assertion is achieved by rewriting assert
|
Reporting details about a failing assertion is achieved by rewriting assert
|
||||||
statements before they are run. Rewritten assert statements put introspection
|
statements before they are run. Rewritten assert statements put introspection
|
||||||
information into the assertion failure message. ``pytest`` only rewrites test
|
information into the assertion failure message. ``pytest`` only rewrites test
|
||||||
modules directly discovered by its test collection process, so asserts in
|
modules directly discovered by its test collection process, so **asserts in
|
||||||
supporting modules which are not themselves test modules will not be rewritten.
|
supporting modules which are not themselves test modules will not be rewritten**.
|
||||||
|
|
||||||
|
You can manually enable assertion rewriting for an imported module by calling
|
||||||
|
`register_assert_rewrite <https://docs.pytest.org/en/latest/writing_plugins.html#assertion-rewriting>`_
|
||||||
|
before you import it (a good place to do that is in ``conftest.py``).
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
|
@ -83,14 +83,24 @@ message please contact the authors so they can change the code.
|
||||||
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
|
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
|
||||||
system for its own warnings, so those two functions are now deprecated.
|
system for its own warnings, so those two functions are now deprecated.
|
||||||
|
|
||||||
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``.
|
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``, example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
config.warn("C1", "some warning")
|
||||||
|
|
||||||
|
Becomes:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
warnings.warn(pytest.PytestWarning("some warning"))
|
||||||
|
|
||||||
``Node.warn`` now supports two signatures:
|
``Node.warn`` now supports two signatures:
|
||||||
|
|
||||||
* ``node.warn(PytestWarning("some message"))``: is now the recommended way to call this function.
|
* ``node.warn(PytestWarning("some message"))``: is now the **recommended** way to call this function.
|
||||||
The warning instance must be a PytestWarning or subclass.
|
The warning instance must be a PytestWarning or subclass.
|
||||||
|
|
||||||
* ``node.warn("CI", "some message")``: this code/message form is now deprecated and should be converted to the warning instance form above.
|
* ``node.warn("CI", "some message")``: this code/message form is now **deprecated** and should be converted to the warning instance form above.
|
||||||
|
|
||||||
|
|
||||||
``pytest_namespace``
|
``pytest_namespace``
|
||||||
|
|
|
@ -31,7 +31,7 @@ You can then restrict a test run to only run tests marked with ``webtest``::
|
||||||
|
|
||||||
$ pytest -v -m webtest
|
$ pytest -v -m webtest
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 4 items / 3 deselected
|
collecting ... collected 4 items / 3 deselected
|
||||||
|
@ -44,7 +44,7 @@ Or the inverse, running all tests except the webtest ones::
|
||||||
|
|
||||||
$ pytest -v -m "not webtest"
|
$ pytest -v -m "not webtest"
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 4 items / 1 deselected
|
collecting ... collected 4 items / 1 deselected
|
||||||
|
@ -64,7 +64,7 @@ tests based on their module, class, method, or function name::
|
||||||
|
|
||||||
$ pytest -v test_server.py::TestClass::test_method
|
$ pytest -v test_server.py::TestClass::test_method
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 1 item
|
collecting ... collected 1 item
|
||||||
|
@ -77,7 +77,7 @@ You can also select on the class::
|
||||||
|
|
||||||
$ pytest -v test_server.py::TestClass
|
$ pytest -v test_server.py::TestClass
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 1 item
|
collecting ... collected 1 item
|
||||||
|
@ -90,7 +90,7 @@ Or select multiple nodes::
|
||||||
|
|
||||||
$ pytest -v test_server.py::TestClass test_server.py::test_send_http
|
$ pytest -v test_server.py::TestClass test_server.py::test_send_http
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 2 items
|
collecting ... collected 2 items
|
||||||
|
@ -128,7 +128,7 @@ select tests based on their names::
|
||||||
|
|
||||||
$ pytest -v -k http # running with the above defined example module
|
$ pytest -v -k http # running with the above defined example module
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 4 items / 3 deselected
|
collecting ... collected 4 items / 3 deselected
|
||||||
|
@ -141,7 +141,7 @@ And you can also run all tests except the ones that match the keyword::
|
||||||
|
|
||||||
$ pytest -k "not send_http" -v
|
$ pytest -k "not send_http" -v
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 4 items / 1 deselected
|
collecting ... collected 4 items / 1 deselected
|
||||||
|
@ -156,7 +156,7 @@ Or to select "http" and "quick" tests::
|
||||||
|
|
||||||
$ pytest -k "http or quick" -v
|
$ pytest -k "http or quick" -v
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 4 items / 2 deselected
|
collecting ... collected 4 items / 2 deselected
|
||||||
|
|
|
@ -59,7 +59,7 @@ consulted when reporting in ``verbose`` mode::
|
||||||
|
|
||||||
nonpython $ pytest -v
|
nonpython $ pytest -v
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
|
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
|
||||||
collecting ... collected 2 items
|
collecting ... collected 2 items
|
||||||
|
|
|
@ -411,11 +411,10 @@ is to be run with different sets of arguments for its three arguments:
|
||||||
Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize)::
|
Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize)::
|
||||||
|
|
||||||
. $ pytest -rs -q multipython.py
|
. $ pytest -rs -q multipython.py
|
||||||
...ssssssssssssssssssssssss [100%]
|
...sss...sssssssss...sss... [100%]
|
||||||
========================= short test summary info ==========================
|
========================= short test summary info ==========================
|
||||||
SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.4' not found
|
SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.4' not found
|
||||||
SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.5' not found
|
12 passed, 15 skipped in 0.12 seconds
|
||||||
3 passed, 24 skipped in 0.12 seconds
|
|
||||||
|
|
||||||
Indirect parametrization of optional implementations/imports
|
Indirect parametrization of optional implementations/imports
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
|
|
|
@ -357,7 +357,7 @@ which will add info only when run with "--v"::
|
||||||
|
|
||||||
$ pytest -v
|
$ pytest -v
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
info1: did you know that ...
|
info1: did you know that ...
|
||||||
did you?
|
did you?
|
||||||
|
|
|
@ -171,6 +171,7 @@ to cause the decorated ``smtp_connection`` fixture function to only be invoked
|
||||||
once per test *module* (the default is to invoke once per test *function*).
|
once per test *module* (the default is to invoke once per test *function*).
|
||||||
Multiple test functions in a test module will thus
|
Multiple test functions in a test module will thus
|
||||||
each receive the same ``smtp_connection`` fixture instance, thus saving time.
|
each receive the same ``smtp_connection`` fixture instance, thus saving time.
|
||||||
|
Possible values for ``scope`` are: ``function``, ``class``, ``module``, ``package`` or ``session``.
|
||||||
|
|
||||||
The next example puts the fixture function into a separate ``conftest.py`` file
|
The next example puts the fixture function into a separate ``conftest.py`` file
|
||||||
so that tests from multiple test modules in the directory can
|
so that tests from multiple test modules in the directory can
|
||||||
|
@ -726,7 +727,7 @@ Running this test will *skip* the invocation of ``data_set`` with value ``2``::
|
||||||
|
|
||||||
$ pytest test_fixture_marks.py -v
|
$ pytest test_fixture_marks.py -v
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 3 items
|
collecting ... collected 3 items
|
||||||
|
@ -769,7 +770,7 @@ Here we declare an ``app`` fixture which receives the previously defined
|
||||||
|
|
||||||
$ pytest -v test_appsetup.py
|
$ pytest -v test_appsetup.py
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 2 items
|
collecting ... collected 2 items
|
||||||
|
@ -838,7 +839,7 @@ Let's run the tests in verbose mode and with looking at the print-output::
|
||||||
|
|
||||||
$ pytest -v -s test_module.py
|
$ pytest -v -s test_module.py
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 8 items
|
collecting ... collected 8 items
|
||||||
|
|
|
@ -255,7 +255,7 @@ Pytest supports the use of ``breakpoint()`` with the following behaviours:
|
||||||
|
|
||||||
- When ``breakpoint()`` is called and ``PYTHONBREAKPOINT`` is set to the default value, pytest will use the custom internal PDB trace UI instead of the system default ``Pdb``.
|
- When ``breakpoint()`` is called and ``PYTHONBREAKPOINT`` is set to the default value, pytest will use the custom internal PDB trace UI instead of the system default ``Pdb``.
|
||||||
- When tests are complete, the system will default back to the system ``Pdb`` trace UI.
|
- When tests are complete, the system will default back to the system ``Pdb`` trace UI.
|
||||||
- If ``--pdb`` is called on execution of pytest, the custom internal Pdb trace UI is used on ``bothbreakpoint()`` and failed tests/unhandled exceptions.
|
- If ``--pdb`` is called on execution of pytest, the custom internal Pdb trace UI is used on both ``breakpoint()`` and failed tests/unhandled exceptions.
|
||||||
- If ``--pdbcls`` is used, the custom class debugger will be executed when a test fails (as expected within existing behaviour), but also when ``breakpoint()`` is called from within a test, the custom class debugger will be instantiated.
|
- If ``--pdbcls`` is used, the custom class debugger will be executed when a test fails (as expected within existing behaviour), but also when ``breakpoint()`` is called from within a test, the custom class debugger will be instantiated.
|
||||||
|
|
||||||
.. _durations:
|
.. _durations:
|
||||||
|
|
|
@ -269,13 +269,13 @@ class AssertionRewritingHook(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
def load_module(self, name):
|
def load_module(self, name):
|
||||||
|
co, pyc = self.modules.pop(name)
|
||||||
|
if name in sys.modules:
|
||||||
# If there is an existing module object named 'fullname' in
|
# If there is an existing module object named 'fullname' in
|
||||||
# sys.modules, the loader must use that existing module. (Otherwise,
|
# sys.modules, the loader must use that existing module. (Otherwise,
|
||||||
# the reload() builtin will not work correctly.)
|
# the reload() builtin will not work correctly.)
|
||||||
if name in sys.modules:
|
mod = sys.modules[name]
|
||||||
return sys.modules[name]
|
else:
|
||||||
|
|
||||||
co, pyc = self.modules.pop(name)
|
|
||||||
# I wish I could just call imp.load_compiled here, but __file__ has to
|
# I wish I could just call imp.load_compiled here, but __file__ has to
|
||||||
# be set properly. In Python 3.2+, this all would be handled correctly
|
# be set properly. In Python 3.2+, this all would be handled correctly
|
||||||
# by load_compiled.
|
# by load_compiled.
|
||||||
|
|
|
@ -351,6 +351,7 @@ class PytestPluginManager(PluginManager):
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
self._noconftest = namespace.noconftest
|
self._noconftest = namespace.noconftest
|
||||||
|
self._using_pyargs = namespace.pyargs
|
||||||
testpaths = namespace.file_or_dir
|
testpaths = namespace.file_or_dir
|
||||||
foundanchor = False
|
foundanchor = False
|
||||||
for path in testpaths:
|
for path in testpaths:
|
||||||
|
@ -416,7 +417,11 @@ class PytestPluginManager(PluginManager):
|
||||||
_ensure_removed_sysmodule(conftestpath.purebasename)
|
_ensure_removed_sysmodule(conftestpath.purebasename)
|
||||||
try:
|
try:
|
||||||
mod = conftestpath.pyimport()
|
mod = conftestpath.pyimport()
|
||||||
if hasattr(mod, "pytest_plugins") and self._configured:
|
if (
|
||||||
|
hasattr(mod, "pytest_plugins")
|
||||||
|
and self._configured
|
||||||
|
and not self._using_pyargs
|
||||||
|
):
|
||||||
from _pytest.deprecated import (
|
from _pytest.deprecated import (
|
||||||
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
)
|
)
|
||||||
|
|
|
@ -562,6 +562,9 @@ def pytest_warning_captured(warning_message, when, item):
|
||||||
* ``"runtest"``: during test execution.
|
* ``"runtest"``: during test execution.
|
||||||
|
|
||||||
:param pytest.Item|None item:
|
:param pytest.Item|None item:
|
||||||
|
**DEPRECATED**: This parameter is incompatible with ``pytest-xdist``, and will always receive ``None``
|
||||||
|
in a future release.
|
||||||
|
|
||||||
The item being executed if ``when`` is ``"runtest"``, otherwise ``None``.
|
The item being executed if ``when`` is ``"runtest"``, otherwise ``None``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,10 @@ python_keywords_allowed_list = ["or", "and", "not"]
|
||||||
|
|
||||||
def matchmark(colitem, markexpr):
|
def matchmark(colitem, markexpr):
|
||||||
"""Tries to match on any marker names, attached to the given colitem."""
|
"""Tries to match on any marker names, attached to the given colitem."""
|
||||||
|
try:
|
||||||
return eval(markexpr, {}, MarkMapping.from_item(colitem))
|
return eval(markexpr, {}, MarkMapping.from_item(colitem))
|
||||||
|
except SyntaxError as e:
|
||||||
|
raise SyntaxError(str(e) + "\nMarker expression must be valid Python!")
|
||||||
|
|
||||||
|
|
||||||
def matchkeyword(colitem, keywordexpr):
|
def matchkeyword(colitem, keywordexpr):
|
||||||
|
|
|
@ -4,9 +4,12 @@ from __future__ import absolute_import, division, print_function
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
import warnings
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
import pytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
|
|
||||||
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
|
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
|
||||||
|
@ -209,13 +212,31 @@ class MonkeyPatch(object):
|
||||||
self._setitem.append((dic, name, dic.get(name, notset)))
|
self._setitem.append((dic, name, dic.get(name, notset)))
|
||||||
del dic[name]
|
del dic[name]
|
||||||
|
|
||||||
|
def _warn_if_env_name_is_not_str(self, name):
|
||||||
|
"""On Python 2, warn if the given environment variable name is not a native str (#4056)"""
|
||||||
|
if six.PY2 and not isinstance(name, str):
|
||||||
|
warnings.warn(
|
||||||
|
pytest.PytestWarning(
|
||||||
|
"Environment variable name {!r} should be str".format(name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def setenv(self, name, value, prepend=None):
|
def setenv(self, name, value, prepend=None):
|
||||||
""" Set environment variable ``name`` to ``value``. If ``prepend``
|
""" Set environment variable ``name`` to ``value``. If ``prepend``
|
||||||
is a character, read the current environment variable value
|
is a character, read the current environment variable value
|
||||||
and prepend the ``value`` adjoined with the ``prepend`` character."""
|
and prepend the ``value`` adjoined with the ``prepend`` character."""
|
||||||
|
if not isinstance(value, str):
|
||||||
|
warnings.warn(
|
||||||
|
pytest.PytestWarning(
|
||||||
|
"Environment variable value {!r} should be str, converted to str implicitly".format(
|
||||||
|
value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
value = str(value)
|
value = str(value)
|
||||||
if prepend and name in os.environ:
|
if prepend and name in os.environ:
|
||||||
value = value + prepend + os.environ[name]
|
value = value + prepend + os.environ[name]
|
||||||
|
self._warn_if_env_name_is_not_str(name)
|
||||||
self.setitem(os.environ, name, value)
|
self.setitem(os.environ, name, value)
|
||||||
|
|
||||||
def delenv(self, name, raising=True):
|
def delenv(self, name, raising=True):
|
||||||
|
@ -225,6 +246,7 @@ class MonkeyPatch(object):
|
||||||
If ``raising`` is set to False, no exception will be raised if the
|
If ``raising`` is set to False, no exception will be raised if the
|
||||||
environment variable is missing.
|
environment variable is missing.
|
||||||
"""
|
"""
|
||||||
|
self._warn_if_env_name_is_not_str(name)
|
||||||
self.delitem(os.environ, name, raising=raising)
|
self.delitem(os.environ, name, raising=raising)
|
||||||
|
|
||||||
def syspath_prepend(self, path):
|
def syspath_prepend(self, path):
|
||||||
|
|
|
@ -212,6 +212,8 @@ class WarningsChecker(WarningsRecorder):
|
||||||
def __exit__(self, *exc_info):
|
def __exit__(self, *exc_info):
|
||||||
super(WarningsChecker, self).__exit__(*exc_info)
|
super(WarningsChecker, self).__exit__(*exc_info)
|
||||||
|
|
||||||
|
__tracebackhide__ = True
|
||||||
|
|
||||||
# only check if we're not currently handling an exception
|
# only check if we're not currently handling an exception
|
||||||
if all(a is None for a in exc_info):
|
if all(a is None for a in exc_info):
|
||||||
if self.expected_warning is not None:
|
if self.expected_warning is not None:
|
||||||
|
|
|
@ -110,7 +110,7 @@ class TestReport(BaseReport):
|
||||||
when,
|
when,
|
||||||
sections=(),
|
sections=(),
|
||||||
duration=0,
|
duration=0,
|
||||||
user_properties=(),
|
user_properties=None,
|
||||||
**extra
|
**extra
|
||||||
):
|
):
|
||||||
#: normalized collection node id
|
#: normalized collection node id
|
||||||
|
@ -136,7 +136,7 @@ class TestReport(BaseReport):
|
||||||
|
|
||||||
#: user properties is a list of tuples (name, value) that holds user
|
#: user properties is a list of tuples (name, value) that holds user
|
||||||
#: defined properties of the test
|
#: defined properties of the test
|
||||||
self.user_properties = user_properties
|
self.user_properties = list(user_properties or [])
|
||||||
|
|
||||||
#: list of pairs ``(str, str)`` of extra information which needs to
|
#: list of pairs ``(str, str)`` of extra information which needs to
|
||||||
#: marshallable. Used by pytest to add captured text
|
#: marshallable. Used by pytest to add captured text
|
||||||
|
|
|
@ -745,6 +745,7 @@ class TerminalReporter(object):
|
||||||
return
|
return
|
||||||
self.write_sep("=", "PASSES")
|
self.write_sep("=", "PASSES")
|
||||||
for rep in reports:
|
for rep in reports:
|
||||||
|
if rep.sections:
|
||||||
msg = self._getfailureheadline(rep)
|
msg = self._getfailureheadline(rep)
|
||||||
self.write_sep("_", msg)
|
self.write_sep("_", msg)
|
||||||
self._outrep_summary(rep)
|
self._outrep_summary(rep)
|
||||||
|
|
|
@ -577,7 +577,7 @@ class TestInvocationVariants(object):
|
||||||
return what
|
return what
|
||||||
|
|
||||||
empty_package = testdir.mkpydir("empty_package")
|
empty_package = testdir.mkpydir("empty_package")
|
||||||
monkeypatch.setenv("PYTHONPATH", join_pythonpath(empty_package))
|
monkeypatch.setenv("PYTHONPATH", str(join_pythonpath(empty_package)))
|
||||||
# the path which is not a package raises a warning on pypy;
|
# the path which is not a package raises a warning on pypy;
|
||||||
# no idea why only pypy and not normal python warn about it here
|
# no idea why only pypy and not normal python warn about it here
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
|
@ -586,7 +586,7 @@ class TestInvocationVariants(object):
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
result.stdout.fnmatch_lines(["*2 passed*"])
|
result.stdout.fnmatch_lines(["*2 passed*"])
|
||||||
|
|
||||||
monkeypatch.setenv("PYTHONPATH", join_pythonpath(testdir))
|
monkeypatch.setenv("PYTHONPATH", str(join_pythonpath(testdir)))
|
||||||
result = testdir.runpytest("--pyargs", "tpkg.test_missing", syspathinsert=True)
|
result = testdir.runpytest("--pyargs", "tpkg.test_missing", syspathinsert=True)
|
||||||
assert result.ret != 0
|
assert result.ret != 0
|
||||||
result.stderr.fnmatch_lines(["*not*found*test_missing*"])
|
result.stderr.fnmatch_lines(["*not*found*test_missing*"])
|
||||||
|
|
|
@ -129,7 +129,7 @@ def test_source_strip_multiline():
|
||||||
def test_syntaxerror_rerepresentation():
|
def test_syntaxerror_rerepresentation():
|
||||||
ex = pytest.raises(SyntaxError, _pytest._code.compile, "xyz xyz")
|
ex = pytest.raises(SyntaxError, _pytest._code.compile, "xyz xyz")
|
||||||
assert ex.value.lineno == 1
|
assert ex.value.lineno == 1
|
||||||
assert ex.value.offset in (4, 7) # XXX pypy/jython versus cpython?
|
assert ex.value.offset in (4, 5, 7) # XXX pypy/jython versus cpython?
|
||||||
assert ex.value.text.strip(), "x x"
|
assert ex.value.text.strip(), "x x"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -246,21 +246,12 @@ def test_pytest_catchlog_deprecated(testdir, plugin):
|
||||||
def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
|
def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
|
||||||
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
|
|
||||||
subdirectory = testdir.tmpdir.join("subdirectory")
|
testdir.makepyfile(
|
||||||
subdirectory.mkdir()
|
**{
|
||||||
# create the inner conftest with makeconftest and then move it to the subdirectory
|
"subdirectory/conftest.py": """
|
||||||
testdir.makeconftest(
|
|
||||||
"""
|
|
||||||
pytest_plugins=['capture']
|
pytest_plugins=['capture']
|
||||||
"""
|
"""
|
||||||
)
|
}
|
||||||
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
|
|
||||||
# make the top level conftest
|
|
||||||
testdir.makeconftest(
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
warnings.filterwarnings('always', category=DeprecationWarning)
|
|
||||||
"""
|
|
||||||
)
|
)
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
@ -268,7 +259,7 @@ def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
|
||||||
pass
|
pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
res = testdir.runpytest_subprocess()
|
res = testdir.runpytest()
|
||||||
assert res.ret == 0
|
assert res.ret == 0
|
||||||
msg = str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
|
msg = str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
|
||||||
res.stdout.fnmatch_lines(
|
res.stdout.fnmatch_lines(
|
||||||
|
@ -278,6 +269,34 @@ def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("use_pyargs", [True, False])
|
||||||
|
def test_pytest_plugins_in_non_top_level_conftest_deprecated_pyargs(
|
||||||
|
testdir, use_pyargs
|
||||||
|
):
|
||||||
|
"""When using --pyargs, do not emit the warning about non-top-level conftest warnings (#4039, #4044)"""
|
||||||
|
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
|
|
||||||
|
files = {
|
||||||
|
"src/pkg/__init__.py": "",
|
||||||
|
"src/pkg/conftest.py": "",
|
||||||
|
"src/pkg/test_root.py": "def test(): pass",
|
||||||
|
"src/pkg/sub/__init__.py": "",
|
||||||
|
"src/pkg/sub/conftest.py": "pytest_plugins=['capture']",
|
||||||
|
"src/pkg/sub/test_bar.py": "def test(): pass",
|
||||||
|
}
|
||||||
|
testdir.makepyfile(**files)
|
||||||
|
testdir.syspathinsert(testdir.tmpdir.join("src"))
|
||||||
|
|
||||||
|
args = ("--pyargs", "pkg") if use_pyargs else ()
|
||||||
|
res = testdir.runpytest(*args)
|
||||||
|
assert res.ret == 0
|
||||||
|
msg = str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
|
||||||
|
if use_pyargs:
|
||||||
|
assert msg not in res.stdout.str()
|
||||||
|
else:
|
||||||
|
res.stdout.fnmatch_lines("*{msg}*".format(msg=msg))
|
||||||
|
|
||||||
|
|
||||||
def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_top_level_conftest(
|
def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_top_level_conftest(
|
||||||
testdir
|
testdir
|
||||||
):
|
):
|
||||||
|
|
|
@ -1050,6 +1050,48 @@ class TestAssertionRewriteHookDetails(object):
|
||||||
result = testdir.runpytest("-s")
|
result = testdir.runpytest("-s")
|
||||||
result.stdout.fnmatch_lines(["* 1 passed*"])
|
result.stdout.fnmatch_lines(["* 1 passed*"])
|
||||||
|
|
||||||
|
def test_reload_reloads(self, testdir):
|
||||||
|
"""Reloading a module after change picks up the change."""
|
||||||
|
testdir.tmpdir.join("file.py").write(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
|
def reloaded():
|
||||||
|
return False
|
||||||
|
|
||||||
|
def rewrite_self():
|
||||||
|
with open(__file__, 'w') as self:
|
||||||
|
self.write('def reloaded(): return True')
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
testdir.tmpdir.join("pytest.ini").write(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
|
[pytest]
|
||||||
|
python_files = *.py
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
testdir.makepyfile(
|
||||||
|
test_fun="""
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
from imp import reload
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_loader():
|
||||||
|
import file
|
||||||
|
assert not file.reloaded()
|
||||||
|
file.rewrite_self()
|
||||||
|
reload(file)
|
||||||
|
assert file.reloaded()
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest("-s")
|
||||||
|
result.stdout.fnmatch_lines(["* 1 passed*"])
|
||||||
|
|
||||||
def test_get_data_support(self, testdir):
|
def test_get_data_support(self, testdir):
|
||||||
"""Implement optional PEP302 api (#808).
|
"""Implement optional PEP302 api (#808).
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -215,7 +215,7 @@ def test_cache_show(testdir):
|
||||||
|
|
||||||
class TestLastFailed(object):
|
class TestLastFailed(object):
|
||||||
def test_lastfailed_usecase(self, testdir, monkeypatch):
|
def test_lastfailed_usecase(self, testdir, monkeypatch):
|
||||||
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1)
|
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1")
|
||||||
p = testdir.makepyfile(
|
p = testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
def test_1():
|
def test_1():
|
||||||
|
@ -301,7 +301,7 @@ class TestLastFailed(object):
|
||||||
assert "test_a.py" not in result.stdout.str()
|
assert "test_a.py" not in result.stdout.str()
|
||||||
|
|
||||||
def test_lastfailed_difference_invocations(self, testdir, monkeypatch):
|
def test_lastfailed_difference_invocations(self, testdir, monkeypatch):
|
||||||
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1)
|
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1")
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
test_a="""\
|
test_a="""\
|
||||||
def test_a1():
|
def test_a1():
|
||||||
|
@ -335,7 +335,7 @@ class TestLastFailed(object):
|
||||||
result.stdout.fnmatch_lines(["*1 failed*1 desel*"])
|
result.stdout.fnmatch_lines(["*1 failed*1 desel*"])
|
||||||
|
|
||||||
def test_lastfailed_usecase_splice(self, testdir, monkeypatch):
|
def test_lastfailed_usecase_splice(self, testdir, monkeypatch):
|
||||||
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1)
|
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1")
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""\
|
"""\
|
||||||
def test_1():
|
def test_1():
|
||||||
|
@ -474,8 +474,8 @@ class TestLastFailed(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
def rlf(fail_import, fail_run):
|
def rlf(fail_import, fail_run):
|
||||||
monkeypatch.setenv("FAILIMPORT", fail_import)
|
monkeypatch.setenv("FAILIMPORT", str(fail_import))
|
||||||
monkeypatch.setenv("FAILTEST", fail_run)
|
monkeypatch.setenv("FAILTEST", str(fail_run))
|
||||||
|
|
||||||
testdir.runpytest("-q")
|
testdir.runpytest("-q")
|
||||||
config = testdir.parseconfigure()
|
config = testdir.parseconfigure()
|
||||||
|
@ -519,8 +519,8 @@ class TestLastFailed(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
def rlf(fail_import, fail_run, args=()):
|
def rlf(fail_import, fail_run, args=()):
|
||||||
monkeypatch.setenv("FAILIMPORT", fail_import)
|
monkeypatch.setenv("FAILIMPORT", str(fail_import))
|
||||||
monkeypatch.setenv("FAILTEST", fail_run)
|
monkeypatch.setenv("FAILTEST", str(fail_run))
|
||||||
|
|
||||||
result = testdir.runpytest("-q", "--lf", *args)
|
result = testdir.runpytest("-q", "--lf", *args)
|
||||||
config = testdir.parseconfigure()
|
config = testdir.parseconfigure()
|
||||||
|
|
|
@ -30,6 +30,7 @@ def conftest_setinitial(conftest, args, confcutdir=None):
|
||||||
self.file_or_dir = args
|
self.file_or_dir = args
|
||||||
self.confcutdir = str(confcutdir)
|
self.confcutdir = str(confcutdir)
|
||||||
self.noconftest = False
|
self.noconftest = False
|
||||||
|
self.pyargs = False
|
||||||
|
|
||||||
conftest._set_initial_conftests(Namespace())
|
conftest._set_initial_conftests(Namespace())
|
||||||
|
|
||||||
|
|
|
@ -850,7 +850,7 @@ def test_logxml_path_expansion(tmpdir, monkeypatch):
|
||||||
assert xml_tilde.logfile == home_tilde
|
assert xml_tilde.logfile == home_tilde
|
||||||
|
|
||||||
# this is here for when $HOME is not set correct
|
# this is here for when $HOME is not set correct
|
||||||
monkeypatch.setenv("HOME", tmpdir)
|
monkeypatch.setenv("HOME", str(tmpdir))
|
||||||
home_var = os.path.normpath(os.path.expandvars("$HOME/test.xml"))
|
home_var = os.path.normpath(os.path.expandvars("$HOME/test.xml"))
|
||||||
|
|
||||||
xml_var = LogXML("$HOME%stest.xml" % tmpdir.sep, None)
|
xml_var = LogXML("$HOME%stest.xml" % tmpdir.sep, None)
|
||||||
|
|
|
@ -799,6 +799,18 @@ class TestFunctional(object):
|
||||||
deselected_tests = dlist[0].items
|
deselected_tests = dlist[0].items
|
||||||
assert len(deselected_tests) == 2
|
assert len(deselected_tests) == 2
|
||||||
|
|
||||||
|
def test_invalid_m_option(self, testdir):
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
def test_a():
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest("-m bogus/")
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
["INTERNALERROR> Marker expression must be valid Python!"]
|
||||||
|
)
|
||||||
|
|
||||||
def test_keywords_at_node_level(self, testdir):
|
def test_keywords_at_node_level(self, testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,6 +3,8 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
|
|
||||||
|
@ -163,6 +165,7 @@ def test_delitem():
|
||||||
|
|
||||||
def test_setenv():
|
def test_setenv():
|
||||||
monkeypatch = MonkeyPatch()
|
monkeypatch = MonkeyPatch()
|
||||||
|
with pytest.warns(pytest.PytestWarning):
|
||||||
monkeypatch.setenv("XYZ123", 2)
|
monkeypatch.setenv("XYZ123", 2)
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -192,12 +195,48 @@ def test_delenv():
|
||||||
del os.environ[name]
|
del os.environ[name]
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnvironWarnings(object):
|
||||||
|
"""
|
||||||
|
os.environ keys and values should be native strings, otherwise it will cause problems with other modules (notably
|
||||||
|
subprocess). On Python 2 os.environ accepts anything without complaining, while Python 3 does the right thing
|
||||||
|
and raises an error.
|
||||||
|
"""
|
||||||
|
|
||||||
|
VAR_NAME = u"PYTEST_INTERNAL_MY_VAR"
|
||||||
|
|
||||||
|
@pytest.mark.skipif(six.PY3, reason="Python 2 only test")
|
||||||
|
def test_setenv_unicode_key(self, monkeypatch):
|
||||||
|
with pytest.warns(
|
||||||
|
pytest.PytestWarning,
|
||||||
|
match="Environment variable name {!r} should be str".format(self.VAR_NAME),
|
||||||
|
):
|
||||||
|
monkeypatch.setenv(self.VAR_NAME, "2")
|
||||||
|
|
||||||
|
@pytest.mark.skipif(six.PY3, reason="Python 2 only test")
|
||||||
|
def test_delenv_unicode_key(self, monkeypatch):
|
||||||
|
with pytest.warns(
|
||||||
|
pytest.PytestWarning,
|
||||||
|
match="Environment variable name {!r} should be str".format(self.VAR_NAME),
|
||||||
|
):
|
||||||
|
monkeypatch.delenv(self.VAR_NAME, raising=False)
|
||||||
|
|
||||||
|
def test_setenv_non_str_warning(self, monkeypatch):
|
||||||
|
value = 2
|
||||||
|
msg = (
|
||||||
|
"Environment variable value {!r} should be str, converted to str implicitly"
|
||||||
|
)
|
||||||
|
with pytest.warns(pytest.PytestWarning, match=msg.format(value)):
|
||||||
|
monkeypatch.setenv(str(self.VAR_NAME), value)
|
||||||
|
|
||||||
|
|
||||||
def test_setenv_prepend():
|
def test_setenv_prepend():
|
||||||
import os
|
import os
|
||||||
|
|
||||||
monkeypatch = MonkeyPatch()
|
monkeypatch = MonkeyPatch()
|
||||||
|
with pytest.warns(pytest.PytestWarning):
|
||||||
monkeypatch.setenv("XYZ123", 2, prepend="-")
|
monkeypatch.setenv("XYZ123", 2, prepend="-")
|
||||||
assert os.environ["XYZ123"] == "2"
|
assert os.environ["XYZ123"] == "2"
|
||||||
|
with pytest.warns(pytest.PytestWarning):
|
||||||
monkeypatch.setenv("XYZ123", 3, prepend="-")
|
monkeypatch.setenv("XYZ123", 3, prepend="-")
|
||||||
assert os.environ["XYZ123"] == "3-2"
|
assert os.environ["XYZ123"] == "3-2"
|
||||||
monkeypatch.undo()
|
monkeypatch.undo()
|
||||||
|
|
|
@ -681,14 +681,22 @@ def test_pass_reporting_on_fail(testdir):
|
||||||
def test_pass_output_reporting(testdir):
|
def test_pass_output_reporting(testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
def test_pass_output():
|
def test_pass_has_output():
|
||||||
print("Four score and seven years ago...")
|
print("Four score and seven years ago...")
|
||||||
|
def test_pass_no_output():
|
||||||
|
pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
assert "Four score and seven years ago..." not in result.stdout.str()
|
s = result.stdout.str()
|
||||||
|
assert "test_pass_has_output" not in s
|
||||||
|
assert "Four score and seven years ago..." not in s
|
||||||
|
assert "test_pass_no_output" not in s
|
||||||
result = testdir.runpytest("-rP")
|
result = testdir.runpytest("-rP")
|
||||||
result.stdout.fnmatch_lines(["Four score and seven years ago..."])
|
result.stdout.fnmatch_lines(
|
||||||
|
["*test_pass_has_output*", "Four score and seven years ago..."]
|
||||||
|
)
|
||||||
|
assert "test_pass_no_output" not in result.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
def test_color_yes(testdir):
|
def test_color_yes(testdir):
|
||||||
|
|
Loading…
Reference in New Issue