[IPython-dev] Patch to fix string exceptions raised by DPyGetOpt.py

Paul Mueller gakusei at dakotacom.net
Tue May 8 20:27:40 EDT 2007


Hi,

There are some string exceptions in IPython/DPyGetOpt.py (in r2314), some of
which are raised when passing bad options to ipython on the command line. Since
string exceptions are deprecated in python 2.5, this raises a
DeprecationWarning (usage message redirected to /dev/null for clarity):

~/src/mods/ipython> ./ipython.py --badopt >/dev/null
/home/yuurei/src/mods/ipython/IPython/DPyGetOpt.py:532: DeprecationWarning: raising a string exception is deprecated
  raise arg_error, 'Illegal option \'' + arg + '\''
WARNING:
Error in Arguments: "Illegal option '--badopt'"

I've attached a patch that fixes this by using exception classes
instead. It also modifies IPython/ipmaker.py and IPython/genutils.py
to catch only the new ArgumentError exception when calling
getopt.processArguments(), as other exceptions indicate errors in DPyGetOpt for
which a crash report should be generated.

The patch also removes uses of sys.exc_value, which is also deprecated.

The _test() function in DPyGetOpt.py produces the same output as it did before
the patch (other than the deprecation warnings, of course).

I've also grepped the rest of ipython, and there appear to be no other string
exceptions.

Paul Mueller
-------------- next part --------------
Index: IPython/genutils.py
===================================================================
--- IPython/genutils.py	(revision 2314)
+++ IPython/genutils.py	(working copy)
@@ -601,9 +601,9 @@
 
     try:
         getopt.processArguments(argv)
-    except:
+    except DPyGetOpt.ArgumentError, exc:
         print usage
-        warn(`sys.exc_value`,level=4)
+        warn('"%s"' % exc,level=4)
 
     defaults.update(getopt.optionValues)
     args = getopt.freeValues
Index: IPython/DPyGetOpt.py
===================================================================
--- IPython/DPyGetOpt.py	(revision 2314)
+++ IPython/DPyGetOpt.py	(working copy)
@@ -74,10 +74,19 @@
 import sys
 import types
 
-arg_error  = 'DPyGetOpt Argument Error'
-spec_error = 'DPyGetOpt Specification Error'
-term_error = 'DPyGetOpt Termination Error'
+class Error(Exception):
+    """Base class for exceptions in the DPyGetOpt module."""
 
+class ArgumentError(Error):
+    """Exception indicating an error in the arguments passed to
+    DPyGetOpt.processArguments."""
+
+class SpecificationError(Error):
+    """Exception indicating an error with an option specification."""
+
+class TerminationError(Error):
+    """Exception indicating an error with an option processing terminator."""
+
 specificationExpr = re.compile('(?P<required>.)(?P<type>.)(?P<multi>@?)')
 
 ArgRequired     = 'Requires an Argument'
@@ -214,7 +223,7 @@
         """
         Adds the option described by oTuple (name, (type, mode,
         default), alias) to optionTuples.  Adds index keyed under name
-        to optionNames.  Raises spec_error if name already in
+        to optionNames.  Raises SpecificationError if name already in
         optionNames
         """
         (name, (type, mode, default, multi), realName) = oTuple
@@ -222,11 +231,13 @@
         # verify name and add to option names dictionary
         if self.optionNames.has_key(name):
             if realName:
-                raise spec_error, 'Alias \'' + name + '\' for \'' + realName + \
-                                '\' already used for another option or alias.'
+                raise SpecificationError('Alias \'' + name + '\' for \'' +
+                                         realName +
+                                         '\' already used for another option or alias.')
             else:
-                raise spec_error, 'Option named \'' + name + \
-                                '\' specified more than once. Specification: ' + option
+                raise SpecificationError('Option named \'' + name +
+                                         '\' specified more than once. Specification: '
+                                         + option)
 
         # validated. add to optionNames
         self.optionNames[name] = self.tupleIndex
@@ -244,11 +255,13 @@
             # verify name and add to option names dictionary
             if self.optionNames.has_key(alias):
                 if realName:
-                    raise spec_error, 'Negated alias \'' + name + '\' for \'' + realName + \
-                                    '\' already used for another option or alias.'
+                    raise SpecificationError('Negated alias \'' + name +
+                                             '\' for \'' + realName +
+                                             '\' already used for another option or alias.')
                 else:
-                    raise spec_error, 'Negated option named \'' + name + \
-                                    '\' specified more than once. Specification: ' + option
+                    raise SpecificationError('Negated option named \'' + name +
+                                             '\' specified more than once. Specification: '
+                                             + option)
 
             # validated. add to optionNames
             self.optionNames[alias] = self.tupleIndex
@@ -299,7 +312,8 @@
             # break into names, specification
             match = splitExpr.match(option)
             if match is None:
-                raise spec_error, 'Invalid specification {' + option + '}'
+                raise SpecificationError('Invalid specification {' + option +
+                                         '}')
 
             names                     = match.group('names')
             specification = match.group('spec')
@@ -328,7 +342,8 @@
                 match = specificationExpr.match(specification)
                 if match is None:
                     # failed to parse, die
-                    raise spec_error, 'Invalid configuration for option \'' + option + '\''
+                    raise SpecificationError('Invalid configuration for option \''
+                                             + option + '\'')
 
                 # determine mode
                 required = match.group('required')
@@ -337,7 +352,8 @@
                 elif required == ':':
                     argMode = ArgOptional
                 else:
