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.
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)
It will raise a TypeError like this:
---------------------------------------------------------------------------
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. 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:
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... =/
Very much appreciated!
Edit for 3) I'm trying to override the default behaviour of TypeError, so far with no success. I created a new MyError class just to test it and made:
import exceptions
exception.TypeError = MyError
but whenever the TypeError is raised, the original version comes up and not MyError
Edit 2 Ok, found out that I actually need to override the sys.excepthook method.
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:
<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.
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. 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! (I only tested with python 2.7, minor changes might be needed for 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.