我正在尝试实现一个系统来帮助用户调用函数/方法。
我知道用户可以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)这似乎有效:
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但没有成功。
关于如何继续前进的任何想法?
答案 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)
有了这个,就应该能够为任何引发的错误添加更多信息。