> The non-Python warning system would however be difficult to escalate > into an error. Then again using the Python warning system would also > be complex due to it's non-trivial implementation.
I think it can be done either way, both have disadvantages. For the non-Python system, it will require something like:
if pedantic: raise RelaxError, msg
in the RelaxWarning.__call__() function. The disadvantage here is that the error will be raised from the warning, not from the point in the code where the warning was trigered. Therefore the traceback will not be as clear as it might be. There is also a risk that the RelaxError might be accidentally caught elswhere in the code, and misinterpreted. One way around that would be to use a specific class of Exception for upgraded warnings (RelaxPedanticError, eg.). Of course this could be subclassed to give more specific behaviour, and could be caught if UI issues demanded.
The error could be raised with a function called by __call__(), caught, the traceback trimmed, and then reraised. The trimming part may not be feasible though. I like the idea of retaining the names RelaxWarning, etc. RelaxPedanticError (or maybe RelaxWarningError) could be raised, the warning message passed to it, and it prints out 'RelaxWarning: ' + message.
Escalation of Warnings in the Python system should also be quite easy, by setting appropriate filters at a high level in the code (prompt/interpreter.py might be the spot, or maybe even the relax main script?). The code would look something like:
if pedantic: warnings.filterwarnings('error', category=RelaxWarning) else: warnings.filterwarnings('always', category=RelaxWarning)
Then all warning classes that are subclasses of RelaxWarning will be raised as an exception if pedantic, otherwise the warning will be printed and execution will continue.
Are you sure we wouldn't need to do this for all the specific RelaxWarnings? This is probably dependent upon how we implement the system.
This approach has none of the drawbacks of the the custom warning system described above, but does suffer from the general obscurity of the python warnings system. I suspect it should be possible to subclass from BaseError as well, meaning that exceptions raised by escalation of a warning will be easily treated by the UI specific try statements and will have the same nice debuging features as we put into the other RelaxErrors.
I guess I'm begining to favour the Python warnings system, because I think it will lead to clearer results for the user, even though it might make life a bit more complicated for the developers. This is not a strong preference, though, so if anyone else feels strongly otherwise, I'm happy either way.
I prefer the Python warning system as well but I have to say - surely they could have come up with a better solution? That system is convoluted and poorly documented, I wouldn't be surprised if the entire thing becomes depreciated and replaced by something a bit more logical in future Python versions. For example the description of category in the warnings filters is:
category is a class (a subclass of Warning) of which the warning category must be a subclass in order to match.
The 'category' keyword is for matching but what exactly is matched? If RelaxZeroVectorWarning is a subclass of BaseWarning (i.e. RelaxZeroVectorWarning(BaseWarning)), does category='BaseWarning' actually match RelaxZeroVectorWarning??? The description is terrible! Firstly 'category' is both the keyword used by the 'filterwarnings()' function and the class object within the filter list that you supply through that keyword. Here is some more bizarre and dodgy behaviour:
relax> import warnings relax> def format(message, category, filename, lineno): relax| return "RelaxWarning: %s\n" % message relax| relax> warnings.formatwarning = format relax> warnings.warn('Hello') RelaxWarning: Hello relax> help(warnings.formatwarning) relax> warnings.warn('Hello') relax>
Huh??? Where did RelaxWarning disappear to??? Same thing happens if you use the real Python help function on any 'warnings' objects, including itself??? I'm pretty sure this should not happen!
If there are too many problems caused by bugs in the Python warning system we can write our own warning system in the future. Anyway, enough bashing of the Python warning system.
A problem that needs to be solved is how do we implement specific warnings? For example if two distant areas of relax test for zero length XH bond vectors, there should be one function which takes the residue number and formats a standard message for that warning. However the 'warn()' function expects a message? What if we have a class object called RelaxZeroLengthWarning which has a __call__() method which returns the formatted string? You could then, from within different parts of relax, generate an error by having the code:
if len(xh) == 0.0: warn(RelaxZeroLengthWarning(res))
where warn was placed into __builtin__ by relax (see the 'nan_catch_test' branch) and 'res' is the residue number. There might, however, be a much better way to implement specific warnings. The rest of the system could be setup as in the 'nan_catch_test' branch.
Edward