Python exceptions: is there a way to find the exception attributes?

Pierre Rouleau pieroul at attglobal.net
Sun Dec 1 15:27:00 EST 2002


Bengt Richter wrote:
> On Sat, 30 Nov 2002 22:16:22 -0500, Pierre Rouleau <pieroul at attglobal.net> wrote:
> 
> 
>>
>>John Hunter wrote:
>>
>>>>>>>>"Pierre" == Pierre Rouleau <pieroul at attglobal.net> writes:
>>>>>>>
>>>
>>>    Pierre> I was looking for a quick way to look at exception
>>>    Pierre> attributes from within my programming environment when i
>>>    Pierre> have to decide what exception i should catch or which one
>>>    Pierre> i should raise and then what information i should pass
>>>    Pierre> inside the exception object.
>>>
>>>Within recent interactive python shells (which include pydoc.help by
>>>default), you can do, for example:
>>>
>>>  help(Exception)
>>>  help(StandardError)
>>>  help(IOError)
>>>  help(StandardError)
>>>  help(AttributeError)
>>>  help(KeyError)
>>>
>>>With some shells (eg, ipython) you can drop the parentheses.  Is this
>>>what you are looking for?
>>>
>>>
>>
>>Not really.  I would like to be able to know what my code can retreive 
> 
>>from a given exception object (its attributes) without having to look 
> 
>>into the code.  Exceptions are different than other objects in the sense 
>>that I can't simply create one and list its attributes.
>>
>>For example, on Python 2.2, if you run help(IOError) you get:
>>
>>
>>Help on class IOError in module exceptions:
>>
>>class IOError(EnvironmentError)
>> |  I/O operation failed.
>> |
>> |  Method resolution order:
>> |      IOError
>> |      EnvironmentError
>> |      StandardError
>> |      Exception
>> |
>> |  Data and non-method functions defined here:
>> |
>> |  __doc__ = 'I/O operation failed.'
>> |
>> |  __module__ = 'exceptions'
>> |
>> |  ----------------------------------------------------------------------
>> |  Methods inherited from EnvironmentError:
>> |
>> |  __init__(...)
>> |
>> |  __str__(...)
>> |
>> |  ----------------------------------------------------------------------
>> |  Methods inherited from Exception:
>> |
>> |  __getitem__(...)
>>
>>
>>There is nothing in that information to tell anyone that IOError 
>>exceptions have 3 attributes: errno, filename and strerror.
>>
>>In my question, I show a way to find out the list of attributes.  The 
>>code is generating the exception, cathing the exception object and use 
>>dir() on the exception object instance to list its attributes.  By 
>>visual inspection it becomes easy to find their names:
>>
>>
>>>>>try:
>>>>
>>...   f=open("/invalid/invalid.oops")
>>... except IOError, e:
>>...    print dir(e)
>>...
>>['__doc__', '__getitem__', '__init__', '__module__', '__str__', 'args', 
>>'errno', 'filename', 'strerror']
>>
>>But lets assume i did not know how to generate an IOError exception.  I 
>>would have to look into the documentation to find out what it is (or its 
>>source code if it is available).  If it is a builtin exception I would 
>>have to find out how to generate the exception before I could write a 
>>small code snippet (like the one above) to be able to get one object for 
>>the type of exception I am interested in.
>>
>>I am just trying to find out if there is a faster way than that.  A 
>>method that does not involve all of this cogitation.  This way, if one 
>>day, with a new release of Python i want to quickly know what are the 
>>attributes to this new exception, I would quickly find out.
>>
>>
> 
> You could just mechanize your code snippet for all the official exceptions:
> 
>  >>> import exceptions
>  >>> for xname in [x for x in dir(exceptions) if not x.startswith('_')]:
>  ...     x = exceptions.__dict__.get(xname)
>  ...     if x is None: print 'Nothing for %s' % x
>  ...     try:
>  ...          raise x
>  ...     except x, e:
>  ...          print '%s:\n    %s' %(x.__name__,[a for a in dir(e) if not a.startswith('_')])
>  ...
> 
That's it!  I should have known that i could just raise the exception and get the attributes from 
it. Oh well...

I wrote the following utilities to mechanize that work in the future, based on your code above.  Thanks!

The main function is exception_info().  It uses printIndented() to print a paragraph of text with a 
left margin. execption_info() accepts different types of arguments and can be used to get a list of 
arguments or simply print them.

def printIndented(indentSize,text,noIndentOn=0) :
    """Print all lines of text indented by specified amount.

    Arguments:
       text       : The single or multi-line string to print.
       indentSize : A string or number representing the size of the left margin.
                    If a string is passed, its size is used for the margin.
       noIndentOn : Number of lines not indented starting from the first one.
    """
    if type(indentSize) in types.StringTypes:
       marginText = " " * len(indentSize)
    elif type(indentSize) is types.IntType:
       marginText = " " * indentSize
    else:
       marginText = ""
    for line in text.split('\n'):
       if (noIndentOn <= 0):
          print "%s%s" % (marginText,line)
       else:
          print line
          noIndentOn -= 1

def exception_info(excClass=None) :
    """Print information about specific builtin exception class (or all of them).

    Arguments:
       excClass  : a builtin exception class name
                   or a string for a builtin exception class.
                   By default none is specified: print information for all
                   builtin exceptions.
    Returns:
       - For a specific exception:  a 2-tuple: (docstring, [argument list])
       - For a report for all exceptions: None
       - On error : None

    Example:
       >>> exception_info(IOError)
       Exception class: IOError
         Documentation:  I/O operation failed.
         Arguments    : ['args', 'errno', 'filename', 'strerror']
       ('I/O operation failed.', ['args', 'errno', 'filename', 'strerror'])
       >>> exception_info('UnicodeError')
       Exception class: UnicodeError
         Documentation:  Unicode related error.
         Arguments    : ['args']
       ('Unicode related error.', ['args'])
    """
    #
    def showInfoFor(anExcptClass):
       try:
          raise anExcptClass
       except anExcptClass, exp:
          print         "Exception class: %s" % anExcptClass.__name__
          print         "  Documentation: ",
          printIndented("  Documentation: ", anExcptClass.__doc__ ,noIndentOn=1)
          argList = [arg for arg in dir(exp) if not arg.startswith('_')]
          print         "  Arguments    : %s" % argList
          return argList
    #
    def getInfoFor(anExcptClass):
       try:
          return (anExcptClass.__doc__, showInfoFor(anExcptClass))
       except :
          print "Unknown exception %s" % anExcptClass
    #
    if isinstance(excClass, types.ClassType):
       return getInfoFor(excClass)
    else:
       if type(excClass) in types.StringTypes:
          return getInfoFor(exceptions.__dict__.get(excClass))
       elif excClass is None:
          for xname in [x for x in dir(exceptions) if not x.startswith('_')]:
             excpt = exceptions.__dict__.get(xname)
             if excpt is not None:
                showInfoFor(excpt)
       else:
          print "Invalid argument: pass name of builtin exception"
          print "                  not a %s" % type(excClass)




> but I agree that there ought to be some visibility in documentation somewhere. Maybe there is?
> 
If there is I did not see it.  If anyone knows where it is let me know!

Thanks again!

-- 
         Pierre Rouleau, ing.





More information about the Python-list mailing list