Merge remote-tracking branch 'origin/master' into merge-master
This commit is contained in:
commit
eee8201e4f
|
@ -13,7 +13,7 @@ repos:
|
||||||
additional_dependencies: [black==18.9b0]
|
additional_dependencies: [black==18.9b0]
|
||||||
language_version: python3
|
language_version: python3
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v1.4.0-1
|
rev: v2.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
|
|
@ -47,6 +47,11 @@ jobs:
|
||||||
env: TOXENV=py37
|
env: TOXENV=py37
|
||||||
before_install:
|
before_install:
|
||||||
- brew update
|
- brew update
|
||||||
|
# remove c++ include files because upgrading python as of 2018-10-23, also
|
||||||
|
# attempts to upgrade gcc, and it fails because the include files already
|
||||||
|
# exist. removing the include files is one of the solutions recommended by brew
|
||||||
|
# this workaround might not be necessary in the future
|
||||||
|
- rm '/usr/local/include/c++'
|
||||||
- brew upgrade python
|
- brew upgrade python
|
||||||
- brew unlink python
|
- brew unlink python
|
||||||
- brew link python
|
- brew link python
|
||||||
|
|
|
@ -18,6 +18,37 @@ with advance notice in the **Deprecations** section of releases.
|
||||||
|
|
||||||
.. towncrier release notes start
|
.. towncrier release notes start
|
||||||
|
|
||||||
|
pytest 3.9.2 (2018-10-22)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `#2909 <https://github.com/pytest-dev/pytest/issues/2909>`_: Improve error message when a recursive dependency between fixtures is detected.
|
||||||
|
|
||||||
|
|
||||||
|
- `#3340 <https://github.com/pytest-dev/pytest/issues/3340>`_: Fix logging messages not shown in hooks ``pytest_sessionstart()`` and ``pytest_sessionfinish()``.
|
||||||
|
|
||||||
|
|
||||||
|
- `#3533 <https://github.com/pytest-dev/pytest/issues/3533>`_: Fix unescaped XML raw objects in JUnit report for skipped tests
|
||||||
|
|
||||||
|
|
||||||
|
- `#3691 <https://github.com/pytest-dev/pytest/issues/3691>`_: Python 2: safely format warning message about passing unicode strings to ``warnings.warn``, which may cause
|
||||||
|
surprising ``MemoryError`` exception when monkey patching ``warnings.warn`` itself.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4026 <https://github.com/pytest-dev/pytest/issues/4026>`_: Improve error message when it is not possible to determine a function's signature.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4177 <https://github.com/pytest-dev/pytest/issues/4177>`_: Pin ``setuptools>=40.0`` to support ``py_modules`` in ``setup.cfg``
|
||||||
|
|
||||||
|
|
||||||
|
- `#4179 <https://github.com/pytest-dev/pytest/issues/4179>`_: Restore the tmpdir behaviour of symlinking the current test run.
|
||||||
|
|
||||||
|
|
||||||
|
- `#4192 <https://github.com/pytest-dev/pytest/issues/4192>`_: Fix filename reported by ``warnings.warn`` when using ``recwarn`` under python2.
|
||||||
|
|
||||||
|
|
||||||
pytest 3.9.1 (2018-10-16)
|
pytest 3.9.1 (2018-10-16)
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Fix unescaped XML raw objects in JUnit report for skipped tests
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add reference to ``empty_parameter_set_mark`` ini option in documentation of ``@pytest.mark.parametrize``
|
|
@ -0,0 +1 @@
|
||||||
|
Fix "ValueError: Plugin already registered" with conftest plugins via symlink.
|
|
@ -1 +0,0 @@
|
||||||
Pin ``setuptools>=40.0`` to support ``py_modules`` in ``setup.cfg``
|
|
|
@ -1 +0,0 @@
|
||||||
Restore the tmpdir behaviour of symlinking the current test run.
|
|
|
@ -6,6 +6,7 @@ Release announcements
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|
||||||
|
release-3.9.2
|
||||||
release-3.9.1
|
release-3.9.1
|
||||||
release-3.9.0
|
release-3.9.0
|
||||||
release-3.8.2
|
release-3.8.2
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
pytest-3.9.2
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
pytest 3.9.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
|
||||||
|
* Ronny Pfannschmidt
|
||||||
|
* Vincent Barbaresi
|
||||||
|
* ykantor
|
||||||
|
|
||||||
|
|
||||||
|
Happy testing,
|
||||||
|
The pytest Development Team
|
|
@ -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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
|
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
|
||||||
collecting ... collected 2 items
|
collecting ... collected 2 items
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
|
||||||
def test_exception_syntax():
|
def test_exception_syntax():
|
||||||
try:
|
try:
|
||||||
0/0
|
0 / 0
|
||||||
except ZeroDivisionError, e:
|
except ZeroDivisionError, e:
|
||||||
pass
|
assert e
|
||||||
|
|
|
@ -2,4 +2,4 @@ def test_exception_syntax():
|
||||||
try:
|
try:
|
||||||
0 / 0
|
0 / 0
|
||||||
except ZeroDivisionError as e:
|
except ZeroDivisionError as e:
|
||||||
pass
|
assert e
|
||||||
|
|
|
@ -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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
info1: did you know that ...
|
info1: did you know that ...
|
||||||
did you?
|
did you?
|
||||||
|
|
|
@ -732,7 +732,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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 3 items
|
collecting ... collected 3 items
|
||||||
|
@ -775,7 +775,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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 2 items
|
collecting ... collected 2 items
|
||||||
|
@ -844,7 +844,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/python
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6
|
||||||
cachedir: .pytest_cache
|
cachedir: .pytest_cache
|
||||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
collecting ... collected 8 items
|
collecting ... collected 8 items
|
||||||
|
|
|
@ -114,6 +114,10 @@ Let's run this::
|
||||||
The one parameter set which caused a failure previously now
|
The one parameter set which caused a failure previously now
|
||||||
shows up as an "xfailed (expected to fail)" test.
|
shows up as an "xfailed (expected to fail)" test.
|
||||||
|
|
||||||
|
In case the values provided to ``parametrize`` result in an empty list - for
|
||||||
|
example, if they're dynamically generated by some function - the behaviour of
|
||||||
|
pytest is defined by the :confval:`empty_parameter_set_mark` option.
|
||||||
|
|
||||||
To get all combinations of multiple parametrized arguments you can stack
|
To get all combinations of multiple parametrized arguments you can stack
|
||||||
``parametrize`` decorators::
|
``parametrize`` decorators::
|
||||||
|
|
||||||
|
|
|
@ -58,18 +58,20 @@ by calling the ``pytest.skip(reason)`` function:
|
||||||
if not valid_config():
|
if not valid_config():
|
||||||
pytest.skip("unsupported configuration")
|
pytest.skip("unsupported configuration")
|
||||||
|
|
||||||
|
The imperative method is useful when it is not possible to evaluate the skip condition
|
||||||
|
during import time.
|
||||||
|
|
||||||
It is also possible to skip the whole module using
|
It is also possible to skip the whole module using
|
||||||
``pytest.skip(reason, allow_module_level=True)`` at the module level:
|
``pytest.skip(reason, allow_module_level=True)`` at the module level:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
if not pytest.config.getoption("--custom-flag"):
|
if not sys.platform.startswith("win"):
|
||||||
pytest.skip("--custom-flag is missing, skipping tests", allow_module_level=True)
|
pytest.skip("skipping windows-only tests", allow_module_level=True)
|
||||||
|
|
||||||
The imperative method is useful when it is not possible to evaluate the skip condition
|
|
||||||
during import time.
|
|
||||||
|
|
||||||
**Reference**: :ref:`pytest.mark.skip ref`
|
**Reference**: :ref:`pytest.mark.skip ref`
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,11 @@ The ``tmp_path`` fixture
|
||||||
.. versionadded:: 3.9
|
.. versionadded:: 3.9
|
||||||
|
|
||||||
|
|
||||||
You can use the ``tmpdir`` fixture which will
|
You can use the ``tmp_path`` fixture which will
|
||||||
provide a temporary directory unique to the test invocation,
|
provide a temporary directory unique to the test invocation,
|
||||||
created in the `base temporary directory`_.
|
created in the `base temporary directory`_.
|
||||||
|
|
||||||
``tmpdir`` is a ``pathlib/pathlib2.Path`` object. Here is an example test usage:
|
``tmp_path`` is a ``pathlib/pathlib2.Path`` object. Here is an example test usage:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -69,10 +69,10 @@ The ``tmp_path_factory`` fixture
|
||||||
.. versionadded:: 3.9
|
.. versionadded:: 3.9
|
||||||
|
|
||||||
|
|
||||||
The ``tmp_path_facotry`` is a session-scoped fixture which can be used
|
The ``tmp_path_factory`` is a session-scoped fixture which can be used
|
||||||
to create arbitrary temporary directories from any other fixture or test.
|
to create arbitrary temporary directories from any other fixture or test.
|
||||||
|
|
||||||
its intended to replace ``tmpdir_factory`` and returns :class:`pathlib.Path` instances.
|
It is intended to replace ``tmpdir_factory``, and returns :class:`pathlib.Path` instances.
|
||||||
|
|
||||||
|
|
||||||
The 'tmpdir' fixture
|
The 'tmpdir' fixture
|
||||||
|
|
|
@ -420,17 +420,17 @@ additionally it is possible to copy examples for a example folder before running
|
||||||
============================= warnings summary =============================
|
============================= warnings summary =============================
|
||||||
$REGENDOC_TMPDIR/test_example.py:4: PytestExperimentalApiWarning: testdir.copy_example is an experimental api that may change over time
|
$REGENDOC_TMPDIR/test_example.py:4: PytestExperimentalApiWarning: testdir.copy_example is an experimental api that may change over time
|
||||||
testdir.copy_example("test_example.py")
|
testdir.copy_example("test_example.py")
|
||||||
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead
|
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead
|
||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.File is deprecated, please use pytest.File instead
|
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.File is deprecated, please use pytest.File instead
|
||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Function is deprecated, please use pytest.Function instead
|
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Function is deprecated, please use pytest.Function instead
|
||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Instance is deprecated, please use pytest.Instance instead
|
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Instance is deprecated, please use pytest.Instance instead
|
||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Item is deprecated, please use pytest.Item instead
|
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Item is deprecated, please use pytest.Item instead
|
||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Module is deprecated, please use pytest.Module instead
|
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Module is deprecated, please use pytest.Module instead
|
||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
|
|
||||||
-- Docs: https://docs.pytest.org/en/latest/warnings.html
|
-- Docs: https://docs.pytest.org/en/latest/warnings.html
|
||||||
|
|
|
@ -706,10 +706,9 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
setattr(node, name, new)
|
setattr(node, name, new)
|
||||||
elif (
|
elif (
|
||||||
isinstance(field, ast.AST)
|
isinstance(field, ast.AST)
|
||||||
and
|
|
||||||
# Don't recurse into expressions as they can't contain
|
# Don't recurse into expressions as they can't contain
|
||||||
# asserts.
|
# asserts.
|
||||||
not isinstance(field, ast.expr)
|
and not isinstance(field, ast.expr)
|
||||||
):
|
):
|
||||||
nodes.append(field)
|
nodes.append(field)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ from contextlib import contextmanager
|
||||||
import py
|
import py
|
||||||
|
|
||||||
import _pytest
|
import _pytest
|
||||||
from _pytest.outcomes import TEST_OUTCOME
|
from _pytest.outcomes import TEST_OUTCOME, fail
|
||||||
from six import text_type
|
from six import text_type
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
@ -131,9 +131,17 @@ def getfuncargnames(function, is_method=False, cls=None):
|
||||||
# ordered mapping of parameter names to Parameter instances. This
|
# ordered mapping of parameter names to Parameter instances. This
|
||||||
# creates a tuple of the names of the parameters that don't have
|
# creates a tuple of the names of the parameters that don't have
|
||||||
# defaults.
|
# defaults.
|
||||||
|
try:
|
||||||
|
parameters = signature(function).parameters
|
||||||
|
except (ValueError, TypeError) as e:
|
||||||
|
fail(
|
||||||
|
"Could not determine arguments of {!r}: {}".format(function, e),
|
||||||
|
pytrace=False,
|
||||||
|
)
|
||||||
|
|
||||||
arg_names = tuple(
|
arg_names = tuple(
|
||||||
p.name
|
p.name
|
||||||
for p in signature(function).parameters.values()
|
for p in parameters.values()
|
||||||
if (
|
if (
|
||||||
p.kind is Parameter.POSITIONAL_OR_KEYWORD
|
p.kind is Parameter.POSITIONAL_OR_KEYWORD
|
||||||
or p.kind is Parameter.KEYWORD_ONLY
|
or p.kind is Parameter.KEYWORD_ONLY
|
||||||
|
|
|
@ -391,7 +391,7 @@ class PytestPluginManager(PluginManager):
|
||||||
# and allow users to opt into looking into the rootdir parent
|
# and allow users to opt into looking into the rootdir parent
|
||||||
# directories instead of requiring to specify confcutdir
|
# directories instead of requiring to specify confcutdir
|
||||||
clist = []
|
clist = []
|
||||||
for parent in directory.parts():
|
for parent in directory.realpath().parts():
|
||||||
if self._confcutdir and self._confcutdir.relto(parent):
|
if self._confcutdir and self._confcutdir.relto(parent):
|
||||||
continue
|
continue
|
||||||
conftestpath = parent.join("conftest.py")
|
conftestpath = parent.join("conftest.py")
|
||||||
|
|
|
@ -762,14 +762,19 @@ class FixtureLookupError(LookupError):
|
||||||
|
|
||||||
if msg is None:
|
if msg is None:
|
||||||
fm = self.request._fixturemanager
|
fm = self.request._fixturemanager
|
||||||
available = []
|
available = set()
|
||||||
parentid = self.request._pyfuncitem.parent.nodeid
|
parentid = self.request._pyfuncitem.parent.nodeid
|
||||||
for name, fixturedefs in fm._arg2fixturedefs.items():
|
for name, fixturedefs in fm._arg2fixturedefs.items():
|
||||||
faclist = list(fm._matchfactories(fixturedefs, parentid))
|
faclist = list(fm._matchfactories(fixturedefs, parentid))
|
||||||
if faclist and name not in available:
|
if faclist:
|
||||||
available.append(name)
|
available.add(name)
|
||||||
msg = "fixture %r not found" % (self.argname,)
|
if self.argname in available:
|
||||||
msg += "\n available fixtures: %s" % (", ".join(sorted(available)),)
|
msg = " recursive dependency involving fixture '{}' detected".format(
|
||||||
|
self.argname
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
msg = "fixture '{}' not found".format(self.argname)
|
||||||
|
msg += "\n available fixtures: {}".format(", ".join(sorted(available)))
|
||||||
msg += "\n use 'pytest --fixtures [testpath]' for help on them."
|
msg += "\n use 'pytest --fixtures [testpath]' for help on them."
|
||||||
|
|
||||||
return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
|
return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
|
||||||
|
|
|
@ -497,6 +497,29 @@ class LoggingPlugin(object):
|
||||||
with self._runtest_for(None, "finish"):
|
with self._runtest_for(None, "finish"):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||||
|
def pytest_sessionfinish(self):
|
||||||
|
with self.live_logs_context():
|
||||||
|
if self.log_cli_handler:
|
||||||
|
self.log_cli_handler.set_when("sessionfinish")
|
||||||
|
if self.log_file_handler is not None:
|
||||||
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
|
yield
|
||||||
|
else:
|
||||||
|
yield
|
||||||
|
|
||||||
|
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||||
|
def pytest_sessionstart(self):
|
||||||
|
self._setup_cli_logging()
|
||||||
|
with self.live_logs_context():
|
||||||
|
if self.log_cli_handler:
|
||||||
|
self.log_cli_handler.set_when("sessionstart")
|
||||||
|
if self.log_file_handler is not None:
|
||||||
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
|
yield
|
||||||
|
else:
|
||||||
|
yield
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
def pytest_runtestloop(self, session):
|
def pytest_runtestloop(self, session):
|
||||||
"""Runs all collected test items."""
|
"""Runs all collected test items."""
|
||||||
|
|
|
@ -237,8 +237,8 @@ def make_numbered_dir_with_cleanup(root, prefix, keep, lock_timeout):
|
||||||
p = make_numbered_dir(root, prefix)
|
p = make_numbered_dir(root, prefix)
|
||||||
lock_path = create_cleanup_lock(p)
|
lock_path = create_cleanup_lock(p)
|
||||||
register_cleanup_lock_removal(lock_path)
|
register_cleanup_lock_removal(lock_path)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
pass
|
e = exc
|
||||||
else:
|
else:
|
||||||
consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout
|
consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout
|
||||||
cleanup_numbered_dir(
|
cleanup_numbered_dir(
|
||||||
|
|
|
@ -156,7 +156,20 @@ class WarningsRecorder(warnings.catch_warnings):
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
|
|
||||||
def warn(*args, **kwargs):
|
def warn(*args, **kwargs):
|
||||||
return self._saved_warn(*args, **kwargs)
|
kwargs.setdefault("stacklevel", 1)
|
||||||
|
kwargs["stacklevel"] += 1
|
||||||
|
|
||||||
|
# emulate resetting the warn registry
|
||||||
|
f_globals = sys._getframe(kwargs["stacklevel"] - 1).f_globals
|
||||||
|
if "__warningregistry__" in f_globals:
|
||||||
|
orig = f_globals["__warningregistry__"]
|
||||||
|
f_globals["__warningregistry__"] = None
|
||||||
|
try:
|
||||||
|
return self._saved_warn(*args, **kwargs)
|
||||||
|
finally:
|
||||||
|
f_globals["__warningregistry__"] = orig
|
||||||
|
else:
|
||||||
|
return self._saved_warn(*args, **kwargs)
|
||||||
|
|
||||||
warnings.warn, self._saved_warn = warn, warnings.warn
|
warnings.warn, self._saved_warn = warn, warnings.warn
|
||||||
return self
|
return self
|
||||||
|
|
|
@ -123,7 +123,7 @@ def warning_record_to_str(warning_message):
|
||||||
if unicode_warning:
|
if unicode_warning:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Warning is using unicode non convertible to ascii, "
|
"Warning is using unicode non convertible to ascii, "
|
||||||
"converting to a safe representation:\n %s" % msg,
|
"converting to a safe representation:\n {!r}".format(compat.safe_str(msg)),
|
||||||
UnicodeWarning,
|
UnicodeWarning,
|
||||||
)
|
)
|
||||||
return msg
|
return msg
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fix1(fix2):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fix2(fix1):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def test(fix1):
|
||||||
|
pass
|
|
@ -966,3 +966,39 @@ def test_collection_logging_to_file(testdir):
|
||||||
assert "Normal message" in contents
|
assert "Normal message" in contents
|
||||||
assert "debug message in test_simple" not in contents
|
assert "debug message in test_simple" not in contents
|
||||||
assert "info message in test_simple" in contents
|
assert "info message in test_simple" in contents
|
||||||
|
|
||||||
|
|
||||||
|
def test_log_in_hooks(testdir):
|
||||||
|
log_file = testdir.tmpdir.join("pytest.log").strpath
|
||||||
|
|
||||||
|
testdir.makeini(
|
||||||
|
"""
|
||||||
|
[pytest]
|
||||||
|
log_file={}
|
||||||
|
log_file_level = INFO
|
||||||
|
log_cli=true
|
||||||
|
""".format(
|
||||||
|
log_file
|
||||||
|
)
|
||||||
|
)
|
||||||
|
testdir.makeconftest(
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
def pytest_runtestloop(session):
|
||||||
|
logging.info('runtestloop')
|
||||||
|
|
||||||
|
def pytest_sessionstart(session):
|
||||||
|
logging.info('sessionstart')
|
||||||
|
|
||||||
|
def pytest_sessionfinish(session, exitstatus):
|
||||||
|
logging.info('sessionfinish')
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(["*sessionstart*", "*runtestloop*", "*sessionfinish*"])
|
||||||
|
with open(log_file) as rfh:
|
||||||
|
contents = rfh.read()
|
||||||
|
assert "sessionstart" in contents
|
||||||
|
assert "runtestloop" in contents
|
||||||
|
assert "sessionfinish" in contents
|
||||||
|
|
|
@ -60,6 +60,13 @@ class TestFillFixtures(object):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_detect_recursive_dependency_error(self, testdir):
|
||||||
|
testdir.copy_example()
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
["*recursive dependency involving fixture 'fix1' detected*"]
|
||||||
|
)
|
||||||
|
|
||||||
def test_funcarg_basic(self, testdir):
|
def test_funcarg_basic(self, testdir):
|
||||||
testdir.copy_example()
|
testdir.copy_example()
|
||||||
item = testdir.getitem(Path("test_funcarg_basic.py"))
|
item = testdir.getitem(Path("test_funcarg_basic.py"))
|
||||||
|
|
|
@ -952,3 +952,23 @@ def test_collect_init_tests(testdir):
|
||||||
"*<Function 'test_foo'>",
|
"*<Function 'test_foo'>",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_invalid_signature_message(testdir):
|
||||||
|
"""Check that we issue a proper message when we can't determine the signature of a test
|
||||||
|
function (#4026).
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
class TestCase:
|
||||||
|
@pytest.fixture
|
||||||
|
def fix():
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
["Could not determine arguments of *.fix *: invalid method signature"]
|
||||||
|
)
|
||||||
|
|
|
@ -192,8 +192,10 @@ def test_conftest_confcutdir(testdir):
|
||||||
)
|
)
|
||||||
def test_conftest_symlink(testdir):
|
def test_conftest_symlink(testdir):
|
||||||
"""Ensure that conftest.py is used for resolved symlinks."""
|
"""Ensure that conftest.py is used for resolved symlinks."""
|
||||||
realtests = testdir.tmpdir.mkdir("real").mkdir("app").mkdir("tests")
|
real = testdir.tmpdir.mkdir("real")
|
||||||
|
realtests = real.mkdir("app").mkdir("tests")
|
||||||
testdir.tmpdir.join("symlinktests").mksymlinkto(realtests)
|
testdir.tmpdir.join("symlinktests").mksymlinkto(realtests)
|
||||||
|
testdir.tmpdir.join("symlink").mksymlinkto(real)
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
**{
|
**{
|
||||||
"real/app/tests/test_foo.py": "def test1(fixture): pass",
|
"real/app/tests/test_foo.py": "def test1(fixture): pass",
|
||||||
|
@ -220,6 +222,10 @@ def test_conftest_symlink(testdir):
|
||||||
)
|
)
|
||||||
assert result.ret == EXIT_OK
|
assert result.ret == EXIT_OK
|
||||||
|
|
||||||
|
# Should not cause "ValueError: Plugin already registered" (#4174).
|
||||||
|
result = testdir.runpytest("-vs", "symlink")
|
||||||
|
assert result.ret == EXIT_OK
|
||||||
|
|
||||||
realtests.ensure("__init__.py")
|
realtests.ensure("__init__.py")
|
||||||
result = testdir.runpytest("-vs", "symlinktests/test_foo.py::test1")
|
result = testdir.runpytest("-vs", "symlinktests/test_foo.py::test1")
|
||||||
result.stdout.fnmatch_lines(
|
result.stdout.fnmatch_lines(
|
||||||
|
|
|
@ -6,6 +6,12 @@ import pytest
|
||||||
from _pytest.recwarn import WarningsRecorder
|
from _pytest.recwarn import WarningsRecorder
|
||||||
|
|
||||||
|
|
||||||
|
def test_recwarn_stacklevel(recwarn):
|
||||||
|
warnings.warn("hello")
|
||||||
|
warn = recwarn.pop()
|
||||||
|
assert warn.filename == __file__
|
||||||
|
|
||||||
|
|
||||||
def test_recwarn_functional(testdir):
|
def test_recwarn_functional(testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,6 +3,8 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@ -562,3 +564,30 @@ class TestDeprecationWarningsByDefault:
|
||||||
monkeypatch.setenv(str("PYTHONWARNINGS"), str("once::UserWarning"))
|
monkeypatch.setenv(str("PYTHONWARNINGS"), str("once::UserWarning"))
|
||||||
result = testdir.runpytest_subprocess()
|
result = testdir.runpytest_subprocess()
|
||||||
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(six.PY3, reason="Python 2 only issue")
|
||||||
|
def test_infinite_loop_warning_against_unicode_usage_py2(testdir):
|
||||||
|
"""
|
||||||
|
We need to be careful when raising the warning about unicode usage with "warnings.warn"
|
||||||
|
because it might be overwritten by users and this itself causes another warning (#3691).
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
# -*- coding: utf8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import warnings
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
def _custom_showwarning(message, *a, **b):
|
||||||
|
return "WARNING: {}".format(message)
|
||||||
|
|
||||||
|
warnings.formatwarning = _custom_showwarning
|
||||||
|
|
||||||
|
@pytest.mark.filterwarnings("default")
|
||||||
|
def test_custom_warning_formatter():
|
||||||
|
warnings.warn("¥")
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest_subprocess()
|
||||||
|
result.stdout.fnmatch_lines(["*1 passed, * warnings in*"])
|
||||||
|
|
6
tox.ini
6
tox.ini
|
@ -18,7 +18,7 @@ envlist =
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands =
|
commands =
|
||||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest --lsof
|
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest --lsof {posargs}
|
||||||
coverage: coverage combine
|
coverage: coverage combine
|
||||||
coverage: coverage report
|
coverage: coverage report
|
||||||
passenv = USER USERNAME COVERAGE_* TRAVIS
|
passenv = USER USERNAME COVERAGE_* TRAVIS
|
||||||
|
@ -41,7 +41,7 @@ deps =
|
||||||
py27: mock
|
py27: mock
|
||||||
nose
|
nose
|
||||||
commands =
|
commands =
|
||||||
pytest -n auto --runpytest=subprocess
|
pytest -n auto --runpytest=subprocess {posargs}
|
||||||
|
|
||||||
|
|
||||||
[testenv:linting]
|
[testenv:linting]
|
||||||
|
@ -58,7 +58,7 @@ deps =
|
||||||
hypothesis>=3.56
|
hypothesis>=3.56
|
||||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||||
commands =
|
commands =
|
||||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto
|
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs}
|
||||||
|
|
||||||
[testenv:py36-xdist]
|
[testenv:py36-xdist]
|
||||||
# NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706.
|
# NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706.
|
||||||
|
|
Loading…
Reference in New Issue