How to raise own error when one argument is missing? - python

Hi I'm pretty new to Python and I've just started to learn about errors and exceptions.I have this function in a class that inserts a line at a given index called num.I know python will raise an error if no num is given but I want to raise my own error.How do I do that?This is what I tried. But the error raised is still the default error?
def insertNum(self, num, line):
if num== None:
raise Exception("Num not specified.")
else:
self.list.insert(num, line)
return self.list

You can use try...except statement.
def insertNum(num, line):
try:
list.insert(num, line)
return list
except:
print('custom error')

You can set the default value of num to None and then check if the value is None.
def insertNum(self, line, num=None):
if num is None:
raise Exception("Num not specified.")
else:
self.list.insert(num, line)
return self.list
If you pass only one parameter to the insertNum method, num will be set the None (the default value) and will raise the exception.
If you don't want to change the order of the arguments, you can use this:
def insertNum(self, num, line=None):
if line is None:
raise Exception("Num not specified.")
else:
self.list.insert(num, line)
return self.list
A simple demonstration for how default arguments work:
>>> def foo(bar, baz=None):
... print(bar, baz)
...
>>> foo(1, 2)
1 2
>>> foo(2)
2 None

I suggest you read about exceptions and errors
But the main idea is that you catch errors and then you handle them the way you like.
try:
#do something
except Exception as e:
# error occured
print("A wild error appeared")

