Implement hack to issue warnings during config
Once we can capture warnings during the config stage, we can then get rid of this function Related to #2891
This commit is contained in:
parent
60499d221e
commit
0fffa6ba2f
|
@ -611,6 +611,8 @@ Session related reporting hooks:
|
|||
.. autofunction:: pytest_terminal_summary
|
||||
.. autofunction:: pytest_fixture_setup
|
||||
.. autofunction:: pytest_fixture_post_finalizer
|
||||
.. autofunction:: pytest_logwarning
|
||||
.. autofunction:: pytest_warning_captured
|
||||
|
||||
And here is the central hook for reporting about
|
||||
test execution:
|
||||
|
|
|
@ -154,7 +154,7 @@ def get_plugin_manager():
|
|||
|
||||
|
||||
def _prepareconfig(args=None, plugins=None):
|
||||
warning = None
|
||||
warning_msg = None
|
||||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
elif isinstance(args, py.path.local):
|
||||
|
@ -165,7 +165,7 @@ def _prepareconfig(args=None, plugins=None):
|
|||
args = shlex.split(args, posix=sys.platform != "win32")
|
||||
from _pytest import deprecated
|
||||
|
||||
warning = deprecated.MAIN_STR_ARGS
|
||||
warning_msg = deprecated.MAIN_STR_ARGS
|
||||
config = get_config()
|
||||
pluginmanager = config.pluginmanager
|
||||
try:
|
||||
|
@ -175,10 +175,11 @@ def _prepareconfig(args=None, plugins=None):
|
|||
pluginmanager.consider_pluginarg(plugin)
|
||||
else:
|
||||
pluginmanager.register(plugin)
|
||||
if warning:
|
||||
if warning_msg:
|
||||
from _pytest.warning_types import PytestWarning
|
||||
from _pytest.warnings import _issue_config_warning
|
||||
|
||||
warnings.warn(warning, PytestWarning)
|
||||
_issue_config_warning(PytestWarning(warning_msg), config=config)
|
||||
return pluginmanager.hook.pytest_cmdline_parse(
|
||||
pluginmanager=pluginmanager, args=args
|
||||
)
|
||||
|
@ -696,6 +697,7 @@ class Config(object):
|
|||
ns.inifilename,
|
||||
ns.file_or_dir + unknown_args,
|
||||
rootdir_cmd_arg=ns.rootdir or None,
|
||||
config=self,
|
||||
)
|
||||
self.rootdir, self.inifile, self.inicfg = r
|
||||
self._parser.extra_info["rootdir"] = self.rootdir
|
||||
|
|
|
@ -10,15 +10,12 @@ def exists(path, ignore=EnvironmentError):
|
|||
return False
|
||||
|
||||
|
||||
def getcfg(args):
|
||||
def getcfg(args, config=None):
|
||||
"""
|
||||
Search the list of arguments for a valid ini-file for pytest,
|
||||
and return a tuple of (rootdir, inifile, cfg-dict).
|
||||
|
||||
note: warnfunc is an optional function used to warn
|
||||
about ini-files that use deprecated features.
|
||||
This parameter should be removed when pytest
|
||||
adopts standard deprecation warnings (#1804).
|
||||
note: config is optional and used only to issue warnings explicitly (#2891).
|
||||
"""
|
||||
from _pytest.deprecated import CFG_PYTEST_SECTION
|
||||
|
||||
|
@ -34,13 +31,15 @@ def getcfg(args):
|
|||
if exists(p):
|
||||
iniconfig = py.iniconfig.IniConfig(p)
|
||||
if "pytest" in iniconfig.sections:
|
||||
if inibasename == "setup.cfg":
|
||||
import warnings
|
||||
if inibasename == "setup.cfg" and config is not None:
|
||||
from _pytest.warnings import _issue_config_warning
|
||||
from _pytest.warning_types import RemovedInPytest4Warning
|
||||
|
||||
warnings.warn(
|
||||
CFG_PYTEST_SECTION.format(filename=inibasename),
|
||||
RemovedInPytest4Warning,
|
||||
_issue_config_warning(
|
||||
RemovedInPytest4Warning(
|
||||
CFG_PYTEST_SECTION.format(filename=inibasename)
|
||||
),
|
||||
config=config,
|
||||
)
|
||||
return base, p, iniconfig["pytest"]
|
||||
if (
|
||||
|
@ -99,7 +98,7 @@ def get_dirs_from_args(args):
|
|||
return [get_dir_from_path(path) for path in possible_paths if path.exists()]
|
||||
|
||||
|
||||
def determine_setup(inifile, args, rootdir_cmd_arg=None):
|
||||
def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None):
|
||||
dirs = get_dirs_from_args(args)
|
||||
if inifile:
|
||||
iniconfig = py.iniconfig.IniConfig(inifile)
|
||||
|
@ -109,14 +108,16 @@ def determine_setup(inifile, args, rootdir_cmd_arg=None):
|
|||
for section in sections:
|
||||
try:
|
||||
inicfg = iniconfig[section]
|
||||
if is_cfg_file and section == "pytest":
|
||||
from _pytest.warning_types import RemovedInPytest4Warning
|
||||
if is_cfg_file and section == "pytest" and config is not None:
|
||||
from _pytest.deprecated import CFG_PYTEST_SECTION
|
||||
import warnings
|
||||
from _pytest.warning_types import RemovedInPytest4Warning
|
||||
from _pytest.warnings import _issue_config_warning
|
||||
|
||||
warnings.warn(
|
||||
CFG_PYTEST_SECTION.format(filename=str(inifile)),
|
||||
RemovedInPytest4Warning,
|
||||
_issue_config_warning(
|
||||
RemovedInPytest4Warning(
|
||||
CFG_PYTEST_SECTION.format(filename=str(inifile))
|
||||
),
|
||||
config,
|
||||
)
|
||||
break
|
||||
except KeyError:
|
||||
|
@ -124,13 +125,13 @@ def determine_setup(inifile, args, rootdir_cmd_arg=None):
|
|||
rootdir = get_common_ancestor(dirs)
|
||||
else:
|
||||
ancestor = get_common_ancestor(dirs)
|
||||
rootdir, inifile, inicfg = getcfg([ancestor])
|
||||
rootdir, inifile, inicfg = getcfg([ancestor], config=config)
|
||||
if rootdir is None:
|
||||
for rootdir in ancestor.parts(reverse=True):
|
||||
if rootdir.join("setup.py").exists():
|
||||
break
|
||||
else:
|
||||
rootdir, inifile, inicfg = getcfg(dirs)
|
||||
rootdir, inifile, inicfg = getcfg(dirs, config=config)
|
||||
if rootdir is None:
|
||||
rootdir = get_common_ancestor([py.path.local(), ancestor])
|
||||
is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/"
|
||||
|
|
|
@ -526,7 +526,17 @@ def pytest_terminal_summary(terminalreporter, exitstatus):
|
|||
|
||||
@hookspec(historic=True)
|
||||
def pytest_logwarning(message, code, nodeid, fslocation):
|
||||
""" process a warning specified by a message, a code string,
|
||||
"""
|
||||
.. deprecated:: 3.8
|
||||
|
||||
This hook is will stop working in a future release.
|
||||
|
||||
pytest no longer triggers this hook, but the
|
||||
terminal writer still implements it to display warnings issued by
|
||||
:meth:`_pytest.config.Config.warn` and :meth:`_pytest.nodes.Node.warn`. Calling those functions will be
|
||||
an error in future releases.
|
||||
|
||||
process a warning specified by a message, a code string,
|
||||
a nodeid and fslocation (both of which may be None
|
||||
if the warning is not tied to a particular node/location).
|
||||
|
||||
|
@ -538,7 +548,7 @@ def pytest_logwarning(message, code, nodeid, fslocation):
|
|||
@hookspec(historic=True)
|
||||
def pytest_warning_captured(warning_message, when, item):
|
||||
"""
|
||||
Process a warning captured by the internal pytest plugin.
|
||||
Process a warning captured by the internal pytest warnings plugin.
|
||||
|
||||
:param warnings.WarningMessage warning_message:
|
||||
The captured warning. This is the same object produced by :py:func:`warnings.catch_warnings`, and contains
|
||||
|
@ -546,6 +556,8 @@ def pytest_warning_captured(warning_message, when, item):
|
|||
|
||||
:param str when:
|
||||
Indicates when the warning was captured. Possible values:
|
||||
|
||||
* ``"config"``: during pytest configuration/initialization stage.
|
||||
* ``"collect"``: during test collection.
|
||||
* ``"runtest"``: during test execution.
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@ def pytest_configure(config):
|
|||
config.pluginmanager.register(config._resultlog)
|
||||
|
||||
from _pytest.deprecated import RESULT_LOG
|
||||
import warnings
|
||||
from _pytest.warning_types import RemovedInPytest4Warning
|
||||
from _pytest.warnings import _issue_config_warning
|
||||
|
||||
warnings.warn(RESULT_LOG, RemovedInPytest4Warning)
|
||||
_issue_config_warning(RemovedInPytest4Warning(RESULT_LOG), config)
|
||||
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
|
|
|
@ -146,3 +146,20 @@ def pytest_terminal_summary(terminalreporter):
|
|||
config = terminalreporter.config
|
||||
with catch_warnings_for_item(config=config, ihook=config.hook, item=None):
|
||||
yield
|
||||
|
||||
|
||||
def _issue_config_warning(warning, config):
|
||||
"""
|
||||
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
|
||||
hook so we can display this warnings in the terminal. This is a hack until we can sort out #2891.
|
||||
|
||||
:param warning: the warning instance.
|
||||
:param config:
|
||||
"""
|
||||
with warnings.catch_warnings(record=True) as records:
|
||||
warnings.simplefilter("always", type(warning))
|
||||
warnings.warn(warning, stacklevel=2)
|
||||
config.hook.pytest_warning_captured.call_historic(
|
||||
kwargs=dict(warning_message=records[0], when="config", item=None)
|
||||
)
|
||||
|
|
|
@ -54,9 +54,6 @@ def test_funcarg_prefix_deprecation(testdir):
|
|||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.xfail(
|
||||
reason="#2891 need to handle warnings during pre-config", strict=True
|
||||
)
|
||||
def test_pytest_setup_cfg_deprecated(testdir):
|
||||
testdir.makefile(
|
||||
".cfg",
|
||||
|
@ -72,9 +69,6 @@ def test_pytest_setup_cfg_deprecated(testdir):
|
|||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.xfail(
|
||||
reason="#2891 need to handle warnings during pre-config", strict=True
|
||||
)
|
||||
def test_pytest_custom_cfg_deprecated(testdir):
|
||||
testdir.makefile(
|
||||
".cfg",
|
||||
|
@ -89,18 +83,15 @@ def test_pytest_custom_cfg_deprecated(testdir):
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="#2891 need to handle warnings during pre-config", strict=True
|
||||
)
|
||||
def test_str_args_deprecated(tmpdir, testdir):
|
||||
def test_str_args_deprecated(tmpdir):
|
||||
"""Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0."""
|
||||
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
||||
|
||||
warnings = []
|
||||
|
||||
class Collect(object):
|
||||
def pytest_logwarning(self, message):
|
||||
warnings.append(message)
|
||||
def pytest_warning_captured(self, warning_message):
|
||||
warnings.append(str(warning_message.message))
|
||||
|
||||
ret = pytest.main("%s -x" % tmpdir, plugins=[Collect()])
|
||||
msg = (
|
||||
|
@ -116,9 +107,6 @@ def test_getfuncargvalue_is_deprecated(request):
|
|||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.xfail(
|
||||
reason="#2891 need to handle warnings during pre-config", strict=True
|
||||
)
|
||||
def test_resultlog_is_deprecated(testdir):
|
||||
result = testdir.runpytest("--help")
|
||||
result.stdout.fnmatch_lines(["*DEPRECATED path for machine-readable result log*"])
|
||||
|
|
Loading…
Reference in New Issue