This PEP proposes a C and Python level API, as well as command line flags, to issue warning messages and control what happens to them. This is mostly based on GvR’s proposal posted to python-dev on 05-Nov-2000, with some ideas (such as using classes to categorize warnings) merged in from Paul Prescod’s counter-proposal posted on the same date. Also, an attempt to implement the proposal caused several small tweaks.
With Python 3000 looming, it is necessary to start issuing warnings about the use of obsolete or deprecated features, in addition to errors. There are also lots of other reasons to be able to issue warnings, both from C and from Python code, both at compile time and at run time.
Warnings aren’t fatal, and thus it’s possible that a program triggers the same warning many times during a single execution. It would be annoying if a program emitted an endless stream of identical warnings. Therefore, a mechanism is needed that suppresses multiple identical warnings.
It is also desirable to have user control over which warnings are printed. While in general it is useful to see all warnings all the time, there may be times where it is impractical to fix the code right away in a production program. In this case, there should be a way to suppress warnings.
It is also useful to be able to suppress specific warnings during program development, e.g. when a warning is generated by a piece of 3rd party code that cannot be fixed right away, or when there is no way to fix the code (possibly a warning message is generated for a perfectly fine piece of code). It would be unwise to offer to suppress all warnings in such cases: the developer would miss warnings about the rest of the code.
On the other hand, there are also situations conceivable where some or all warnings are better treated as errors. For example, it may be a local coding standard that a particular deprecated feature should not be used. In order to enforce this, it is useful to be able to turn the warning about this particular feature into an error, raising an exception (without necessarily turning all warnings into errors).
Therefore, I propose to introduce a flexible “warning filter” which can filter out warnings or change them into exceptions, based on:
The warning filter must be controllable both from the command line and from Python code.
The category argument, if given, must be a warning category class (see below); it defaults to warnings.UserWarning. This may raise an exception if the particular warning issued is changed into an error by the warnings filter. The stacklevel can be used by wrapper functions written in Python, like this:
This makes the warning refer to the deprecation()’s caller, rather than to the source of deprecation() itself (since the latter would defeat the purpose of the warning message).
Return 0 normally, 1 if an exception is raised (either because the warning was transformed into an exception, or because of a malfunction in the implementation, such as running out of memory). The category argument must be a warning category class (see below) or NULL, in which case it defaults to PyExc_RuntimeWarning. When PyErr_Warn() function returns 1, the caller should do normal exception handling.
The current C implementation of PyErr_Warn() imports the warnings module (implemented in Python) and calls its warn() function. This minimizes the amount of C code that needs to be added to implement the warning feature.
[XXX Open Issue: what about issuing warnings during lexing or parsing, which don’t have the exception machinery available?]
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:
[XXX: Other warning categories may be proposed during the review period for this PEP.]
These standard warning categories are available from C as PyExc_Warning, PyExc_UserWarning, etc. From Python, they are available in the __builtin__ module, so no import is necessary.
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 Warning class.
The warnings filter control whether warnings are ignored, displayed, or turned into errors (raising an exception).
There are three sides to the warnings filter:
The warnings filter works in several stages. It is optimized for the (expected to be common) case where the same warning is issued from the same place in the code over and over.
First, the warning filter collects the module and line number where the warning is issued; this information is readily available through sys._getframe().
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 the disposition of the match. Each entry is a tuple as follows:
Since the Warning class is derived from the built-in Exception class, to turn a warning into an error we simply raise category(message).
When the warnings filter decides to issue a warning (but not when it decides to raise an exception), it passes the information about the function warnings.showwarning(message, category, filename, lineno). The default implementation of this function writes the warning text to sys.stderr, and shows the source line of the filename. It has an optional 5th argument which can be used to specify a different file than sys.stderr.
The formatting of warnings is done by a separate function, warnings.formatwarning(message, category, filename, lineno). This returns a string (that may contain newlines and ends in a newline) that can be printed to get the identical effect of the showwarning() function.
This checks the types of the arguments, compiles the message and module regular expressions, and inserts them as a tuple in front of the warnings filter.
Reset the warnings filter to empty.
There should be command line options to specify the most common filtering actions, which I expect to include at least:
I propose the following command line option syntax:
Where:
All parts except ‘action’ may be omitted, where an empty value after stripping whitespace is the same as an omitted value.
The C code that parses the Python command line saves the body of all -W options in a list of strings, which is made available to the warnings module as sys.warnoptions. The warnings module parses these when it is first imported. Errors detected during the parsing of sys.warnoptions are not fatal; a message is written to sys.stderr and processing continues with the option.
Examples:
-WerrorTurn all warnings into errors -WallShow all warnings -WignoreIgnore all warnings -Wi:helloIgnore warnings whose message text starts with “hello” -We::DeprecationTurn deprecation warnings into errors -Wi:::spam:10Ignore all warnings on line 10 of module spam -Wi:::spam -Wd:::spam:10Ignore all warnings in module spam except on line 10 -We::Deprecation -Wd::Deprecation:spamTurn deprecation warnings into errors except in module spamSome open issues off the top of my head:
Paul Prescod, Barry Warsaw and Fred Drake have brought up several additional concerns that I feel aren’t critical. I address them here (the concerns are paraphrased, not exactly their words):
Response: “from warnings import warn” is easy enough.
Response: rewrite the inner loop to avoid triggering the warning.
Response: use -Werror to turn it into an exception.
Response: I don’t.
Response: Too much complexity already.
Response: For that purpose you would override warnings.showwarning().
Response: that’s the simplest implementation, given that the warning categories must be available in C before the first PyErr_Warn() call, which imports the warnings module. I see no problem with making them available as built-ins.
Here’s a prototype implementation: http://sourceforge.net/patch/?func=detailpatch&patch_id=102715&group_id=5470
Source: https://github.com/python/peps/blob/main/peps/pep-0230.rst
Last modified: 2025-02-01 08:55:40 UTC