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 []
 | 
			
		||||
    inifilters = item.config.getini("filterwarnings")
 | 
			
		||||
    with warnings.catch_warnings(record=True) as log:
 | 
			
		||||
        warnings.simplefilter('once')
 | 
			
		||||
        for arg in args:
 | 
			
		||||
            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
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
    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
 | 
			
		||||
Starting from version ``3.1``, pytest now automatically catches warnings during test execution
 | 
			
		||||
and displays them at the end of the session::
 | 
			
		||||
 | 
			
		||||
    # content of test_show_warnings.py
 | 
			
		||||
    import warnings
 | 
			
		||||
 | 
			
		||||
    def deprecated_function():
 | 
			
		||||
        warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
 | 
			
		||||
    def api_v1():
 | 
			
		||||
        warnings.warn(UserWarning("api v1, should use functions from v2"))
 | 
			
		||||
        return 1
 | 
			
		||||
 | 
			
		||||
    def test_one():
 | 
			
		||||
        assert deprecated_function() == 1
 | 
			
		||||
        assert api_v1() == 1
 | 
			
		||||
 | 
			
		||||
Running pytest now produces this output::
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,10 +36,12 @@ Running pytest now produces this output::
 | 
			
		|||
    -- Docs: http://doc.pytest.org/en/latest/warnings.html
 | 
			
		||||
    ======= 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
 | 
			
		||||
them into errors::
 | 
			
		||||
 | 
			
		||||
    $ pytest -q test_show_warnings.py -W error::DeprecationWarning
 | 
			
		||||
    $ pytest -q test_show_warnings.py -W error::UserWarning
 | 
			
		||||
    F
 | 
			
		||||
    ======= FAILURES ========
 | 
			
		||||
    _______ test_one ________
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +60,7 @@ them into errors::
 | 
			
		|||
    1 failed in 0.12 seconds
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
.. code-block:: ini
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +68,7 @@ all other warnings into errors.
 | 
			
		|||
    [pytest]
 | 
			
		||||
    filterwarnings =
 | 
			
		||||
        error
 | 
			
		||||
        ignore::DeprecationWarning
 | 
			
		||||
        ignore::UserWarning
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
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`_
 | 
			
		||||
*plugin.*
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +98,19 @@ documentation for other examples and advanced usage.
 | 
			
		|||
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
 | 
			
		||||
.. _`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`:
 | 
			
		||||
 | 
			
		||||
.. _assertwarnings:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,8 @@ from __future__ import absolute_import, division, print_function
 | 
			
		|||
import warnings
 | 
			
		||||
import re
 | 
			
		||||
import py
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
from _pytest.recwarn import WarningsRecorder
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -149,9 +151,12 @@ class TestDeprecatedCall(object):
 | 
			
		|||
                pytest.deprecated_call(deprecated_function)
 | 
			
		||||
        """)
 | 
			
		||||
        result = testdir.runpytest()
 | 
			
		||||
        # the 2 tests must pass, but the call to test_one() will generate a warning
 | 
			
		||||
        # in pytest's summary
 | 
			
		||||
        result.stdout.fnmatch_lines('*=== 2 passed, 1 warnings in *===')
 | 
			
		||||
        # for some reason in py26 catch_warnings manages to catch the deprecation warning
 | 
			
		||||
        # from deprecated_function(), even with default filters active (which ignore deprecation
 | 
			
		||||
        # 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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,8 +20,8 @@ def pyfile_with_warnings(testdir, request):
 | 
			
		|||
        module_name: '''
 | 
			
		||||
            import warnings
 | 
			
		||||
            def foo():
 | 
			
		||||
                warnings.warn(PendingDeprecationWarning("functionality is pending deprecation"))
 | 
			
		||||
                warnings.warn(DeprecationWarning("functionality is deprecated"))
 | 
			
		||||
                warnings.warn(UserWarning("user warning"))
 | 
			
		||||
                warnings.warn(RuntimeWarning("runtime warning"))
 | 
			
		||||
                return 1
 | 
			
		||||
        ''',
 | 
			
		||||
        test_name: '''
 | 
			
		||||
| 
						 | 
				
			
			@ -43,11 +43,11 @@ def test_normal_flow(testdir, pyfile_with_warnings):
 | 
			
		|||
 | 
			
		||||
        '*test_normal_flow.py::test_func',
 | 
			
		||||
 | 
			
		||||
        '*normal_flow_module.py:3: PendingDeprecationWarning: functionality is pending deprecation',
 | 
			
		||||
        '*  warnings.warn(PendingDeprecationWarning("functionality is pending deprecation"))',
 | 
			
		||||
        '*normal_flow_module.py:3: UserWarning: user warning',
 | 
			
		||||
        '*  warnings.warn(UserWarning("user warning"))',
 | 
			
		||||
 | 
			
		||||
        '*normal_flow_module.py:4: DeprecationWarning: functionality is deprecated',
 | 
			
		||||
        '*  warnings.warn(DeprecationWarning("functionality is deprecated"))',
 | 
			
		||||
        '*normal_flow_module.py:4: RuntimeWarning: runtime warning',
 | 
			
		||||
        '*  warnings.warn(RuntimeWarning("runtime warning"))',
 | 
			
		||||
        '* 1 passed, 2 warnings*',
 | 
			
		||||
    ])
 | 
			
		||||
    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.stdout.fnmatch_lines([
 | 
			
		||||
        'E       PendingDeprecationWarning: functionality is pending deprecation',
 | 
			
		||||
        'as_errors_module.py:3: PendingDeprecationWarning',
 | 
			
		||||
        'E       UserWarning: user warning',
 | 
			
		||||
        'as_errors_module.py:3: UserWarning',
 | 
			
		||||
        '* 1 failed in *',
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -133,9 +133,7 @@ def test_unicode(testdir, pyfile_with_warnings):
 | 
			
		|||
    result = testdir.runpytest()
 | 
			
		||||
    result.stdout.fnmatch_lines([
 | 
			
		||||
        '*== %s ==*' % WARNINGS_SUMMARY_HEADER,
 | 
			
		||||
 | 
			
		||||
        '*test_unicode.py:8: UserWarning: \u6d4b\u8bd5',
 | 
			
		||||
        '*warnings.warn(u"\u6d4b\u8bd5")',
 | 
			
		||||
        '*test_unicode.py:8: UserWarning: \u6d4b\u8bd5*',
 | 
			
		||||
        '* 1 passed, 1 warnings*',
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -163,6 +161,30 @@ def test_py2_unicode(testdir, pyfile_with_warnings):
 | 
			
		|||
 | 
			
		||||
        '*test_py2_unicode.py:8: UserWarning: \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*',
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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_functions=test
 | 
			
		||||
norecursedirs = .tox ja .hg cx_freeze_source
 | 
			
		||||
filterwarnings= error
 | 
			
		||||
filterwarnings=
 | 
			
		||||
                # produced by path.local
 | 
			
		||||
                ignore:bad escape.*:DeprecationWarning:re
 | 
			
		||||
                # produced by path.readlines
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue