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): + if issubclass(category, self.BaseWarning): + message = "RelaxWarning: %s\n\n" % message + + if Debug: + tb = "" + for frame in inspect.stack()[4:]: + 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 + + # 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 + + + # 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 + 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)) self.relax.data.res[self.run][j].xh_vect.append(None) # Test if the heteronucleus atom exists for residue i. elif not pdb_res.atoms.has_key(self.heteronuc): if self.print_flag: - print "The heteronucleus atom " + `self.heteronuc` + " 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.heteronuc, self.relax.data.res[self.run][j].num)) self.relax.data.res[self.run][j].xh_vect.append(None) # Calculate the vector. Modified: branches/warning/relax URL: http://svn.gna.org/viewcvs/relax/branches/warning/relax?rev=2540&r1=2539&r2=2540&view=diff ============================================================================== --- branches/warning/relax (original) +++ branches/warning/relax Thu Aug 17 18:32:54 2006 @@ -41,6 +41,7 @@ from re import match from string import split, strip import sys +from warnings import warn # Numeric. try: @@ -66,7 +67,7 @@ # relax modules. from colour import Colour from data import Data -from errors import RelaxErrors +from errors import RelaxErrors, RelaxWarnings from io import IO from generic_fns.main import Generic from prompt.gpl import gpl @@ -92,11 +93,16 @@ # Get and store the PID of this process. self.pid = getpid() - # Set up the program internal errors. - RelaxErrors(self) + # Set up the program internal errors and warnings. + #RelaxErrors() + #RelaxWarnings() + #__builtin__.warn = warn # Debugging flag (default is off). __builtin__.Debug = 0 + + # Pedantic flag (default is off). + __builtin__.Pedantic = 0 # Set the program introduction string to nothing. self.intro_string = None @@ -127,7 +133,12 @@ # Process the command line arguments and determine the relax mode. mode, log_file, tee_file = self.arguments() - + + # Set up the program internal errors and warnings. + RelaxErrors() + RelaxWarnings() + __builtin__.warn = warn + # Show the version number and exit. if mode == 'version': print 'relax ' + self.version @@ -199,6 +210,7 @@ parser.add_option('-l', '--log', action='store', type='string', dest='log', help='log relax output to the file LOG_FILE', metavar='LOG_FILE') parser.add_option('--licence', action='store_true', dest='licence', default=0, help='display the licence') parser.add_option('-t', '--tee', action='store', type='string', dest='tee', help='tee relax output to sdtout and the file LOG_FILE', metavar='LOG_FILE') + parser.add_option('-p', '--pedantic', action='store_true', dest='pedantic', default=0, help='escalate all warnings to errors') parser.add_option('--test', action='store_true', dest='test', default=0, help='run relax in test mode') parser.add_option('--test-suite', action='store_true', dest='test_suite', default=0, help='execute the relax test suite') parser.add_option('--thread', action='store_true', dest='thread', default=0, help='run relax in threading mode (this mode should not be invoked by a user)') @@ -210,6 +222,10 @@ # Debugging flag. if options.debug: __builtin__.Debug = 1 + + # Pedantic flag. + if options.pedantic: + __builtin__.Pedantic = 1 # Logging. if options.log: