Fix existing tests now that we are using standard warnings

This commit is contained in:
Bruno Oliveira 2018-09-01 17:10:26 -03:00
parent 8e4501ee29
commit 0c8dbdcd92
10 changed files with 80 additions and 97 deletions

View File

@ -417,7 +417,14 @@ class PytestPluginManager(PluginManager):
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
) )
warnings.warn(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST) from _pytest.warning_types import RemovedInPytest4Warning
warnings.warn_explicit(
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST,
RemovedInPytest4Warning,
filename=str(conftestpath),
lineno=0,
)
except Exception: except Exception:
raise ConftestImportFailure(conftestpath, sys.exc_info()) raise ConftestImportFailure(conftestpath, sys.exc_info())

View File

@ -63,7 +63,7 @@ METAFUNC_ADD_CALL = (
"Please use Metafunc.parametrize instead." "Please use Metafunc.parametrize instead."
) )
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning( PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = (
"Defining pytest_plugins in a non-top-level conftest is deprecated, " "Defining pytest_plugins in a non-top-level conftest is deprecated, "
"because it affects the entire directory tree in a non-explicit way.\n" "because it affects the entire directory tree in a non-explicit way.\n"
"Please move it to the top level conftest file instead." "Please move it to the top level conftest file instead."

View File

@ -94,7 +94,7 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
if legacy_force_tuple: if legacy_force_tuple:
argval = (argval,) argval = (argval,)
if newmarks: if newmarks and item is not None:
item.std_warn(MARK_PARAMETERSET_UNPACKING) item.std_warn(MARK_PARAMETERSET_UNPACKING)
return cls(argval, marks=newmarks, id=None) return cls(argval, marks=newmarks, id=None)

View File

@ -44,7 +44,7 @@ from _pytest.mark.structures import (
get_unpacked_marks, get_unpacked_marks,
normalize_mark_list, normalize_mark_list,
) )
from _pytest.warning_types import PytestUsageWarning from _pytest.warning_types import PytestUsageWarning, RemovedInPytest4Warning
# relative paths that we use to filter traceback entries from appearing to the user; # relative paths that we use to filter traceback entries from appearing to the user;
# see filter_traceback # see filter_traceback
@ -982,7 +982,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
arg_values_types = self._resolve_arg_value_types(argnames, indirect) arg_values_types = self._resolve_arg_value_types(argnames, indirect)
ids = self._resolve_arg_ids(argnames, ids, parameters) ids = self._resolve_arg_ids(argnames, ids, parameters, item=self.definition)
scopenum = scope2index(scope, descr="call to {}".format(self.parametrize)) scopenum = scope2index(scope, descr="call to {}".format(self.parametrize))
@ -1005,13 +1005,14 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
newcalls.append(newcallspec) newcalls.append(newcallspec)
self._calls = newcalls self._calls = newcalls
def _resolve_arg_ids(self, argnames, ids, parameters): def _resolve_arg_ids(self, argnames, ids, parameters, item):
"""Resolves the actual ids for the given argnames, based on the ``ids`` parameter given """Resolves the actual ids for the given argnames, based on the ``ids`` parameter given
to ``parametrize``. to ``parametrize``.
:param List[str] argnames: list of argument names passed to ``parametrize()``. :param List[str] argnames: list of argument names passed to ``parametrize()``.
:param ids: the ids parameter of the parametrized call (see docs). :param ids: the ids parameter of the parametrized call (see docs).
:param List[ParameterSet] parameters: the list of parameter values, same size as ``argnames``. :param List[ParameterSet] parameters: the list of parameter values, same size as ``argnames``.
:param Item item: the item that generated this parametrized call.
:rtype: List[str] :rtype: List[str]
:return: the list of ids for each argname given :return: the list of ids for each argname given
""" """
@ -1032,7 +1033,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
raise ValueError( raise ValueError(
msg % (saferepr(id_value), type(id_value).__name__) msg % (saferepr(id_value), type(id_value).__name__)
) )
ids = idmaker(argnames, parameters, idfn, ids, self.config) ids = idmaker(argnames, parameters, idfn, ids, self.config, item=item)
return ids return ids
def _resolve_arg_value_types(self, argnames, indirect): def _resolve_arg_value_types(self, argnames, indirect):
@ -1158,21 +1159,22 @@ def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
return "function" return "function"
def _idval(val, argname, idx, idfn, config=None): def _idval(val, argname, idx, idfn, config=None, item=None):
if idfn: if idfn:
s = None s = None
try: try:
s = idfn(val) s = idfn(val)
except Exception: except Exception as e:
# See issue https://github.com/pytest-dev/pytest/issues/2169 # See issue https://github.com/pytest-dev/pytest/issues/2169
import warnings if item is not None:
# should really be None only when unit-testing this function!
msg = ( msg = (
"Raised while trying to determine id of parameter %s at position %d." "While trying to determine id of parameter {} at position "
% (argname, idx) "{} the following exception was raised:\n".format(argname, idx)
) )
msg += "\nUpdate your code as this will raise an error in pytest-4.0." msg += " {}: {}\n".format(type(e).__name__, e)
warnings.warn(msg, DeprecationWarning) msg += "This warning will be an error error in pytest-4.0."
item.std_warn(msg, RemovedInPytest4Warning)
if s: if s:
return ascii_escaped(s) return ascii_escaped(s)
@ -1196,12 +1198,12 @@ def _idval(val, argname, idx, idfn, config=None):
return str(argname) + str(idx) return str(argname) + str(idx)
def _idvalset(idx, parameterset, argnames, idfn, ids, config=None): def _idvalset(idx, parameterset, argnames, idfn, ids, config=None, item=None):
if parameterset.id is not None: if parameterset.id is not None:
return parameterset.id return parameterset.id
if ids is None or (idx >= len(ids) or ids[idx] is None): if ids is None or (idx >= len(ids) or ids[idx] is None):
this_id = [ this_id = [
_idval(val, argname, idx, idfn, config) _idval(val, argname, idx, idfn, config, item)
for val, argname in zip(parameterset.values, argnames) for val, argname in zip(parameterset.values, argnames)
] ]
return "-".join(this_id) return "-".join(this_id)
@ -1209,9 +1211,9 @@ def _idvalset(idx, parameterset, argnames, idfn, ids, config=None):
return ascii_escaped(ids[idx]) return ascii_escaped(ids[idx])
def idmaker(argnames, parametersets, idfn=None, ids=None, config=None): def idmaker(argnames, parametersets, idfn=None, ids=None, config=None, item=None):
ids = [ ids = [
_idvalset(valindex, parameterset, argnames, idfn, ids, config) _idvalset(valindex, parameterset, argnames, idfn, ids, config, item)
for valindex, parameterset in enumerate(parametersets) for valindex, parameterset in enumerate(parametersets)
] ]
if len(set(ids)) != len(ids): if len(set(ids)) != len(ids):

View File

@ -6,5 +6,5 @@ class PytestUsageWarning(PytestWarning):
"""Warnings related to pytest usage: either command line or testing code.""" """Warnings related to pytest usage: either command line or testing code."""
class RemovedInPytest4Warning(PytestWarning): class RemovedInPytest4Warning(PytestWarning, DeprecationWarning):
"""warning class for features that will be removed in pytest 4.0""" """warning class for features that will be removed in pytest 4.0"""

View File

@ -91,7 +91,7 @@ def catch_warnings_for_item(config, ihook, item):
def warning_record_to_str(warning_message): def warning_record_to_str(warning_message):
"""Convert a warnings.WarningMessage to a string, taking in account a lot of unicode shenaningans in Python 2. """Convert a warnings.WarningMessage to a string, taking in account a lot of unicode shenaningans in Python 2.
When Python 2 support is tropped this function can be greatly simplified. When Python 2 support is dropped this function can be greatly simplified.
""" """
warn_msg = warning_message.message warn_msg = warning_message.message
unicode_warning = False unicode_warning = False
@ -131,3 +131,10 @@ def pytest_collection(session):
config = session.config config = session.config
with catch_warnings_for_item(config=config, ihook=config.hook, item=None): with catch_warnings_for_item(config=config, ihook=config.hook, item=None):
yield yield
@pytest.hookimpl(hookwrapper=True)
def pytest_terminal_summary(terminalreporter):
config = terminalreporter.config
with catch_warnings_for_item(config=config, ihook=config.hook, item=None):
yield

View File

@ -1,5 +1,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import os
import pytest import pytest
@ -197,8 +198,11 @@ def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
) )
res = testdir.runpytest_subprocess() res = testdir.runpytest_subprocess()
assert res.ret == 0 assert res.ret == 0
res.stderr.fnmatch_lines( msg = PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST.splitlines()[0]
"*" + str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0] res.stdout.fnmatch_lines(
"*subdirectory{sep}conftest.py:0: RemovedInPytest4Warning: {msg}*".format(
sep=os.sep, msg=msg
)
) )
@ -227,8 +231,11 @@ def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_top_level_confte
res = testdir.runpytest_subprocess() res = testdir.runpytest_subprocess()
assert res.ret == 0 assert res.ret == 0
res.stderr.fnmatch_lines( msg = PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST.splitlines()[0]
"*" + str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0] res.stdout.fnmatch_lines(
"*subdirectory{sep}conftest.py:0: RemovedInPytest4Warning: {msg}*".format(
sep=os.sep, msg=msg
)
) )
@ -261,10 +268,8 @@ def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_false_positives(
) )
res = testdir.runpytest_subprocess() res = testdir.runpytest_subprocess()
assert res.ret == 0 assert res.ret == 0
assert ( msg = PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST.splitlines()[0]
str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0] assert msg not in res.stdout.str()
not in res.stderr.str()
)
def test_call_fixture_function_deprecated(): def test_call_fixture_function_deprecated():
@ -276,3 +281,22 @@ def test_call_fixture_function_deprecated():
with pytest.deprecated_call(): with pytest.deprecated_call():
assert fix() == 1 assert fix() == 1
def test_pycollector_makeitem_is_deprecated():
from _pytest.python import PyCollector
class PyCollectorMock(PyCollector):
"""evil hack"""
def __init__(self):
self.called = False
def _makeitem(self, *k):
"""hack to disable the actual behaviour"""
self.called = True
collector = PyCollectorMock()
with pytest.deprecated_call():
collector.makeitem("foo", "bar")
assert collector.called

