[Python-Dev] Warnings PEP

Paul Prescod paulp@ActiveState.com
Sun, 5 Nov 2000 22:24:27 -0800 (PST)


Abstract

    This PEP describes a generalized warning mechanism for Python 2.1. The
    primary purpose of this mechanism is to alert the programmer or user
    of a program to potential or likely errors which, for whatever reason,
    are not considered exception-worthy. For example, this might be done
    to keep old code working during a transitional period or to alert the
    programmer or user of a recoverable error.

Syntax

    assert >> cls, test[[[, arg], arg]...]

    "cls" may be any callable object that takes a list as a single
    argument argument list and returns an object with the required
    attributes "get_action" and "format_message"
    
       * get_action() -> "warn"|"error"|"suppress"
       * format_message() -> string

    A provided base class implements these methods in a reusable
    fashion. Warning creators are encouraged to merely subclass.

    This extended form of the assertion statement calls the assertion
    handler code in the new "assertions" module. 

    The semantics of the built-in assertion handler are defined by the
    following code. It should be exposed in a new "assertions" module.

    def handle_assertion(cls, message = ""):
        "This code is called when an assertion fails and cls is not None"

	obj = cls(message)
	action = obj.get_action()
            
        if action=="error":
            *** existing assertion code ***
        elif action=="warn":
	    sys.stderr.write(obj.format_message())
        elif action=="suppress":
            pass
        else:
            assert action in ["warn","error","suppress"]

    Even if handle_assertion is implemented in C, it should be exposed as
    assertions.handle_assertion so that it may be overriden. 

    The generic warning base class is defined below:

    class Assertion:
        def __init__(self, *args):
	    if len(args) == 1:
	       self.args = args[0]
	    else:
	        self.args = args

	def format_message(self):
            sys.stderr.write("%s: %s" %(obj.__name__, self.args))

	def get_action(self):
	    return (self.get_user_request(self.__class__) 
                                or sys.default_warning_action)

        def get_user_request(self, cls):
            if cls.__name__ in sys.errors:
                return "error"
	    elif cls.__name__ in sys.warnings:
                return "warn"
            elif cls.__name__ in sys.disabled_warnings:
                return "suppress"
	    for base in cls.__bases__:
	        rc = self.get_user_request(base)
		if rc:
		    return rc
            else:
                return None

    The Assertion class should be implemented in Python so that it can be 
    used as a base class.

    Because this code inherently implements "warning state inheritance",
    it would be rare to override any of the methods, but this is possible
    in exceptional circumstances.

Command line

    By default the special variables have the following contents:

    sys.warnings = []
    sys.errors = []
    sys.suppress = []
    sys.default_warning_action = "warn"
    
    These variables may be changed from the command line. The command line
    arguments are interpreted as described below:

    -w XXX => sys.warnings.append("XXX")
    -e XXX => sys.errors.append("XXX")
    -no-w XXX => sys.suppress.append("XXX")
    -wall => sys.default_warning_action => "warn"
    -eall => sys.default_warning_action => "error"
    -no-wall => sys.default_warning_action => "suppress"

    As per the code above, errors take precedence over warnings and
    warnings over suppressions unless a particular assertion class
    specifies otherwise.

Built-in warning objects:

    class exception_in_del(Assertion):
        "An exception was ignored in an __del__ method"

    class deprecation(Assertion):
        "This feature may be removed in a future version of Python."

    class dubious(Assertion):
        "There is a common error associated with this feature."

    These class definitions are part of the "Assertion" module. They
    should only ever be used when there exists a way for the programmer to 
    accomplish the same thing without triggering the warning. For instance
    the way to suppress the deletion exception is to trap exceptions in
    __del__ methods with a try/except block.