Skip to content

Commit fd48cd5

Browse files
committed
Remove config.warn, Node.warn; pytest_logwarning issues a warning when implemented
Fix pytest-dev#3078
1 parent 26d202a commit fd48cd5

20 files changed

+107
-269
lines changed

changelog/3078.removal.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Remove legacy internal warnings system: ``config.warn``, ``Node.warn``. The ``pytest_logwarning`` now issues a warning when implemented.
2+
3+
See our `docs <https://docs.pytest.org/en/latest/deprecations.html#config-warn-and-node-warn>`__ on information on how to update your code.

doc/en/deprecations.rst

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -74,34 +74,6 @@ Becomes:
7474
7575
7676
77-
``Config.warn`` and ``Node.warn``
78-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79-
80-
.. deprecated:: 3.8
81-
82-
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
83-
system for its own warnings, so those two functions are now deprecated.
84-
85-
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``, example:
86-
87-
.. code-block:: python
88-
89-
config.warn("C1", "some warning")
90-
91-
Becomes:
92-
93-
.. code-block:: python
94-
95-
warnings.warn(pytest.PytestWarning("some warning"))
96-
97-
``Node.warn`` now supports two signatures:
98-
99-
* ``node.warn(PytestWarning("some message"))``: is now the **recommended** way to call this function.
100-
The warning instance must be a PytestWarning or subclass.
101-
102-
* ``node.warn("CI", "some message")``: this code/message form is now **deprecated** and should be converted to the warning instance form above.
103-
104-
10577
Calling fixtures directly
10678
~~~~~~~~~~~~~~~~~~~~~~~~~
10779

