Merge remote-tracking branch 'origin/master' into merge-master

This commit is contained in:
Daniel Hahler 2018-10-24 22:36:34 +02:00
commit eee8201e4f
36 changed files with 284 additions and 53 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
=========================

View File

@ -1 +0,0 @@
Fix unescaped XML raw objects in JUnit report for skipped tests

1
changelog/3851.doc.rst Normal file
View File

@ -0,0 +1 @@
Add reference to ``empty_parameter_set_mark`` ini option in documentation of ``@pytest.mark.parametrize``

View File

@ -0,0 +1 @@
Fix "ValueError: Plugin already registered" with conftest plugins via symlink.

View File

@ -1 +0,0 @@
Pin ``setuptools>=40.0`` to support ``py_modules`` in ``setup.cfg``

View File

@ -1 +0,0 @@
Restore the tmpdir behaviour of symlinking the current test run.

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2
release-3.9.2
release-3.9.1
release-3.9.0
release-3.8.2

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,6 +1,5 @@
def test_exception_syntax():
try:
0/0
0 / 0
except ZeroDivisionError, e:
pass
assert e

View File

@ -2,4 +2,4 @@ def test_exception_syntax():
try:
0 / 0
except ZeroDivisionError as e:
pass
assert e

View File

@ -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?

View File

@ -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

View File

@ -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::

View File

@ -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`

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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")

View File

@ -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)

View File

@ -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."""

View File

@ -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(

View File

@ -156,7 +156,20 @@ class WarningsRecorder(warnings.catch_warnings):
if six.PY2:
def warn(*args, **kwargs):
return self._saved_warn(*args, **kwargs)
kwargs.setdefault("stacklevel", 1)
kwargs["stacklevel"] += 1
# emulate resetting the warn registry
f_globals = sys._getframe(kwargs["stacklevel"] - 1).f_globals
if "__warningregistry__" in f_globals:
orig = f_globals["__warningregistry__"]
f_globals["__warningregistry__"] = None
try:
return self._saved_warn(*args, **kwargs)
finally:
f_globals["__warningregistry__"] = orig
else:
return self._saved_warn(*args, **kwargs)
warnings.warn, self._saved_warn = warn, warnings.warn
return self

View File

@ -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

View File

@ -0,0 +1,15 @@
import pytest
@pytest.fixture
def fix1(fix2):
return 1
@pytest.fixture
def fix2(fix1):
return 1
def test(fix1):
pass

View File

@ -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

View File

@ -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"))

View File

@ -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"]
)

View File

@ -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(

View File

@ -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(
"""

View File

@ -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*"])

View File

@ -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.