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] | ||||
|         language_version: python3 | ||||
| -   repo: https://github.com/pre-commit/pre-commit-hooks | ||||
|     rev: v1.4.0-1 | ||||
|     rev: v2.0.0 | ||||
|     hooks: | ||||
|     -   id: trailing-whitespace | ||||
|     -   id: end-of-file-fixer | ||||
|  |  | |||
|  | @ -47,6 +47,11 @@ jobs: | |||
|       env: TOXENV=py37 | ||||
|       before_install: | ||||
|         - 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 unlink python | ||||
|         - brew link python | ||||
|  |  | |||
|  | @ -18,6 +18,37 @@ with advance notice in the **Deprecations** section of releases. | |||
| 
 | ||||
| .. 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) | ||||
| ========================= | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
| 
 | ||||
|    release-3.9.2 | ||||
|    release-3.9.1 | ||||
|    release-3.9.0 | ||||
|    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 | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     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" | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     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 | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     collecting ... collected 1 item | ||||
|  | @ -77,7 +77,7 @@ You can also select on the class:: | |||
| 
 | ||||
|     $ pytest -v test_server.py::TestClass | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     collecting ... collected 1 item | ||||
|  | @ -90,7 +90,7 @@ Or select multiple nodes:: | |||
| 
 | ||||
|   $ pytest -v test_server.py::TestClass test_server.py::test_send_http | ||||
|   =========================== 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 | ||||
|   rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|   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 | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     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 | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     collecting ... collected 4 items / 1 deselected | ||||
|  | @ -156,7 +156,7 @@ Or to select "http" and "quick" tests:: | |||
| 
 | ||||
|     $ pytest -k "http or quick" -v | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     collecting ... collected 4 items / 2 deselected | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ consulted when reporting in ``verbose`` mode:: | |||
| 
 | ||||
|     nonpython $ pytest -v | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR/nonpython, inifile: | ||||
|     collecting ... collected 2 items | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| 
 | ||||
| def test_exception_syntax(): | ||||
|     try: | ||||
|         0 / 0 | ||||
|     except ZeroDivisionError, e: | ||||
|         pass | ||||
|         assert e | ||||
|  |  | |||
|  | @ -2,4 +2,4 @@ def test_exception_syntax(): | |||
|     try: | ||||
|         0 / 0 | ||||
|     except ZeroDivisionError as e: | ||||
|         pass | ||||
|         assert e | ||||
|  |  | |||
|  | @ -357,7 +357,7 @@ which will add info only when run with "--v":: | |||
| 
 | ||||
|     $ pytest -v | ||||
|     =========================== 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 | ||||
|     info1: did you know that ... | ||||
|     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 | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     collecting ... collected 3 items | ||||
|  | @ -775,7 +775,7 @@ Here we declare an ``app`` fixture which receives the previously defined | |||
| 
 | ||||
|     $ pytest -v test_appsetup.py | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     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 | ||||
|     =========================== 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 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: | ||||
|     collecting ... collected 8 items | ||||
|  |  | |||
|  | @ -114,6 +114,10 @@ Let's run this:: | |||
| The one parameter set which caused a failure previously now | ||||
| 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 | ||||
| ``parametrize`` decorators:: | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,18 +58,20 @@ by calling the ``pytest.skip(reason)`` function: | |||
|         if not valid_config(): | ||||
|             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 | ||||
| ``pytest.skip(reason, allow_module_level=True)`` at the module level: | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|     import sys | ||||
|     import pytest | ||||
| 
 | ||||
