Merge pull request #4524 from blueyed/merge-master
Merge master into features
This commit is contained in:
commit
038f1f94c2
|
@ -0,0 +1 @@
|
||||||
|
Document common doctest fixture directory tree structure pitfalls
|
|
@ -0,0 +1 @@
|
||||||
|
Validate arguments from the ``PYTEST_ADDOPTS`` environment variable and the ``addopts`` ini option separately.
|
|
@ -0,0 +1 @@
|
||||||
|
When a fixture yields and a log call is made after the test runs, and, if the test is interrupted, capture attributes are ``None``.
|
|
@ -154,6 +154,9 @@ which can then be used in your doctests directly::
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
Note that like the normal ``conftest.py``, the fixtures are discovered in the directory tree conftest is in.
|
||||||
|
Meaning that if you put your doctest with your source code, the relevant conftest.py needs to be in the same directory tree.
|
||||||
|
Fixtures will not be discovered in a sibling directory tree!
|
||||||
|
|
||||||
Output format
|
Output format
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -156,4 +156,4 @@ More details can be found in the `original PR <https://github.com/pytest-dev/pyt
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
in a future major relase of pytest we will introduce class based markers,
|
in a future major relase of pytest we will introduce class based markers,
|
||||||
at which points markers will no longer be limited to instances of :py:class:`Mark`
|
at which point markers will no longer be limited to instances of :py:class:`Mark`
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
pygments-pytest>=1.0.4
|
pygments-pytest>=1.1.0
|
||||||
# pinning sphinx to 1.4.* due to search issues with rtd:
|
sphinx>=1.8.2
|
||||||
# https://github.com/rtfd/readthedocs-sphinx-ext/issues/25
|
|
||||||
sphinx ==1.4.*
|
|
||||||
sphinxcontrib-trio
|
sphinxcontrib-trio
|
||||||
|
|
|
@ -117,7 +117,10 @@ class CaptureManager(object):
|
||||||
self._global_capturing = None
|
self._global_capturing = None
|
||||||
|
|
||||||
def resume_global_capture(self):
|
def resume_global_capture(self):
|
||||||
self._global_capturing.resume_capturing()
|
# During teardown of the python process, and on rare occasions, capture
|
||||||
|
# attributes can be `None` while trying to resume global capture.
|
||||||
|
if self._global_capturing is not None:
|
||||||
|
self._global_capturing.resume_capturing()
|
||||||
|
|
||||||
def suspend_global_capture(self, in_=False):
|
def suspend_global_capture(self, in_=False):
|
||||||
cap = getattr(self, "_global_capturing", None)
|
cap = getattr(self, "_global_capturing", None)
|
||||||
|
|
|
@ -777,12 +777,21 @@ class Config(object):
|
||||||
for name in _iter_rewritable_modules(package_files):
|
for name in _iter_rewritable_modules(package_files):
|
||||||
hook.mark_rewrite(name)
|
hook.mark_rewrite(name)
|
||||||
|
|
||||||
|
def _validate_args(self, args):
|
||||||
|
"""Validate known args."""
|
||||||
|
self._parser.parse_known_and_unknown_args(
|
||||||
|
args, namespace=copy.copy(self.option)
|
||||||
|
)
|
||||||
|
return args
|
||||||
|
|
||||||
def _preparse(self, args, addopts=True):
|
def _preparse(self, args, addopts=True):
|
||||||
if addopts:
|
if addopts:
|
||||||
args[:] = shlex.split(os.environ.get("PYTEST_ADDOPTS", "")) + args
|
env_addopts = os.environ.get("PYTEST_ADDOPTS", "")
|
||||||
|
if len(env_addopts):
|
||||||
|
args[:] = self._validate_args(shlex.split(env_addopts)) + args
|
||||||
self._initini(args)
|
self._initini(args)
|
||||||
if addopts:
|
if addopts:
|
||||||
args[:] = self.getini("addopts") + args
|
args[:] = self._validate_args(self.getini("addopts")) + args
|
||||||
self._checkversion()
|
self._checkversion()
|
||||||
self._consider_importhook(args)
|
self._consider_importhook(args)
|
||||||
self.pluginmanager.consider_preparse(args)
|
self.pluginmanager.consider_preparse(args)
|
||||||
|
|
|
@ -197,7 +197,8 @@ class TestRaises(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
Failed, match="DID NOT RAISE <class 'raises.ClassLooksIterableException'>"
|
Failed,
|
||||||
|
match=r"DID NOT RAISE <class 'raises(\..*)*ClassLooksIterableException'>",
|
||||||
):
|
):
|
||||||
pytest.raises(ClassLooksIterableException, lambda: None)
|
pytest.raises(ClassLooksIterableException, lambda: None)
|
||||||
|
|
||||||
|
|
|
@ -302,14 +302,14 @@ class TestLoggingInteraction(object):
|
||||||
"""\
|
"""\
|
||||||
import logging
|
import logging
|
||||||
def setup_function(function):
|
def setup_function(function):
|
||||||
logging.warn("hello1")
|
logging.warning("hello1")
|
||||||
|
|
||||||
def test_logging():
|
def test_logging():
|
||||||
logging.warn("hello2")
|
logging.warning("hello2")
|
||||||
assert 0
|
assert 0
|
||||||
|
|
||||||
def teardown_function(function):
|
def teardown_function(function):
|
||||||
logging.warn("hello3")
|
logging.warning("hello3")
|
||||||
assert 0
|
assert 0
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -328,14 +328,14 @@ class TestLoggingInteraction(object):
|
||||||
"""\
|
"""\
|
||||||
import logging
|
import logging
|
||||||
def setup_module(function):
|
def setup_module(function):
|
||||||
logging.warn("hello1")
|
logging.warning("hello1")
|
||||||
|
|
||||||
def test_logging():
|
def test_logging():
|
||||||
logging.warn("hello2")
|
logging.warning("hello2")
|
||||||
assert 0
|
assert 0
|
||||||
|
|
||||||
def teardown_module(function):
|
def teardown_module(function):
|
||||||
logging.warn("hello3")
|
logging.warning("hello3")
|
||||||
assert 0
|
assert 0
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -354,7 +354,7 @@ class TestLoggingInteraction(object):
|
||||||
"""\
|
"""\
|
||||||
import logging
|
import logging
|
||||||
logging.basicConfig()
|
logging.basicConfig()
|
||||||
logging.warn("hello435")
|
logging.warning("hello435")
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
# make sure that logging is still captured in tests
|
# make sure that logging is still captured in tests
|
||||||
|
@ -375,7 +375,7 @@ class TestLoggingInteraction(object):
|
||||||
"""\
|
"""\
|
||||||
def test_hello():
|
def test_hello():
|
||||||
import logging
|
import logging
|
||||||
logging.warn("hello433")
|
logging.warning("hello433")
|
||||||
assert 0
|
assert 0
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -385,6 +385,40 @@ class TestLoggingInteraction(object):
|
||||||
assert "something" not in result.stderr.str()
|
assert "something" not in result.stderr.str()
|
||||||
assert "operation on closed file" not in result.stderr.str()
|
assert "operation on closed file" not in result.stderr.str()
|
||||||
|
|
||||||
|
def test_logging_after_cap_stopped(self, testdir):
|
||||||
|
testdir.makeconftest(
|
||||||
|
"""\
|
||||||
|
import pytest
|
||||||
|
import logging
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def log_on_teardown():
|
||||||
|
yield
|
||||||
|
log.warning('Logging on teardown')
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
# make sure that logging is still captured in tests
|
||||||
|
p = testdir.makepyfile(
|
||||||
|
"""\
|
||||||
|
def test_hello(log_on_teardown):
|
||||||
|
import logging
|
||||||
|
logging.warning("hello433")
|
||||||
|
assert 1
|
||||||
|
raise KeyboardInterrupt()
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest_subprocess(p, "--log-cli-level", "info")
|
||||||
|
assert result.ret != 0
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
["*WARNING*hello433*", "*WARNING*Logging on teardown*"]
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"AttributeError: 'NoneType' object has no attribute 'resume_capturing'"
|
||||||
|
not in result.stderr.str()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestCaptureFixture(object):
|
class TestCaptureFixture(object):
|
||||||
@pytest.mark.parametrize("opt", [[], ["-s"]])
|
@pytest.mark.parametrize("opt", [[], ["-s"]])
|
||||||
|
@ -1300,13 +1334,13 @@ def test_capturing_and_logging_fundamentals(testdir, method):
|
||||||
Capture=capture.%s)
|
Capture=capture.%s)
|
||||||
cap.start_capturing()
|
cap.start_capturing()
|
||||||
|
|
||||||
logging.warn("hello1")
|
logging.warning("hello1")
|
||||||
outerr = cap.readouterr()
|
outerr = cap.readouterr()
|
||||||
print("suspend, captured %%s" %%(outerr,))
|
print("suspend, captured %%s" %%(outerr,))
|
||||||
logging.warn("hello2")
|
logging.warning("hello2")
|
||||||
|
|
||||||
cap.pop_outerr_to_orig()
|
cap.pop_outerr_to_orig()
|
||||||
logging.warn("hello3")
|
logging.warning("hello3")
|
||||||
|
|
||||||
outerr = cap.readouterr()
|
outerr = cap.readouterr()
|
||||||
print("suspend2, captured %%s" %% (outerr,))
|
print("suspend2, captured %%s" %% (outerr,))
|
||||||
|
|
|
@ -1083,6 +1083,33 @@ class TestOverrideIniArgs(object):
|
||||||
config._preparse([], addopts=True)
|
config._preparse([], addopts=True)
|
||||||
assert config._override_ini == ["cache_dir=%s" % cache_dir]
|
assert config._override_ini == ["cache_dir=%s" % cache_dir]
|
||||||
|
|
||||||
|
def test_addopts_from_env_not_concatenated(self, monkeypatch):
|
||||||
|
"""PYTEST_ADDOPTS should not take values from normal args (#4265)."""
|
||||||
|
from _pytest.config import get_config
|
||||||
|
|
||||||
|
monkeypatch.setenv("PYTEST_ADDOPTS", "-o")
|
||||||
|
config = get_config()
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
config._preparse(["cache_dir=ignored"], addopts=True)
|
||||||
|
assert excinfo.value.args[0] == _pytest.main.EXIT_USAGEERROR
|
||||||
|
|
||||||
|
def test_addopts_from_ini_not_concatenated(self, testdir):
|
||||||
|
"""addopts from ini should not take values from normal args (#4265)."""
|
||||||
|
testdir.makeini(
|
||||||
|
"""
|
||||||
|
[pytest]
|
||||||
|
addopts=-o
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest("cache_dir=ignored")
|
||||||
|
result.stderr.fnmatch_lines(
|
||||||
|
[
|
||||||
|
"%s: error: argument -o/--override-ini: expected one argument"
|
||||||
|
% (testdir.request.config._parser.optparser.prog,)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
assert result.ret == _pytest.main.EXIT_USAGEERROR
|
||||||
|
|
||||||
def test_override_ini_does_not_contain_paths(self):
|
def test_override_ini_does_not_contain_paths(self):
|
||||||
"""Check that -o no longer swallows all options after it (#3103)"""
|
"""Check that -o no longer swallows all options after it (#3103)"""
|
||||||
from _pytest.config import get_config
|
from _pytest.config import get_config
|
||||||
|
|
Loading…
Reference in New Issue