Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 230 – Warning Framework

Author:
Guido van Rossum <guido at python.org>
Status:
Final
Type:
Standards Track
Created:
28-Nov-2000
Python-Version:
2.1
Post-History:
05-Nov-2000

Table of Contents

Abstract

This PEP proposes a C and Python level API, as well as commandline flags, to issue warning messages and control what happens tothem. This is mostly based on GvR’s proposal posted to python-devon 05-Nov-2000, with some ideas (such as using classes tocategorize warnings) merged in from Paul Prescod’scounter-proposal posted on the same date. Also, an attempt toimplement the proposal caused several small tweaks.

Motivation

With Python 3000 looming, it is necessary to start issuingwarnings about the use of obsolete or deprecated features, inaddition to errors. There are also lots of other reasons to beable to issue warnings, both from C and from Python code, both atcompile time and at run time.

Warnings aren’t fatal, and thus it’s possible that a programtriggers the same warning many times during a single execution.It would be annoying if a program emitted an endless stream ofidentical warnings. Therefore, a mechanism is needed thatsuppresses multiple identical warnings.

It is also desirable to have user control over which warnings areprinted. While in general it is useful to see all warnings allthe time, there may be times where it is impractical to fix thecode right away in a production program. In this case, thereshould be a way to suppress warnings.

It is also useful to be able to suppress specific warnings duringprogram development, e.g. when a warning is generated by a pieceof 3rd party code that cannot be fixed right away, or when thereis no way to fix the code (possibly a warning message is generatedfor a perfectly fine piece of code). It would be unwise to offerto suppress all warnings in such cases: the developer would misswarnings about the rest of the code.