View File

@ -383,44 +383,7 @@ class TestMetafunc(object):
) )
assert result == ["a-a0", "a-a1", "a-a2"] assert result == ["a-a0", "a-a1", "a-a2"]
@pytest.mark.issue351 @pytest.mark.filterwarnings("default")
def test_idmaker_idfn_exception(self):
from _pytest.python import idmaker
from _pytest.recwarn import WarningsRecorder
class BadIdsException(Exception):
pass
def ids(val):
raise BadIdsException("ids raised")
rec = WarningsRecorder()
with rec:
idmaker(
("a", "b"),
[
pytest.param(10.0, IndexError()),
pytest.param(20, KeyError()),
pytest.param("three", [1, 2, 3]),
],
idfn=ids,
)
assert [str(i.message) for i in rec.list] == [
"Raised while trying to determine id of parameter a at position 0."
"\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter b at position 0."
"\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter a at position 1."
"\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter b at position 1."
"\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter a at position 2."
"\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter b at position 2."
"\nUpdate your code as this will raise an error in pytest-4.0.",
]
def test_parametrize_ids_exception(self, testdir): def test_parametrize_ids_exception(self, testdir):
""" """
:param testdir: the instance of Testdir class, a temporary :param testdir: the instance of Testdir class, a temporary
@ -438,13 +401,14 @@ class TestMetafunc(object):
pass pass
""" """
) )
with pytest.warns(DeprecationWarning): result = testdir.runpytest("--collect-only")
result = testdir.runpytest("--collect-only")
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
[ [
"<Module 'test_parametrize_ids_exception.py'>", "<Module 'test_parametrize_ids_exception.py'>",
" <Function 'test_foo[a]'>", " <Function 'test_foo[a]'>",
" <Function 'test_foo[b]'>", " <Function 'test_foo[b]'>",
"*test_parametrize_ids_exception.py:5: *parameter arg at position 0*",
"*test_parametrize_ids_exception.py:5: *parameter arg at position 1*",
] ]
) )

