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:
parent
d13889214a
commit
9b99747386
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
-----------------------------
|
||||
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue