commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

r6240 - in trunk/gnue-common/src: apps datasources


From: johannes
Subject: r6240 - in trunk/gnue-common/src: apps datasources
Date: Thu, 2 Sep 2004 06:47:26 -0500 (CDT)

Author: johannes
Date: 2004-09-02 06:47:24 -0500 (Thu, 02 Sep 2004)
New Revision: 6240

Modified:
   trunk/gnue-common/src/apps/GBaseApp.py
   trunk/gnue-common/src/apps/errors.py
   trunk/gnue-common/src/datasources/GConnections.py
Log:
Added an exception hook for uncaught exceptions


Modified: trunk/gnue-common/src/apps/GBaseApp.py
===================================================================
--- trunk/gnue-common/src/apps/GBaseApp.py      2004-09-02 09:46:27 UTC (rev 
6239)
+++ trunk/gnue-common/src/apps/GBaseApp.py      2004-09-02 11:47:24 UTC (rev 
6240)
@@ -34,11 +34,14 @@
 
 from gnue import paths
 
-from gnue.common.apps import GConfig
+from gnue.common.apps import GConfig, errors
 from gnue.common.apps import GDebug
 from gnue.common.datasources import GConnections
 from CommandOption import CommandOption
 
+class StartupError (errors.UserError):
+  pass
+
 class GBaseApp:
   """
   The base class of the various GNUe application classes.
@@ -81,109 +84,113 @@
 
   def __init__(self, connections=None, application='common', defaults=None):
 
+    sys.excepthook = self.excepthook
+
     # Basic options
     self._base_options = [
+      ##
+      ## Base options
+      ##
+      CommandOption ('version', category = "base", action = self.doVersion,
+        help = _('Displays the version information for this program.')),
 
-         ##
-         ## Base options
-         ##
+      CommandOption ('debug-level', category = "base", default = 0,
+        argument = _("level"),
+        help = _('Enables debugging messages.  Argument specifies the '
+                 'level of messages to display (e.g., "--debug-level 5" '
+                 'displays all debugging messages at level 5 or below.)')),
 
-         CommandOption('version', category="base", action=self.doVersion,
-              help=_('Displays the version information for this program.') ),
+      CommandOption ('debug-file', category = "base", argument = _("filename"),
+        help = _('Sends all debugging messages to a specified file '
+                 '(e.g., "--debug-file trace.log" sends all output to '
+                 '"trace.log")')),
 
-         CommandOption('debug-level', category="base", default=0, 
argument=_("level"),
-              help=_('Enables debugging messages.  Argument specifies the '
-                      'level of messages to display (e.g., "--debug-level 5" 
displays '
-                      'all debugging messages at level 5 or below.)') ),
+      CommandOption ('help', category = "base", action = self.printHelp,
+        help = _('Displays this help screen.')),
 
-         CommandOption('debug-file', category="base", argument=_("filename"),
-              help=_('Sends all debugging messages to a specified file '
-                     '(e.g., "--debug-file trace.log" sends all output to 
"trace.log")') ),
+      CommandOption ('help-config', category = "base",
+        action = self.doHelpConfig,
+        help = _('Displays a list of valid configuration file entries, their '
+                 'purpose, and their default values.')),
 
-         CommandOption('help', category="base",  action=self.printHelp,
-              help=_('Displays this help screen.') ),
+      ##
+      ## Developer options
+      ##
 
-         CommandOption('help-config', category="base",  
action=self.doHelpConfig,
-              help=_('Displays a list of valid configuration file entries, 
their '
-                     'purpose, and their default values.') ),
+      CommandOption ('help-dev', category = "base", action = self.printHelpDev,
+        help = _('Display all options of interest to core developers. ')),
 
-         ##
-         ## Developer options
-         ##
+      CommandOption ('selfdoc', category = "dev", action = self.doSelfDoc,
+        argument = _("type[,subtype]"),
+        help = _('Generates self-documentation.')),
 
-         CommandOption('help-dev', category="base", action=self.printHelpDev,
-              help=_('Display all options of interest to core developers. ') ),
+      CommandOption ('selfdoc-format', category = "dev", argument = 
_("format"),
+        help = _('Format to output the self-documentation in. Supported '
+                 'formats are dependent on the type of selfdoc being '
+                 'created.')),
 
-         CommandOption('selfdoc', category="dev",  action=self.doSelfDoc,
-              argument=_("type[,subtype]"),
-              help=_('Generates self-documentation.') ),
+      CommandOption ('selfdoc-file', category = "dev", argument = 
_("filename"),
+        help = _('Specifies the filename that selfdoc should write to. If not '
+                 'provided, output is sent to stdout.')),
 
-         CommandOption('selfdoc-format', category="dev", argument=_("format"),
-              help=_('Format to output the self-documentation in. Supported 
formats '
-                     'are dependent on the type of selfdoc being created.') ),
+      CommandOption ('selfdoc-options', category = "dev",
+        argument = _("options"),
+        help = _('Options specific to individual selfdoc types.')),
 
-         CommandOption('selfdoc-file', category="dev", argument=_("filename"),
-              help=_('Specifies the filename that selfdoc should write to. If 
not provided, output is sent to stdout.') ),
+      CommandOption ('profile', category = "dev",
+        help = _("Run Python's built-in profiler and display the resulting "
+                 "run statistics.")),
 
-         CommandOption('selfdoc-options', category="dev", 
argument=_("options"),
-              help=_('Options specific to individual selfdoc types.') ),
-
-         CommandOption('profile', category="dev",
-              help=_("Run Python's built-in profiler and display the resulting 
"
-                      "run statistics.") ),
-
-         CommandOption('interactive-debugger', category="dev",
-              help=_("Run the app inside Python's built-in debugger ")),
+      CommandOption ('interactive-debugger', category = "dev",
+        help = _("Run the app inside Python's built-in debugger ")),
     ]
 
     if self.USE_DATABASE_OPTIONS:
       self.USE_CONNECTIONS = 1
-      self._base_options += [
+      self._base_options.extend ([ \
+        CommandOption ('username', category = "connections", default = '',
+          argument = 'name',
+          help = _('Username used to log into the database.  Note that if '
+                   'specified, this will be used for all databases.  If not '
+                   'supplied, the program will prompt for username.')),
 
-        CommandOption('username', category="connections", default='',
-              argument='name',
-              help=_('Username used to log into the database.  Note that if '
-                     'specified, this will be used for all databases.  If not '
-                     'supplied, the program will prompt for username.') ),
+        CommandOption ('password', category = "connections", default = '',
+          argument = 'passwd',
+          help = _('Password used to log into the database.  Note that if '
+                   'specified, this will be used for all databases.  If not '
+                   'supplied, the program will prompt for password if needed.'
+                   '\nNOTE: SUPPLYING A PASSWORD VIA THE COMMAND LINE MAY BE '
+                   'CONSIDERED A SECURITY RISK AND IS NOT RECOMMENDED.'))])
 
-        CommandOption('password', category="connections", default='',
-              argument='passwd',
-              help=_('Password used to log into the database.  Note that if '
-                     'specified, this will be used for all databases.  If not '
-                     'supplied, the program will prompt for password if 
needed.'
-                     '\nNOTE: SUPPLYING A PASSWORD VIA THE COMMAND LINE MAY BE 
'
-                     'CONSIDERED A SECURITY RISK AND IS NOT RECOMMENDED.)') )
-      ]
-
     if self.USE_CONNECTIONS:
       self._base_options += [
-        CommandOption('help-connections', category="base", 
action=self.printHelpConn,
-              help=_('Display help information related to database '
-                     'connections, including a list of available drivers.') ),
+        CommandOption ('help-connections', category = "base",
+          action = self.printHelpConn,
+          help = _('Display help information related to database '
+                   'connections, including a list of available drivers.')),
 
-        CommandOption('connections', category="connections",
-              argument="loc",
-              help=_('Specifies the location of the connection definition 
file. '
-                     '<loc> may specify a file name '
-                     '(/usr/local/gnue/etc/connections.conf),'
-                     'or a URL location '
-                     '(http://localhost/connections.conf).'
-                     'If this option is not specified, the environent variable 
'
-                     'GNUE_CONNECTIONS is checked.'
-                     'If neither of them is set, "%s" is used as a default.') %
+        CommandOption ('connections', category = "connections",
+          argument = "loc",
+          help = _('Specifies the location of the connection definition file. '
+                   '<loc> may specify a file name '
+                   '(/usr/local/gnue/etc/connections.conf),'
+                   'or a URL location '
+                   '(http://localhost/connections.conf).'
+                   'If this option is not specified, the environent variable '
+                   'GNUE_CONNECTIONS is checked.'
+                   'If neither of them is set, "%s" is used as a default.') %
              os.path.join (paths.config, "connections.conf")) ]
 
     # Python version check
-    try:
-      if sys.hexversion < 0x02010000:
-        self.handleStartupError (u_("This application requires Python 2.1 or "
-                    "greater. You are running Python %s") % sys.version [:5])
-    except AttributeError:
-      # Really, really old version of Python...
-      self.handleStartupError (_("This application requires Python 2.1 or "
-                                 "greater."))
+    if not hasattr (sys, 'hexversion') or sys.hexversion < 0x02010000:
+      msg = _("This application requires Python 2.1 or greater.")
+      if hasattr (sys, 'version'):
+        msg = u_("This application requires Python 2.1 or greater. "
+                 "You are running Python %s") % sys.version [:5]
 
+      raise errors.AdminError, msg
 
+
     #
     # Get all command line options and arguments
     #
@@ -224,9 +231,10 @@
       sys.argv=[]
 
     try:
-      opt, self.ARGUMENTS = getopt.getopt(sys.argv[1:], shortoptions, 
longoptions)
+      opt, self.ARGUMENTS = getopt.getopt (sys.argv[1:], shortoptions,
+                                           longoptions)
     except getopt.error, msg:
-      self.handleStartupError(msg)
+      raise StartupError, "%s" % msg
 
     pendingActions = []
     for o in opt:
@@ -259,28 +267,21 @@
       GDebug.setDebug(int("%s" % self.OPTIONS['debug-level']),
           self.OPTIONS['debug-file'])
     except ValueError:
-      self.handleStartupError(_('The debug_level option ("-d") expects a 
numerical value.'))
+      raise StartupError, \
+          _('The debug_level option ("-d") expects a numerical value.')
 
+    gDebug (1, "Python %s" % sys.version)
+    gDebug (1, "Run Options: %s" % opt)
+    gDebug (1, "Run Arguments: %s" % self.ARGUMENTS)
 
-
-    GDebug.printMesg(1,"Python %s" % sys.version)
-    GDebug.printMesg(1,"Run Options: %s" % opt)
-    GDebug.printMesg(1,"Run Arguments: %s" % self.ARGUMENTS)
-
     # Read the config files
     if application:
       try:
-        self.configurationManager = GConfig.GConfig(application, defaults, 
configFilename=self.CONFIGFILE)
+        self.configurationManager = GConfig.GConfig (application, defaults,
+                                              configFilename = self.CONFIGFILE)
       except ConfigParser.NoSectionError, msg:
-        self.handleStartupError (u_("The gnue.conf file is incomplete:\n"
-                                    "   %s") % msg)
-      except Exception, msg:
-        etype = string.splitfields (str (sys.exc_type), '.')
-        etype.reverse ()
-        self.handleStartupError (u_("%(exType)s while reading gnue.conf:\n"
-                                    "   %(message)s") \
-                                 % {'exType' : etype [0],
-                                    'message': msg})
+        raise errors.AdminError, \
+            u_("The gnue.conf file is incomplete:\n   %s") % msg
 
     # Add custom import to python's namespace
     try:
@@ -313,10 +314,6 @@
         self.connections_file = os.environ['GNUE_CONNECTIONS']
       else:
         self.connections_file = os.path.join (paths.config, "connections.conf")
-#        self.handleStartupError(
-#            _('Unable to load the connections definition file.\n') \
-#            + _('\n   Please set the environmental variable GNUE_CONNECTIONS 
or ') \
-#            + _('\n   use the "-f" command option.'))
 
       GDebug.printMesg(1, 'Connection Definition: "%s"' % 
self.connections_file)
 
@@ -324,16 +321,14 @@
         self.connections = GConnections.GConnections (self.connections_file,
                                                       loginOptions = lhOptions)
       except GConnections.InvalidFormatError, msg:
-        self.handleStartupError(
+        raise errors.AdminError, \
             u_("Unable to load the connections definition file.\n\n"
-               "The connections file is in an invalid format.\n%s") % msg)
+               "The connections file is in an invalid format.\n%s") % msg
 
-      except IOError:
-        self.handleStartupError (
-             u_("Unable to load the connections definition file.\n\n"
-                "The connections file specified either does "
-                "not exist or is not readable by your account.\n"
-                "Location: \"%s\"") % self.connections_file)
+      except IOError, err:
+        raise StartupError, \
+            u_("Unable to load the connections definition file: %s.") \
+            % self.connections_file
 
   def addCommandOption(self, *args, **parms):
     self.COMMAND_OPTIONS.append(CommandOption(*args, **parms))
@@ -565,3 +560,26 @@
     self.printHelpHeader()
     print GConfig.printableConfigOptions(defaults)
     sys.exit()
+
+
+  # ---------------------------------------------------------------------------
+  # Catch an exception
+  # ---------------------------------------------------------------------------
+
+  def excepthook (self, etype, value, traceback):
+    """
+    This function catches an exception and evaluates it using getException ().
+    Depending on the exception group it just drops the command and message to
+    stderr or writes a complete traceback to stderr.
+    """
+    sys.excepthook = sys.__excepthook__
+    (group, name, message, detail) = errors.getException (None, etype, value,
+        traceback)
+
+    if group in ['user', 'admin']:
+      sys.__stderr__.write ("%s: %s\n" % (self.COMMAND, o(message)))
+      sys.__stderr__.write ("%s\n" % \
+                           o(u_("For help, type: %s --help") % self.COMMAND))
+    else:
+      sys.stderr.write ("%s\n" % o(detail))
+

Modified: trunk/gnue-common/src/apps/errors.py
===================================================================
--- trunk/gnue-common/src/apps/errors.py        2004-09-02 09:46:27 UTC (rev 
6239)
+++ trunk/gnue-common/src/apps/errors.py        2004-09-02 11:47:24 UTC (rev 
6240)
@@ -64,12 +64,12 @@
   # Return the name of the exception
   # ---------------------------------------------------------------------------
 
-  def getName (self):
+  def getName (self, aType = None):
     """
     This function returns the name of the exception (i.e. 'FooBarError')
     @return: name of the exception as unicode string
     """
-    rep = self.name or "%s" % sys.exc_info () [0]
+    rep = self.name or "%s" % (sys.exc_info () [0] or aType)
     return self._fmtUnicode (rep.split ('.') [-1])
 
 
@@ -77,7 +77,7 @@
   # Get the detail of an exception
   # ---------------------------------------------------------------------------
 
-  def getDetail (self, count = None):
+  def getDetail (self, count = None, type = None, value = None, trace = None):
     """
     This function returns the exception's detail which is a traceback for
     gException instances.
@@ -87,7 +87,10 @@
     if self.detail is not None:
       return self._fmtUnicode (self.detail, i18n.encoding)
 
-    tStack = traceback.format_exception (*sys.exc_info ())
+    if sys.exc_info () == (None, None, None):
+      tStack = traceback.format_exception (type, value, trace)
+    else:
+      tStack = traceback.format_exception (*sys.exc_info ())
     if count is not None:
       del tStack [1:count + 1]
     return self._fmtUnicode ("%s" % string.join (tStack), i18n.encoding)
@@ -202,7 +205,7 @@
 # Get a tuple (type, name, message, detail) for the last exception raised
 # -----------------------------------------------------------------------------
 
-def getException (count = None):
+def getException (count = None, aType = None, aValue = None, aTrace = None):
   """
   This function creates a tuple (type, name, message, detail) for the last
   exception raised. The optional parameter determines the number of lines
@@ -210,11 +213,14 @@
   @param count: number of lines to skip in the traceback
   @returns: tuple with type, name, message and detail of the last exception.
   """
-  (aType, aValue, aTrace) = sys.exc_info ()
+  (sType, sValue, sTrace) = sys.exc_info ()
+  aType  = aType  or sType
+  aValue = aValue or sValue
+  aTrace = aTrace or sTrace
 
   if isinstance (aValue, gException):
     return (aValue.getGroup (), aValue.getName (), aValue.getMessage (),
-            aValue.getDetail (count))
+            aValue.getDetail (count, aType, aValue, aTrace))
   else:
     # Exception was not a descendant of gException, so we construct the tuple
     # from the exception information