@@ -350,7 +322,33 @@ This should be updated to make use of standard fixture mechanisms:
350322
You can consult `funcarg comparison section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_ for
351323
more information.
352324

353-
This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings.
325+
326+
``Config.warn`` and ``Node.warn``
327+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
328+
329+
*Removed in version 4.0.*
330+
331+
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
332+
system for its own warnings, so those two functions are now deprecated.
333+
334+
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``, example:
335+
336+
.. code-block:: python
337+
338+
config.warn("C1", "some warning")
339+
340+
Becomes:
341+
342+
.. code-block:: python
343+
344+
warnings.warn(pytest.PytestWarning("some warning"))
345+
346+
``Node.warn`` now supports two signatures:
347+
348+
* ``node.warn(PytestWarning("some message"))``: is now the **recommended** way to call this function.
349+
The warning instance must be a PytestWarning or subclass.
350+
351+
* ``node.warn("CI", "some message")``: this code/message form has been **removed** and should be converted to the warning instance form above.
354352

355353
``yield`` tests
356354
~~~~~~~~~~~~~~~

doc/en/reference.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,6 @@ Session related reporting hooks:
618618
.. autofunction:: pytest_terminal_summary
619619
.. autofunction:: pytest_fixture_setup
620620
.. autofunction:: pytest_fixture_post_finalizer
621-
.. autofunction:: pytest_logwarning
622621
.. autofunction:: pytest_warning_captured
623622

624623
And here is the central hook for reporting about

src/_pytest/assertion/rewrite.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,11 @@ def mark_rewrite(self, *names):
278278

279279
def _warn_already_imported(self, name):
280280
from _pytest.warning_types import PytestWarning
281-
from _pytest.warnings import _issue_config_warning
281+
from _pytest.warnings import _issue_warning_captured
282282

283-
_issue_config_warning(
283+
_issue_warning_captured(
284284
PytestWarning("Module already imported so cannot be rewritten: %s" % name),
285-
self.config,
285+
self.config.hook,
286286
stacklevel=5,
287287
)
288288

src/_pytest/cacheprovider.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ def cache_dir_from_config(config):
5959
return resolve_from_str(config.getini("cache_dir"), config.rootdir)
6060

6161
def warn(self, fmt, **args):
62-
from _pytest.warnings import _issue_config_warning
62+
from _pytest.warnings import _issue_warning_captured
6363
from _pytest.warning_types import PytestWarning
6464

65-
_issue_config_warning(
65+
_issue_warning_captured(
6666
PytestWarning(fmt.format(**args) if args else fmt),
67-
self._config,
67+
self._config.hook,
6868
stacklevel=3,
6969
)
7070

src/_pytest/config/__init__.py

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
from .exceptions import UsageError
2727
from .findpaths import determine_setup
2828
from .findpaths import exists
29+
from _pytest import deprecated
2930
from _pytest._code import ExceptionInfo
3031
from _pytest._code import filter_traceback
3132
from _pytest.compat import lru_cache
3233
from _pytest.compat import safe_str
3334
from _pytest.outcomes import Skipped
35+
from _pytest.warning_types import PytestWarning
3436

3537
hookimpl = HookimplMarker("pytest")
3638
hookspec = HookspecMarker("pytest")
@@ -189,9 +191,9 @@ def _prepareconfig(args=None, plugins=None):
189191
else:
190192
pluginmanager.register(plugin)
191193
if warning:
192-
from _pytest.warnings import _issue_config_warning
194+
from _pytest.warnings import _issue_warning_captured
193195

194-
_issue_config_warning(warning, config=config, stacklevel=4)
196+
_issue_warning_captured(warning, hook=config.hook, stacklevel=4)
195197
return pluginmanager.hook.pytest_cmdline_parse(
196198
pluginmanager=pluginmanager, args=args
197199
)
@@ -245,14 +247,7 @@ def addhooks(self, module_or_class):
245247
Use :py:meth:`pluggy.PluginManager.add_hookspecs <PluginManager.add_hookspecs>`
246248
instead.
247249
"""
248-
warning = dict(
249-
code="I2",
250-
fslocation=_pytest._code.getfslineno(sys._getframe(1)),
251-
nodeid=None,
252-
message="use pluginmanager.add_hookspecs instead of "
253-
"deprecated addhooks() method.",
254-
)
255-
self._warn(warning)
250+
warnings.warn(deprecated.PLUGIN_MANAGER_ADDHOOKS, stacklevel=2)
256251
return self.add_hookspecs(module_or_class)
257252

258253
def parse_hookimpl_opts(self, plugin, name):
@@ -296,10 +291,12 @@ def parse_hookspec_opts(self, module_or_class, name):
296291

297292
def register(self, plugin, name=None):
298293
if name in ["pytest_catchlog", "pytest_capturelog"]:
299-
self._warn(
300-
"{} plugin has been merged into the core, "
301-
"please remove it from your requirements.".format(
302-
name.replace("_", "-")
294+
warnings.warn(
295+
PytestWarning(
296+
"{} plugin has been merged into the core, "
297+
"please remove it from your requirements.".format(
298+
name.replace("_", "-")
299+
)
303300
)
304301
)
305302
return
@@ -336,14 +333,6 @@ def pytest_configure(self, config):
336333
)
337334
self._configured = True
338335

339-
def _warn(self, message):
340-
kwargs = (
341-
message
342-
if isinstance(message, dict)
343-
else {"code": "I1", "message": message, "fslocation": None, "nodeid": None}
344-
)
345-
self.hook.pytest_logwarning.call_historic(kwargs=kwargs)
346-
347336
#
348337
# internal API for local conftest plugin handling
349338
#
@@ -542,7 +531,13 @@ def import_plugin(self, modname):
542531
six.reraise(new_exc_type, new_exc, sys.exc_info()[2])
543532

544533
except Skipped as e:
545-
self._warn("skipped plugin %r: %s" % ((modname, e.msg)))
534+
from _pytest.warnings import _issue_warning_captured
535+
536+
_issue_warning_captured(
537+
PytestWarning("skipped plugin %r: %s" % (modname, e.msg)),
538+
self.hook,
539+
stacklevel=1,
540+
)
546541
else:
547542
mod = sys.modules[importspec]
548543
self.register(mod, modname)
@@ -617,7 +612,6 @@ def __init__(self, pluginmanager):
617612
self._override_ini = ()
618613
self._opt2dest = {}
619614
self._cleanup = []
620-
self._warn = self.pluginmanager._warn
621615
self.pluginmanager.register(self, "pytestconfig")
622616
self._configured = False
623617
self.invocation_dir = py.path.local()
@@ -642,36 +636,6 @@ def _ensure_unconfigure(self):
642636
fin = self._cleanup.pop()
643637
fin()
644638

645-
def warn(self, code, message, fslocation=None, nodeid=None):
646-
"""
647-
.. deprecated:: 3.8
648-
649-
Use :py:func:`warnings.warn` or :py:func:`warnings.warn_explicit` directly instead.
650-
651-
Generate a warning for this test session.
652-
"""
653-
from _pytest.warning_types import RemovedInPytest4Warning
654-
655-
if isinstance(fslocation, (tuple, list)) and len(fslocation) > 2:
656-
filename, lineno = fslocation[:2]
657-
else:
658-
filename = "unknown file"
659-
lineno = 0
660-
msg = "config.warn has been deprecated, use warnings.warn instead"
661-
if nodeid:
662-
msg = "{}: {}".format(nodeid, msg)
663-
warnings.warn_explicit(
664-
RemovedInPytest4Warning(msg),
665-
category=None,
666-
filename=filename,
667-
lineno=lineno,
668-
)
669-
self.hook.pytest_logwarning.call_historic(
670-
kwargs=dict(
671-
code=code, message=message, fslocation=fslocation, nodeid=nodeid
672-
)
673-
)
674-
675639
def get_terminal_writer(self):
676640
return self.pluginmanager.get_plugin("terminalreporter")._tw
677641

@@ -826,7 +790,15 @@ def _preparse(self, args, addopts=True):
826790
if ns.help or ns.version:
827791
# we don't want to prevent --help/--version to work
828792
# so just let is pass and print a warning at the end
829-
self._warn("could not load initial conftests (%s)\n" % e.path)
793+
from _pytest.warnings import _issue_warning_captured
794+
795+
_issue_warning_captured(
796+
PytestWarning(
797+
"could not load initial conftests: {}".format(e.path)
798+
),
799+
self.hook,
800+
stacklevel=2,
801+
)
830802
else:
831803
raise
832804

src/_pytest/config/findpaths.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ def getcfg(args, config=None):
3434
iniconfig = py.iniconfig.IniConfig(p)
3535
if "pytest" in iniconfig.sections:
3636
if inibasename == "setup.cfg" and config is not None:
37-
from _pytest.warnings import _issue_config_warning
37+
from _pytest.warnings import _issue_warning_captured
3838
from _pytest.warning_types import RemovedInPytest4Warning
3939

40-
_issue_config_warning(
40+
_issue_warning_captured(
4141
RemovedInPytest4Warning(
4242
CFG_PYTEST_SECTION.format(filename=inibasename)
4343
),
44-
config=config,
44+
hook=config.hook,
4545
stacklevel=2,
4646
)
4747
return base, p, iniconfig["pytest"]
@@ -112,13 +112,13 @@ def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None):
112112
inicfg = iniconfig[section]
113113
if is_cfg_file and section == "pytest" and config is not None:
114114
from _pytest.deprecated import CFG_PYTEST_SECTION
115-
from _pytest.warnings import _issue_config_warning
115+
from _pytest.warnings import _issue_warning_captured
116116

117117
# TODO: [pytest] section in *.cfg files is deprecated. Need refactoring once
118118
# the deprecation expires.
119-
_issue_config_warning(
119+
_issue_warning_captured(
120120
CFG_PYTEST_SECTION.format(filename=str(inifile)),
121-
config,
121+
config.hook,
122122
stacklevel=2,
123123
)
124124
break

src/_pytest/deprecated.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,6 @@
7575
"For more details, see: https://docs.pytest.org/en/latest/parametrize.html"
7676
)
7777

78-
NODE_WARN = RemovedInPytest4Warning(
79-
"Node.warn(code, message) form has been deprecated, use Node.warn(warning_instance) instead."
80-
)
81-
8278
RAISES_EXEC = PytestDeprecationWarning(
8379
"raises(..., 'code(as_a_string)') is deprecated, use the context manager form or use `exec()` directly\n\n"
8480
"See https://docs.pytest.org/en/latest/deprecations.html#raises-warns-exec"
@@ -94,6 +90,13 @@
9490
'"record_xml_property" is now deprecated.'
9591
)
9692

93+
PLUGIN_MANAGER_ADDHOOKS = PytestDeprecationWarning(
94+
"use pluginmanager.add_hookspecs instead of deprecated addhooks() method."
95+
)
96+
97+
COLLECTOR_MAKEITEM = RemovedInPytest4Warning(
98+
"pycollector makeitem was removed as it is an accidentially leaked internal api"
99+
)
97100

98101
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning(
99102
"Defining pytest_plugins in a non-top-level conftest is deprecated, "
@@ -110,3 +113,8 @@
110113
"pytest/tmpdir_factory.ensuretemp is deprecated, \n"
111114
"please use the tmp_path fixture or tmp_path_factory.mktemp"
112115
)
116+
117+
PYTEST_LOGWARNING = PytestDeprecationWarning(
118+
"pytest_logwarning is deprecated, no longer being called, and will be removed soon\n"
119+
"please use pytest_warning_captured instead"
120+
)

src/_pytest/hookspec.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """
22
from pluggy import HookspecMarker
33

4+
from _pytest.deprecated import PYTEST_LOGWARNING
5+
46

57
hookspec = HookspecMarker("pytest")
68

@@ -496,7 +498,7 @@ def pytest_terminal_summary(terminalreporter, exitstatus):
496498
"""
497499

498500

499-
@hookspec(historic=True)
501+
@hookspec(historic=True, warn_on_impl=PYTEST_LOGWARNING)
500502
def pytest_logwarning(message, code, nodeid, fslocation):
501503
"""
502504
.. deprecated:: 3.8

0 commit comments

Comments
 (0)