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

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.

Related

how to throw an error if certain condition evaluates to true

I have below code block:
try:
if str(symbol.args[0]) != str(expr.args[0]):
print('true')
raise SyntaxError('====error')
except:
pass
Here I am trying to raise Syntax error if certain condition is true.I am testing this code block, I can see 'true' is getting printed which means condition is met but even after that also the code is not throwing syntax error.
I am trying to understand what is wrong in the above code.
You're putting pass in the except: block which is swallowing the exception. Either remove the code from the try-except block or change pass to raise
Above answer is pointing the issue, I just want to give some examples to help you better understand how try/except works:
# Just raise an exception (no try/except is needed)
if 1 != 2:
raise ValueError("Values do not match")
# Catch an exception and handle it
a = "1"
b = 2
try:
a += b
except TypeError:
print("Cannot add an int to a str")
# Catch an exception, do something about it and re-raise it
a = "1"
b = 2
try:
a += b
except TypeError:
print("Got to add an int to a str. I'm re-raising the exception")
raise
try/except can also be followed by else and finally, you can check more about these here: try-except-else-finally

How to return two different error messages when querying the same model in Django

Take a look at the following:
def mutate(self, info, first_id, second_id):
try:
first = Model.objects.get(pk=first_id)
second = Model.objects.get(pk=second_id)
except Model.DoesNotExist:
return Exception('Object does not exist.')
else:
...
How can I return a custom error message depending on which of the ids actually does not exist? It's be nice to have something like:
{first_id} does not exist
I can't have two different except blocks because it's the same Model. What to do?
You can simply split up your query's in two statements:
def mutate(self, info, first_id, second_id):
try:
first = Model.objects.get(pk=first_id)
except Model.DoesNotExist:
raise Exception('Your first id {} Does not exist'.format(first_id))
try:
second = Model.objects.get(pk=second_id)
except Model.DoesNotExist:
raise Exception('Your second id {} Does not exist'.format(second_id))
...
PS: you need to raise exceptions. Not return them.

Declaring None type exception

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')

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')

Wrapping all possible method calls of a class in a try/except block

