[英]Python TypeError to give more information about arguments
I'm trying to implement a system to help the user when calling functions/methods. 我正在尝试实现一个系统来在调用函数/方法时帮助用户。
I know the user can just help(function)
to get some kind of a documentation provided by me but I wanted to reimplement the TypeError
do it would also print that documentation if available. 我知道用户可以只是通过
help(function)
来获得我提供的某种文档,但是我想重新实现TypeError
,它还会打印该文档(如果有)。
For example: 例如:
Suppose I have: 假设我有:
def foo(bar):
''' Adds 1 to 'bar' and prints output '''
print 1+bar
And the user decide to call foo()
(with no arguments) 然后用户决定调用
foo()
(不带参数)
It will raise a TypeError like this: 它将引发一个TypeError:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-624891b0d01a> in <module>()
----> 1 foo()
TypeError: foo() takes exactly 1 argument (0 given)
I would like it to also print the information from the help(foo)
as well. 我也希望它也可以打印来自
help(foo)
的信息。 ie: 即:
foo(bar)
Adds 1 to 'bar' and prints output
Any ideas on how to do that? 关于如何做到这一点的任何想法? I realise I need
我意识到我需要
for 1) this seems to work: 对于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]
for 2) and 3) and have no ideas on how to proceed... =/ 对于2)和3),并且不知道如何进行... = /
Very much appreciated! 非常感谢!
Edit for 3) I'm trying to override the default behaviour of TypeError, so far with no success. 编辑 3)我试图覆盖TypeError的默认行为,到目前为止没有成功。 I created a new MyError class just to test it and made:
我创建了一个新的MyError类来进行测试并进行了以下操作:
import exceptions
exception.TypeError = MyError
but whenever the TypeError is raised, the original version comes up and not MyError 但是每当引发TypeError时,就会出现原始版本,而不是MyError
Edit 2 Ok, found out that I actually need to override the sys.excepthook method. 编辑2好的,发现我实际上需要重写sys.excepthook方法。
As a test, I created: 作为测试,我创建了:
import sys
def handler(exc, value, tb):
print 'Oops'
sys.excepthook = handler
However, whenever a error occurs it still brings the original error and not the 'Oops' message. 但是,无论何时发生错误,它仍然会带来原始错误,而不是“糟糕”消息。 Also,
sys.excepthook
still returns the original message: 同样,
sys.excepthook
仍返回原始消息:
<bound method TerminalInteractiveShell.excepthook of <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x10f4320d0>>
I also tried overriding the IPython.terminal.interactiveshell.TerminalInteractiveShell.excepthook with no success. 我也尝试覆盖IPython.terminal.interactiveshell.TerminalInteractiveShell.excepthook,但没有成功。
Any ideas on how to keep going? 关于如何继续前进的任何想法?
For number two: 对于第二个:
>>> def foo(bar):
... '''Adds "1" to bar and prints output'''
... return 1 + bar
...
>>> print foo.__doc__
Adds "1" to bar and prints output
For number three, you may want to use the raise
keyword to raise an error. 对于第三个,您可能要使用
raise
关键字来引发错误。 You could probably use this with your first solution, but I've never used the traceback module so I can't help you there, sorry. 您可能会在第一个解决方案中使用它,但是对我而言,我从未使用过追溯模块,因此我无法为您提供帮助。
Ok, I finally got it! 好吧,我终于明白了!
This answer is valid for both python and ipython! 此答案对python和ipython均有效! (I only tested with python 2.7, minor changes might be needed for python 3)
(我仅使用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)
With this, one should be able to add more information to any Error being raised. 有了它,人们应该能够向正在引发的任何错误中添加更多信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.