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,6 +156,19 @@ class WarningsRecorder(warnings.catch_warnings): | ||||||
|         if six.PY2: |         if six.PY2: | ||||||
| 
 | 
 | ||||||
|             def warn(*args, **kwargs): |             def 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) |                     return self._saved_warn(*args, **kwargs) | ||||||
| 
 | 
 | ||||||
|             warnings.warn, self._saved_warn = warn, warnings.warn |             warnings.warn, self._saved_warn = warn, warnings.warn | ||||||
|  |  | ||||||
|  | @ -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