View File

@ -1,22 +0,0 @@
import pytest
from _pytest.python import PyCollector
class PyCollectorMock(PyCollector):
"""evil hack"""
def __init__(self):
self.called = False
def _makeitem(self, *k):
"""hack to disable the actual behaviour"""
self.called = True
def test_pycollector_makeitem_is_deprecated():
collector = PyCollectorMock()
with pytest.deprecated_call():
collector.makeitem("foo", "bar")
assert collector.called

View File

@ -1047,20 +1047,21 @@ def test_terminal_summary(testdir):
) )
@pytest.mark.filterwarnings("default")
def test_terminal_summary_warnings_are_displayed(testdir): def test_terminal_summary_warnings_are_displayed(testdir):
"""Test that warnings emitted during pytest_terminal_summary are displayed. """Test that warnings emitted during pytest_terminal_summary are displayed.
(#1305). (#1305).
""" """
testdir.makeconftest( testdir.makeconftest(
""" """
import warnings
def pytest_terminal_summary(terminalreporter): def pytest_terminal_summary(terminalreporter):
config = terminalreporter.config warnings.warn(UserWarning('internal warning'))
config.warn('C1', 'internal warning')
""" """
) )
result = testdir.runpytest("-rw") result = testdir.runpytest()
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
["<undetermined location>", "*internal warning", "*== 1 warnings in *"] ["*conftest.py:3:*internal warning", "*== 1 warnings in *"]
) )
assert "None" not in result.stdout.str() assert "None" not in result.stdout.str()