Merge remote-tracking branch 'upstream/master' into merge-master-into-features
This commit is contained in:
@@ -270,6 +270,7 @@ class AssertionRewritingHook(object):
|
||||
_issue_config_warning(
|
||||
PytestWarning("Module already imported so cannot be rewritten: %s" % name),
|
||||
self.config,
|
||||
stacklevel=5,
|
||||
)
|
||||
|
||||
def load_module(self, name):
|
||||
|
||||
@@ -56,7 +56,9 @@ class Cache(object):
|
||||
from _pytest.warning_types import PytestWarning
|
||||
|
||||
_issue_config_warning(
|
||||
PytestWarning(fmt.format(**args) if args else fmt), self._config
|
||||
PytestWarning(fmt.format(**args) if args else fmt),
|
||||
self._config,
|
||||
stacklevel=3,
|
||||
)
|
||||
|
||||
def makedir(self, name):
|
||||
@@ -108,6 +110,10 @@ class Cache(object):
|
||||
"""
|
||||
path = self._getvaluepath(key)
|
||||
try:
|
||||
if path.parent.is_dir():
|
||||
cache_dir_exists_already = True
|
||||
else:
|
||||
cache_dir_exists_already = self._cachedir.exists()
|
||||
path.parent.mkdir(exist_ok=True, parents=True)
|
||||
except (IOError, OSError):
|
||||
self.warn("could not create cache path {path}", path=path)
|
||||
@@ -119,6 +125,7 @@ class Cache(object):
|
||||
else:
|
||||
with f:
|
||||
json.dump(value, f, indent=2, sort_keys=True)
|
||||
if not cache_dir_exists_already:
|
||||
self._ensure_supporting_files()
|
||||
|
||||
def _ensure_supporting_files(self):
|
||||
@@ -128,8 +135,10 @@ class Cache(object):
|
||||
if not readme_path.is_file():
|
||||
readme_path.write_text(README_CONTENT)
|
||||
|
||||
msg = u"# created by pytest automatically, do not change\n*"
|
||||
self._cachedir.joinpath(".gitignore").write_text(msg, encoding="UTF-8")
|
||||
gitignore_path = self._cachedir.joinpath(".gitignore")
|
||||
if not gitignore_path.is_file():
|
||||
msg = u"# Created by pytest automatically.\n*"
|
||||
gitignore_path.write_text(msg, encoding="UTF-8")
|
||||
|
||||
|
||||
class LFPlugin(object):
|
||||
|
||||
@@ -11,10 +11,10 @@ import shlex
|
||||
import sys
|
||||
import types
|
||||
import warnings
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
import py
|
||||
import six
|
||||
from pkg_resources import parse_version
|
||||
from pluggy import HookimplMarker
|
||||
from pluggy import HookspecMarker
|
||||
from pluggy import PluginManager
|
||||
@@ -191,7 +191,7 @@ def _prepareconfig(args=None, plugins=None):
|
||||
if warning:
|
||||
from _pytest.warnings import _issue_config_warning
|
||||
|
||||
_issue_config_warning(warning, config=config)
|
||||
_issue_config_warning(warning, config=config, stacklevel=4)
|
||||
return pluginmanager.hook.pytest_cmdline_parse(
|
||||
pluginmanager=pluginmanager, args=args
|
||||
)
|
||||
@@ -815,7 +815,7 @@ class Config(object):
|
||||
|
||||
minver = self.inicfg.get("minversion", None)
|
||||
if minver:
|
||||
if LooseVersion(minver) > LooseVersion(pytest.__version__):
|
||||
if parse_version(minver) > parse_version(pytest.__version__):
|
||||
raise pytest.UsageError(
|
||||
"%s:%d: requires pytest-%s, actual pytest-%s'"
|
||||
% (
|
||||
|
||||
@@ -42,6 +42,7 @@ def getcfg(args, config=None):
|
||||
CFG_PYTEST_SECTION.format(filename=inibasename)
|
||||
),
|
||||
config=config,
|
||||
stacklevel=2,
|
||||
)
|
||||
return base, p, iniconfig["pytest"]
|
||||
if (
|
||||
@@ -116,7 +117,9 @@ def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None):
|
||||
# TODO: [pytest] section in *.cfg files is deprecated. Need refactoring once
|
||||
# the deprecation expires.
|
||||
_issue_config_warning(
|
||||
CFG_PYTEST_SECTION.format(filename=str(inifile)), config
|
||||
CFG_PYTEST_SECTION.format(filename=str(inifile)),
|
||||
config,
|
||||
stacklevel=2,
|
||||
)
|
||||
break
|
||||
except KeyError:
|
||||
|
||||
@@ -13,8 +13,9 @@ import six
|
||||
|
||||
import pytest
|
||||
from _pytest.fixtures import fixture
|
||||
from _pytest.pathlib import Path
|
||||
|
||||
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
|
||||
RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$")
|
||||
|
||||
|
||||
@fixture
|
||||
@@ -267,6 +268,9 @@ class MonkeyPatch(object):
|
||||
self._cwd = os.getcwd()
|
||||
if hasattr(path, "chdir"):
|
||||
path.chdir()
|
||||
elif isinstance(path, Path):
|
||||
# modern python uses the fspath protocol here LEGACY
|
||||
os.chdir(str(path))
|
||||
else:
|
||||
os.chdir(path)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ def pytest_configure(config):
|
||||
from _pytest.deprecated import RESULT_LOG
|
||||
from _pytest.warnings import _issue_config_warning
|
||||
|
||||
_issue_config_warning(RESULT_LOG, config)
|
||||
_issue_config_warning(RESULT_LOG, config, stacklevel=2)
|
||||
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
|
||||
@@ -647,9 +647,11 @@ class TerminalReporter(object):
|
||||
def pytest_terminal_summary(self):
|
||||
self.summary_errors()
|
||||
self.summary_failures()
|
||||
yield
|
||||
self.summary_warnings()
|
||||
yield
|
||||
self.summary_passes()
|
||||
# Display any extra warnings from teardown here (if any).
|
||||
self.summary_warnings()
|
||||
|
||||
def pytest_keyboard_interrupt(self, excinfo):
|
||||
self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True)
|
||||
@@ -726,11 +728,21 @@ class TerminalReporter(object):
|
||||
if not all_warnings:
|
||||
return
|
||||
|
||||
final = hasattr(self, "_already_displayed_warnings")
|
||||
if final:
|
||||
warnings = all_warnings[self._already_displayed_warnings :]
|
||||
else:
|
||||
warnings = all_warnings
|
||||
self._already_displayed_warnings = len(warnings)
|
||||
if not warnings:
|
||||
return
|
||||
|
||||
grouped = itertools.groupby(
|
||||
all_warnings, key=lambda wr: wr.get_location(self.config)
|
||||
warnings, key=lambda wr: wr.get_location(self.config)
|
||||
)
|
||||
|
||||
self.write_sep("=", "warnings summary", yellow=True, bold=False)
|
||||
title = "warnings summary (final)" if final else "warnings summary"
|
||||
self.write_sep("=", title, yellow=True, bold=False)
|
||||
for location, warning_records in grouped:
|
||||
# legacy warnings show their location explicitly, while standard warnings look better without
|
||||
# it because the location is already formatted into the message
|
||||
@@ -786,8 +798,7 @@ class TerminalReporter(object):
|
||||
self.write_line(line)
|
||||
else:
|
||||
msg = self._getfailureheadline(rep)
|
||||
markup = {"red": True, "bold": True}
|
||||
self.write_sep("_", msg, **markup)
|
||||
self.write_sep("_", msg, red=True, bold=True)
|
||||
self._outrep_summary(rep)
|
||||
for report in self.getreports(""):
|
||||
if report.nodeid == rep.nodeid and report.when == "teardown":
|
||||
@@ -808,7 +819,7 @@ class TerminalReporter(object):
|
||||
msg = "ERROR at setup of " + msg
|
||||
elif rep.when == "teardown":
|
||||
msg = "ERROR at teardown of " + msg
|
||||
self.write_sep("_", msg)
|
||||
self.write_sep("_", msg, red=True, bold=True)
|
||||
self._outrep_summary(rep)
|
||||
|
||||
def _outrep_summary(self, rep):
|
||||
|
||||
@@ -10,6 +10,7 @@ import warnings
|
||||
|
||||
import attr
|
||||
import py
|
||||
import six
|
||||
|
||||
import pytest
|
||||
from .pathlib import ensure_reset_dir
|
||||
@@ -26,7 +27,14 @@ class TempPathFactory(object):
|
||||
|
||||
The base directory can be configured using the ``--basetemp`` option."""
|
||||
|
||||
_given_basetemp = attr.ib()
|
||||
_given_basetemp = attr.ib(
|
||||
# using os.path.abspath() to get absolute path instead of resolve() as it
|
||||
# does not work the same in all platforms (see #4427)
|
||||
# Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012)
|
||||
convert=attr.converters.optional(
|
||||
lambda p: Path(os.path.abspath(six.text_type(p)))
|
||||
)
|
||||
)
|
||||
_trace = attr.ib()
|
||||
_basetemp = attr.ib(default=None)
|
||||
|
||||
@@ -53,7 +61,7 @@ class TempPathFactory(object):
|
||||
""" return base temporary directory. """
|
||||
if self._basetemp is None:
|
||||
if self._given_basetemp is not None:
|
||||
basetemp = Path(self._given_basetemp)
|
||||
basetemp = self._given_basetemp
|
||||
ensure_reset_dir(basetemp)
|
||||
else:
|
||||
from_env = os.environ.get("PYTEST_DEBUG_TEMPROOT")
|
||||
|
||||
@@ -160,7 +160,7 @@ def pytest_terminal_summary(terminalreporter):
|
||||
yield
|
||||
|
||||
|
||||
def _issue_config_warning(warning, config):
|
||||
def _issue_config_warning(warning, config, stacklevel):
|
||||
"""
|
||||
This function should be used instead of calling ``warnings.warn`` directly when we are in the "configure" stage:
|
||||
at this point the actual options might not have been set, so we manually trigger the pytest_warning_captured
|
||||
@@ -168,10 +168,11 @@ def _issue_config_warning(warning, config):
|
||||
|
||||
:param warning: the warning instance.
|
||||
:param config:
|
||||
:param stacklevel: stacklevel forwarded to warnings.warn
|
||||
"""
|
||||
with warnings.catch_warnings(record=True) as records:
|
||||
warnings.simplefilter("always", type(warning))
|
||||
warnings.warn(warning, stacklevel=2)
|
||||
warnings.warn(warning, stacklevel=stacklevel)
|
||||
config.hook.pytest_warning_captured.call_historic(
|
||||
kwargs=dict(warning_message=records[0], when="config", item=None)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user