Smart help again

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • bearophileHUGS@lycos.com

    #1

    Smart help again

    Hello, here I extend the idea of the smart help I've discussed
    recently.
    When I receive an error like:

    TypeError: fun() takes exactly 2 arguments (1 given)

    I'd also like to see that method/function parameters (or the first line
    of its docstring).[color=blue]
    >From a discussion with gentle programmers in another newsgroup, I've[/color]
    see that this problem can probably be solved with something like:

    .. import sys, exceptions, difflib, inspect
    ..
    .. def excepthook(type , value, tb):
    .. extra = ""
    .. if sys.last_type == exceptions.Type Error:
    .. # extra = string of function/method +
    .. # parameters inspect.getargs pec(function or method)
    .. import traceback
    .. tblines = traceback.forma t_exception(typ e, value, tb)
    .. tblines.append( extra)
    .. print "".join( map(str, tblines) )
    .. sys.exit(1)
    ..
    .. sys.excepthook = excepthook


    inspect.getargs pec is useful, but how can I find there the class+method
    or (function name) of the raised error? I can find the function name
    with something like this, but it doesn't look like a nice solution, and
    it cannot be used to find the class of the method:

    extra = str(sys.last_va lue)
    extra = extra[:extra.find("() ")]

    Thank you,
    Bearophile

  • wittempj@hotmail.com

    #2
    Re: Smart help again

    You can create your own Exception class, based on thisrecipe:
    http://aspn.activestate.com/ASPN/Coo...n/Recipe/52215, it will
    look like

    -import sys, traceback
    -
    -class Error:
    - def __init__(self, arg):
    - self._arg = arg
    - tb = sys.exc_info()[2]
    - while 1:
    - if not tb.tb_next:
    - break
    - tb = tb.tb_next
    - stack = []
    - f = tb.tb_frame
    - while f:
    - stack.append(f)
    - f = f.f_back
    - stack.reverse()
    - #traceback.prin t_exc()
    - print "Locals by frame, innermost last"
    - for frame in stack:
    - print
    - print "Frame %s in %s at line %s" % \
    - (frame.f_code.c o_name, frame.f_code.co _filename,
    -frame.f_lineno)
    - for key, value in frame.f_locals. items():
    - print "\t%20s = " % key,
    - #We have to be careful not to cause a new error in our
    -error
    - #printer! Calling str() on an unknown object could
    cause -an
    - #error we don't want.
    - try:
    - print value
    - except:
    - print "<ERROR WHILE PRINTING VALUE>"-
    -
    - def __repr__(self):
    - return repr(self._arg)
    -

    suppose this class is in a module named test.py, then your code can be
    like:

    -#!/usr/bin/env python
    -import test, sys

    -try:
    - try:
    - class Spam:
    - def eggs(self):
    - return 1/0
    - foo = Spam()
    - foo.eggs()
    - except:
    - raise test.Error('xxx ')
    -except test.Error, e:
    - print >> sys.stderr, e.__class__.__n ame__, e


    The output will be:
    -Locals by frame, innermost last
    -
    -Frame ? in ./test2.py at line 12
    - Spam = __main__.Spam
    - __builtins__ = <module '__builtin__' (built-in)>
    - __file__ = ./test2.py
    - sys = <module 'sys' (built-in)>
    - test = <module 'test' from
    '/home/martin/test.pyc'>
    - __name__ = __main__
    - foo = <__main__.Spa m instance at 0xb7e0720c>
    - __doc__ = None

    -Frame eggs in ./test2.py at line 8
    - self = <__main__.Spa m instance at 0xb7e0720c>
    -Error 'xxx'

    Comment

    • bearophileHUGS@lycos.com

      #3
      Re: Smart help again

      >You can create your own Exception class, based on this recipe:<

      Thank you for your answer, the recipe you have suggested gives a very
      big output, but it doesn't contain what I've asked for... :-) I was
      asking to see that faulty method/function parameters (or the first line
      of its docstring).
      Probably the use of sys.excepthook is better, because you don't need
      that
      except: raise test.Error('xxx ')
      I've studied that solution of yours, and I think I still have to learn
      many things about Python :-)

      Bye, thank you,
      Bearophile

      Comment

      • wittempj@hotmail.com

        #4
        Re: Smart help again

        I hope a rewrite makes it a bit more clear for you.

        The test module is defined below, it contains a simplified Error
        object, it resemble the one I use a lot in my own scripting. The test
        file generates an error ( A ZeroDivisionErr or in method eggs of class
        Spam).

        -#!/usr/bin/env python

        -import test, sys
        -
        -try:
        - try:
        - class Spam:
        - def eggs(self):
        - return 1/0
        - foo = Spam()
        - foo.eggs()
        - except Exception, e:
        - raise test.Error('%s: %s' % (e.__class__.__ name__, e))
        -except test.Error, e:
        - print >> sys.stderr, e.__class__.__n ame__, e

        The Error class takes the last exception, and tries to find the
        originating method of that exception, by unwinding the stacktrace


        -import sys, traceback
        -class Error:
        - def __init__(self, arg):
        - tb = sys.exc_info()[2]
        - while 1:
        - if not tb.tb_next:
        - break
        - tb = tb.tb_next
        - stack = []
        - f = tb.tb_frame
        - while f:
        - stack.append(f)
        - f = f.f_back
        -
        - error_originato r = stack[0]
        -
        - (obj, instance) = error_originato r.f_locals.item s()[0]
        -
        - self._str = 'class instance: %s, method: %s raises %s' % \
        - (instance, \
        - error_originato r.f_code.co_nam e, \
        - arg)
        -
        - def __repr__(self):
        - return repr(self._str)

        Now the output is:


        Error 'class instance: <__main__.Spa m instance at 0xb7e0444c>, method:
        eggs raises ZeroDivisionErr or: integer division or modulo by zero'

        Now you see the class and methos where the exception was raised,
        although I admit that it is quite complicated with all the exception
        handling

        Comment

        Working...