mailRe: RelaxWarnings


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by Chris MacRaild on August 16, 2006 - 19:02:
On Thu, 2006-08-17 at 02:17 +1000, Edward d'Auvergne wrote:

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.

Of course I should have used BaseWarning here, not RelaxWarning, for
consistency with the names of the relax exception classes. But I'm
fairly sure that a single filter will catch all relax warnings as long
as all of them subclass BaseWarning.


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!

I think the problem is that the default warning behaviour is to print a
given warning only once from a specific location in the code. Because
you are working at the interactive prompt, it always looks like the same
location, so the warning will only be printed once (it has nothing to do
with help). Try:

relax> import warnings
relax> warnings.filterwarnings('always')
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')
RelaxWarning: Hello



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.


This is a good point. After some head-scratching, I think the 'correct'
way to do it is to treat each warning category specifically in the
formatwarning function. So we would have something more like:

def format(message, category, filename, lineno):
    if issubclass(category, RelaxZeroLengthWarning):
        message = "Zero length vector at residue %s" % message

    # ...lots more specific warning cases...

    if issubclass(category, BaseWarning):
        message = "RelaxWarning: %s\n" % message

    return message

warnings.formatwarning = format


Then the 'message' for RelaxZeroLengthWarning when we do warn() is just
the residue, and format() does the rest.

Chris




Related Messages


Powered by MHonArc, Updated Wed Aug 16 19:20:43 2006