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 Chris MacRaild on August 30, 2006 - 11:43:
On Wed, 2006-08-30 at 15:50 +1000, Edward d'Auvergne wrote:
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.



+# 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.


Fine.

+            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.

Do you have anything specific in mind? Clearly your code is more
generally flexible, but is there anything you would like to apply that
flexibility to? If so feel free to modify/replace my suggestions.


-    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?

I thought this was the best way to do it, but I'm happy to consider
other arguments. My logic was that if a warning is upgraded to an
exception, then it should be treated like any other relax error. This
means that when we need to catch all relax errors (eg. for UI specific
error handling) then we just need 'except BaseError' to do that. Are
there any reasons you are uncomfortable with this approach?


+
+
+    # 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.

Of course. Feel free to modify as you like.



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 Wed Aug 30 12:21:05 2006