Remove config.warn, Node.warn; pytest_logwarning issues a warning when implemented

Fix #3078
This commit is contained in:
Bruno Oliveira 2018-12-11 20:02:36 -02:00
parent 26d202a7bd
commit fd48cd57f9
20 changed files with 109 additions and 271 deletions

View File

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

View File

@ -74,34 +74,6 @@ Becomes:
``Config.warn`` and ``Node.warn``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.8
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
system for its own warnings, so those two functions are now deprecated.
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``, example:
.. code-block:: python
config.warn("C1", "some warning")
Becomes:
.. code-block:: python
warnings.warn(pytest.PytestWarning("some warning"))
``Node.warn`` now supports two signatures:
* ``node.warn(PytestWarning("some message"))``: is now the **recommended** way to call this function.
The warning instance must be a PytestWarning or subclass.
* ``node.warn("CI", "some message")``: this code/message form is now **deprecated** and should be converted to the warning instance form above.
Calling fixtures directly Calling fixtures directly
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
@ -350,7 +322,33 @@ This should be updated to make use of standard fixture mechanisms:
You can consult `funcarg comparison section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_ for You can consult `funcarg comparison section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_ for
more information. more information.
This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings.
``Config.warn`` and ``Node.warn``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.*
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
system for its own warnings, so those two functions are now deprecated.
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``, example:
.. code-block:: python
config.warn("C1", "some warning")
Becomes:
.. code-block:: python
warnings.warn(pytest.PytestWarning("some warning"))
``Node.warn`` now supports two signatures:
* ``node.warn(PytestWarning("some message"))``: is now the **recommended** way to call this function.
The warning instance must be a PytestWarning or subclass.
* ``node.warn("CI", "some message")``: this code/message form has been **removed** and should be converted to the warning instance form above.
``yield`` tests ``yield`` tests
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~

View File

@ -618,7 +618,6 @@ Session related reporting hooks:
.. autofunction:: pytest_terminal_summary .. autofunction:: pytest_terminal_summary
.. autofunction:: pytest_fixture_setup .. autofunction:: pytest_fixture_setup
.. autofunction:: pytest_fixture_post_finalizer .. autofunction:: pytest_fixture_post_finalizer
.. autofunction:: pytest_logwarning
.. autofunction:: pytest_warning_captured .. autofunction:: pytest_warning_captured
And here is the central hook for reporting about And here is the central hook for reporting about

View File

@ -278,11 +278,11 @@ class AssertionRewritingHook(object):
def _warn_already_imported(self, name): def _warn_already_imported(self, name):
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
from _pytest.warnings import _issue_config_warning from _pytest.warnings import _issue_warning_captured
_issue_config_warning( _issue_warning_captured(
PytestWarning("Module already imported so cannot be rewritten: %s" % name), PytestWarning("Module already imported so cannot be rewritten: %s" % name),
self.config, self.config.hook,
stacklevel=5, stacklevel=5,
) )

View File

@ -59,12 +59,12 @@ class Cache(object):
return resolve_from_str(config.getini("cache_dir"), config.rootdir) return resolve_from_str(config.getini("cache_dir"), config.rootdir)
def warn(self, fmt, **args): def warn(self, fmt, **args):
from _pytest.warnings import _issue_config_warning from _pytest.warnings import _issue_warning_captured
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
_issue_config_warning( _issue_warning_captured(
PytestWarning(fmt.format(**args) if args else fmt), PytestWarning(fmt.format(**args) if args else fmt),
self._config, self._config.hook,
stacklevel=3, stacklevel=3,
) )

View File