@@ -222,7 +228,7 @@
     if count is not None:
       del lines [1:count + 1]
 
-    name    = unicode (aType)
+    name    = unicode (aType).split ('.') [-1]
     message = unicode (aValue)
     detail  = string.join (lines)
     if isinstance (detail, types.StringType):

Modified: trunk/gnue-common/src/datasources/GConnections.py
===================================================================
--- trunk/gnue-common/src/datasources/GConnections.py   2004-09-02 09:46:27 UTC 
(rev 6239)
+++ trunk/gnue-common/src/datasources/GConnections.py   2004-09-02 11:47:24 UTC 
(rev 6240)
@@ -39,7 +39,7 @@
 
 from ConfigParser import *
 import sys, string, copy, netrc
-from gnue.common.apps import GDebug, plugin
+from gnue.common.apps import plugin, errors
 from gnue.common.datasources import Exceptions
 from gnue.common.datasources import GLoginHandler
 from gnue.common.utils.FileUtils import openResource, dyn_import
@@ -54,12 +54,12 @@
   # exist in the Connections Definition File.
   pass
 
-class AdapterNotInstalled (Error):
+class AdapterNotInstalled (errors.AdminError):
   # Raised if a provider is requested for which
   # the python libraries are not installed.
   pass
 
-class DependencyError (Error):
+class DependencyError (errors.AdminError):
   # Raised by the dbdrivers if a dependency module is missing
   def __init__ (self, modulename, url):
     self.modulename = modulename
@@ -69,7 +69,7 @@
       message += u_("  You can download it from %s.") % self.url
     Error.__init__ (self, message)
 
-class InvalidFormatError (Error):
+class InvalidFormatError (errors.AdminError):
   # Raised if the Connections Definition File is
   # in an unreadable format.
   pass
@@ -89,13 +89,14 @@
     self._authenticatedUsers = {}
     self._eventHandler=eventhandler
 
-    GDebug.printMesg(1,'Conn File: "%s"' % location)
+    gDebug (1, 'Conn File: "%s"' % location)
 
     if len(location):
       fileHandle = openResource(location)
 
       try:
         self._parser.readfp(fileHandle)
+
       except DuplicateSectionError:
         tmsg =  u_("The connections file has duplicate source definitions."
                    "\n\nFile: %s") % location
@@ -104,7 +105,7 @@
         tmsg = u_("The connections file has no source definitions."
                   "\n\nFile: %s") % location
         raise InvalidFormatError, tmsg
-      except:
+      except Exception:
         tmsg =  u_("The connections file cannot be parsed."
                    "\n\nFile: %s") % location
         raise InvalidFormatError, tmsg
@@ -298,7 +299,8 @@
 
     try:
       dd = connection.supportedDataObjects[connection_type](connection)
-      GDebug.printMesg (1,'Attaching to %s (%s)' % (dd.__class__.__name__, 
connection_type))
+      gDebug (1, 'Attaching to %s (%s)' \
+          % (dd.__class__.__name__, connection_type))
       return dd
     except KeyError:
       tmsg = u_("DB Driver '%(connection)s' does not support source type "
@@ -370,11 +372,11 @@
         netrcData = netrc.netrc ().authenticators ("'gnue://%s/'" \
                                                    % connection_base)
         if netrcData is not None:
-          GDebug.printMesg (5, 'Read the user\'s .netrc file')
+          gDebug (5, 'Read the user\'s .netrc file')
           loginData ['_username'] = netrcData [0][1:-1]
           loginData ['_password'] = netrcData [2][1:-1]
 
-          GDebug.printMesg (5, "Found useful stuff for connection %s in "
+          gDebug (5, "Found useful stuff for connection %s in "
                                "the user\'s .netrc file" % connection_name)
 
       except (IOError, netrc.NetrcParseError, KeyError):
@@ -417,7 +419,7 @@
       else:
         attempts = 4
 
-        GDebug.printMesg(5,'Getting new data connection to %s' % 
connection_name)
+        gDebug (5, 'Getting new data connection to %s' % connection_name)
 
         errortext = None
         while attempts:





reply via email to

[Prev in Thread] Current Thread [Next in Thread]