[Python-Dev] Warning framework

Guido van Rossum guido@python.org
Sun, 05 Nov 2000 22:35:26 -0500


Before I fall asleep let me write up my ideas about the warning
framework.


Requirements:

- A C-level API that lets C code issue a warning with a single call
  taking one or two arguments, e.g. Py_Warning(level, message).  (The
  'level' argument is an example only; I'm not sure what if any we
  need.)

- After the first time a specific warning is issued for a given source
  code location, the overhead of calling Py_Warning() should be
  minimal.

- An equivalent Python level API, e.g. sys.warning(level, message).

- Flexible control over which warnings are printed or not; there
  should be a way to set this up from within the Python program but
  also from the command line or possible using an environment
  variable.

- Control over the disposition of warnings; by default they should be
  printed to sys.stderr but an alternative disposition should be
  supported (the mechanism could be either a different file or a
  different callback function).

- By default, a warning is printed once (the first time it is issued)
  for each source line where it is issued.

- For a specific warning at a specific source code location, it should
  be possible to specify the following alternatives:

  - Turn it into an exception

  - Don't print it at all

  - Print it each time it is issued

- It should also be possible to specify these alternatives:

  - For all warnings

  - For all warnings in a specific module or file

  - For all warnings at a specific source code location

  - For a specific warning everywhere in a specific module or file

  - For a specific warning everywhere in the program

  - For all warnings at/above/below (?) a specific level, if we use
    warning levels


Possible implementation:

- Each module can has a dictionary __warnings__ in its global
  __dict__, which records the state of warnings.  It is created as an
  emprt dict if it doesn't exist when it is needed.  The keys are
  (message, linenumber) tuples (the module or file is implicit through
  the use of the module's __dict__).  The value is None if no more
  action is needed for this particular warning and location.  Some
  other values may indicate the options "always print warning" (1?)
  and "raise an exception" (-1?).

- There's a list of "filters" in the sys module
  (e.g. sys.warningfilters) that is checked whenever a warning doesn't
  have a hit in the __warnings__ dict.  Entries in the filter list are
  (file, line, message, action) tuples.  (If we decide to implement
  warning levels, these must also be represented here somewhere.)

  - The file must be None or a shell matching pattern, e.g. "*foo";
    the ".py" suffix is optional; a partial pathname may be given too.
    So "foo/bar" matches "/usr/lib/python2.0/foo/bar.py" but also
    "/home/guido/libp/tralala/foo/bar.py".  If the file is None or "*"
    the filter applies regardless of the file.

  - The line must be None or an integer.  If the file is None or "*"
    (indicating all files) the line must be None and is ignored.

  - The message must be a None or a string.  If it is None, the filter
    applies to all messages.  The message string may end in "*" to
    match all messages with the given text (up to the "*").

  - The action must be one of the following strings:

    - "ignore" -- the warning is never printed

    - "always" -- the warning is always printed

    - "once" -- the warning is printed for the first occurrence
      matching the filter

    - "module" -- the warning is printed for the first occurrence in
      each module matching the filter

    - "location" -- the warning is printed for the first occurrence at
      each source code location (module + line) matching the filter

    - "exception" -- the warning is turned into an exception whenever
      it matches the filter

    Note: implementation of "once" and "module" require additional
    state per filter entry; I'm not sure if that's worth the effort.

  - When the warning system decides to print a warning, it is given to
    sys.displaywarning(file, line, message), which by default does
    something like print >>sys.stderr, file, ":", line, ":", message

  - There should be a function sys.addwarningfilter(file, line,
    message, action) that appends items to sys.warningfilters after
    some sanity checking.

  - There should be command line options to specify the most common
    filtering 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

--Guido van Rossum (home page: http://www.python.org/~guido/)