|     if not pytest.config.getoption("--custom-flag"): | ||||
|         pytest.skip("--custom-flag is missing, skipping tests", allow_module_level=True) | ||||
|     if not sys.platform.startswith("win"): | ||||
|         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` | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,11 +11,11 @@ The ``tmp_path`` fixture | |||
| .. 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, | ||||
| 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 | ||||
| 
 | ||||
|  | @ -69,10 +69,10 @@ The ``tmp_path_factory`` fixture | |||
| .. 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. | ||||
| 
 | ||||
| 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 | ||||
|  |  | |||
|  | @ -420,17 +420,17 @@ additionally it is possible to copy examples for a example folder before running | |||
|     ============================= warnings summary ============================= | ||||
|     $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") | ||||
|     $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) | ||||
|     $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) | ||||
|     $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) | ||||
|     $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) | ||||
|     $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) | ||||
|     $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) | ||||
| 
 | ||||
|     -- Docs: https://docs.pytest.org/en/latest/warnings.html | ||||
|  |  | |||
|  | @ -706,10 +706,9 @@ class AssertionRewriter(ast.NodeVisitor): | |||
|                     setattr(node, name, new) | ||||
|                 elif ( | ||||
|                     isinstance(field, ast.AST) | ||||
|                     and | ||||
|                     # Don't recurse into expressions as they can't contain | ||||
|                     # asserts. | ||||
|                     not isinstance(field, ast.expr) | ||||
|                     and not isinstance(field, ast.expr) | ||||
|                 ): | ||||
|                     nodes.append(field) | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ from contextlib import contextmanager | |||
| import py | ||||
| 
 | ||||
| import _pytest | ||||
| from _pytest.outcomes import TEST_OUTCOME | ||||
| from _pytest.outcomes import TEST_OUTCOME, fail | ||||
| from six import text_type | ||||
| import six | ||||
| 
 | ||||
|  | @ -131,9 +131,17 @@ def getfuncargnames(function, is_method=False, cls=None): | |||
|     # ordered mapping of parameter names to Parameter instances.  This | ||||
|     # creates a tuple of the names of the parameters that don't have | ||||
|     # 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( | ||||
|         p.name | ||||
|         for p in signature(function).parameters.values() | ||||
|         for p in parameters.values() | ||||
|         if ( | ||||
|             p.kind is Parameter.POSITIONAL_OR_KEYWORD | ||||
|             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 | ||||
|             # directories instead of requiring to specify confcutdir | ||||
|             clist = [] | ||||
|             for parent in directory.parts(): | ||||
|             for parent in directory.realpath().parts(): | ||||
|                 if self._confcutdir and self._confcutdir.relto(parent): | ||||
|                     continue | ||||
|                 conftestpath = parent.join("conftest.py") | ||||
|  |  | |||
|  | @ -762,14 +762,19 @@ class FixtureLookupError(LookupError): | |||
| 
 | ||||
|         if msg is None: | ||||
|             fm = self.request._fixturemanager | ||||
|             available = [] | ||||
|             available = set() | ||||
|             parentid = self.request._pyfuncitem.parent.nodeid | ||||
|             for name, fixturedefs in fm._arg2fixturedefs.items(): | ||||
|                 faclist = list(fm._matchfactories(fixturedefs, parentid)) | ||||
|                 if faclist and name not in available: | ||||
|                     available.append(name) | ||||
|             msg = "fixture %r not found" % (self.argname,) | ||||
|             msg += "\n available fixtures: %s" % (", ".join(sorted(available)),) | ||||
|                 if faclist: | ||||
|                     available.add(name) | ||||
|             if self.argname in 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." | ||||
| 
 | ||||
|         return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) | ||||
|  |  | |||
|  | @ -497,6 +497,29 @@ class LoggingPlugin(object): | |||
|         with self._runtest_for(None, "finish"): | ||||
|             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) | ||||
|     def pytest_runtestloop(self, session): | ||||
|         """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) | ||||
|             lock_path = create_cleanup_lock(p) | ||||
|             register_cleanup_lock_removal(lock_path) | ||||
|         except Exception as e: | ||||
|             pass | ||||
|         except Exception as exc: | ||||
|             e = exc | ||||
|         else: | ||||
|             consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout | ||||
|             cleanup_numbered_dir( | ||||
|  |  | |||
|  | @ -156,6 +156,19 @@ class WarningsRecorder(warnings.catch_warnings): | |||
|         if six.PY2: | ||||
| 
 | ||||
|             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) | ||||
| 
 | ||||
|             warnings.warn, self._saved_warn = warn, warnings.warn | ||||
|  |  | |||
|  | @ -123,7 +123,7 @@ def warning_record_to_str(warning_message): | |||
|     if unicode_warning: | ||||
|         warnings.warn( | ||||
|             "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, | ||||
|         ) | ||||
|     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 "debug message in test_simple" not 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): | ||||
|         testdir.copy_example() | ||||
|         item = testdir.getitem(Path("test_funcarg_basic.py")) | ||||
|  |  | |||
|  | @ -952,3 +952,23 @@ def test_collect_init_tests(testdir): | |||
|             "*<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): | ||||
|     """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("symlink").mksymlinkto(real) | ||||
|     testdir.makepyfile( | ||||
|         **{ | ||||
|             "real/app/tests/test_foo.py": "def test1(fixture): pass", | ||||
|  | @ -220,6 +222,10 @@ def test_conftest_symlink(testdir): | |||
|     ) | ||||
|     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") | ||||
|     result = testdir.runpytest("-vs", "symlinktests/test_foo.py::test1") | ||||
|     result.stdout.fnmatch_lines( | ||||
|  |  | |||
|  | @ -6,6 +6,12 @@ import pytest | |||
| 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): | ||||
|     testdir.makepyfile( | ||||
|         """ | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ from __future__ import unicode_literals | |||
| 
 | ||||
| import sys | ||||
| 
 | ||||
| import six | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| 
 | ||||
|  | @ -562,3 +564,30 @@ class TestDeprecationWarningsByDefault: | |||
|         monkeypatch.setenv(str("PYTHONWARNINGS"), str("once::UserWarning")) | ||||
|         result = testdir.runpytest_subprocess() | ||||
|         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] | ||||
| commands = | ||||
|     {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --lsof | ||||
|     {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --lsof {posargs} | ||||
|     coverage: coverage combine | ||||
|     coverage: coverage report | ||||
| passenv = USER USERNAME COVERAGE_* TRAVIS | ||||
|  | @ -41,7 +41,7 @@ deps = | |||
|     py27: mock | ||||
|     nose | ||||
| commands = | ||||
|     pytest -n auto --runpytest=subprocess | ||||
|     pytest -n auto --runpytest=subprocess {posargs} | ||||
| 
 | ||||
| 
 | ||||
| [testenv:linting] | ||||
|  | @ -58,7 +58,7 @@ deps = | |||
|     hypothesis>=3.56 | ||||
|     {env:_PYTEST_TOX_EXTRA_DEP:} | ||||
| commands = | ||||
|     {env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto | ||||
|     {env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs} | ||||
| 
 | ||||
| [testenv:py36-xdist] | ||||
| # NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706. | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue