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