Declaring None type exception - python-3.x

I want to define a custom Exception class for the NoneType error in python inheriting from Exception class. I expect the code below to do such a thing for me but no success. Is there any way to do this?
class NoneTypeException(Exception):
pass
try:
image = cv2.imread("/path/")
gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY) #exception should be raised here
...
except NoneTypeException:
raise NoneTypeException("Image not found") # and should be caught here
I want to the try except block raise the NoneTypeException. Any way?

While you can declare an exception to represent whatever you want, existing code won't raise it for you. In specific, operations on None already raise some well-defined errors and you cannot replace them. Strictly speaking, you cannot get the desired behaviour.
If you know that a certain section of code is vulnerable to None values, you can catch the generic Exception and raise a specific one. This hinges on the assumption that None is the only bogus value you might get:
class NoneTypeException(Exception):
pass
try:
image = cv2.imread("/path/")
gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)
...
except AttributeError as err: # handle generic exception from action on ``None``
raise NoneTypeException("Image not found")
Take note that this is rarely what you should be doing - the None value is a symptom, not the cause of the error. It would be more appropriate to raise a FileNotFoundError.
Since None can trigger errors anywhere, it is easier to protect against it at its origin. Checking for identity with None is very cheap:
try:
image = cv2.imread("/path/")
if image is None: # verify value immediately
raise NoneTypeException()
# safely work with image
gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)
...
except NoneTypeException:
raise FileNotFoundError('image not found')

Related

How to write code to catch null exception in python

I have below code, which I want to write in a way so that it catches proper exception when none is passed when argument value is required.
def MyFunction(MyArg1, MyArg2):
if not MyArg2:
raise ?Error?
I think it will be type error but I need the exception to be more explicit
Maybe try this
if key is None:
raise TypeError
or
if key is None:
print("There is no key.")
This is what I have trieD
if MyArg2 is None:
raise TypeError

Is there a way in a python exception handling, to silently ignore exception/undeclared names without muliplying try/except blocs

let's say that i have a bunch of instruction which might all raise exceptions and I'd like to simply ignore those that fail.
failable_1
failable_2
...
failable_n
Ignoring them with the usual exception pattern might quickly become cumbersome:
try:
failable_1
except SomeError:
pass
try:
failable_2
except SomeError:
pass
...
try:
failable_n
except SomeError:
pass
This is especially true if it is about declaring a list of possibly non existing symbols:
my_list=[optional_1, optional_2, ..., optional_n]
(Let's axiomatically assume that somewhere else in the code, there was something like:
for (var,val) in zip(optional_variable_names_list, values):
exec(var+"="+repr(val))
)...
Because in this case, you cannot even write the name in the code.
my_list=[]
for variable in [optional_1, optional_2, ..., optional_n]: # problem remains here
try:
my_list.append(variable)
except:
pass
wouldn't work. You have to use eval():
my_list=[]
for variable in ["optional_1", "optional_2", ..., "optional_n"]:
try:
my_list.append(eval(variable))
except:
pass
So my question is :
Isn't there a way to write something like the on error next or on error ignore that existed in some old time languages. some kind of :
ignore SomeError:
failable_1
failable_2
...
failable_n
or
ignore NameError:
my_list=[optional_1, optional_2, ..., optional_n]
And if not, why would it be a bad idea ?
You can simplify the pattern somewhat by using a context manager that suppresses an exception by returning True if the exception that occurs is one the those specified with the constructor, or otherwise re-raises the exception:
class Ignore:
def __init__(self, *ignored_exceptions):
self.ignored_exceptions = ignored_exceptions
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if isinstance(exc_value, self.ignored_exceptions):
return True
raise
so that:
with Ignore(NameError, ValueError):
a = b
outputs nothing, while:
with Ignore(NameError, ValueError):
1 / 0
raises ZeroDivisionError: division by zero as expected.

Retrieve Python exception object