-                    raise spec_error, 'Unknown requirement configuration \'' + required + '\''
+                    raise SpecificationError('Unknown requirement configuration \''
+                                             + required + '\'')
 
                 # determine type
                 type = match.group('type')
@@ -351,7 +367,8 @@
                     argType   = RealArgType
                     argDefault = 1
                 else:
-                    raise spec_error, 'Unknown type specifier \'' + type + '\''
+                    raise SpecificationError('Unknown type specifier \'' +
+                                             type + '\'')
 
                 # determine quantity
                 if match.group('multi') == '@':
@@ -425,7 +442,7 @@
         terminator.  If it is, sets self.terminator to the full name of
         the terminator.
 
-        If more than one terminator matched, raises a term_error with a
+        If more than one terminator matched, raises a TerminationError with a
         string describing the ambiguity.
         """
 
@@ -445,8 +462,8 @@
         if not len(terms):
             return None
         elif len(terms) > 1:
-            raise term_error, 'Ambiguous terminator \'' + optionName + \
-                            '\' matches ' + repr(terms)
+            raise TerminationError('Ambiguous terminator \'' + optionName +
+                                   '\' matches ' + repr(terms))
 
         self.terminator = terms[0]
         return self.terminator
@@ -529,10 +546,11 @@
             tuples = self._getArgTuple(optName)
 
             if tuples == None:
-                raise arg_error, 'Illegal option \'' + arg + '\''
+                raise ArgumentError('Illegal option \'' + arg + '\'')
             elif len(tuples) > 1:
-                raise arg_error, 'Ambiguous option \'' + arg + '\';  matches ' + \
-                                repr(map(lambda x: x[0], tuples))
+                raise ArgumentError('Ambiguous option \'' + arg +
+                                    '\';  matches ' +
+                                    repr(map(lambda x: x[0], tuples)))
             else:
                 config = tuples[0]
 
@@ -545,8 +563,9 @@
             if (optMode == ArgRequired):
                 if (not nextArg) or self._isTerminator(nextArg):
 #                                       print nextArg
-                    raise arg_error, 'Option \'' + arg + \
-                                    '\' requires an argument of type ' + optType
+                    raise ArgumentError('Option \'' + arg +
+                                        '\' requires an argument of type ' +
+                                        optType)
 
             if (not optMode == None) and nextArg and (not self._isTerminator(nextArg)):
                 # nextArg defined, option configured to possibly consume arg
@@ -559,15 +578,17 @@
                     except:
                         # only raise conversion error if REQUIRED to consume argument
                         if optMode == ArgRequired:
-                            raise arg_error, 'Invalid argument to option \'' + arg + \
-                                            '\';  should be \'' + optType + '\''
+                            raise ArgumentError('Invalid argument to option \''
+                                                + arg + '\';  should be \'' +
+                                                optType + '\'')
                         else:
                             optionValue = optDefault
-                except arg_error:
-                    raise arg_error, sys.exc_value
+                except ArgumentError:
+                    raise
                 except:
-                    raise arg_error, '(' + arg + \
-                                    ') Conversion function for \'' + optType + '\' not found.'
+                    raise ArgumentError('(' + arg +
+                                        ') Conversion function for \'' +
+                                        optType + '\' not found.')
             else:
                 optionValue = optDefault
 
@@ -583,7 +604,8 @@
             else:
                 # only one value per
                 if self.isPosixCompliant and self.optionValues.has_key(realName):
-                    raise arg_error, 'Argument \'' + arg + '\' occurs multiple times.'
+                    raise ArgumentError('Argument \'' + arg +
+                                        '\' occurs multiple times.')
 
                 self.optionValues[realName] = optionValue
 
@@ -610,25 +632,25 @@
     """
     try:
         DPyGetOpt(['foo', 'bar=s', 'foo'])
-    except:
-        print 'EXCEPTION (should be \'foo\' already used..): ' + sys.exc_value
+    except Error, exc:
+        print 'EXCEPTION (should be \'foo\' already used..): %s' % exc
 
     try:
         DPyGetOpt(['foo|bar|apple=s@', 'baz|apple!'])
-    except:
-        print 'EXCEPTION (should be duplicate alias/name error): ' + sys.exc_value
+    except Error, exc:
+        print 'EXCEPTION (should be duplicate alias/name error): %s' % exc
 
     x = DPyGetOpt(['apple|atlas=i@', 'application|executable=f@'])
     try:
         x.processArguments(['-app', '29.3'])
-    except:
-        print 'EXCEPTION (should be ambiguous argument): ' +    sys.exc_value
+    except Error, exc:
+        print 'EXCEPTION (should be ambiguous argument): %s' % exc
 
     x = DPyGetOpt(['foo'], ['antigravity', 'antithesis'])
     try:
         x.processArguments(['-foo', 'anti'])
-    except:
-        print 'EXCEPTION (should be ambiguous terminator): ' + sys.exc_value
+    except Error, exc:
+        print 'EXCEPTION (should be ambiguous terminator): %s' % exc
 
     profile = ['plain-option',
                               'boolean-option!',
Index: IPython/ipmaker.py
===================================================================
--- IPython/ipmaker.py	(revision 2314)
+++ IPython/ipmaker.py	(working copy)
@@ -299,9 +299,9 @@
 
     try:
         getopt.processArguments(argv)
-    except:
+    except DPyGetOpt.ArgumentError, exc:
         print cmd_line_usage
-        warn('\nError in Arguments: ' + `sys.exc_value`)
+        warn('\nError in Arguments: "%s"' % exc)
         sys.exit(1)
 
     # convert the options dict to a struct for much lighter syntax later


More information about the IPython-dev mailing list