wrap your function with another function that will have try and except` and there you could raise what ever error/exception you want.
def wrapper_func(self, num, line):
try:
self.insertNum(num, line)
except Exception as e:
raise Exception("whatever you want")

Related

except ValueError in Python

Is there better way of writing this code:
def add (exe1, exe2):
try:
a = float (exe1)
b = float (exe2)
total = float (a + b)
except ValueError:
return None
else:
return total
You can have it all inside a try/except block (calculation and return):
def add(exe1, exe2):
try:
return float(exe1) + float(exe2)
except ValueError:
return None
Also note, the default return value from function is None, so the second return is not really necessary (you could have pass instead), but it makes code more readable.
You can also use contextlib.suppress, if you find it more readable.
from contextlib import suppress
def add(exe1, exe2):
with suppress(ValueError):
return float(exe1) + float(exe2)
See the documentation here.

Python 3.x - Run function before appending item to list

In Python 3.x, is it possible to run a function before an item gets appended to a list ?
I have a class which inherits from a list, with some additionnal custom functions. I would like a series of checks to be performed on the data of any element which gets added to this list. If an added element does not meet certain criteria, the list will raise an error.
class ListWithExtraFunctions(list):
def __beforeappend__(self):
... run some code ...
... perform checks ...
... raise error if checks fail ...
Define ListWithExtraFunctions.append and call super().append(value) if value passes all the checks:
class ListWithExtraFunctions(list):
def append(self, value):
if okay():
return super().append(value)
else:
raise NotOkay()
This option is very similar to the solution that Vaultah wrote. It only uses “try…except” that will allow you to handle exceptions in certain way.
class Nw_list(list):
def val_check(self, value):
# Accepts only integer
if type(value) == int:
return value
else:
# Any other input type will raise exception
raise ValueError
def append(self, value):
try:
# Try to append checked value
super().append(self.val_check(value))
except ValueError:
# If value error is raised prints msg
print("You can append only int values")

Adding print statement to ValueError exception

New to Python, so I'm sure this is a noob question, but Googling isn't availing me of a clear answer.
Given the following function which is intended to ensure that the user input is a string, why can't I (or how can I) add a print statement when the exception is triggered? The print statement I've inserted there doesn't work.
def string_checker(action):
try:
check = isinstance(action, basestring)
if check == True:
return True
except ValueError:
print "We need a string here!"
return None
action = "words"
string_checker(action)
This may do what you want:
def string_checker(action):
try:
assert isinstance(action, basestring)
return True
except AssertionError:
print "We need a string here!"
return None
action = "words"
string_checker(action)
string_checker(21)
But you could also return "We need a string here!" instead of printing it, or return False, for consistency.
The problem is that you're never raising a value error if action isn't a string. Try this:
def string_checker(action):
try:
check = isinstance(action, basestring)
if check:
return True
else:
raise ValueError
except ValueError:
print "We need a string here!"
return None
But really, I don't think you need an exception. This should work fine:
def string_checker(action):
try:
check = isinstance(action, basestring)
if check:
return True
else:
print "We need a string here!"
return None
I'm not sure I understand. This appears to print "We need a string here!":
def string_checker(action):
try:
raise ValueError()
check = isinstance(action, basestring)
if check == True:
return True
except ValueError:
print "We need a string here!"
return None
action = "words"
string_checker(action)
raw_input('#')
Note the raise ValueError() in the try. Are you sure an exception is being thrown?

How to suppress displaying the parent exception (the cause) for subsequent exceptions

I'm aware of raise ... from None and have read How can I more easily suppress previous exceptions when I raise my own exception in response?.
However, how can I achieve that same effect (of suppressing the "During handling of the above exception, another exception occurred" message) without having control over the code that is executed from the except clause? I thought that sys.exc_clear() could be used for this, but that function doesn't exist in Python 3.
Why am I asking this? I have some simple caching code that looks like (simplified):
try:
value = cache_dict[key]
except KeyError:
value = some_api.get_the_value_via_web_service_call(key)
cache_dict[key] = value
When there's an exception in the API call, the output will be something like this:
Traceback (most recent call last):
File ..., line ..., in ...
KeyError: '...'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ..., line ..., in ...
some_api.TheInterestingException: ...
This is misleading, as the original KeyError is not really an error at all. I could of course avoid the situation by changing the try/except (EAFP) into a test for the key's presence (LBYL) but that's not very Pythonic and less thread-friendly (not that the above is thread-safe as is, but that's beside the point).
It's unreasonable to expect all code in some_api to change their raise X to raise X from None (and it wouldn't even make sense in all cases). Is there a clean solution to avoid the unwanted exception chain in the error message?
(By the way, bonus question: the cache thing I used in the example is basically equivalent to cache_dict.setdefault(key, some_api.get_the_value_via_web_service_call(key)), if only the second argument to setdefault could be a callable that would only be called when the value needs to be set. Isn't there a better / canonical way to do it?)
You have a few options here.
First, a cleaner version of what orlp suggested:
try:
value = cache_dict[key]
except KeyError:
try:
value = some_api.get_the_value(key)
except Exception as e:
raise e from None
cache_dict[key] = value
For the second option, I'm assuming there's a return value hiding in there somewhere that you're not showing:
try:
return cache_dict[key]
except KeyError:
pass
value = cache_dict[key] = some_api.get_the_value(key)
return value
Third option, LBYL:
if key not in cache_dict:
cache_dict[key] = some_api.get_the_value(key)
return cache_dict[key]
For the bonus question, define your own dict subclass that defines __missing__:
class MyCacheDict(dict):
def __missing__(self, key):
value = self[key] = some_api.get_the_value(key)
return value
Hope this helps!
You can try suppressing the context yourself:
try:
value = cache_dict[key]
except KeyError:
try:
value = some_api.get_the_value_via_web_service_call(key)
except Exception as e:
e.__context__ = None
raise
cache_dict[key] = value
Here is a version of #Zachary's second option whose use is a little simpler. First, a helper subclass of dict which returns a sentinal value on a "miss" rather than throwing an exception:
class DictCache(dict):
def __missing__(self, key):
return self
then in use:
cache = DictCache()
...
value = cache[K]
if value is cache:
value = cache[K] = some_expensive_call(K)
Notice the use of "is" rather than "==" to ensure there is no collision with a valid entry.
If the thing being assigned to is a simple variable (i.e. "value" rather than an attribute of another variable "x.value"), you can even write just 2 lines:
if (value := cache[K]) is cache:
value = cache[K] = some_expensive_call(K)

Wrapping exceptions in Python

I'm working on a mail-sending library, and I want to be able to catch exceptions produced by the senders (SMTP, Google AppEngine, etc.) and wrap them in easily catchable exceptions specific to my library (ConnectionError, MessageSendError, etc.), with the original traceback intact so it can be debugged. What is the best way to do this in Python 2?
The simplest way would be to reraise with the old trace object. The following example shows this:
import sys
def a():
def b():
raise AssertionError("1")
b()
try:
a()
except AssertionError: # some specific exception you want to wrap
trace = sys.exc_info()[2]
raise Exception("error description"), None, trace
Check the documentation of the raise statement for details of the three parameters. My example would print:
Traceback (most recent call last):
File "C:\...\test.py", line 9, in <module>
a()
File "C:\...\test.py", line 6, in a
b()
File "C:\...\test.py", line 5, in b
raise AssertionError("1")
Exception: error description
For completeness, in Python 3 you'd use the raise MyException(...) from e syntax.
This answer is probably a little bit late, but you can wrap the function in a python decorator.
Here is a simple cheatsheet on how different decorators.
Here is some sample code of how to do this. Just change the decorator to catch different errors in the different ways that you need.
def decorator(wrapped_function):
def _wrapper(*args, **kwargs):
try:
# do something before the function call
result = wrapped_function(*args, **kwargs)
# do something after the function call
except TypeError:
print("TypeError")
except IndexError:
print("IndexError")
# return result
return _wrapper
#decorator
def type_error():
return 1 / 'a'
#decorator
def index_error():
return ['foo', 'bar'][5]
type_error()
index_error()
Use raise_from from the future.utils package.
Relevant example copied below:
from future.utils import raise_from
class FileDatabase:
def __init__(self, filename):
try:
self.file = open(filename)
except IOError as exc:
raise_from(DatabaseError('failed to open'), exc)
Within that package, raise_from is implemented as follows:
def raise_from(exc, cause):
"""
Equivalent to:
raise EXCEPTION from CAUSE
on Python 3. (See PEP 3134).
"""
# Is either arg an exception class (e.g. IndexError) rather than
# instance (e.g. IndexError('my message here')? If so, pass the
# name of the class undisturbed through to "raise ... from ...".
if isinstance(exc, type) and issubclass(exc, Exception):
e = exc()
# exc = exc.__name__
# execstr = "e = " + _repr_strip(exc) + "()"
# myglobals, mylocals = _get_caller_globals_and_locals()
# exec(execstr, myglobals, mylocals)
else:
e = exc
e.__suppress_context__ = False
if isinstance(cause, type) and issubclass(cause, Exception):
e.__cause__ = cause()
e.__suppress_context__ = True
elif cause is None:
e.__cause__ = None
e.__suppress_context__ = True
elif isinstance(cause, BaseException):
e.__cause__ = cause
e.__suppress_context__ = True
else:
raise TypeError("exception causes must derive from BaseException")
e.__context__ = sys.exc_info()[1]
raise e

Categories