On Thu, 2006-08-17 at 03:15 +1000, Edward d'Auvergne wrote:
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.
Another good point. That proposal wont work.
How about using the '__call__()' function to pass in the relevant data to the class using keywords and then store it within the object.
The problem here is that __call__() works when you call an instance of a class. RelaxZeroLengthWarning is a class, so RelaxZeroLengthWarning(res) instanciates the class, effectively calling __init__(res). After some more head-scratching and some help from Gary, I realise that this is a actually what we want. warn() can be called with a single argument which is an instance of a Warning class, then message is str() called on that instance, and category is class() called on that instance. So if we code the message formatting in __str__() for each of the warning classes, we can do: warn(RelaxZeroLengthWarning(res)) as you propose, and this will allow for an arbitrary number and type of arguments. It might even be possible to subclass the warning classes from the equivalent error class, making for even more streamlining of the code. I'll have a shot at making this work, based on the start you have made in the nan_catch_test branch. Chris
Then the subsequently called format function can use the else-if chain to pull out and format the stored data? Edward