Besides wrapping it in a try
statement, there are two other ways you can go about suppressing a given exception in a context manager:
Using an if
condition that returns True
if a given exception should be suppressed. This is based on the documentation which specifies that a True
value suppresses the exception.
This will work and on Python 2.x
and on Python 3.x
versions.
Using contextlib.suppress
with the given exception name(s) as a parameter.
This only works for versions > 3.3
The first option is an option worth noting due to the fact that it will work on most Pythons, so portability points. It can simply be done by initializing the context manager with the needed exception and, on __exit__
, adding an if
clause which allows only given exceptions to propagate:
class contextMan:
def __init__(self, exception):
self.exception = exception
def __enter__(self):
print("Entering Context")
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting Context")
return isinstance(exc_value, self.exception)
if __name__ == "__main__":
with contextMan(IndexError):
raise IndexError
This will now suppress any instances of IndexError
or any instance of a subclass of IndexError
resulting in output of:
Entering Context
Exiting Context
The downside to this approach is that you're adding an extra attribute to each instance and essentially combining two different logical tasks in a single object instead of segregating them.
The second option is more robust, explicit and general. It was created specifically for these sort of scenarios. It is also a context manager and, as such, can generally be used in any case where specific exceptions should get suppressed.
It's call signature is of the form:
contextlib.suppress(*exceptions)
Where *exceptions
is a tuple of exceptions to be suppressed. Keeping the original context manager as is, we can now create a nested context manager which also suppresses specific exceptions:
class contextMan:
def __enter__(self):
print("Entering Context")
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting Context")
if __name__ == "__main__":
with contextlib.suppress("IndexError")
with contextMan():
raise IndexError
Which could alternatively be written on the same line but that results in a rather lengthy statement. The obvious downside to this is that it introduces another statement each time you use the context manager.
Even though there are two options, there should be one-- and preferably only one --obvious way to do it and I believe the second one is the obvious way (at least for recent versions).