I have a piece of code that I don't control and while running it raises an error. I'd like to capture the value of exc object inside the exc_func method.
As you can see exc_func raises two exceptions, one of which is handled. What I care about is the value of the exc object, but so far have little luck retrieving it. The value does not exist in exc_traceback object and the exception message is not very helpful.
import traceback
import sys
def exc_func():
try:
a = 1
a.length()
except Exception as exc:
exc.with_not_existing()
def main():
try:
exc_func()
except Exception as exc:
exc_type, exc_value, exc_traceback = sys.exc_info()
tb_walk = traceback.walk_tb(exc_traceback)
# Need this in order to pickle traceback
tb_summary = traceback.StackSummary.extract(tb_walk, capture_locals=True)
if __name__ == '__main__':
main()
EDIT:
For instance, the exc object in main is AttributeError("'AttributeError' object has no attribute 'with_not_existing'"). What I really want to see is the exc object inside exc_func. Just to be clear, I need the exc object itself, something like traceback.format_exc() is not helpful in my case, due to the nature of the exception (it's a C lib that raises this exception)
When an exception is raised during handling another exception, the initial exception is stored as the __context__. It can be extracted when handling the new exception.
try:
exc_func()
except Exception as exc:
parent = exc.__context__ # the previously handled exception
print(type(parent), parent)
Note that an exception handler may also explicitly chain exceptions via __cause__.
Built-in Exceptions
[...]
When raising (or re-raising) an exception in an except or finally clause __context__ is automatically set to the last exception caught; if the new exception is not handled the traceback that is eventually displayed will include the originating exception(s) and the final exception.
The raise statement
[...]
The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable).
[...]
A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

Catching Outer Exceptions in Python

My code tries to do something, but it triggers an Error... which triggers another Error. So, the error message looks something like this:
SillyError: you can`t do that becuz blablabla
The above exception was the direct cause of the following exception:
LoopyError: you can`t do that becuz blobloblo
I want to create a try except block that only catches this specific duo of errors. However, I am only able to catch the first one, because once I do, the second one never gets a chance to trigger.
This other question is about catching either exception, but I want to catch only if both are triggered in succession. Is there a way?
If you have a try\except, you will always catch the error based on the outer exception. However you do have the option to pass on any exceptions you don't want to process.
In this code, the ZeroDivisionError is caught and wrapped in another exception which is then caught by the calling code. The calling code checks for the inner exception and decides whether to re-raise the exception up the stack.
def xtest():
try:
a = 1/0 # exception - division by zero
except ZeroDivisionError as e:
raise Exception("Outer Exception") from e # wrap exception (e not needed for wrap)
try:
xtest()
except Exception as ex:
print(ex) # Outer Exception
print(ex.__cause__) # division by zero
if (str(ex) == "Outer Exception" and str(ex.__cause__) == "division by zero"):
print("Got both exceptions")
else:
raise # pass exception up the stack
Just for completion, you can do the check based on the exception class name also:
if (type(ex).__name__ == "Exception" and type(ex.__cause__).__name__ == "ZeroDivisionError"):
print("Got both exceptions")
#ShadowRanger pointed out that it may be quicker to just check the class type instead of the class name:
if (type(ex) == Exception and type(ex.__cause__) == ZeroDivisionError):
print("Got both exceptions")

Python3 missing exception when looping

I have to define an attribute in a class and I would like to manage error in the most pythonic way.
Here is the code I have tried so far. I can't figure out why I can not "reach" the exception in the following code.
# global variable to be used in the example
my_dict = {"key1": {"property": 10}, "key2": {}}
class Test(object):
#property
def my_attribute(self):
try:
return self._my_attribute
except AttributeError:
self._my_attribute = {}
for key, value in my_dict.items():
print(key)
self._my_attribute[key] = value['property']
except Exception:
print('error')
# I would like to manage my error here with a log or something
print("I am not reaching here")
finally:
return self._my_attribute
if __name__ == '__main__':
Test().my_attribute
I expected to reach the Exception case in the second iteration of the for loop since it is a KeyError ("key2" has no "property"). But it just passes by it. In this example, if the script is run, it does not print "I am not reaching here". Could anyone explain why I am seeing this wrong? Thanks!
The potential KeyError in self._my_attribute[key] = value['property'] is not covered by the except Exception block. Once it is raised the finally block is executed (as a matter of fact the finally block is always executed, regardless of an exception being raised or even handled). This can be easily verified by using a step-by-step debugger or with a simple print('finally') inside the finally block.
This is (among other reasons) why try blocks should be as minimal as possible. If you know that line might raise a KeyError then explicitly try-except it:
for key, value in my_dict.items():
print(key)
try:
self._my_attribute[key] = value['property']
except KeyError as e:
print('Key ', e, 'does not exist')

Resources