I'm trying to wrap all methods of an existing Class (not of my creation) into a try/except suite. It could be any Class, but I'll use the pandas.DataFrame class here as a practical example.
So if the invoked method succeeds, we simply move on. But if it should generate an exception, it is appended to a list for later inspection/discovery (although the below example just issues a print statement for simplicity).
(Note that the kinds of data-related exceptions that can occur when a method on the instance is invoked, isn't yet known; and that's the reason for this exercise: discovery).
This post was quite helpful (particularly #martineau Python-3 answer), but I'm having trouble adapting it. Below, I expected the second call to the (wrapped) info() method to emit print output but, sadly, it doesn't.
#!/usr/bin/env python3
import functools, types, pandas
def method_wrapper(method):
#functools.wraps(method)
def wrapper(*args, **kwargs): #Note: args[0] points to 'self'.
try:
print('Calling: {}.{}()... '.format(args[0].__class__.__name__,
method.__name__))
return method(*args, **kwargs)
except Exception:
print('Exception: %r' % sys.exc_info()) # Something trivial.
#<Actual code would append that exception info to a list>.
return wrapper
class MetaClass(type):
def __new__(mcs, class_name, base_classes, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if type(attribute) == types.FunctionType: # Replace it with a
attribute = method_wrapper(attribute) # decorated version.
newClassDict[attributeName] = attribute
return type.__new__(mcs, class_name, base_classes, newClassDict)
class WrappedDataFrame2(MetaClass('WrappedDataFrame',
(pandas.DataFrame, object,), {}),
metaclass=type):
pass
print('Unwrapped pandas.DataFrame().info():')
pandas.DataFrame().info()
print('\n\nWrapped pandas.DataFrame().info():')
WrappedDataFrame2().info()
print()
This outputs:
Unwrapped pandas.DataFrame().info():
<class 'pandas.core.frame.DataFrame'>
Index: 0 entries
Empty DataFrame
Wrapped pandas.DataFrame().info(): <-- Missing print statement after this line.
<class '__main__.WrappedDataFrame2'>
Index: 0 entries
Empty WrappedDataFrame2
In summary,...
>>> unwrapped_object.someMethod(...)
# Should be mirrored by ...
>>> wrapping_object.someMethod(...)
# Including signature, docstring, etc. (i.e. all attributes); except that it
# executes inside a try/except suite (so I can catch exceptions generically).
long time no see. ;-) In fact it's been such a long time you may no longer care, but in case you (or others) do...
Here's something I think will do what you want. I've never answered your question before now because I don't have pandas installed on my system. However, today I decided to see if there was a workaround for not having it and created a trivial dummy module to mock it (only as far as I needed). Here's the only thing in it:
mockpandas.py:
""" Fake pandas module. """
class DataFrame:
def info(self):
print('pandas.DataFrame.info() called')
raise RuntimeError('Exception raised')
Below is code that seems to do what you need by implementing #Blckknght's suggestion of iterating through the MRO—but ignores the limitations noted in his answer that could arise from doing it that way). It ain't pretty, but as I said, it seems to work with at least the mocked pandas library I created.
import functools
import mockpandas as pandas # mock the library
import sys
import traceback
import types
def method_wrapper(method):
#functools.wraps(method)
def wrapper(*args, **kwargs): # Note: args[0] points to 'self'.
try:
print('Calling: {}.{}()... '.format(args[0].__class__.__name__,
method.__name__))
return method(*args, **kwargs)
except Exception:
print('An exception occurred in the wrapped method {}.{}()'.format(
args[0].__class__.__name__, method.__name__))
traceback.print_exc(file=sys.stdout)
# (Actual code would append that exception info to a list)
return wrapper
class MetaClass(type):
def __new__(meta, class_name, base_classes, classDict):
""" See if any of the base classes were created by with_metaclass() function. """
marker = None
for base in base_classes:
if hasattr(base, '_marker'):
marker = getattr(base, '_marker') # remember class name of temp base class
break # quit looking
if class_name == marker: # temporary base class being created by with_metaclass()?
return type.__new__(meta, class_name, base_classes, classDict)
# Temporarily create an unmodified version of class so it's MRO can be used below.
TempClass = type.__new__(meta, 'TempClass', base_classes, classDict)
newClassDict = {}
for cls in TempClass.mro():
for attributeName, attribute in cls.__dict__.items():
if isinstance(attribute, types.FunctionType):
# Convert it to a decorated version.
attribute = method_wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, class_name, base_classes, newClassDict)
def with_metaclass(meta, classname, bases):
""" Create a class with the supplied bases and metaclass, that has been tagged with a
special '_marker' attribute.
"""
return type.__new__(meta, classname, bases, {'_marker': classname})
class WrappedDataFrame2(
with_metaclass(MetaClass, 'WrappedDataFrame', (pandas.DataFrame, object))):
pass
print('Unwrapped pandas.DataFrame().info():')
try:
pandas.DataFrame().info()
except RuntimeError:
print(' RuntimeError exception was raised as expected')
print('\n\nWrapped pandas.DataFrame().info():')
WrappedDataFrame2().info()
Output:
Unwrapped pandas.DataFrame().info():
pandas.DataFrame.info() called
RuntimeError exception was raised as expected
Wrapped pandas.DataFrame().info():
Calling: WrappedDataFrame2.info()...
pandas.DataFrame.info() called
An exception occurred in the wrapped method WrappedDataFrame2.info()
Traceback (most recent call last):
File "test.py", line 16, in wrapper
return method(*args, **kwargs)
File "mockpandas.py", line 9, in info
raise RuntimeError('Exception raised')
RuntimeError: Exception raised
As the above illustrates, the method_wrapper() decoratored version is being used by methods of the wrapped class.
Your metaclass only applies your decorator to the methods defined in classes that are instances of it. It doesn't decorate inherited methods, since they're not in the classDict.
I'm not sure there's a good way to make it work. You could try iterating through the MRO and wrapping all the inherited methods as well as your own, but I suspect you'd get into trouble if there were multiple levels of inheritance after you start using MetaClass (as each level will decorate the already decorated methods of the previous class).

Resources