Merge pull request #2445 from nicoddemus/warnings-remove-filter
No longer override existing warning filters during warnings capture
This commit is contained in:
		
						commit
						1dee443c2b
					
				| 
						 | 
					@ -53,7 +53,6 @@ def catch_warnings_for_item(item):
 | 
				
			||||||
    args = item.config.getoption('pythonwarnings') or []
 | 
					    args = item.config.getoption('pythonwarnings') or []
 | 
				
			||||||
    inifilters = item.config.getini("filterwarnings")
 | 
					    inifilters = item.config.getini("filterwarnings")
 | 
				
			||||||
    with warnings.catch_warnings(record=True) as log:
 | 
					    with warnings.catch_warnings(record=True) as log:
 | 
				
			||||||
        warnings.simplefilter('once')
 | 
					 | 
				
			||||||
        for arg in args:
 | 
					        for arg in args:
 | 
				
			||||||
            warnings._setoption(arg)
 | 
					            warnings._setoption(arg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
initial addition of towncrier
 | 
					Addition of towncrier for changelog management.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					pytest warning capture no longer overrides existing warning filters. The previous
 | 
				
			||||||
 | 
					behaviour would override all filters and caused regressions in test suites which configure warning
 | 
				
			||||||
 | 
					filters to match their needs. Note that as a side-effect of this is that ``DeprecationWarning``
 | 
				
			||||||
 | 
					and ``PendingDeprecationWarning`` are no longer shown by default.
 | 
				
			||||||
| 
						 | 
					@ -5,32 +5,18 @@ Warnings Capture
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. versionadded:: 3.1
 | 
					.. versionadded:: 3.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. warning::
 | 
					Starting from version ``3.1``, pytest now automatically catches warnings during test execution
 | 
				
			||||||
    pytest captures all warnings between tests, which prevents custom warning
 | 
					 | 
				
			||||||
    filters in existing test suites from working. If this causes problems to your test suite,
 | 
					 | 
				
			||||||
    this plugin can be disabled in your ``pytest.ini`` file with:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .. code-block:: ini
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        [pytest]
 | 
					 | 
				
			||||||
        addopts = -p no:warnings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    There's an ongoing discussion about this on `#2430
 | 
					 | 
				
			||||||
    <https://github.com/pytest-dev/pytest/issues/2430>`_.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Starting from version ``3.1``, pytest now automatically catches all warnings during test execution
 | 
					 | 
				
			||||||
and displays them at the end of the session::
 | 
					and displays them at the end of the session::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # content of test_show_warnings.py
 | 
					    # content of test_show_warnings.py
 | 
				
			||||||
    import warnings
 | 
					    import warnings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def deprecated_function():
 | 
					    def api_v1():
 | 
				
			||||||
        warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
 | 
					        warnings.warn(UserWarning("api v1, should use functions from v2"))
 | 
				
			||||||
        return 1
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_one():
 | 
					    def test_one():
 | 
				
			||||||
        assert deprecated_function() == 1
 | 
					        assert api_v1() == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Running pytest now produces this output::
 | 
					Running pytest now produces this output::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,40 +25,42 @@ Running pytest now produces this output::
 | 
				
			||||||
    platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
 | 
					    platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
 | 
				
			||||||
    rootdir: $REGENDOC_TMPDIR, inifile:
 | 
					    rootdir: $REGENDOC_TMPDIR, inifile:
 | 
				
			||||||
    collected 1 items
 | 
					    collected 1 items
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    test_show_warnings.py .
 | 
					    test_show_warnings.py .
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    ======= warnings summary ========
 | 
					    ======= warnings summary ========
 | 
				
			||||||
    test_show_warnings.py::test_one
 | 
					    test_show_warnings.py::test_one
 | 
				
			||||||
      $REGENDOC_TMPDIR/test_show_warnings.py:4: DeprecationWarning: this function is deprecated, use another_function()
 | 
					      $REGENDOC_TMPDIR/test_show_warnings.py:4: DeprecationWarning: this function is deprecated, use another_function()
 | 
				
			||||||
        warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
 | 
					        warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    -- Docs: http://doc.pytest.org/en/latest/warnings.html
 | 
					    -- Docs: http://doc.pytest.org/en/latest/warnings.html
 | 
				
			||||||
    ======= 1 passed, 1 warnings in 0.12 seconds ========
 | 
					    ======= 1 passed, 1 warnings in 0.12 seconds ========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pytest by default catches all warnings except for ``DeprecationWarning`` and ``PendingDeprecationWarning``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The ``-W`` flag can be passed to control which warnings will be displayed or even turn
 | 
					The ``-W`` flag can be passed to control which warnings will be displayed or even turn
 | 
				
			||||||
them into errors::
 | 
					them into errors::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $ pytest -q test_show_warnings.py -W error::DeprecationWarning
 | 
					    $ pytest -q test_show_warnings.py -W error::UserWarning
 | 
				
			||||||
    F
 | 
					    F
 | 
				
			||||||
    ======= FAILURES ========
 | 
					    ======= FAILURES ========
 | 
				
			||||||
    _______ test_one ________
 | 
					    _______ test_one ________
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
        def test_one():
 | 
					        def test_one():
 | 
				
			||||||
    >       assert deprecated_function() == 1
 | 
					    >       assert deprecated_function() == 1
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    test_show_warnings.py:8: 
 | 
					    test_show_warnings.py:8:
 | 
				
			||||||
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
 | 
					    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
        def deprecated_function():
 | 
					        def deprecated_function():
 | 
				
			||||||
    >       warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
 | 
					    >       warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
 | 
				
			||||||
    E       DeprecationWarning: this function is deprecated, use another_function()
 | 
					    E       DeprecationWarning: this function is deprecated, use another_function()
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    test_show_warnings.py:4: DeprecationWarning
 | 
					    test_show_warnings.py:4: DeprecationWarning
 | 
				
			||||||
    1 failed in 0.12 seconds
 | 
					    1 failed in 0.12 seconds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The same option can be set in the ``pytest.ini`` file using the ``filterwarnings`` ini option.
 | 
					The same option can be set in the ``pytest.ini`` file using the ``filterwarnings`` ini option.
 | 
				
			||||||
For example, the configuration below will ignore all deprecation warnings, but will transform
 | 
					For example, the configuration below will ignore all user warnings, but will transform
 | 
				
			||||||
all other warnings into errors.
 | 
					all other warnings into errors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: ini
 | 
					.. code-block:: ini
 | 
				
			||||||
| 
						 | 
					@ -80,7 +68,7 @@ all other warnings into errors.
 | 
				
			||||||
    [pytest]
 | 
					    [pytest]
 | 
				
			||||||
    filterwarnings =
 | 
					    filterwarnings =
 | 
				
			||||||
        error
 | 
					        error
 | 
				
			||||||
        ignore::DeprecationWarning
 | 
					        ignore::UserWarning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When a warning matches more than one option in the list, the action for the last matching option
 | 
					When a warning matches more than one option in the list, the action for the last matching option
 | 
				
			||||||
| 
						 | 
					@ -90,6 +78,19 @@ Both ``-W`` command-line option and ``filterwarnings`` ini option are based on P
 | 
				
			||||||
`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python
 | 
					`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python
 | 
				
			||||||
documentation for other examples and advanced usage.
 | 
					documentation for other examples and advanced usage.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. note::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ``DeprecationWarning`` and ``PendingDeprecationWarning`` are hidden by the standard library
 | 
				
			||||||
 | 
					    by default so you have to explicitly configure them to be displayed in your ``pytest.ini``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. code-block:: ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [pytest]
 | 
				
			||||||
 | 
					        filterwarnings =
 | 
				
			||||||
 | 
					            once::DeprecationWarning
 | 
				
			||||||
 | 
					            once::PendingDeprecationWarning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
 | 
					*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
 | 
				
			||||||
*plugin.*
 | 
					*plugin.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,6 +98,19 @@ documentation for other examples and advanced usage.
 | 
				
			||||||
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
 | 
					.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
 | 
				
			||||||
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
 | 
					.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Disabling warning capture
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This feature is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. code-block:: ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [pytest]
 | 
				
			||||||
 | 
					        addopts = -p no:warnings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Or passing ``-p no:warnings`` in the command-line.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _`asserting warnings`:
 | 
					.. _`asserting warnings`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _assertwarnings:
 | 
					.. _assertwarnings:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,8 @@ from __future__ import absolute_import, division, print_function
 | 
				
			||||||
import warnings
 | 
					import warnings
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
import py
 | 
					import py
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from _pytest.recwarn import WarningsRecorder
 | 
					from _pytest.recwarn import WarningsRecorder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,9 +151,12 @@ class TestDeprecatedCall(object):
 | 
				
			||||||
                pytest.deprecated_call(deprecated_function)
 | 
					                pytest.deprecated_call(deprecated_function)
 | 
				
			||||||
        """)
 | 
					        """)
 | 
				
			||||||
        result = testdir.runpytest()
 | 
					        result = testdir.runpytest()
 | 
				
			||||||
        # the 2 tests must pass, but the call to test_one() will generate a warning
 | 
					        # for some reason in py26 catch_warnings manages to catch the deprecation warning
 | 
				
			||||||
        # in pytest's summary
 | 
					        # from deprecated_function(), even with default filters active (which ignore deprecation
 | 
				
			||||||
        result.stdout.fnmatch_lines('*=== 2 passed, 1 warnings in *===')
 | 
					        # warnings)
 | 
				
			||||||
 | 
					        py26 = sys.version_info[:2] == (2, 6)
 | 
				
			||||||
 | 
					        expected = '*=== 2 passed in *===' if not py26 else '*=== 2 passed, 1 warnings in *==='
 | 
				
			||||||
 | 
					        result.stdout.fnmatch_lines(expected)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestWarns(object):
 | 
					class TestWarns(object):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,8 +20,8 @@ def pyfile_with_warnings(testdir, request):
 | 
				
			||||||
        module_name: '''
 | 
					        module_name: '''
 | 
				
			||||||
            import warnings
 | 
					            import warnings
 | 
				
			||||||
            def foo():
 | 
					            def foo():
 | 
				
			||||||
                warnings.warn(PendingDeprecationWarning("functionality is pending deprecation"))
 | 
					                warnings.warn(UserWarning("user warning"))
 | 
				
			||||||
                warnings.warn(DeprecationWarning("functionality is deprecated"))
 | 
					                warnings.warn(RuntimeWarning("runtime warning"))
 | 
				
			||||||
                return 1
 | 
					                return 1
 | 
				
			||||||
        ''',
 | 
					        ''',
 | 
				
			||||||
        test_name: '''
 | 
					        test_name: '''
 | 
				
			||||||
