Paul, thanks for submitting a warnings framework. I'd like to give some feedback, comparing it to my own proposal. Please also give explicit feedback on mine! [Paul Prescod] > 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. What's missing here is a set of requirements. Comparing your proposal to my requirements, I find that you are not addressing two requirements that are important in my mind: a convenient and efficient C API, and a mechanism that prints a warning message only the first time that the warning is issued. These are important to me, because I expect that most warnings will probably be generated by C code, and in order to be useful we must avoid mindless repetition. If a function divides two integers using the / operator, this is being detected by C code (the int or long division implementation) and we only want to print the warning once per program execution and per source location. My expectation is that if a single occurrence (in the program) of a warning condition caused an endless sequence of warnings to be spit out, people would quickly grow a habit of disabling all warnings, thus defeating the purposes. Warnings are more a human engineering issue than a technical issue! That's also why I am emphasizing a C API -- I want to make it real easy to ussue quality warnings in the runtime. It's also why I specify a rich (probably too rich!) filtering mechanism. > Syntax > > assert >> cls, test[[[, arg], arg]...] I have several problems with this. First of all, using "assert" means that in "optimizing" mode (python -O) you won't get *any* warnings. I think that the decision to disable all warnings should be independent from the decision to "optimize". Second, you're hypergeneralizing the extended print syntax. Just because I think it's okay to add >>file to the print syntax doesn't mean that it's now okay to add >>object syntax to all statements! I also don't see what warnings have to do with assertions. Assertions are a mechanism to check for error conditions. What happens if the error is detected is of less importance -- it could raise an exception (Python), issue a fatal error (C), or do nothing (in -O mode). With warnings I believe the issue is not so much the detection of the condition (for which a regular 'if' statement does just fine) but the reporting. Again, this is motivated by the fact that I expect that flexible filtering is essential for a successful warning mechanism. > "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 is just a matter of exposition, but when I first read your PEP I had a hard time figuring out the purpose of the cls object. It wasn't until I got to the very end where I saw your example classes that I realized what it is: it represents a specific warning condition or a group of related warning conditions. > This extended form of the assertion statement calls the assertion > handler code in the new "assertions" module. I won't harp on this each time, but I'd like to point out once more that "assertion" is the wrong name for a warning feature. Although it isn't part of the Zen of Python (by Tim Peters), it should be: a suggestive name for a feature is worth half a spec! > 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 *** That's just raise AssertionError, message Right? > 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. Suggestion: have separate warning and error handlers, so that if I want to override these branches of the if statement I don't have to repeat the entire handler. > 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: I see no definition of sys.disabled_warnings. Instead of sys.disabled_warnings you meant sys.suppress, right? > return "suppress" > for base in cls.__bases__: > rc = self.get_user_request(base) > if rc: > return rc > else: > return None This approach (searching for the class name or the name of one of its base classes in a list) doesn't look very object-oriented. It would make more sense to store the desired return value as a class or instance attribute. The default warning action could be stored on the base class. > 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" Python doesn't support long options (I don't *like* long options so I doubt that this is a good occasion to start lobbying for them :-). We can come up with different options though. > As per the code above, errors take precedence over warnings and > warnings over suppressions unless a particular assertion class > specifies otherwise. I would use a different precedence scheme: a more specific filter takes precedence over a more general filter. So -eall -wdubious would mean that "dubious" class warnings are warnings but all others are errors, and -wall -edubious would mean the opposite. > 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. --Guido van Rossum (home page: http://www.python.org/~guido/)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4