595 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			595 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
| # -*- coding: utf8 -*-
 | |
| from __future__ import unicode_literals
 | |
| 
 | |
| import sys
 | |
| 
 | |
| import six
 | |
| 
 | |
| import pytest
 | |
| 
 | |
| 
 | |
| WARNINGS_SUMMARY_HEADER = "warnings summary"
 | |
| 
 | |
| 
 | |
| @pytest.fixture
 | |
| def pyfile_with_warnings(testdir, request):
 | |
|     """
 | |
|     Create a test file which calls a function in a module which generates warnings.
 | |
|     """
 | |
|     testdir.syspathinsert()
 | |
|     test_name = request.function.__name__
 | |
|     module_name = test_name.lstrip("test_") + "_module"
 | |
|     testdir.makepyfile(
 | |
|         **{
 | |
|             module_name: """
 | |
|             import warnings
 | |
|             def foo():
 | |
|                 warnings.warn(UserWarning("user warning"))
 | |
|                 warnings.warn(RuntimeWarning("runtime warning"))
 | |
|                 return 1
 | |
|         """,
 | |
|             test_name: """
 | |
|             import {module_name}
 | |
|             def test_func():
 | |
|                 assert {module_name}.foo() == 1
 | |
|         """.format(
 | |
|                 module_name=module_name
 | |
|             ),
 | |
|         }
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.filterwarnings("default")
 | |
| def test_normal_flow(testdir, pyfile_with_warnings):
 | |
|     """
 | |
|     Check that the warnings section is displayed.
 | |
|     """
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         [
 | |
|             "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|             "test_normal_flow.py::test_func",
 | |
|             "*normal_flow_module.py:3: UserWarning: user warning",
 | |
|             '*  warnings.warn(UserWarning("user warning"))',
 | |
|             "*normal_flow_module.py:4: RuntimeWarning: runtime warning",
 | |
|             '*  warnings.warn(RuntimeWarning("runtime warning"))',
 | |
|             "* 1 passed, 2 warnings*",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.filterwarnings("always")
 | |
| def test_setup_teardown_warnings(testdir, pyfile_with_warnings):
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import warnings
 | |
|         import pytest
 | |
| 
 | |
|         @pytest.fixture
 | |
|         def fix():
 | |
|             warnings.warn(UserWarning("warning during setup"))
 | |
|             yield
 | |
|             warnings.warn(UserWarning("warning during teardown"))
 | |
| 
 | |
|         def test_func(fix):
 | |
|             pass
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         [
 | |
|             "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|             "*test_setup_teardown_warnings.py:6: UserWarning: warning during setup",
 | |
|             '*warnings.warn(UserWarning("warning during setup"))',
 | |
|             "*test_setup_teardown_warnings.py:8: UserWarning: warning during teardown",
 | |
|             '*warnings.warn(UserWarning("warning during teardown"))',
 | |
|             "* 1 passed, 2 warnings*",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize("method", ["cmdline", "ini"])
 | |
| def test_as_errors(testdir, pyfile_with_warnings, method):
 | |
|     args = ("-W", "error") if method == "cmdline" else ()
 | |
|     if method == "ini":
 | |
|         testdir.makeini(
 | |
|             """
 | |
|             [pytest]
 | |
|             filterwarnings= error
 | |
|             """
 | |
|         )
 | |
|     result = testdir.runpytest(*args)
 | |
|     result.stdout.fnmatch_lines(
 | |
|         [
 | |
|             "E       UserWarning: user warning",
 | |
|             "as_errors_module.py:3: UserWarning",
 | |
|             "* 1 failed in *",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize("method", ["cmdline", "ini"])
 | |
| def test_ignore(testdir, pyfile_with_warnings, method):
 | |
|     args = ("-W", "ignore") if method == "cmdline" else ()
 | |
|     if method == "ini":
 | |
|         testdir.makeini(
 | |
|             """
 | |
|         [pytest]
 | |
|         filterwarnings= ignore
 | |
|         """
 | |
|         )
 | |
| 
 | |
|     result = testdir.runpytest(*args)
 | |
|     result.stdout.fnmatch_lines(["* 1 passed in *"])
 | |
|     assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
 | |
| 
 | |
| 
 | |
| @pytest.mark.skipif(
 | |
|     sys.version_info < (3, 0), reason="warnings message is unicode is ok in python3"
 | |
| )
 | |
| @pytest.mark.filterwarnings("always")
 | |
| def test_unicode(testdir, pyfile_with_warnings):
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         # -*- coding: utf8 -*-
 | |
|         import warnings
 | |
|         import pytest
 | |
| 
 | |
| 
 | |
|         @pytest.fixture
 | |
|         def fix():
 | |
|             warnings.warn(u"测试")
 | |
|             yield
 | |
| 
 | |
|         def test_func(fix):
 | |
|             pass
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         [
 | |
|             "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|             "*test_unicode.py:8: UserWarning: \u6d4b\u8bd5*",
 | |
|             "* 1 passed, 1 warnings*",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.skipif(
 | |
|     sys.version_info >= (3, 0),
 | |
|     reason="warnings message is broken as it is not str instance",
 | |
| )
 | |
| def test_py2_unicode(testdir, pyfile_with_warnings):
 | |
|     if getattr(sys, "pypy_version_info", ())[:2] == (5, 9) and sys.platform.startswith(
 | |
|         "win"
 | |
|     ):
 | |
|         pytest.xfail("fails with unicode error on PyPy2 5.9 and Windows (#2905)")
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         # -*- coding: utf8 -*-
 | |
|         import warnings
 | |
|         import pytest
 | |
| 
 | |
| 
 | |
|         @pytest.fixture
 | |
|         def fix():
 | |
|             warnings.warn(u"测试")
 | |
|             yield
 | |
| 
 | |
|         @pytest.mark.filterwarnings('always')
 | |
|         def test_func(fix):
 | |
|             pass
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         [
 | |
|             "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|             "*test_py2_unicode.py:8: UserWarning: \\u6d4b\\u8bd5",
 | |
|             '*warnings.warn(u"\u6d4b\u8bd5")',
 | |
|             "*warnings.py:*: UnicodeWarning: Warning is using unicode non*",
 | |
|             "* 1 passed, 2 warnings*",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| def test_py2_unicode_ascii(testdir):
 | |
|     """Ensure that our warning about 'unicode warnings containing non-ascii messages'
 | |
|     does not trigger with ascii-convertible messages"""
 | |
|     testdir.makeini("[pytest]")
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import pytest
 | |
|         import warnings
 | |
| 
 | |
|         @pytest.mark.filterwarnings('always')
 | |
|         def test_func():
 | |
|             warnings.warn(u"hello")
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         [
 | |
|             "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|             '*warnings.warn(u"hello")',
 | |
|             "* 1 passed, 1 warnings in*",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| def test_works_with_filterwarnings(testdir):
 | |
|     """Ensure our warnings capture does not mess with pre-installed filters (#2430)."""
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import warnings
 | |
| 
 | |
|         class MyWarning(Warning):
 | |
|             pass
 | |
| 
 | |
|         warnings.filterwarnings("error", category=MyWarning)
 | |
| 
 | |
|         class TestWarnings(object):
 | |
|             def test_my_warning(self):
 | |
|                 try:
 | |
|                     warnings.warn(MyWarning("warn!"))
 | |
|                     assert False
 | |
|                 except MyWarning:
 | |
|                     assert True
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(["*== 1 passed in *"])
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize("default_config", ["ini", "cmdline"])
 | |
| def test_filterwarnings_mark(testdir, default_config):
 | |
|     """
 | |
|     Test ``filterwarnings`` mark works and takes precedence over command line and ini options.
 | |
|     """
 | |
|     if default_config == "ini":
 | |
|         testdir.makeini(
 | |
|             """
 | |
|             [pytest]
 | |
|             filterwarnings = always
 | |
|         """
 | |
|         )
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import warnings
 | |
|         import pytest
 | |
| 
 | |
|         @pytest.mark.filterwarnings('ignore::RuntimeWarning')
 | |
|         def test_ignore_runtime_warning():
 | |
|             warnings.warn(RuntimeWarning())
 | |
| 
 | |
|         @pytest.mark.filterwarnings('error')
 | |
|         def test_warning_error():
 | |
|             warnings.warn(RuntimeWarning())
 | |
| 
 | |
|         def test_show_warning():
 | |
|             warnings.warn(RuntimeWarning())
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest("-W always" if default_config == "cmdline" else "")
 | |
|     result.stdout.fnmatch_lines(["*= 1 failed, 2 passed, 1 warnings in *"])
 | |
| 
 | |
| 
 | |
| def test_non_string_warning_argument(testdir):
 | |
|     """Non-str argument passed to warning breaks pytest (#2956)"""
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import warnings
 | |
|         import pytest
 | |
| 
 | |
|         def test():
 | |
|             warnings.warn(UserWarning(1, u'foo'))
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest("-W", "always")
 | |
|     result.stdout.fnmatch_lines(["*= 1 passed, 1 warnings in *"])
 | |
| 
 | |
| 
 | |
| def test_filterwarnings_mark_registration(testdir):
 | |
|     """Ensure filterwarnings mark is registered"""
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import pytest
 | |
| 
 | |
|         @pytest.mark.filterwarnings('error')
 | |
|         def test_func():
 | |
|             pass
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest("--strict")
 | |
|     assert result.ret == 0
 | |
| 
 | |
| 
 | |
| @pytest.mark.filterwarnings("always")
 | |
| def test_warning_captured_hook(testdir):
 | |
|     testdir.makeconftest(
 | |
|         """
 | |
|         from _pytest.warnings import _issue_config_warning
 | |
|         def pytest_configure(config):
 | |
|             _issue_config_warning(UserWarning("config warning"), config)
 | |
|     """
 | |
|     )
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import pytest, warnings
 | |
| 
 | |
|         warnings.warn(UserWarning("collect warning"))
 | |
| 
 | |
|         @pytest.fixture
 | |
|         def fix():
 | |
|             warnings.warn(UserWarning("setup warning"))
 | |
|             yield 1
 | |
|             warnings.warn(UserWarning("teardown warning"))
 | |
| 
 | |
|         def test_func(fix):
 | |
|             warnings.warn(UserWarning("call warning"))
 | |
|             assert fix == 1
 | |
|         """
 | |
|     )
 | |
| 
 | |
|     collected = []
 | |
| 
 | |
|     class WarningCollector:
 | |
|         def pytest_warning_captured(self, warning_message, when, item):
 | |
|             imge_name = item.name if item is not None else ""
 | |
|             collected.append((str(warning_message.message), when, imge_name))
 | |
| 
 | |
|     result = testdir.runpytest(plugins=[WarningCollector()])
 | |
|     result.stdout.fnmatch_lines(["*1 passed*"])
 | |
| 
 | |
|     expected = [
 | |
|         ("config warning", "config", ""),
 | |
|         ("collect warning", "collect", ""),
 | |
|         ("setup warning", "runtest", "test_func"),
 | |
|         ("call warning", "runtest", "test_func"),
 | |
|         ("teardown warning", "runtest", "test_func"),
 | |
|     ]
 | |
|     assert collected == expected
 | |
| 
 | |
| 
 | |
| @pytest.mark.filterwarnings("always")
 | |
| def test_collection_warnings(testdir):
 | |
|     """
 | |
|     Check that we also capture warnings issued during test collection (#3251).
 | |
|     """
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import warnings
 | |
| 
 | |
|         warnings.warn(UserWarning("collection warning"))
 | |
| 
 | |
|         def test_foo():
 | |
|             pass
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         [
 | |
|             "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|             "  *collection_warnings.py:3: UserWarning: collection warning",
 | |
|             '    warnings.warn(UserWarning("collection warning"))',
 | |
|             "* 1 passed, 1 warnings*",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.filterwarnings("always")
 | |
| def test_mark_regex_escape(testdir):
 | |
|     """@pytest.mark.filterwarnings should not try to escape regex characters (#3936)"""
 | |
|     testdir.makepyfile(
 | |
|         r"""
 | |
|         import pytest, warnings
 | |
| 
 | |
|         @pytest.mark.filterwarnings(r"ignore:some \(warning\)")
 | |
|         def test_foo():
 | |
|             warnings.warn(UserWarning("some (warning)"))
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
 | |
| 
 | |
| 
 | |
| @pytest.mark.filterwarnings("default")
 | |
| @pytest.mark.parametrize("ignore_pytest_warnings", ["no", "ini", "cmdline"])
 | |
| def test_hide_pytest_internal_warnings(testdir, ignore_pytest_warnings):
 | |
|     """Make sure we can ignore internal pytest warnings using a warnings filter."""
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import pytest
 | |
|         import warnings
 | |
| 
 | |
|         warnings.warn(pytest.PytestWarning("some internal warning"))
 | |
| 
 | |
|         def test_bar():
 | |
|             pass
 | |
|     """
 | |
|     )
 | |
|     if ignore_pytest_warnings == "ini":
 | |
|         testdir.makeini(
 | |
|             """
 | |
|             [pytest]
 | |
|             filterwarnings = ignore::pytest.PytestWarning
 | |
|         """
 | |
|         )
 | |
|     args = (
 | |
|         ["-W", "ignore::pytest.PytestWarning"]
 | |
|         if ignore_pytest_warnings == "cmdline"
 | |
|         else []
 | |
|     )
 | |
|     result = testdir.runpytest(*args)
 | |
|     if ignore_pytest_warnings != "no":
 | |
|         assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
 | |
|     else:
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|                 "*test_hide_pytest_internal_warnings.py:4: PytestWarning: some internal warning",
 | |
|                 "* 1 passed, 1 warnings *",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize("ignore_on_cmdline", [True, False])
 | |
| def test_option_precedence_cmdline_over_ini(testdir, ignore_on_cmdline):
 | |
|     """filters defined in the command-line should take precedence over filters in ini files (#3946)."""
 | |
|     testdir.makeini(
 | |
|         """
 | |
|         [pytest]
 | |
|         filterwarnings = error
 | |
|     """
 | |
|     )
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import warnings
 | |
|         def test():
 | |
|             warnings.warn(UserWarning('hello'))
 | |
|     """
 | |
|     )
 | |
|     args = ["-W", "ignore"] if ignore_on_cmdline else []
 | |
|     result = testdir.runpytest(*args)
 | |
|     if ignore_on_cmdline:
 | |
|         result.stdout.fnmatch_lines(["* 1 passed in*"])
 | |
|     else:
 | |
|         result.stdout.fnmatch_lines(["* 1 failed in*"])
 | |
| 
 | |
| 
 | |
| def test_option_precedence_mark(testdir):
 | |
|     """Filters defined by marks should always take precedence (#3946)."""
 | |
|     testdir.makeini(
 | |
|         """
 | |
|         [pytest]
 | |
|         filterwarnings = ignore
 | |
|     """
 | |
|     )
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import pytest, warnings
 | |
|         @pytest.mark.filterwarnings('error')
 | |
|         def test():
 | |
|             warnings.warn(UserWarning('hello'))
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest("-W", "ignore")
 | |
|     result.stdout.fnmatch_lines(["* 1 failed in*"])
 | |
| 
 | |
| 
 | |
| class TestDeprecationWarningsByDefault:
 | |
|     """
 | |
|     Note: all pytest runs are executed in a subprocess so we don't inherit warning filters
 | |
|     from pytest's own test suite
 | |
|     """
 | |
| 
 | |
|     def create_file(self, testdir, mark=""):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             import pytest, warnings
 | |
| 
 | |
|             warnings.warn(DeprecationWarning("collection"))
 | |
| 
 | |
|             {mark}
 | |
|             def test_foo():
 | |
|                 warnings.warn(PendingDeprecationWarning("test run"))
 | |
|         """.format(
 | |
|                 mark=mark
 | |
|             )
 | |
|         )
 | |
| 
 | |
|     @pytest.mark.parametrize("customize_filters", [True, False])
 | |
|     def test_shown_by_default(self, testdir, customize_filters):
 | |
|         """Show deprecation warnings by default, even if user has customized the warnings filters (#4013)."""
 | |
|         self.create_file(testdir)
 | |
|         if customize_filters:
 | |
|             testdir.makeini(
 | |
|                 """
 | |
|                 [pytest]
 | |
|                 filterwarnings =
 | |
|                     once::UserWarning
 | |
|             """
 | |
|             )
 | |
|         result = testdir.runpytest_subprocess()
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|                 "*test_shown_by_default.py:3: DeprecationWarning: collection",
 | |
|                 "*test_shown_by_default.py:7: PendingDeprecationWarning: test run",
 | |
|                 "* 1 passed, 2 warnings*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|     def test_hidden_by_ini(self, testdir):
 | |
|         self.create_file(testdir)
 | |
|         testdir.makeini(
 | |
|             """
 | |
|             [pytest]
 | |
|             filterwarnings =
 | |
|                 ignore::DeprecationWarning
 | |
|                 ignore::PendingDeprecationWarning
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest_subprocess()
 | |
|         assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
 | |
| 
 | |
|     def test_hidden_by_mark(self, testdir):
 | |
|         """Should hide the deprecation warning from the function, but the warning during collection should
 | |
|         be displayed normally.
 | |
|         """
 | |
|         self.create_file(
 | |
|             testdir,
 | |
|             mark='@pytest.mark.filterwarnings("ignore::PendingDeprecationWarning")',
 | |
|         )
 | |
|         result = testdir.runpytest_subprocess()
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
 | |
|                 "*test_hidden_by_mark.py:3: DeprecationWarning: collection",
 | |
|                 "* 1 passed, 1 warnings*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|     def test_hidden_by_cmdline(self, testdir):
 | |
|         self.create_file(testdir)
 | |
|         result = testdir.runpytest_subprocess(
 | |
|             "-W",
 | |
|             "ignore::DeprecationWarning",
 | |
|             "-W",
 | |
|             "ignore::PendingDeprecationWarning",
 | |
|         )
 | |
|         assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
 | |
| 
 | |
|     def test_hidden_by_system(self, testdir, monkeypatch):
 | |
|         self.create_file(testdir)
 | |
|         monkeypatch.setenv(str("PYTHONWARNINGS"), str("once::UserWarning"))
 | |
|         result = testdir.runpytest_subprocess()
 | |
|         assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
 | |
| 
 | |
| 
 | |
| @pytest.mark.skipif(six.PY3, reason="Python 2 only issue")
 | |
| def test_infinite_loop_warning_against_unicode_usage_py2(testdir):
 | |
|     """
 | |
|     We need to be careful when raising the warning about unicode usage with "warnings.warn"
 | |
|     because it might be overwritten by users and this itself causes another warning (#3691).
 | |
|     """
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         # -*- coding: utf8 -*-
 | |
|         from __future__ import unicode_literals
 | |
|         import warnings
 | |
|         import pytest
 | |
| 
 | |
|         def _custom_showwarning(message, *a, **b):
 | |
|             return "WARNING: {}".format(message)
 | |
| 
 | |
|         warnings.formatwarning = _custom_showwarning
 | |
| 
 | |
|         @pytest.mark.filterwarnings("default")
 | |
|         def test_custom_warning_formatter():
 | |
|             warnings.warn("¥")
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest_subprocess()
 | |
|     result.stdout.fnmatch_lines(["*1 passed, * warnings in*"])
 |