mailRe: r2540 - in /branches/warning: errors.py generic_fns/pdb.py relax


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

Header


Content

Posted by Edward d'Auvergne on August 30, 2006 - 07:51:
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



Related Messages


Powered by MHonArc, Updated Thu Aug 31 13:41:22 2006