@ -26,11 +26,13 @@ from .exceptions import PrintHelp
from .exceptions import UsageError from .exceptions import UsageError
from .findpaths import determine_setup from .findpaths import determine_setup
from .findpaths import exists from .findpaths import exists
from _pytest import deprecated
from _pytest._code import ExceptionInfo from _pytest._code import ExceptionInfo
from _pytest._code import filter_traceback from _pytest._code import filter_traceback
from _pytest.compat import lru_cache from _pytest.compat import lru_cache
from _pytest.compat import safe_str from _pytest.compat import safe_str
from _pytest.outcomes import Skipped from _pytest.outcomes import Skipped
from _pytest.warning_types import PytestWarning
hookimpl = HookimplMarker("pytest") hookimpl = HookimplMarker("pytest")
hookspec = HookspecMarker("pytest") hookspec = HookspecMarker("pytest")
@ -189,9 +191,9 @@ def _prepareconfig(args=None, plugins=None):
else: else:
pluginmanager.register(plugin) pluginmanager.register(plugin)
if warning: if warning:
from _pytest.warnings import _issue_config_warning from _pytest.warnings import _issue_warning_captured
_issue_config_warning(warning, config=config, stacklevel=4) _issue_warning_captured(warning, hook=config.hook, stacklevel=4)
return pluginmanager.hook.pytest_cmdline_parse( return pluginmanager.hook.pytest_cmdline_parse(
pluginmanager=pluginmanager, args=args pluginmanager=pluginmanager, args=args
) )
@ -245,14 +247,7 @@ class PytestPluginManager(PluginManager):
Use :py:meth:`pluggy.PluginManager.add_hookspecs <PluginManager.add_hookspecs>` Use :py:meth:`pluggy.PluginManager.add_hookspecs <PluginManager.add_hookspecs>`
instead. instead.
""" """
warning = dict( warnings.warn(deprecated.PLUGIN_MANAGER_ADDHOOKS, stacklevel=2)
code="I2",
fslocation=_pytest._code.getfslineno(sys._getframe(1)),
nodeid=None,
message="use pluginmanager.add_hookspecs instead of "
"deprecated addhooks() method.",
)
self._warn(warning)
return self.add_hookspecs(module_or_class) return self.add_hookspecs(module_or_class)
def parse_hookimpl_opts(self, plugin, name): def parse_hookimpl_opts(self, plugin, name):
@ -296,10 +291,12 @@ class PytestPluginManager(PluginManager):
def register(self, plugin, name=None): def register(self, plugin, name=None):
if name in ["pytest_catchlog", "pytest_capturelog"]: if name in ["pytest_catchlog", "pytest_capturelog"]:
self._warn( warnings.warn(
"{} plugin has been merged into the core, " PytestWarning(
"please remove it from your requirements.".format( "{} plugin has been merged into the core, "
name.replace("_", "-") "please remove it from your requirements.".format(
name.replace("_", "-")
)
) )
) )
return return
@ -336,14 +333,6 @@ class PytestPluginManager(PluginManager):
) )
self._configured = True self._configured = True
def _warn(self, message):
kwargs = (
message
if isinstance(message, dict)
else {"code": "I1", "message": message, "fslocation": None, "nodeid": None}
)
self.hook.pytest_logwarning.call_historic(kwargs=kwargs)
# #
# internal API for local conftest plugin handling # internal API for local conftest plugin handling
# #
@ -542,7 +531,13 @@ class PytestPluginManager(PluginManager):
six.reraise(new_exc_type, new_exc, sys.exc_info()[2]) six.reraise(new_exc_type, new_exc, sys.exc_info()[2])
except Skipped as e: except Skipped as e:
self._warn("skipped plugin %r: %s" % ((modname, e.msg))) from _pytest.warnings import _issue_warning_captured
_issue_warning_captured(
PytestWarning("skipped plugin %r: %s" % (modname, e.msg)),
self.hook,
stacklevel=1,
)
else: else:
mod = sys.modules[importspec] mod = sys.modules[importspec]
self.register(mod, modname) self.register(mod, modname)
@ -617,7 +612,6 @@ class Config(object):
self._override_ini = () self._override_ini = ()
self._opt2dest = {} self._opt2dest = {}
self._cleanup = [] self._cleanup = []
self._warn = self.pluginmanager._warn
self.pluginmanager.register(self, "pytestconfig") self.pluginmanager.register(self, "pytestconfig")
self._configured = False self._configured = False
self.invocation_dir = py.path.local() self.invocation_dir = py.path.local()
@ -642,36 +636,6 @@ class Config(object):
fin = self._cleanup.pop() fin = self._cleanup.pop()
fin() fin()
def warn(self, code, message, fslocation=None, nodeid=None):
"""
.. deprecated:: 3.8
Use :py:func:`warnings.warn` or :py:func:`warnings.warn_explicit` directly instead.
Generate a warning for this test session.
"""
from _pytest.warning_types import RemovedInPytest4Warning
if isinstance(fslocation, (tuple, list)) and len(fslocation) > 2:
filename, lineno = fslocation[:2]
else:
filename = "unknown file"
lineno = 0
msg = "config.warn has been deprecated, use warnings.warn instead"
if nodeid:
msg = "{}: {}".format(nodeid, msg)
warnings.warn_explicit(
RemovedInPytest4Warning(msg),
category=None,
filename=filename,
lineno=lineno,
)
self.hook.pytest_logwarning.call_historic(
kwargs=dict(
code=code, message=message, fslocation=fslocation, nodeid=nodeid
)
)
def get_terminal_writer(self): def get_terminal_writer(self):
return self.pluginmanager.get_plugin("terminalreporter")._tw return self.pluginmanager.get_plugin("terminalreporter")._tw
@ -826,7 +790,15 @@ class Config(object):
if ns.help or ns.version: if ns.help or ns.version:
# we don't want to prevent --help/--version to work # we don't want to prevent --help/--version to work
# so just let is pass and print a warning at the end # so just let is pass and print a warning at the end
self._warn("could not load initial conftests (%s)\n" % e.path) from _pytest.warnings import _issue_warning_captured
_issue_warning_captured(
PytestWarning(
"could not load initial conftests: {}".format(e.path)
),
self.hook,
stacklevel=2,
)
else: else:
raise raise

View File

@ -34,14 +34,14 @@ def getcfg(args, config=None):
iniconfig = py.iniconfig.IniConfig(p) iniconfig = py.iniconfig.IniConfig(p)
if "pytest" in iniconfig.sections: if "pytest" in iniconfig.sections:
if inibasename == "setup.cfg" and config is not None: if inibasename == "setup.cfg" and config is not None:
from _pytest.warnings import _issue_config_warning from _pytest.warnings import _issue_warning_captured
from _pytest.warning_types import RemovedInPytest4Warning from _pytest.warning_types import RemovedInPytest4Warning
_issue_config_warning( _issue_warning_captured(
RemovedInPytest4Warning( RemovedInPytest4Warning(
CFG_PYTEST_SECTION.format(filename=inibasename) CFG_PYTEST_SECTION.format(filename=inibasename)
), ),
config=config, hook=config.hook,
stacklevel=2, stacklevel=2,
) )
return base, p, iniconfig["pytest"] return base, p, iniconfig["pytest"]
@ -112,13 +112,13 @@ def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None):
inicfg = iniconfig[section] inicfg = iniconfig[section]
if is_cfg_file and section == "pytest" and config is not None: if is_cfg_file and section == "pytest" and config is not None:
from _pytest.deprecated import CFG_PYTEST_SECTION from _pytest.deprecated import CFG_PYTEST_SECTION
from _pytest.warnings import _issue_config_warning from _pytest.warnings import _issue_warning_captured
# TODO: [pytest] section in *.cfg files is deprecated. Need refactoring once # TODO: [pytest] section in *.cfg files is deprecated. Need refactoring once
# the deprecation expires. # the deprecation expires.
_issue_config_warning( _issue_warning_captured(
CFG_PYTEST_SECTION.format(filename=str(inifile)), CFG_PYTEST_SECTION.format(filename=str(inifile)),
config, config.hook,
stacklevel=2, stacklevel=2,
) )
break break

View File

@ -75,10 +75,6 @@ MARK_PARAMETERSET_UNPACKING = RemovedInPytest4Warning(
"For more details, see: https://docs.pytest.org/en/latest/parametrize.html" "For more details, see: https://docs.pytest.org/en/latest/parametrize.html"
) )
NODE_WARN = RemovedInPytest4Warning(
"Node.warn(code, message) form has been deprecated, use Node.warn(warning_instance) instead."
)
RAISES_EXEC = PytestDeprecationWarning( RAISES_EXEC = PytestDeprecationWarning(
"raises(..., 'code(as_a_string)') is deprecated, use the context manager form or use `exec()` directly\n\n" "raises(..., 'code(as_a_string)') is deprecated, use the context manager form or use `exec()` directly\n\n"
"See https://docs.pytest.org/en/latest/deprecations.html#raises-warns-exec" "See https://docs.pytest.org/en/latest/deprecations.html#raises-warns-exec"
@ -94,6 +90,13 @@ RECORD_XML_PROPERTY = RemovedInPytest4Warning(
'"record_xml_property" is now deprecated.' '"record_xml_property" is now deprecated.'
) )
PLUGIN_MANAGER_ADDHOOKS = PytestDeprecationWarning(
"use pluginmanager.add_hookspecs instead of deprecated addhooks() method."
)
COLLECTOR_MAKEITEM = RemovedInPytest4Warning(
"pycollector makeitem was removed as it is an accidentially leaked internal api"
)
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning( PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning(
"Defining pytest_plugins in a non-top-level conftest is deprecated, " "Defining pytest_plugins in a non-top-level conftest is deprecated, "
@ -110,3 +113,8 @@ PYTEST_ENSURETEMP = RemovedInPytest4Warning(
"pytest/tmpdir_factory.ensuretemp is deprecated, \n" "pytest/tmpdir_factory.ensuretemp is deprecated, \n"
"please use the tmp_path fixture or tmp_path_factory.mktemp" "please use the tmp_path fixture or tmp_path_factory.mktemp"
) )
PYTEST_LOGWARNING = PytestDeprecationWarning(
"pytest_logwarning is deprecated, no longer being called, and will be removed soon\n"
"please use pytest_warning_captured instead"
)

View File

@ -1,6 +1,8 @@
""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """ """ hook specifications for pytest plugins, invoked from main.py and builtin plugins. """
from pluggy import HookspecMarker from pluggy import HookspecMarker
from _pytest.deprecated import PYTEST_LOGWARNING
hookspec = HookspecMarker("pytest") hookspec = HookspecMarker("pytest")
@ -496,7 +498,7 @@ def pytest_terminal_summary(terminalreporter, exitstatus):
""" """
@hookspec(historic=True) @hookspec(historic=True, warn_on_impl=PYTEST_LOGWARNING)
def pytest_logwarning(message, code, nodeid, fslocation): def pytest_logwarning(message, code, nodeid, fslocation):
""" """
.. deprecated:: 3.8 .. deprecated:: 3.8

View File

@ -105,74 +105,7 @@ class Node(object):
def __repr__(self): def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, getattr(self, "name", None)) return "<%s %s>" % (self.__class__.__name__, getattr(self, "name", None))
def warn(self, _code_or_warning=None, message=None, code=None): def warn(self, warning):
"""Issue a warning for this item.
Warnings will be displayed after the test session, unless explicitly suppressed.
This can be called in two forms:
**Warning instance**
This was introduced in pytest 3.8 and uses the standard warning mechanism to issue warnings.
.. code-block:: python
node.warn(PytestWarning("some message"))
The warning instance must be a subclass of :class:`pytest.PytestWarning`.
**code/message (deprecated)**
This form was used in pytest prior to 3.8 and is considered deprecated. Using this form will emit another
warning about the deprecation:
.. code-block:: python
node.warn("CI", "some message")
:param Union[Warning,str] _code_or_warning:
warning instance or warning code (legacy). This parameter receives an underscore for backward
compatibility with the legacy code/message form, and will be replaced for something
more usual when the legacy form is removed.
:param Union[str,None] message: message to display when called in the legacy form.
:param str code: code for the warning, in legacy form when using keyword arguments.
:return:
"""
if message is None:
if _code_or_warning is None:
raise ValueError("code_or_warning must be given")
self._std_warn(_code_or_warning)
else:
if _code_or_warning and code:
raise ValueError(
"code_or_warning and code cannot both be passed to this function"
)
code = _code_or_warning or code
self._legacy_warn(code, message)
def _legacy_warn(self, code, message):
"""
.. deprecated:: 3.8
Use :meth:`Node.std_warn <_pytest.nodes.Node.std_warn>` instead.
Generate a warning with the given code and message for this item.
"""
from _pytest.deprecated import NODE_WARN
self._std_warn(NODE_WARN)
assert isinstance(code, str)
fslocation = get_fslocation_from_item(self)
self.ihook.pytest_logwarning.call_historic(
kwargs=dict(
code=code, message=message, nodeid=self.nodeid, fslocation=fslocation
)
)
def _std_warn(self, warning):
"""Issue a warning for this item. """Issue a warning for this item.
Warnings will be displayed after the test session, unless explicitly suppressed Warnings will be displayed after the test session, unless explicitly suppressed
@ -180,6 +113,12 @@ class Node(object):
:param Warning warning: the warning instance to issue. Must be a subclass of PytestWarning. :param Warning warning: the warning instance to issue. Must be a subclass of PytestWarning.
:raise ValueError: if ``warning`` instance is not a subclass of PytestWarning. :raise ValueError: if ``warning`` instance is not a subclass of PytestWarning.
Example usage::
.. code-block:: python
node.warn(PytestWarning("some message"))
""" """
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning

View File

@ -34,9 +34,9 @@ def pytest_configure(config):
config.pluginmanager.register(config._resultlog) config.pluginmanager.register(config._resultlog)
from _pytest.deprecated import RESULT_LOG from _pytest.deprecated import RESULT_LOG
from _pytest.warnings import _issue_config_warning from _pytest.warnings import _issue_warning_captured
_issue_config_warning(RESULT_LOG, config, stacklevel=2) _issue_warning_captured(RESULT_LOG, config.hook, stacklevel=2)
def pytest_unconfigure(config): def pytest_unconfigure(config):

View File

@ -186,20 +186,17 @@ def pytest_report_teststatus(report):
@attr.s @attr.s
class WarningReport(object): class WarningReport(object):
""" """
Simple structure to hold warnings information captured by ``pytest_logwarning`` and ``pytest_warning_captured``. Simple structure to hold warnings information captured by ``pytest_warning_captured``.
:ivar str message: user friendly message about the warning :ivar str message: user friendly message about the warning
:ivar str|None nodeid: node id that generated the warning (see ``get_location``). :ivar str|None nodeid: node id that generated the warning (see ``get_location``).
:ivar tuple|py.path.local fslocation: :ivar tuple|py.path.local fslocation:
file system location of the source of the warning (see ``get_location``). file system location of the source of the warning (see ``get_location``).
:ivar bool legacy: if this warning report was generated from the deprecated ``pytest_logwarning`` hook.
""" """
message = attr.ib() message = attr.ib()
nodeid = attr.ib(default=None) nodeid = attr.ib(default=None)
fslocation = attr.ib(default=None) fslocation = attr.ib(default=None)
legacy = attr.ib(default=False)
def get_location(self, config): def get_location(self, config):
""" """
@ -329,13 +326,6 @@ class TerminalReporter(object):
self.write_line("INTERNALERROR> " + line) self.write_line("INTERNALERROR> " + line)
return 1 return 1
def pytest_logwarning(self, fslocation, message, nodeid):
warnings = self.stats.setdefault("warnings", [])
warning = WarningReport(
fslocation=fslocation, message=message, nodeid=nodeid, legacy=True
)
warnings.append(warning)
def pytest_warning_captured(self, warning_message, item): def pytest_warning_captured(self, warning_message, item):
# from _pytest.nodes import get_fslocation_from_item # from _pytest.nodes import get_fslocation_from_item
from _pytest.warnings import warning_record_to_str from _pytest.warnings import warning_record_to_str

View File

@ -160,19 +160,19 @@ def pytest_terminal_summary(terminalreporter):
yield yield
def _issue_config_warning(warning, config, stacklevel): def _issue_warning_captured(warning, hook, stacklevel):
""" """
This function should be used instead of calling ``warnings.warn`` directly when we are in the "configure" stage: 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 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. 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 warning: the warning instance.
:param config: :param hook: the hook caller
:param stacklevel: stacklevel forwarded to warnings.warn :param stacklevel: stacklevel forwarded to warnings.warn
""" """
with warnings.catch_warnings(record=True) as records: with warnings.catch_warnings(record=True) as records:
warnings.simplefilter("always", type(warning)) warnings.simplefilter("always", type(warning))
warnings.warn(warning, stacklevel=stacklevel) warnings.warn(warning, stacklevel=stacklevel)
config.hook.pytest_warning_captured.call_historic( hook.pytest_warning_captured.call_historic(
kwargs=dict(warning_message=records[0], when="config", item=None) kwargs=dict(warning_message=records[0], when="config", item=None)
) )

View File

@ -146,6 +146,7 @@ class TestGeneralUsage(object):
assert result.ret assert result.ret
result.stderr.fnmatch_lines(["*ERROR: not found:*{}".format(p2.basename)]) result.stderr.fnmatch_lines(["*ERROR: not found:*{}".format(p2.basename)])
@pytest.mark.filterwarnings("default")
def test_better_reporting_on_conftest_load_failure(self, testdir, request): def test_better_reporting_on_conftest_load_failure(self, testdir, request):
"""Show a user-friendly traceback on conftest import failures (#486, #3332)""" """Show a user-friendly traceback on conftest import failures (#486, #3332)"""
testdir.makepyfile("") testdir.makepyfile("")

View File

@ -120,6 +120,7 @@ def test_terminal_reporter_writer_attr(pytestconfig):
@pytest.mark.parametrize("plugin", ["catchlog", "capturelog"]) @pytest.mark.parametrize("plugin", ["catchlog", "capturelog"])
@pytest.mark.filterwarnings("default")
def test_pytest_catchlog_deprecated(testdir, plugin): def test_pytest_catchlog_deprecated(testdir, plugin):
testdir.makepyfile( testdir.makepyfile(
""" """

View File

@ -823,7 +823,9 @@ def test_rewritten():
testdir.makepyfile(test_remember_rewritten_modules="") testdir.makepyfile(test_remember_rewritten_modules="")
warnings = [] warnings = []
hook = AssertionRewritingHook(pytestconfig) hook = AssertionRewritingHook(pytestconfig)
monkeypatch.setattr(hook.config, "warn", lambda code, msg: warnings.append(msg)) monkeypatch.setattr(
hook, "_warn_already_imported", lambda code, msg: warnings.append(msg)
)
hook.find_module("test_remember_rewritten_modules") hook.find_module("test_remember_rewritten_modules")
hook.load_module("test_remember_rewritten_modules") hook.load_module("test_remember_rewritten_modules")
hook.mark_rewrite("test_remember_rewritten_modules") hook.mark_rewrite("test_remember_rewritten_modules")

View File

@ -12,7 +12,6 @@ from _pytest.config.findpaths import determine_setup
from _pytest.config.findpaths import get_common_ancestor from _pytest.config.findpaths import get_common_ancestor
from _pytest.config.findpaths import getcfg from _pytest.config.findpaths import getcfg
from _pytest.main import EXIT_NOTESTSCOLLECTED from _pytest.main import EXIT_NOTESTSCOLLECTED
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
class TestParseIni(object): class TestParseIni(object):
@ -790,66 +789,6 @@ def test_collect_pytest_prefix_bug(pytestconfig):
assert pm.parse_hookimpl_opts(Dummy(), "pytest_something") is None assert pm.parse_hookimpl_opts(Dummy(), "pytest_something") is None
class TestLegacyWarning(object):
@pytest.mark.filterwarnings("default")
def test_warn_config(self, testdir):
testdir.makeconftest(
"""
values = []
def pytest_runtest_setup(item):
item.config.warn("C1", "hello")
def pytest_logwarning(code, message):
if message == "hello" and code == "C1":
values.append(1)
"""
)
testdir.makepyfile(
"""
def test_proper(pytestconfig):
import conftest
assert conftest.values == [1]
"""
)
result = testdir.runpytest(SHOW_PYTEST_WARNINGS_ARG)
result.stdout.fnmatch_lines(
["*hello", "*config.warn has been deprecated*", "*1 passed*"]
)
@pytest.mark.filterwarnings("default")
@pytest.mark.parametrize("use_kw", [True, False])
def test_warn_on_test_item_from_request(self, testdir, use_kw):
code_kw = "code=" if use_kw else ""
message_kw = "message=" if use_kw else ""
testdir.makepyfile(
"""
import pytest
@pytest.fixture
def fix(request):
request.node.warn({code_kw}"T1", {message_kw}"hello")
def test_hello(fix):
pass
""".format(
code_kw=code_kw, message_kw=message_kw
)
)
result = testdir.runpytest(
"--disable-pytest-warnings", SHOW_PYTEST_WARNINGS_ARG
)
assert "hello" not in result.stdout.str()
result = testdir.runpytest(SHOW_PYTEST_WARNINGS_ARG)
result.stdout.fnmatch_lines(
"""
===*warnings summary*===
*test_warn_on_test_item_from_request.py::test_hello*
*hello*
*test_warn_on_test_item_from_request.py:7:*Node.warn(code, message) form has been deprecated*
"""
)
class TestRootdir(object): class TestRootdir(object):
def test_simple_noini(self, tmpdir): def test_simple_noini(self, tmpdir):
assert get_common_ancestor([tmpdir]) == tmpdir assert get_common_ancestor([tmpdir]) == tmpdir

View File

@ -32,7 +32,7 @@ class TestPytestPluginInteractions(object):
""" """
import newhooks import newhooks
def pytest_addhooks(pluginmanager): def pytest_addhooks(pluginmanager):
pluginmanager.addhooks(newhooks) pluginmanager.add_hookspecs(newhooks)
def pytest_myhook(xyz): def pytest_myhook(xyz):
return xyz + 1 return xyz + 1
""" """
@ -52,7 +52,7 @@ class TestPytestPluginInteractions(object):
""" """
import sys import sys
def pytest_addhooks(pluginmanager): def pytest_addhooks(pluginmanager):
pluginmanager.addhooks(sys) pluginmanager.add_hookspecs(sys)
""" """
) )
res = testdir.runpytest() res = testdir.runpytest()
@ -141,23 +141,6 @@ class TestPytestPluginInteractions(object):
ihook_b = session.gethookproxy(testdir.tmpdir.join("tests")) ihook_b = session.gethookproxy(testdir.tmpdir.join("tests"))
assert ihook_a is not ihook_b assert ihook_a is not ihook_b
def test_warn_on_deprecated_addhooks(self, pytestpm):
warnings = []
class get_warnings(object):
def pytest_logwarning(self, code, fslocation, message, nodeid):
warnings.append(message)
class Plugin(object):
def pytest_testhook():
pass
pytestpm.register(get_warnings())
before = list(warnings)
pytestpm.addhooks(Plugin())
assert len(warnings) == len(before) + 1
assert "deprecated" in warnings[-1]
def test_default_markers(testdir): def test_default_markers(testdir):
result = testdir.runpytest("--markers") result = testdir.runpytest("--markers")
@ -240,11 +223,12 @@ class TestPytestPluginManager(object):
with pytest.raises(ImportError): with pytest.raises(ImportError):
pytestpm.consider_env() pytestpm.consider_env()
@pytest.mark.filterwarnings("always")
def test_plugin_skip(self, testdir, monkeypatch): def test_plugin_skip(self, testdir, monkeypatch):
p = testdir.makepyfile( p = testdir.makepyfile(
skipping1=""" skipping1="""
import pytest import pytest
pytest.skip("hello") pytest.skip("hello", allow_module_level=True)
""" """
) )
p.copy(p.dirpath("skipping2.py")) p.copy(p.dirpath("skipping2.py"))

View File

@ -168,7 +168,7 @@ def make_holder():
@pytest.mark.parametrize("holder", make_holder()) @pytest.mark.parametrize("holder", make_holder())
def test_hookrecorder_basic(holder): def test_hookrecorder_basic(holder):
pm = PytestPluginManager() pm = PytestPluginManager()
pm.addhooks(holder) pm.add_hookspecs(holder)
rec = HookRecorder(pm) rec = HookRecorder(pm)
pm.hook.pytest_xyz(arg=123) pm.hook.pytest_xyz(arg=123)
call = rec.popcall("pytest_xyz") call = rec.popcall("pytest_xyz")

View File

@ -308,9 +308,9 @@ def test_filterwarnings_mark_registration(testdir):
def test_warning_captured_hook(testdir): def test_warning_captured_hook(testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
from _pytest.warnings import _issue_config_warning from _pytest.warnings import _issue_warning_captured
def pytest_configure(config): def pytest_configure(config):
_issue_config_warning(UserWarning("config warning"), config, stacklevel=2) _issue_warning_captured(UserWarning("config warning"), config.hook, stacklevel=2)
""" """
) )
testdir.makepyfile( testdir.makepyfile(