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
This commit is contained in:
Nick Coghlan 2018-01-08 12:45:02 +10:00 committed by GitHub
parent d13889214a
commit 9b99747386
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 329 additions and 120 deletions

View File

@ -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

View File

@ -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
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 Filters
~~~~~~~~~~~~~~~~~~~~~~~
.. _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
----------------------------------------
Updating Code For New Versions of Dependencies
----------------------------------------------
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.
Warning categories that are primarily of interest to Python developers (rather
than end users of applications written in Python) are ignored by default.
To programmatically do the same as :option:`!-Wd`, use::
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).
warnings.simplefilter('default')
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).
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.
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:

View File

@ -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

1 c-api/arg :ref PyArg_ParseTuple(args, "O|O:ref", &object, &callback)
259 tutorial/stdlib2 :start fields = struct.unpack('<IIIHH', data[start:start+16])
260 tutorial/stdlib2 :start filename = data[start:start+filenamesize]
261 tutorial/stdlib2 :Warning WARNING:root:Warning:config file server.conf not found
using/cmdline :category action:message:category:module:line
262 using/cmdline :errorhandler :errorhandler
using/cmdline :line action:message:category:module:line
263 using/cmdline :line file:line: category: message
using/cmdline :message action:message:category:module:line
using/cmdline :module action:message:category:module:line
264 using/unix :Packaging https://en.opensuse.org/Portal:Packaging
265 whatsnew/2.0 :len
266 whatsnew/2.3 ::
298 library/re ` !#$%&'*+-.^_`|~:
299 library/re ` !\#\$%\&'\*\+\-\.\^_`\|\~:
300 library/tarfile :xz 'x:xz'
301 library/warnings :message action:message:category:module:line
302 library/warnings :category action:message:category:module:line
303 library/warnings :module action:message:category:module:line
304 library/warnings :line action:message:category:module:line
305 library/warnings :: error::ResourceWarning
306 library/warnings :: default::DeprecationWarning
307 library/warnings :: default:::mymodule
308 library/warnings :mymodule default:::mymodule
309 library/warnings :: error:::mymodule
310 library/warnings :mymodule error:::mymodule
311 library/warnings :: ignore::DeprecationWarning
312 library/warnings :: ignore::PendingDeprecationWarning
313 library/warnings :: ignore::ImportWarning
314 library/warnings :: ignore::ResourceWarning
315 library/xml.etree.elementtree :sometag prefix:sometag
316 library/xml.etree.elementtree :fictional <actors xmlns:fictional="http://characters.example.com"
317 library/xml.etree.elementtree :character <fictional:character>Lancelot</fictional:character>
340 whatsnew/3.7 :: error::BytesWarning
341 whatsnew/changelog :: error::BytesWarning
342 whatsnew/changelog :: default::BytesWarning
343 whatsnew/changelog :: default::DeprecationWarning

View File

@ -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):
The simplest settings apply a particular action unconditionally to all
warnings emitted by a process (even those that are otherwise ignored by
default)::
``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.
-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
The full form of argument is::
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.
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.
.. seealso::
:mod:`warnings` -- the warnings module
:pep:`230` -- Warning framework
: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

View File

@ -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
-----------------------------

View File

@ -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 "

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -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_PendingDeprecationWarning, &PyId_ignore));
create_filter(PyExc_DeprecationWarning, &PyId_ignore, NULL));
PyList_SET_ITEM(filters, pos++,
create_filter(PyExc_ImportWarning, &PyId_ignore));
create_filter(PyExc_PendingDeprecationWarning, &PyId_ignore, NULL));
PyList_SET_ITEM(filters, pos++,
create_filter(PyExc_ResourceWarning, &PyId_ignore));
create_filter(PyExc_ImportWarning, &PyId_ignore, NULL));
PyList_SET_ITEM(filters, pos++,
create_filter(PyExc_ResourceWarning, &PyId_ignore, NULL));
for (size_t x = 0; x < pos; x++) {
if (PyList_GET_ITEM(filters, x) == NULL) {