On the other hand, there are also situations conceivable wheresome or all warnings are better treated as errors. For example,it may be a local coding standard that a particular deprecatedfeature should not be used. In order to enforce this, it isuseful to be able to turn the warning about this particularfeature into an error, raising an exception (without necessarilyturning 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:

  • Where in the code they are generated (per package, module, orfunction)
  • The warning category (warning categories are discussed below)
  • A specific warning message

The warning filter must be controllable both from the command lineand from Python code.

APIs For Issuing Warnings

  • To issue a warning from Python:
    importwarningswarnings.warn(message[,category[,stacklevel]])

    The category argument, if given, must be a warning categoryclass (see below); it defaults to warnings.UserWarning. Thismay raise an exception if the particular warning issued ischanged into an error by the warnings filter. The stacklevelcan be used by wrapper functions written in Python, like this:

    defdeprecation(message):warn(message,DeprecationWarning,level=2)

    This makes the warning refer to the deprecation()’s caller,rather than to the source of deprecation() itself (since thelatter would defeat the purpose of the warning message).

  • To issue a warning from C:
    intPyErr_Warn(PyObject*category,char*message);

    Return 0 normally, 1 if an exception is raised (either becausethe warning was transformed into an exception, or because of amalfunction in the implementation, such as running out ofmemory). The category argument must be a warning category class(see below) orNULL, in which case it defaults toPyExc_RuntimeWarning. WhenPyErr_Warn() function returns 1, thecaller should do normal exception handling.

    The current C implementation ofPyErr_Warn() imports thewarnings module (implemented in Python) and calls itswarn()function. This minimizes the amount of C code that needs to beadded to implement the warning feature.

    [XXX Open Issue: what about issuing warnings during lexing orparsing, which don’t have the exception machinery available?]

Warnings Categories

There are a number of built-in exceptions that represent warningcategories. This categorization is useful to be able to filterout groups of warnings. The following warnings category classesare currently defined:

  • Warning – this is the base class of all warning categoryclasses and it itself a subclass of Exception
  • UserWarning – the default category forwarnings.warn()
  • DeprecationWarning – base category for warnings about deprecatedfeatures
  • SyntaxWarning – base category for warnings about dubioussyntactic features
  • RuntimeWarning – base category for warnings about dubiousruntime features

[XXX: Other warning categories may be proposed during the reviewperiod for this PEP.]

These standard warning categories are available from C asPyExc_Warning,PyExc_UserWarning, etc. From Python, they areavailable in the__builtin__ module, so no import is necessary.

User code can define additional warning categories by subclassingone of the standard warning categories. A warning category mustalways be a subclass of the Warning class.

The Warnings Filter

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 data structures used to efficiently determine thedisposition of a particularwarnings.warn() orPyErr_Warn()call.
  • The API to control the filter from Python source code.
  • The command line switches to control the filter.

The warnings filter works in several stages. It is optimized forthe (expected to be common) case where the same warning is issuedfrom the same place in the code over and over.

First, the warning filter collects the module and line numberwhere the warning is issued; this information is readily availablethroughsys._getframe().

Conceptually, the warnings filter maintains an ordered list offilter specifications; any specific warning is matched againsteach filter specification in the list in turn until a match isfound; the match determines the disposition of the match. Eachentry is a tuple as follows:

(category,message,module,lineno,action)
  • category is a class (a subclass ofwarnings.Warning) of whichthe warning category must be a subclass in order to match
  • message is a compiled regular expression that the warningmessage must match (the match is case-insensitive)
  • module is a compiled regular expression that the module namemust match
  • lineno is an integer that the line number where the warningoccurred must match, or 0 to match all line numbers
  • action is one of the following strings:
    • “error” – turn matching warnings into exceptions
    • “ignore” – never print matching warnings
    • “always” – always print matching warnings
    • “default” – print the first occurrence of matching warningsfor each location where the warning is issued
    • “module” – print the first occurrence of matching warningsfor each module where the warning is issued
    • “once” – print only the first occurrence of matchingwarnings

Since theWarning class is derived from the built-inExceptionclass, to turn a warning into an error we simply raisecategory(message).

Warnings Output And Formatting Hooks

When the warnings filter decides to issue a warning (but not whenit decides to raise an exception), it passes the information aboutthe functionwarnings.showwarning(message,category,filename,lineno).The default implementation of this function writes the warning texttosys.stderr, and shows the source line of the filename. It hasan optional 5th argument which can be used to specify a differentfile thansys.stderr.

The formatting of warnings is done by a separate function,warnings.formatwarning(message,category,filename,lineno). Thisreturns a string (that may contain newlines and ends in a newline)that can be printed to get the identical effect of theshowwarning() function.

API For Manipulating Warning Filters

warnings.filterwarnings(message,category,module,lineno,action)

This checks the types of the arguments, compiles the message andmodule regular expressions, and inserts them as a tuple in frontof the warnings filter.

warnings.resetwarnings()

Reset the warnings filter to empty.

Command Line Syntax

There should be command line options to specify the most commonfiltering actions, which I expect to include at least:

  • suppress all warnings
  • suppress a particular warning message everywhere
  • suppress all warnings in a particular module
  • turn all warnings into exceptions

I propose the following command line option syntax:

-Waction[:message[:category[:module[:lineno]]]]

Where:

  • ‘action’ is an abbreviation of one of the allowed actions(“error”, “default”, “ignore”, “always”, “once”, or “module”)
  • ‘message’ is a message string; matches warnings whose messagetext is an initial substring of ‘message’ (matching iscase-insensitive)
  • ‘category’ is an abbreviation of a standard warning categoryclass nameor a fully-qualified name for a user-definedwarning category class of the form [package.]module.classname
  • ‘module’ is a module name (possibly package.module)
  • ‘lineno’ is an integral line number

All parts except ‘action’ may be omitted, where an empty valueafter stripping whitespace is the same as an omitted value.

The C code that parses the Python command line saves the body ofall -W options in a list of strings, which is made available tothe warnings module as sys.warnoptions. The warnings moduleparses these when it is first imported. Errors detected duringthe parsing of sys.warnoptions are not fatal; a message is writtento sys.stderr and processing continues with the option.

Examples:

-Werror
Turn all warnings into errors
-Wall
Show all warnings
-Wignore
Ignore all warnings
-Wi:hello
Ignore warnings whose message text starts with “hello”
-We::Deprecation
Turn deprecation warnings into errors
-Wi:::spam:10
Ignore all warnings on line 10 of module spam
-Wi:::spam-Wd:::spam:10
Ignore all warnings in module spam except on line 10
-We::Deprecation-Wd::Deprecation:spam
Turn deprecation warnings into errors except in module spam

Open Issues

Some open issues off the top of my head:

  • What about issuing warnings during lexing or parsing, whichdon’t have the exception machinery available?
  • The proposed command line syntax is a bit ugly (although thesimple cases aren’t so bad:-Werror,-Wignore, etc.). Anybodygot a better idea?
  • I’m a bit worried that the filter specifications are toocomplex. Perhaps filtering only on category and module (not onmessage text and line number) would be enough?
  • There’s a bit of confusion between module names and file names.The reporting uses file names, but the filter specification usesmodule names. Maybe it should allow filenames as well?
  • I’m not at all convinced that packages are handled right.
  • Do we need more standard warning categories? Fewer?
  • In order to minimize the start-up overhead, the warnings moduleis imported by the first call toPyErr_Warn(). It does thecommand line parsing for-W options upon import. Therefore, itis possible that warning-free programs will not complain aboutinvalid-W options.

Rejected Concerns

Paul Prescod, Barry Warsaw and Fred Drake have brought up severaladditional concerns that I feel aren’t critical. I address themhere (the concerns are paraphrased, not exactly their words):

  • Paul:warn() should be a built-in or a statement to make it easilyavailable.

    Response: “from warnings import warn” is easy enough.

  • Paul: What if I have a speed-critical module that triggerswarnings in an inner loop. It should be possible to disable theoverhead for detecting the warning (not just suppress thewarning).

    Response: rewrite the inner loop to avoid triggering thewarning.

  • Paul: What if I want to see the full context of a warning?

    Response: use-Werror to turn it into an exception.

  • Paul: I prefer “:*:*:” to “:::” for leaving parts of the warningspec out.

    Response: I don’t.

  • Barry: It would be nice if lineno can be a range specification.

    Response: Too much complexity already.

  • Barry: I’d like to add my own warning action. Maybe if ‘action’could be a callable as well as a string. Then in my IDE, Icould set that to “mygui.popupWarningsDialog”.

    Response: For that purpose you would overridewarnings.showwarning().

  • Fred: why do the Warning category classes have to be in__builtin__?

    Response: that’s the simplest implementation, given that thewarning categories must be available in C before the firstPyErr_Warn() call, which imports the warnings module. I see noproblem with making them available as built-ins.

Implementation

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 GMT


[8]ページ先頭

©2009-2025 Movatter.jp