| 
						 | 
					@ -43,11 +43,11 @@ def test_normal_flow(testdir, pyfile_with_warnings):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '*test_normal_flow.py::test_func',
 | 
					        '*test_normal_flow.py::test_func',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '*normal_flow_module.py:3: PendingDeprecationWarning: functionality is pending deprecation',
 | 
					        '*normal_flow_module.py:3: UserWarning: user warning',
 | 
				
			||||||
        '*  warnings.warn(PendingDeprecationWarning("functionality is pending deprecation"))',
 | 
					        '*  warnings.warn(UserWarning("user warning"))',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '*normal_flow_module.py:4: DeprecationWarning: functionality is deprecated',
 | 
					        '*normal_flow_module.py:4: RuntimeWarning: runtime warning',
 | 
				
			||||||
        '*  warnings.warn(DeprecationWarning("functionality is deprecated"))',
 | 
					        '*  warnings.warn(RuntimeWarning("runtime warning"))',
 | 
				
			||||||
        '* 1 passed, 2 warnings*',
 | 
					        '* 1 passed, 2 warnings*',
 | 
				
			||||||
    ])
 | 
					    ])
 | 
				
			||||||
    assert result.stdout.str().count('test_normal_flow.py::test_func') == 1
 | 
					    assert result.stdout.str().count('test_normal_flow.py::test_func') == 1
 | 
				
			||||||
