summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2018-01-08 12:45:02 +1000
committerGitHub <noreply@github.com>2018-01-08 12:45:02 +1000
commit9b99747386b690007027c3be2a5d7cfe3d3634f5 (patch)
treeba319d02ddc0e437bd0f90d520a4409efa7af6e2
parentd13889214a4c81b78fa8683d35bdbd17ff22f4fe (diff)
downloadcpython-git-9b99747386b690007027c3be2a5d7cfe3d3634f5.tar.gz
bpo-31975 (PEP 565): Show DeprecationWarning in __main__ (GH-4458)
- primary change is to add a new default filter entry for 'default::DeprecationWarning:__main__' - secondary change is an internal one to cope with plain strings in the warning module's internal filter list (this avoids the need to create a compiled regex object early on during interpreter startup) - assorted documentation updates, including many more examples of configuring the warnings settings - additional tests to ensure that both the pure Python and the C accelerated warnings modules have the expected default configuration
-rw-r--r--Doc/library/exceptions.rst19
-rw-r--r--Doc/library/warnings.rst221
-rw-r--r--Doc/tools/susp-ignored.csv19
-rw-r--r--Doc/using/cmdline.rst72
-rw-r--r--Doc/whatsnew/3.7.rst40
-rw-r--r--Lib/test/test_cmd_line.py2
-rw-r--r--Lib/test/test_warnings/__init__.py36
-rw-r--r--Lib/warnings.py4
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2018-01-05-20-54-27.bpo-31975.AmftlU.rst4
-rw-r--r--Python/_warnings.c40
10 files changed, 333 insertions, 124 deletions
diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst
index c8d32cff4e..aa3141053b 100644
--- a/Doc/library/exceptions.rst
+++ b/Doc/library/exceptions.rst
@@ -661,11 +661,13 @@ depending on the system error code.
:pep:`3151` - Reworking the OS and IO exception hierarchy
+.. _warning-categories-as-exceptions:
+
Warnings
--------
-The following exceptions are used as warning categories; see the :mod:`warnings`
-module for more information.
+The following exceptions are used as warning categories; see the
+:ref:`warning-categories` documentation for more details.
.. exception:: Warning
@@ -679,12 +681,14 @@ module for more information.
.. exception:: DeprecationWarning
- Base class for warnings about deprecated features.
+ Base class for warnings about deprecated features when those warnings are
+ intended for other Python developers.
.. exception:: PendingDeprecationWarning
- Base class for warnings about features which will be deprecated in the future.
+ Base class for warnings about features which will be deprecated in the
+ future.
.. exception:: SyntaxWarning
@@ -699,8 +703,8 @@ module for more information.
.. exception:: FutureWarning
- Base class for warnings about constructs that will change semantically in the
- future.
+ Base class for warnings about deprecated features when those warnings are
+ intended for end users of applications that are written in Python.
.. exception:: ImportWarning
@@ -720,7 +724,8 @@ module for more information.
.. exception:: ResourceWarning
- Base class for warnings related to resource usage.
+ Base class for warnings related to resource usage. Ignored by the default
+ warning filters.
.. versionadded:: 3.2
diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst
index f67f4bc24c..b04bd79e4b 100644
--- a/Doc/library/warnings.rst
+++ b/Doc/library/warnings.rst
@@ -51,8 +51,17 @@ Warning Categories
------------------
There are a number of built-in exceptions that represent warning categories.
-This categorization is useful to be able to filter out groups of warnings. The
-following warnings category classes are currently defined:
+This categorization is useful to be able to filter out groups of warnings.
+
+While these are technically
+:ref:`built-in exceptions <warning-categories-as-exceptions>`, they are
+documented here, because conceptually they belong to the warnings mechanism.
+
+User code can define additional warning categories by subclassing one of the
+standard warning categories. A warning category must always be a subclass of
+the :exc:`Warning` class.
+
+The following warnings category classes are currently defined:
.. tabularcolumns:: |l|p{0.6\linewidth}|
@@ -66,7 +75,9 @@ following warnings category classes are currently defined:
| :exc:`UserWarning` | The default category for :func:`warn`. |
+----------------------------------+-----------------------------------------------+
| :exc:`DeprecationWarning` | Base category for warnings about deprecated |
-| | features (ignored by default). |
+| | features when those warnings are intended for |
+| | other Python developers (ignored by default, |
+| | unless triggered by code in ``__main__``). |
+----------------------------------+-----------------------------------------------+
| :exc:`SyntaxWarning` | Base category for warnings about dubious |
| | syntactic features. |
@@ -74,8 +85,10 @@ following warnings category classes are currently defined:
| :exc:`RuntimeWarning` | Base category for warnings about dubious |
| | runtime features. |
+----------------------------------+-----------------------------------------------+
-| :exc:`FutureWarning` | Base category for warnings about constructs |
-| | that will change semantically in the future. |
+| :exc:`FutureWarning` | Base category for warnings about deprecated |
+| | features when those warnings are intended for |
+| | end users of applications that are written in |
+| | Python. |
+----------------------------------+-----------------------------------------------+
| :exc:`PendingDeprecationWarning` | Base category for warnings about features |
| | that will be deprecated in the future |
@@ -95,13 +108,12 @@ following warnings category classes are currently defined:
| | resource usage. |
+----------------------------------+-----------------------------------------------+
-
-While these are technically built-in exceptions, they are documented here,
-because conceptually they belong to the warnings mechanism.
-
-User code can define additional warning categories by subclassing one of the
-standard warning categories. A warning category must always be a subclass of
-the :exc:`Warning` class.
+.. versionchanged:: 3.7
+ Previously :exc:`DeprecationWarning` and :exc:`FutureWarning` were
+ distinguished based on whether a feature was being removed entirely or
+ changing its behaviour. They are now distinguished based on their
+ intended audience and the way they're handled by the default warnings
+ filters.
.. _warning-filter:
@@ -114,7 +126,7 @@ into errors (raising an exception).
Conceptually, the warnings filter maintains an ordered list of filter
specifications; any specific warning is matched against each filter
-specification in the list in turn until a match is found; the match determines
+specification in the list in turn until a match is found; the filter determines
the disposition of the match. Each entry is a tuple of the form (*action*,
*message*, *category*, *module*, *lineno*), where:
@@ -123,19 +135,19 @@ the disposition of the match. Each entry is a tuple of the form (*action*,
+---------------+----------------------------------------------+
| Value | Disposition |
+===============+==============================================+
+ | ``"default"`` | print the first occurrence of matching |
+ | | warnings for each location (module + |
+ | | line number) where the warning is issued |
+ +---------------+----------------------------------------------+
| ``"error"`` | turn matching warnings into exceptions |
+---------------+----------------------------------------------+
| ``"ignore"`` | never print matching warnings |
+---------------+----------------------------------------------+
| ``"always"`` | always print matching warnings |
+---------------+----------------------------------------------+
- | ``"default"`` | print the first occurrence of matching |
- | | warnings for each location where the warning |
- | | is issued |
- +---------------+----------------------------------------------+
| ``"module"`` | print the first occurrence of matching |
| | warnings for each module where the warning |
- | | is issued |
+ | | is issued (regardless of line number) |
+---------------+----------------------------------------------+
| ``"once"`` | print only the first occurrence of matching |
| | warnings, regardless of location |
@@ -157,33 +169,119 @@ the disposition of the match. Each entry is a tuple of the form (*action*,
Since the :exc:`Warning` class is derived from the built-in :exc:`Exception`
class, to turn a warning into an error we simply raise ``category(message)``.
+If a warning is reported and doesn't match any registered filter then the
+"default" action is applied (hence its name).
+
+
+.. _describing-warning-filters:
+
+Describing Warning Filters
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
The warnings filter is initialized by :option:`-W` options passed to the Python
-interpreter command line. The interpreter saves the arguments for all
-:option:`-W` options without interpretation in ``sys.warnoptions``; the
-:mod:`warnings` module parses these when it is first imported (invalid options
-are ignored, after printing a message to ``sys.stderr``).
+interpreter command line and the :envvar:`PYTHONWARNINGS` environment variable.
+The interpreter saves the arguments for all supplied entries without
+interpretation in ``sys.warnoptions``; the :mod:`warnings` module parses these
+when it is first imported (invalid options are ignored, after printing a
+message to ``sys.stderr``).
+
+Individual warnings filters are specified as a sequence of fields separated by
+colons::
+ action:message:category:module:line
-Default Warning Filters
-~~~~~~~~~~~~~~~~~~~~~~~
+The meaning of each of these fields is as described in :ref:`warning-filter`.
+When listing multiple filters on a single line (as for
+:envvar:`PYTHONWARNINGS`), the individual filters are separated by commas,and
+the filters listed later take precedence over those listed before them (as
+they're applied left-to-right, and the most recently applied filters take
+precedence over earlier ones).
+
+Commonly used warning filters apply to either all warnings, warnings in a
+particular category, or warnings raised by particular modules or packages.
+Some examples::
+
+ default # Show all warnings (even those ignored by default)
+ ignore # Ignore all warnings
+ error # Convert all warnings to errors
+ error::ResourceWarning # Treat ResourceWarning messages as errors
+ default::DeprecationWarning # Show DeprecationWarning messages
+ ignore,default:::mymodule # Only report warnings triggered by "mymodule"
+ error:::mymodule[.*] # Convert warnings to errors in "mymodule"
+ # and any subpackages of "mymodule"
+
+
+.. _default-warning-filter:
+
+Default Warning Filter
+~~~~~~~~~~~~~~~~~~~~~~
By default, Python installs several warning filters, which can be overridden by
-the command-line options passed to :option:`-W` and calls to
-:func:`filterwarnings`.
+the :option:`-W` command-line option, the :envvar:`PYTHONWARNINGS` environment
+variable and calls to :func:`filterwarnings`.
-* :exc:`DeprecationWarning` and :exc:`PendingDeprecationWarning`, and
- :exc:`ImportWarning` are ignored.
+In regular release builds, the default warning filter has the following entries
+(in order of precedence)::
-* :exc:`BytesWarning` is ignored unless the :option:`-b` option is given once or
- twice; in this case this warning is either printed (``-b``) or turned into an
- exception (``-bb``).
+ default::DeprecationWarning:__main__
+ ignore::DeprecationWarning
+ ignore::PendingDeprecationWarning
+ ignore::ImportWarning
+ ignore::ResourceWarning
-* :exc:`ResourceWarning` is ignored unless Python was built in debug mode.
+In debug builds, the list of default warning filters is empty.
.. versionchanged:: 3.2
:exc:`DeprecationWarning` is now ignored by default in addition to
:exc:`PendingDeprecationWarning`.
+.. versionchanged:: 3.7
+ :exc:`DeprecationWarning` is once again shown by default when triggered
+ directly by code in ``__main__``.
+
+.. versionchanged:: 3.7
+ :exc:`BytesWarning` no longer appears in the default filter list and is
+ instead configured via :data:`sys.warnoptions` when :option:`-b` is specified
+ twice.
+
+
+.. _warning-disable:
+
+Overriding the default filter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Developers of applications written in Python may wish to hide *all* Python level
+warnings from their users by default, and only display them when running tests
+or otherwise working on the application. The :data:`sys.warnoptions` attribute
+used to pass filter configurations to the interpreter can be used as a marker to
+indicate whether or not warnings should be disabled::
+
+ import sys
+
+ if not sys.warnoptions:
+ import warnings
+ warnings.simplefilter("ignore")
+
+Developers of test runners for Python code are advised to instead ensure that
+*all* warnings are displayed by default for the code under test, using code
+like::
+
+ import sys
+
+ if not sys.warnoptions:
+ import os, warnings
+ warnings.simplefilter("default") # Change the filter in this process
+ os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses
+
+Finally, developers of interactive shells that run user code in a namespace
+other than ``__main__`` are advised to ensure that :exc:`DeprecationWarning`
+messages are made visible by default, using code like the following (where
+``user_ns`` is the module used to execute code entered interactively)::
+
+ import warnings
+ warnings.filterwarnings("default", category=DeprecationWarning,
+ module=user_ns.get("__name__"))
+
.. _warning-suppress:
@@ -191,7 +289,8 @@ Temporarily Suppressing Warnings
--------------------------------
If you are using code that you know will raise a warning, such as a deprecated
-function, but do not want to see the warning, then it is possible to suppress
+function, but do not want to see the warning (even when warnings have been
+explicitly configured via the command line), then it is possible to suppress
the warning using the :class:`catch_warnings` context manager::
import warnings
@@ -261,38 +360,30 @@ entries from the warnings list before each new operation).
.. _warning-ignored:
-Updating Code For New Versions of Python
-----------------------------------------
-
-Warnings that are only of interest to the developer are ignored by default. As
-such you should make sure to test your code with typically ignored warnings
-made visible. You can do this from the command-line by passing :option:`-Wd <-W>`
-to the interpreter (this is shorthand for :option:`!-W default`). This enables
-default handling for all warnings, including those that are ignored by default.
-To change what action is taken for encountered warnings you simply change what
-argument is passed to :option:`-W`, e.g. :option:`!-W error`. See the
-:option:`-W` flag for more details on what is possible.
-
-To programmatically do the same as :option:`!-Wd`, use::
-
- warnings.simplefilter('default')
-
-Make sure to execute this code as soon as possible. This prevents the
-registering of what warnings have been raised from unexpectedly influencing how
-future warnings are treated.
-
-Having certain warnings ignored by default is done to prevent a user from
-seeing warnings that are only of interest to the developer. As you do not
-necessarily have control over what interpreter a user uses to run their code,
-it is possible that a new version of Python will be released between your
-release cycles. The new interpreter release could trigger new warnings in your
-code that were not there in an older interpreter, e.g.
-:exc:`DeprecationWarning` for a module that you are using. While you as a
-developer want to be notified that your code is using a deprecated module, to a
-user this information is essentially noise and provides no benefit to them.
-
-The :mod:`unittest` module has been also updated to use the ``'default'``
-filter while running tests.
+Updating Code For New Versions of Dependencies
+----------------------------------------------
+
+Warning categories that are primarily of interest to Python developers (rather
+than end users of applications written in Python) are ignored by default.
+
+Notably, this "ignored by default" list includes :exc:`DeprecationWarning`
+(for every module except ``__main__``), which means developers should make sure
+to test their code with typically ignored warnings made visible in order to
+receive timely notifications of future breaking API changes (whether in the
+standard library or third party packages).
+
+In the ideal case, the code will have a suitable test suite, and the test runner
+will take care of implicitly enabling all warnings when running tests
+(the test runner provided by the :mod:`unittest` module does this).
+
+In less ideal cases, applications can be checked for use of deprecated
+interfaces by passing :option:`-Wd <-W>` to the Python interpreter (this is
+shorthand for :option:`!-W default`) or setting ``PYTHONWARNINGS=default`` in
+the environment. This enables default handling for all warnings, including those
+that are ignored by default. To change what action is taken for encountered
+warnings you can change what argument is passed to :option:`-W` (e.g.
+:option:`!-W error`). See the :option:`-W` flag for more details on what is
+possible.
.. _warning-functions:
diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv
index 48dd53f85d..cfdd5266c5 100644
--- a/Doc/tools/susp-ignored.csv
+++ b/Doc/tools/susp-ignored.csv
@@ -259,12 +259,8 @@ tutorial/stdlib2,,:start,extra = data[start:start+extra_size]
tutorial/stdlib2,,:start,"fields = struct.unpack('<IIIHH', data[start:start+16])"
tutorial/stdlib2,,:start,filename = data[start:start+filenamesize]
tutorial/stdlib2,,:Warning,WARNING:root:Warning:config file server.conf not found
-using/cmdline,,:category,action:message:category:module:line
using/cmdline,,:errorhandler,:errorhandler
-using/cmdline,,:line,action:message:category:module:line
using/cmdline,,:line,file:line: category: message
-using/cmdline,,:message,action:message:category:module:line
-using/cmdline,,:module,action:message:category:module:line
using/unix,,:Packaging,https://en.opensuse.org/Portal:Packaging
whatsnew/2.0,,:len,
whatsnew/2.3,,::,
@@ -302,6 +298,20 @@ whatsnew/3.2,,:prefix,zope-conf = ${custom:prefix}/etc/zope.conf
library/re,,`,!#$%&'*+-.^_`|~:
library/re,,`,!\#\$%\&'\*\+\-\.\^_`\|\~:
library/tarfile,,:xz,'x:xz'
+library/warnings,,:message,action:message:category:module:line
+library/warnings,,:category,action:message:category:module:line
+library/warnings,,:module,action:message:category:module:line
+library/warnings,,:line,action:message:category:module:line
+library/warnings,,::,error::ResourceWarning
+library/warnings,,::,default::DeprecationWarning
+library/warnings,,::,default:::mymodule
+library/warnings,,:mymodule,default:::mymodule
+library/warnings,,::,error:::mymodule
+library/warnings,,:mymodule,error:::mymodule
+library/warnings,,::,ignore::DeprecationWarning
+library/warnings,,::,ignore::PendingDeprecationWarning
+library/warnings,,::,ignore::ImportWarning
+library/warnings,,::,ignore::ResourceWarning
library/xml.etree.elementtree,,:sometag,prefix:sometag
library/xml.etree.elementtree,,:fictional,"<actors xmlns:fictional=""http://characters.example.com"""
library/xml.etree.elementtree,,:character,<fictional:character>Lancelot</fictional:character>
@@ -330,3 +340,4 @@ whatsnew/3.7,,`,'`'
whatsnew/3.7,,::,error::BytesWarning
whatsnew/changelog,,::,error::BytesWarning
whatsnew/changelog,,::,default::BytesWarning
+whatsnew/changelog,,::,default::DeprecationWarning
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index b1bd47fa6b..1e9ed6e645 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -356,49 +356,27 @@ Miscellaneous options
:option:`-W` options are ignored (though, a warning message is printed about
invalid options when the first warning is issued).
- Warnings can also be controlled from within a Python program using the
+ Warnings can also be controlled using the :envvar:`PYTHONWARNINGS`
+ environment variable and from within a Python program using the
:mod:`warnings` module.
- The simplest form of argument is one of the following action strings (or a
- unique abbreviation):
-
- ``ignore``
- Ignore all warnings.
- ``default``
- Explicitly request the default behavior (printing each warning once per
- source line).
- ``all``
- Print a warning each time it occurs (this may generate many messages if a
- warning is triggered repeatedly for the same source line, such as inside a
- loop).
- ``module``
- Print each warning only the first time it occurs in each module.
- ``once``
- Print each warning only the first time it occurs in the program.
- ``error``
- Raise an exception instead of printing a warning message.
-
- The full form of argument is::
-
- action:message:category:module:line
-
- Here, *action* is as explained above but only applies to messages that match
- the remaining fields. Empty fields match all values; trailing empty fields
- may be omitted. The *message* field matches the start of the warning message
- printed; this match is case-insensitive. The *category* field matches the
- warning category. This must be a class name; the match tests whether the
- actual warning category of the message is a subclass of the specified warning
- category. The full class name must be given. The *module* field matches the
- (fully-qualified) module name; this match is case-sensitive. The *line*
- field matches the line number, where zero matches all line numbers and is
- thus equivalent to an omitted line number.
+ The simplest settings apply a particular action unconditionally to all
+ warnings emitted by a process (even those that are otherwise ignored by
+ default)::
- .. seealso::
- :mod:`warnings` -- the warnings module
+ -Wdefault # Warn once per call location
+ -Werror # Convert to exceptions
+ -Walways # Warn every time
+ -Wmodule # Warn once per calling module
+ -Wonce # Warn once per Python process
+ -Wignore # Never warn
- :pep:`230` -- Warning framework
+ The action names can be abbreviated as desired (e.g. ``-Wi``, ``-Wd``,
+ ``-Wa``, ``-We``) and the interpreter will resolve them to the appropriate
+ action name.
- :envvar:`PYTHONWARNINGS`
+ See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
+ details.
.. cmdoption:: -x
@@ -659,7 +637,23 @@ conflict.
This is equivalent to the :option:`-W` option. If set to a comma
separated string, it is equivalent to specifying :option:`-W` multiple
- times.
+ times, with filters later in the list taking precedence over those earlier
+ in the list.
+
+ The simplest settings apply a particular action unconditionally to all
+ warnings emitted by a process (even those that are otherwise ignored by
+ default)::
+
+ PYTHONWARNINGS=default # Warn once per call location
+ PYTHONWARNINGS=error # Convert to exceptions
+ PYTHONWARNINGS=always # Warn every time
+ PYTHONWARNINGS=module # Warn once per calling module
+ PYTHONWARNINGS=once # Warn once per Python process
+ PYTHONWARNINGS=ignore # Never warn
+
+ See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
+ details.
+
.. envvar:: PYTHONFAULTHANDLER
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index 9785d599dd..992d9ba6e5 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -70,6 +70,7 @@ Summary -- Release highlights
New Features
============
+
.. _whatsnew37-pep538:
PEP 538: Legacy C Locale Coercion
@@ -107,6 +108,7 @@ locale remains active when the core interpreter is initialized.
:pep:`538` -- Coercing the legacy C locale to a UTF-8 based locale
PEP written and implemented by Nick Coghlan.
+
.. _whatsnew37-pep553:
PEP 553: Built-in breakpoint()
@@ -203,6 +205,44 @@ resolution on Linux and Windows.
PEP written and implemented by Victor Stinner
+.. _whatsnew37-pep565:
+
+PEP 565: Show DeprecationWarning in ``__main__``
+------------------------------------------------
+
+The default handling of :exc:`DeprecationWarning` has been changed such that
+these warnings are once more shown by default, but only when the code
+triggering them is running directly in the ``__main__`` module. As a result,
+developers of single file scripts and those using Python interactively should
+once again start seeing deprecation warnings for the APIs they use, but
+deprecation warnings triggered by imported application, library and framework
+modules will continue to be hidden by default.
+
+As a result of this change, the standard library now allows developers to choose
+between three different deprecation warning behaviours:
+
+* :exc:`FutureWarning`: always displayed by default, recommended for warnings
+ intended to be seen by application end users (e.g. for deprecated application
+ configuration settings).
+* :exc:`DeprecationWarning`: displayed by default only in ``__main__`` and when
+ running tests, recommended for warnings intended to be seen by other Python
+ developers where a version upgrade may result in changed behaviour or an
+ error.
+* :exc:`PendingDeprecationWarning`: displayed by default only when running
+ tests, intended for cases where a future version upgrade will change the
+ warning category to :exc:`DeprecationWarning` or :exc:`FutureWarning`.
+
+Previously both :exc:`DeprecationWarning` and :exc:`PendingDeprecationWarning`
+were only visible when running tests, which meant that developers primarily
+writing single file scripts or using Python interactively could be surprised
+by breaking changes in the APIs they used.
+
+.. seealso::
+
+ :pep:`565` -- Show DeprecationWarning in ``__main__``
+ PEP written and implemented by Nick Coghlan
+
+
PEP 540: Add a new UTF-8 mode
-----------------------------
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index 54ea3773a0..a6b663403f 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -558,6 +558,7 @@ class CmdLineTest(unittest.TestCase):
expected_filters = "default::Warning"
else:
expected_filters = ("default::Warning "
+ "default::DeprecationWarning "
"ignore::DeprecationWarning "
"ignore::PendingDeprecationWarning "
"ignore::ImportWarning "
@@ -626,6 +627,7 @@ class CmdLineTest(unittest.TestCase):
"always::UserWarning")
if not Py_DEBUG:
expected_filters += (" "
+ "default::DeprecationWarning "
"ignore::DeprecationWarning "
"ignore::PendingDeprecationWarning "
"ignore::ImportWarning "
diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py
index 039c96e02c..31ab94b747 100644
--- a/Lib/test/test_warnings/__init__.py
+++ b/Lib/test/test_warnings/__init__.py
@@ -16,6 +16,8 @@ import warnings as original_warnings
py_warnings = support.import_fresh_module('warnings', blocked=['_warnings'])
c_warnings = support.import_fresh_module('warnings', fresh=['_warnings'])
+Py_DEBUG = hasattr(sys, 'gettotalrefcount')
+
@contextmanager
def warnings_state(module):
"""Use a specific warnings implementation in warning_tests."""
@@ -320,6 +322,7 @@ class FilterTests(BaseTest):
self.module.filters[0][0], "error",
"simplefilter did not promote filter to the beginning of list"
)
+
def test_append_duplicate(self):
with original_warnings.catch_warnings(module=self.module,
record=True) as w:
@@ -1143,6 +1146,37 @@ class EnvironmentVariableTests(BaseTest):
b" File \"<string>\", line 1, in <module>",
b"DeprecationWarning: Message"])
+ def test_default_filter_configuration(self):
+ pure_python_api = self.module is py_warnings
+ if Py_DEBUG:
+ expected_default_filters = []
+ else:
+ if pure_python_api:
+ main_module_filter = re.compile("__main__")
+ else:
+ main_module_filter = "__main__"
+ expected_default_filters = [
+ ('default', None, DeprecationWarning, main_module_filter, 0),
+ ('ignore', None, DeprecationWarning, None, 0),
+ ('ignore', None, PendingDeprecationWarning, None, 0),
+ ('ignore', None, ImportWarning, None, 0),
+ ('ignore', None, ResourceWarning, None, 0),
+ ]
+ expected_output = [str(f).encode() for f in expected_default_filters]
+
+ if pure_python_api:
+ # Disable the warnings acceleration module in the subprocess
+ code = "import sys; sys.modules.pop('warnings', None); sys.modules['_warnings'] = None; "
+ else:
+ code = ""
+ code += "import warnings; [print(f) for f in warnings.filters]"
+
+ rc, stdout, stderr = assert_python_ok("-c", code, __isolated=True)
+ stdout_lines = [line.strip() for line in stdout.splitlines()]
+ self.maxDiff = None
+ self.assertEqual(stdout_lines, expected_output)
+
+
@unittest.skipUnless(sys.getfilesystemencoding() != 'ascii',
'requires non-ascii filesystemencoding')
def test_nonascii(self):
@@ -1192,7 +1226,7 @@ a=A()
rc, out, err = assert_python_ok("-c", code)
# note: "__main__" filename is not correct, it should be the name
# of the script
- self.assertEqual(err, b'__main__:7: UserWarning: test')
+ self.assertEqual(err.decode(), '__main__:7: UserWarning: test')
def test_late_resource_warning(self):
# Issue #21925: Emitting a ResourceWarning late during the Python
diff --git a/Lib/warnings.py b/Lib/warnings.py
index f4331c8ac3..76ad4dac01 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -519,8 +519,10 @@ except ImportError:
# Module initialization
_processoptions(sys.warnoptions)
if not _warnings_defaults:
- # Several warning categories are ignored by default in Py_DEBUG builds
+ # Several warning categories are ignored by default in regular builds
if not hasattr(sys, 'gettotalrefcount'):
+ filterwarnings("default", category=DeprecationWarning,
+ module="__main__", append=1)
simplefilter("ignore", category=DeprecationWarning, append=1)
simplefilter("ignore", category=PendingDeprecationWarning, append=1)
simplefilter("ignore", category=ImportWarning, append=1)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-01-05-20-54-27.bpo-31975.AmftlU.rst b/Misc/NEWS.d/next/Core and Builtins/2018-01-05-20-54-27.bpo-31975.AmftlU.rst
new file mode 100644
index 0000000000..98cfae0dd8
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-01-05-20-54-27.bpo-31975.AmftlU.rst
@@ -0,0 +1,4 @@
+The default warning filter list now starts with a
+"default::DeprecationWarning:__main__" entry, so deprecation warnings are
+once again shown by default in single-file scripts and at the interactive
+prompt.
diff --git a/Python/_warnings.c b/Python/_warnings.c
index be8370da06..c286364dda 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -12,6 +12,7 @@ MODULE_NAME " provides basic warning filtering support.\n"
_Py_IDENTIFIER(argv);
_Py_IDENTIFIER(stderr);
#ifndef Py_DEBUG
+_Py_IDENTIFIER(default);
_Py_IDENTIFIER(ignore);
#endif
@@ -22,8 +23,20 @@ check_matched(PyObject *obj, PyObject *arg)
_Py_IDENTIFIER(match);
int rc;
+ /* A 'None' filter always matches */
if (obj == Py_None)
return 1;
+
+ /* An internal plain text default filter must match exactly */
+ if (PyUnicode_CheckExact(obj)) {
+ int cmp_result = PyUnicode_Compare(obj, arg);
+ if (cmp_result == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ return !cmp_result;
+ }
+
+ /* Otherwise assume a regex filter and call its match() method */
result = _PyObject_CallMethodIdObjArgs(obj, &PyId_match, arg, NULL);
if (result == NULL)
return -1;
@@ -1158,16 +1171,27 @@ static PyMethodDef warnings_functions[] = {
#ifndef Py_DEBUG
static PyObject *
-create_filter(PyObject *category, _Py_Identifier *id)
+create_filter(PyObject *category, _Py_Identifier *id, const char *modname)
{
+ PyObject *modname_obj = NULL;
PyObject *action_str = _PyUnicode_FromId(id);
if (action_str == NULL) {
return NULL;
}
+ /* Default to "no module name" for initial filter set */
+ if (modname != NULL) {
+ modname_obj = PyUnicode_InternFromString(modname);
+ if (modname_obj == NULL) {
+ return NULL;
+ }
+ } else {
+ modname_obj = Py_None;
+ }
+
/* This assumes the line number is zero for now. */
return PyTuple_Pack(5, action_str, Py_None,
- category, Py_None, _PyLong_Zero);
+ category, modname_obj, _PyLong_Zero);
}
#endif
@@ -1180,20 +1204,22 @@ init_filters(void)
return PyList_New(0);
#else
/* Other builds ignore a number of warning categories by default */
- PyObject *filters = PyList_New(4);
+ PyObject *filters = PyList_New(5);
if (filters == NULL) {
return NULL;
}
size_t pos = 0; /* Post-incremented in each use. */
PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_DeprecationWarning, &PyId_ignore));
+ create_filter(PyExc_DeprecationWarning, &PyId_default, "__main__"));
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_DeprecationWarning, &PyId_ignore, NULL));
PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_PendingDeprecationWarning, &PyId_ignore));
+ create_filter(PyExc_PendingDeprecationWarning, &PyId_ignore, NULL));
PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_ImportWarning, &PyId_ignore));
+ create_filter(PyExc_ImportWarning, &PyId_ignore, NULL));
PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_ResourceWarning, &PyId_ignore));
+ create_filter(PyExc_ResourceWarning, &PyId_ignore, NULL));
for (size_t x = 0; x < pos; x++) {
if (PyList_GET_ITEM(filters, x) == NULL) {