Make Node.warn support two forms, new and deprecated
As suggested during review, it now accepts two forms: Node.warn(warning_instance) (recommended) Node.warn(code, message) (deprecated)
This commit is contained in:
parent
5ef51262f7
commit
47bf58d69e
|
@ -1,5 +1,12 @@
|
||||||
The functions ``Node.warn`` and ``Config.warn`` have been deprecated. Instead of ``Node.warn`` users should now use
|
``Config.warn`` has been deprecated, it should be replaced by calls to the standard ``warnings.warn``.
|
||||||
``Node.std_warn``, while ``Config.warn`` should be replaced by the standard ``warnings.warn``.
|
|
||||||
|
``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 instance.
|
||||||
|
|
||||||
|
* ``node.warn("CI", "some message")``: this code/message form is now deprecated and should be converted to
|
||||||
|
the warning instance form above.
|
||||||
|
|
||||||
``RemovedInPytest4Warning`` and ``PytestExperimentalApiWarning`` are now part of the public API and should be accessed
|
``RemovedInPytest4Warning`` and ``PytestExperimentalApiWarning`` are now part of the public API and should be accessed
|
||||||
using ``pytest.RemovedInPytest4Warning`` and ``pytest.PytestExperimentalApiWarning``.
|
using ``pytest.RemovedInPytest4Warning`` and ``pytest.PytestExperimentalApiWarning``.
|
||||||
|
|
|
@ -54,7 +54,7 @@ MARK_PARAMETERSET_UNPACKING = RemovedInPytest4Warning(
|
||||||
)
|
)
|
||||||
|
|
||||||
NODE_WARN = RemovedInPytest4Warning(
|
NODE_WARN = RemovedInPytest4Warning(
|
||||||
"Node.warn has been deprecated, use Node.std_warn instead"
|
"Node.warn(code, message) form has been deprecated, use Node.warn(warning_instance) instead."
|
||||||
)
|
)
|
||||||
|
|
||||||
RECORD_XML_PROPERTY = RemovedInPytest4Warning(
|
RECORD_XML_PROPERTY = RemovedInPytest4Warning(
|
||||||
|
|
|
@ -262,7 +262,7 @@ def record_xml_property(record_property, request):
|
||||||
"""(Deprecated) use record_property."""
|
"""(Deprecated) use record_property."""
|
||||||
from _pytest import deprecated
|
from _pytest import deprecated
|
||||||
|
|
||||||
request.node.std_warn(deprecated.RECORD_XML_PROPERTY)
|
request.node.warn(deprecated.RECORD_XML_PROPERTY)
|
||||||
|
|
||||||
return record_property
|
return record_property
|
||||||
|
|
||||||
|
@ -275,9 +275,7 @@ def record_xml_attribute(request):
|
||||||
"""
|
"""
|
||||||
from _pytest.warning_types import PytestWarning
|
from _pytest.warning_types import PytestWarning
|
||||||
|
|
||||||
request.node.std_warn(
|
request.node.warn(PytestWarning("record_xml_attribute is an experimental feature"))
|
||||||
PytestWarning("record_xml_attribute is an experimental feature")
|
|
||||||
)
|
|
||||||
xml = getattr(request.config, "_xml", None)
|
xml = getattr(request.config, "_xml", None)
|
||||||
if xml is not None:
|
if xml is not None:
|
||||||
node_reporter = xml.node_reporter(request.node.nodeid)
|
node_reporter = xml.node_reporter(request.node.nodeid)
|
||||||
|
|
|
@ -95,7 +95,7 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
|
||||||
argval = (argval,)
|
argval = (argval,)
|
||||||
|
|
||||||
if newmarks and belonging_definition is not None:
|
if newmarks and belonging_definition is not None:
|
||||||
belonging_definition.std_warn(MARK_PARAMETERSET_UNPACKING)
|
belonging_definition.warn(MARK_PARAMETERSET_UNPACKING)
|
||||||
|
|
||||||
return cls(argval, marks=newmarks, id=None)
|
return cls(argval, marks=newmarks, id=None)
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,42 @@ class Node(object):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s %r>" % (self.__class__.__name__, getattr(self, "name", None))
|
return "<%s %r>" % (self.__class__.__name__, getattr(self, "name", None))
|
||||||
|
|
||||||
def warn(self, code, message):
|
def warn(self, code_or_warning, message=None):
|
||||||
|
"""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).
|
||||||
|
:param Union[str,None] message: message to display when called in the legacy form.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if message is None:
|
||||||
|
self._std_warn(code_or_warning)
|
||||||
|
else:
|
||||||
|
self._legacy_warn(code_or_warning, message)
|
||||||
|
|
||||||
|
def _legacy_warn(self, code, message):
|
||||||
"""
|
"""
|
||||||
.. deprecated:: 3.8
|
.. deprecated:: 3.8
|
||||||
|
|
||||||
|
@ -146,7 +181,7 @@ class Node(object):
|
||||||
"""
|
"""
|
||||||
from _pytest.deprecated import NODE_WARN
|
from _pytest.deprecated import NODE_WARN
|
||||||
|
|
||||||
self.std_warn(NODE_WARN)
|
self._std_warn(NODE_WARN)
|
||||||
|
|
||||||
assert isinstance(code, str)
|
assert isinstance(code, str)
|
||||||
fslocation = get_fslocation_from_item(self)
|
fslocation = get_fslocation_from_item(self)
|
||||||
|
@ -156,7 +191,7 @@ class Node(object):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def std_warn(self, warning):
|
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
|
||||||
|
@ -175,8 +210,8 @@ class Node(object):
|
||||||
)
|
)
|
||||||
path, lineno = get_fslocation_from_item(self)
|
path, lineno = get_fslocation_from_item(self)
|
||||||
warnings.warn_explicit(
|
warnings.warn_explicit(
|
||||||
six.text_type(warning),
|
warning,
|
||||||
type(warning),
|
category=None,
|
||||||
filename=str(path),
|
filename=str(path),
|
||||||
lineno=lineno + 1 if lineno is not None else None,
|
lineno=lineno + 1 if lineno is not None else None,
|
||||||
)
|
)
|
||||||
|
|
|
@ -126,7 +126,7 @@ class LsofFdLeakChecker(object):
|
||||||
error.append(error[0])
|
error.append(error[0])
|
||||||
error.append("*** function %s:%s: %s " % item.location)
|
error.append("*** function %s:%s: %s " % item.location)
|
||||||
error.append("See issue #2366")
|
error.append("See issue #2366")
|
||||||
item.std_warn(pytest.PytestWarning("\n".join(error)))
|
item.warn(pytest.PytestWarning("\n".join(error)))
|
||||||
|
|
||||||
|
|
||||||
# XXX copied from execnet's conftest.py - needs to be merged
|
# XXX copied from execnet's conftest.py - needs to be merged
|
||||||
|
|
|
@ -659,7 +659,7 @@ class Class(PyCollector):
|
||||||
if not safe_getattr(self.obj, "__test__", True):
|
if not safe_getattr(self.obj, "__test__", True):
|
||||||
return []
|
return []
|
||||||
if hasinit(self.obj):
|
if hasinit(self.obj):
|
||||||
self.std_warn(
|
self.warn(
|
||||||
PytestWarning(
|
PytestWarning(
|
||||||
"cannot collect test class %r because it has a "
|
"cannot collect test class %r because it has a "
|
||||||
"__init__ constructor" % self.obj.__name__
|
"__init__ constructor" % self.obj.__name__
|
||||||
|
@ -667,7 +667,7 @@ class Class(PyCollector):
|
||||||
)
|
)
|
||||||
return []
|
return []
|
||||||
elif hasnew(self.obj):
|
elif hasnew(self.obj):
|
||||||
self.std_warn(
|
self.warn(
|
||||||
PytestWarning(
|
PytestWarning(
|
||||||
"cannot collect test class %r because it has a "
|
"cannot collect test class %r because it has a "
|
||||||
"__new__ constructor" % self.obj.__name__
|
"__new__ constructor" % self.obj.__name__
|
||||||
|
@ -799,7 +799,7 @@ class Generator(FunctionMixin, PyCollector):
|
||||||
)
|
)
|
||||||
seen[name] = True
|
seen[name] = True
|
||||||
values.append(self.Function(name, self, args=args, callobj=call))
|
values.append(self.Function(name, self, args=args, callobj=call))
|
||||||
self.std_warn(deprecated.YIELD_TESTS)
|
self.warn(deprecated.YIELD_TESTS)
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def getcallargs(self, obj):
|
def getcallargs(self, obj):
|
||||||
|
@ -1106,7 +1106,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
||||||
invocation through the ``request.param`` attribute.
|
invocation through the ``request.param`` attribute.
|
||||||
"""
|
"""
|
||||||
if self.config:
|
if self.config:
|
||||||
self.definition.std_warn(deprecated.METAFUNC_ADD_CALL)
|
self.definition.warn(deprecated.METAFUNC_ADD_CALL)
|
||||||
|
|
||||||
assert funcargs is None or isinstance(funcargs, dict)
|
assert funcargs is None or isinstance(funcargs, dict)
|
||||||
if funcargs is not None:
|
if funcargs is not None:
|
||||||
|
@ -1170,7 +1170,7 @@ def _idval(val, argname, idx, idfn, item, config=None):
|
||||||
)
|
)
|
||||||
msg += " {}: {}\n".format(type(e).__name__, e)
|
msg += " {}: {}\n".format(type(e).__name__, e)
|
||||||
msg += "This warning will be an error error in pytest-4.0."
|
msg += "This warning will be an error error in pytest-4.0."
|
||||||
item.std_warn(RemovedInPytest4Warning(msg))
|
item.warn(RemovedInPytest4Warning(msg))
|
||||||
if s:
|
if s:
|
||||||
return ascii_escaped(s)
|
return ascii_escaped(s)
|
||||||
|
|
||||||
|
|
|
@ -831,7 +831,7 @@ class TestLegacyWarning(object):
|
||||||
===*warnings summary*===
|
===*warnings summary*===
|
||||||
*test_warn_on_test_item_from_request.py::test_hello*
|
*test_warn_on_test_item_from_request.py::test_hello*
|
||||||
*hello*
|
*hello*
|
||||||
*test_warn_on_test_item_from_request.py:7:*Node.warn has been deprecated, use Node.std_warn instead*
|
*test_warn_on_test_item_from_request.py:7:*Node.warn(code, message) form has been deprecated*
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1042,7 +1042,7 @@ class TestKeywordSelection(object):
|
||||||
@pytest.mark.filterwarnings("ignore")
|
@pytest.mark.filterwarnings("ignore")
|
||||||
def test_parameterset_extractfrom(argval, expected):
|
def test_parameterset_extractfrom(argval, expected):
|
||||||
class DummyItem:
|
class DummyItem:
|
||||||
def std_warn(self, warning):
|
def warn(self, warning):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
extracted = ParameterSet.extract_from(argval, belonging_definition=DummyItem())
|
extracted = ParameterSet.extract_from(argval, belonging_definition=DummyItem())
|
||||||
|
|
|
@ -29,4 +29,4 @@ def test_std_warn_not_pytestwarning(testdir):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
with pytest.raises(ValueError, match=".*instance of PytestWarning.*"):
|
with pytest.raises(ValueError, match=".*instance of PytestWarning.*"):
|
||||||
items[0].std_warn(UserWarning("some warning"))
|
items[0].warn(UserWarning("some warning"))
|
||||||
|
|
Loading…
Reference in New Issue