| 
						 | 
					@ -90,8 +90,8 @@ def test_as_errors(testdir, pyfile_with_warnings, method):
 | 
				
			||||||
            ''')
 | 
					            ''')
 | 
				
			||||||
    result = testdir.runpytest(*args)
 | 
					    result = testdir.runpytest(*args)
 | 
				
			||||||
    result.stdout.fnmatch_lines([
 | 
					    result.stdout.fnmatch_lines([
 | 
				
			||||||
        'E       PendingDeprecationWarning: functionality is pending deprecation',
 | 
					        'E       UserWarning: user warning',
 | 
				
			||||||
        'as_errors_module.py:3: PendingDeprecationWarning',
 | 
					        'as_errors_module.py:3: UserWarning',
 | 
				
			||||||
        '* 1 failed in *',
 | 
					        '* 1 failed in *',
 | 
				
			||||||
    ])
 | 
					    ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -133,9 +133,7 @@ def test_unicode(testdir, pyfile_with_warnings):
 | 
				
			||||||
    result = testdir.runpytest()
 | 
					    result = testdir.runpytest()
 | 
				
			||||||
    result.stdout.fnmatch_lines([
 | 
					    result.stdout.fnmatch_lines([
 | 
				
			||||||
        '*== %s ==*' % WARNINGS_SUMMARY_HEADER,
 | 
					        '*== %s ==*' % WARNINGS_SUMMARY_HEADER,
 | 
				
			||||||
 | 
					        '*test_unicode.py:8: UserWarning: \u6d4b\u8bd5*',
 | 
				
			||||||
        '*test_unicode.py:8: UserWarning: \u6d4b\u8bd5',
 | 
					 | 
				
			||||||
        '*warnings.warn(u"\u6d4b\u8bd5")',
 | 
					 | 
				
			||||||
        '* 1 passed, 1 warnings*',
 | 
					        '* 1 passed, 1 warnings*',
 | 
				
			||||||
    ])
 | 
					    ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,6 +161,30 @@ def test_py2_unicode(testdir, pyfile_with_warnings):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '*test_py2_unicode.py:8: UserWarning: \u6d4b\u8bd5',
 | 
					        '*test_py2_unicode.py:8: UserWarning: \u6d4b\u8bd5',
 | 
				
			||||||
        '*warnings.warn(u"\u6d4b\u8bd5")',
 | 
					        '*warnings.warn(u"\u6d4b\u8bd5")',
 | 
				
			||||||
        '*warnings.py:82: UnicodeWarning: This warning*\u6d4b\u8bd5',
 | 
					        '*warnings.py:*: UnicodeWarning: This warning*\u6d4b\u8bd5',
 | 
				
			||||||
        '* 1 passed, 2 warnings*',
 | 
					        '* 1 passed, 2 warnings*',
 | 
				
			||||||
    ])
 | 
					    ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 *',
 | 
				
			||||||
 | 
					    ])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								tox.ini
								
								
								
								
							
							
						
						
									
										2
									
								
								tox.ini
								
								
								
								
							| 
						 | 
					@ -184,7 +184,7 @@ python_files=test_*.py *_test.py testing/*/*.py
 | 
				
			||||||
python_classes=Test Acceptance
 | 
					python_classes=Test Acceptance
 | 
				
			||||||
python_functions=test
 | 
					python_functions=test
 | 
				
			||||||
norecursedirs = .tox ja .hg cx_freeze_source
 | 
					norecursedirs = .tox ja .hg cx_freeze_source
 | 
				
			||||||
filterwarnings= error
 | 
					filterwarnings=
 | 
				
			||||||
                # produced by path.local
 | 
					                # produced by path.local
 | 
				
			||||||
                ignore:bad escape.*:DeprecationWarning:re
 | 
					                ignore:bad escape.*:DeprecationWarning:re
 | 
				
			||||||
                # produced by path.readlines
 | 
					                # produced by path.readlines
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue