Thanks, these changes look very promising. A few things need to be
discussed and tested before merging this code back into the main 1.2
line. I have a few points below interspersed between your code.
Firstly I have committed a change which affects the order of
initialisation so that the RelaxErrors and RelaxWarnings are
initialised after the pedantic flag but before the command line
parsing (see https://mail.gna.org/public/relax-commits/2006-08/msg00014.html,
Message-id: <E1GIIBN-00026c-Ga@xxxxxxxxxxxxxxxxxx>). This removes the
missing AllRelaxErrors error.
On 8/18/06, c.a.macraild wrote:
Author: macraild
Date: Thu Aug 17 18:32:54 2006
New Revision: 2540
URL: http://svn.gna.org/viewcvs/relax?rev=2540&view=rev
Log:
A warning system for relax.
This is based on the system started in r2532, and is discussed in
detail in the thread starting:
https://mail.gna.org/public/relax-devel/2006-08/msg00071.html
The system is based on the standard Python warnings system.
Warnings are generated with the syntax:
warn(RelaxWarning(args))
where RelaxWarning can be any of the Warning classes defined in
errors.py, and args is an arbitrary number of arguments of
arbitrary type which are used by the Warning class to generate a
meaningful message string.
The system also impliments a --pedantic command-line flag, which
causes all warnings to be escalated to exceptions. All of the
relax warnings are subclasses of both BaseWarning and BaseError,
so the escalated exceptions will be caught by except clauses
based on these types.
A further feature in the current implimentation is to include
an exception-like traceback in the warning message when in
debug mode.
Modified:
branches/warning/errors.py
branches/warning/generic_fns/pdb.py
branches/warning/relax
Modified: branches/warning/errors.py
URL:
http://svn.gna.org/viewcvs/relax/branches/warning/errors.py?rev=2540&r1=2539&r2=2540&view=diff
==============================================================================
--- branches/warning/errors.py (original)
+++ branches/warning/errors.py Thu Aug 17 18:32:54 2006
@@ -597,4 +597,97 @@
self.text = "The colour " + `colour` + " is invalid."
if Debug:
self.save_state()
-
+
+
+# Warning objects.
+##################
+
+class RelaxWarnings:
+ def __init__(self):
+ """Class for placing all the warnings below into __builtin__"""
+
+ # Loop over all objects in 'self'.
+ for name in dir(self):
+ # Get the object.
+ object = getattr(self, name)
+
+ # Skip over all non-warning class objects.
+ if type(object) != ClassType or not match('Relax', name):
+ continue
+
+ # Place the warnings into __builtin__
+ __builtin__.__setattr__(name, object)
+
+ # Tuple of all the warnings.
+ if hasattr(__builtin__, 'AllRelaxWarnings'):
+ __builtin__.AllRelaxWarnings = __builtin__.AllRelaxWarnings,
object
+ else:
+ __builtin__.AllRelaxWarnings = object,
+
+ # Format warning messages.
+ def format(message, category, filename, lineno):
Should this function be indented so that it is located within
self.__init__() or should it be referred to as self.function()? I'd
prefer to stay away from functions nested within other functions.
This nesting is very rare in relax and I'm slowly trying to eliminate
all instances of it.
+ if issubclass(category, self.BaseWarning):
+ message = "RelaxWarning: %s\n\n" % message
+
+ if Debug:
+ tb = ""
+ for frame in inspect.stack()[4:]:
It's probably worth trimming the other side of the stack as well, see
below.
+ file = frame[1]
+ lineNo = frame[2]
+ func = frame[3]
+ tb_frame = ' File "%s", line %i, in %s\n' % (file,
lineNo, func)
+ try:
+ context = frame[4][frame[5]]
+ except TypeError:
+ pass
+ else:
+ tb_frame = '%s %s\n' % (tb_frame, context.strip())
+ tb = tb_frame + tb
+ tb = "Traceback (most recent call last):\n%s" % tb
+ message = tb + message
+
+ return message
+
+ warnings.formatwarning = format
I had a very similar logic in the code which was rolled back at
https://mail.gna.org/public/relax-commits/2006-08/msg00010.html
(Message-id: <E1GDk40-0003vf-Do@xxxxxxxxxxxxxxxxxx>) and discussed at
the thread starting at
https://mail.gna.org/public/relax-devel/2006-08/msg00052.html
(Message-id: <7f080ed10608100336r3dc92d80h1ce3251e55b49347@xxxxxxxxxxxxxx>).
However I used the 'extract_stack' function to get the stack instead
and then used the 'format_list' function to do the formatting similar
to that which you have coded. The relevant code was in the traceback
function which I've reproduced below. Some of the ideas in the code
may be useful to further customise the traceback message.
- def traceback(self):
- """Function for formatting and printing out the traceback."""
-
- # Get the stack.
- stack = extract_stack()
-
- # Initialise the trimmed stack and stack start flag.
- trimmed_stack = []
- start = 0
-
- # Trim the stack (script mode):
- if self.UI_mode == 'script':
- for i in xrange(len(stack)):
- # Find the 'interact_script()' function, the start of
the scripting.
- if stack[i][2] == 'interact_script':
- start = 1
- continue
-
- # Not at the start of the script section of the stack.
- if not start:
- continue
-
- # Append the next item.
- trimmed_stack.append(stack[i])
-
- # Find the RelaxError and then stop.
- if search('^Relax.*Error', stack[i][3]):
- break
-
- # Trim the stack (default).
- else:
- for i in xrange(len(stack)):
- # Append the next item.
- trimmed_stack.append(stack[i])
-
- # Find the RelaxError and then stop.
- if search('^Relax.*Error', stack[i][3]):
- break
-
- # Default formatting of the stack.
- string_stack = format_list(trimmed_stack)
-
- # Print out the formatted stack.
- for i in xrange(len(string_stack)):
- sys.stderr.write(string_stack[i])
+
+ # Set warning filters.
+ if Pedantic:
+ warnings.filterwarnings('error', category=self.BaseWarning)
+ else:
+ warnings.filterwarnings('always', category=self.BaseWarning)
+
+
+ # Base class for all warnings.
+ ############################
+
+ class BaseWarning(Warning, RelaxErrors.BaseError):
+ def __str__(self):
+ return self.text
Does this need to be a subclass of RelaxErrors.BaseError?
+
+
+ # Standard warnings.
+ ####################
+
+ class RelaxWarning(BaseWarning):
+ def __init__(self, text):
+ self.text = text
+
+
+ # Zero length vector.
+ #####################
+
+ class RelaxZeroVectorWarning(BaseWarning):
+ def __init__(self, res):
+ self.text = "The XH bond vector for residue " + `res` + " is of zero
length."
+
+ # PDB warnings.
+ ###############
+
+ class RelaxNoAtomWarning(BaseWarning):
+ def __init__(self, atom, res):
+ self.text = "The atom %s could not be found for residue %i" %
(atom, res)
+
+ class RelaxNoPDBFileWarning(BaseWarning):
+ def __init__(self, file):
+ self.text = "The PDB file %s cannot be found, no structures will be
loaded." % file
+
Although obvious I like comments above each class describing in a
little more detail, compared to the class name, what each object is
used for. I can add these if you don't mind Chris.
Modified: branches/warning/generic_fns/pdb.py
URL:
http://svn.gna.org/viewcvs/relax/branches/warning/generic_fns/pdb.py?rev=2540&r1=2539&r2=2540&view=diff
==============================================================================
--- branches/warning/generic_fns/pdb.py (original)
+++ branches/warning/generic_fns/pdb.py Thu Aug 17 18:32:54 2006
@@ -153,7 +153,7 @@
raise RelaxFileError, ('PDB', self.file_path)
else:
if self.print_flag:
- print "The PDB file " + `self.file_path` + " cannot be found,
no structures will be loaded."
+ warn(RelaxNoPDBFileWarning(self.file_path))
return
@@ -239,13 +239,13 @@
# Test if the proton atom exists for residue i.
if not pdb_res.atoms.has_key(self.proton):
if self.print_flag:
- print "The proton atom " + `self.proton` + " could not be found for residue
'" + `self.relax.data.res[self.run][j].num` + " " + self.relax.data.res[self.run][j].name +
"'."
+ warn(RelaxNoAtomWarning(self.proton,
self.relax.data.res[self.run][j].num))
Perfect place for a warning. I'll have to do a code audit one day and
change numerous print messages to warning messages. There are a lot
of places in the code where warnings presented using print statements
exist. I think there are even cases where I print warning messages to
stderr - the system is not very consistent. The rest of the changes
are all good, so I won't reproduce any more. The pedantic option and
the traceback when in debug mode will be very useful debugging tools.
Thanks again,
Edward