> > 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
Of course! I should have seen that one.
> > 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.
A number of RelaxErrors take a number of arguments and from my reading
of the docs I would guess that the warning system would assert that
the 'message' argument to 'warn()' must be a string. How about using
the '__call__()' function to pass in the relevant data to the class
using keywords and then store it within the object. Then the
subsequently called format function can use the else-if chain to pull
out and format the stored data?
Edward