Python TypeError提供有关参数的更多信息

时间:2013-09-18 12:10:58

标签: python helper typeerror

我正在尝试实现一个系统来帮助用户调用函数/方法。

我知道用户可以help(function)获取我提供的某种文档,但我想重新实现TypeError它是否会打印该文档(如果有的话)。


例如:
假设我有:

def foo(bar):
    ''' Adds 1 to 'bar' and prints output '''
    print 1+bar

用户决定拨打foo()(没有参数)
它会引发类似这样的TypeError:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-624891b0d01a> in <module>()
----> 1 foo()

TypeError: foo() takes exactly 1 argument (0 given)

我希望它也可以打印来自help(foo)的信息。即:

foo(bar)
    Adds 1 to 'bar' and prints output

关于如何做到这一点的任何想法?我意识到我需要

  1. 检测引发TypeError的函数
  2. 获取该功能的帮助文本
  3. 将其添加到引发的TypeError。
  4. 1)这似乎有效:

    import sys, traceback
    # Get latest traceback information
    tb = sys.exc_info()[-1]
    stk = traceback.extract_tb(tb, 1)
    # Extract called function and remove '()' - This actually limits functionality as the user might had inputed some extra arguments for example
    fname = stk[0][-1]
    fname = str(fname).split('()')[0]
    

    2)和3)并且没有关于如何进行的想法... = /


    非常感谢!


    编辑 3)我试图覆盖TypeError的默认行为,到目前为止没有成功。 我创建了一个新的MyError类来测试它并制作:

    import exceptions
    exception.TypeError = MyError
    

    但是每当引发TypeError时,原始版本就出现而不是MyError


    编辑2 好的,发现我确实需要覆盖sys.excepthook方法。

    作为测试,我创建了:

    import sys
    def handler(exc, value, tb):
        print 'Oops'
    
    sys.excepthook = handler
    

    但是,每当发生错误时,它仍然会带来原始错误,而不是“Oops”消息。此外,sys.excepthook仍会返回原始邮件:

    <bound method TerminalInteractiveShell.excepthook of <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x10f4320d0>>
    

    我也尝试重写IPython.terminal.interactiveshell.TerminalInteractiveShell.excepthook但没有成功。

    关于如何继续前进的任何想法?

2 个答案:

答案 0 :(得分:0)

第二名:

>>> def foo(bar):
...     '''Adds "1" to bar and prints output'''
...     return 1 + bar
...
>>> print foo.__doc__
Adds "1" to bar and prints output

对于第三个,您可能希望使用raise关键字来引发错误。你可以在你的第一个解决方案中使用它,但我从未使用过追溯模块,所以我无法帮助你,抱歉。

答案 1 :(得分:0)

好的,我终于明白了!

这个答案对python和ipython都有效! (我只测试了python 2.7,python 3可能需要进行微小的更改)

import sys
import traceback
import inspect


def get_args(func):
    """Get function arguments, varargs, kwargs and defaults.

    This function will be called whenever a exception is raised."""
    args, varargs, kwargs, defs = inspect.getargspec(func)

    if defs is not None:
        # If there are defaults, include them in the main argument list
        for i in range(-len(defs), 0):
            args[i] += ' = {}'.format(defs[i])

    if varargs is not None:
        # If the function accept extra arguments, include them at the end of the list.
        args.append('*' + varargs)

    if kwargs is not None:
        # If the function accept extra keyworded arguments, include them at the end of the list.
        args.append('**' + kwargs)

    return args  # args contain information about all the function arguments.


def value_handler(exc, value, tb):
    """Changes the default message to include additional information.

    This handler will be called whenever an exception happens."""
    args = list(value)  # Value typically contains the error message.

    if exc == TypeError and '()' in str(value):
        # I want to change only TypeError from function calls.
        func_name = str(value).split('()')[0]  # Obtain the function name from the error message.
        func = globals()[func_name]  # Get function object from globals
        func_doc = func.__doc__      # Function docstring
        func_args = get_args(func)   # Get function arguments
        if func_doc is not None:     # Add docstring to the message
            args[0] += '\nDoc: \t{}'.format(func_doc)
        args[0] += '\nArgs: \t' + '\n\t'.join(func_args)  # Finally, add all the arguments to the message.

    # Apply changes to the original error
    value.args = args
    return value

def custom_exc(shell, exc, value, tb, tb_offset=None):
    """Add aditional information and call original excepthook

    This version works with iPython"""
    value = value_handler(exc, value, tb)  # Changes the error message
    shell.showtraceback((exc, value, tb), tb_offset=tb_offset)  # Raise the error with the new message (keeping traceback and other information).

def custom_python_exc(exc, value, tb):
    """Add aditional information and call original excepthook

    This version works with regular python"""
    value = value_handler(exc, value, tb)  # Changes the error message
    sys.__excepthook__(exc, value, tb)     # Raise the error with the new message (keeping traceback and other information).

try:
    __IPYTHON__  # Check if we're running iPython
except NameError:
    # Not iPython enviroment, override excepthook
    sys.excepthook = custom_python_exc
else:
    # iPython enviroment, need to set custom excepthook
    get_ipython().set_custom_exc((Exception,), custom_exc)


有了这个,就应该能够为任何引发的错误添加更多信息。