I need to create a context manager that, when certain conditions are met, can be forced to exit early.
More details:
The context manager needs to handle checking/locking/releasing a resource. On __enter__, the context manager needs to check if the resource is locked. If it is, I'd like to have __exit__ called without executing the code in the context. Otherwise, the context manager acquires the resource, executes the context code, and cleans up the resource in __exit__.
It might look something like this:
class my_context_manager:
def __enter__(self):
if resource_locked():
self.__exit__(None, ResourceLockedException(), None)
else:
acquire_resource()
def __exit__(self, *exc_info):
if not isinstance(exc_info[1], ResourceLockedException):
release_resource()
else:
log.warn("Resource already in use.")
The code above doesn't actually work, however, because calling __exit__ inside of __enter__ doesn't stop the code within the context from being executed.
Alternatively, I could throw ResourceLockedException from within __enter__, but then __exit__ won't be called, since the exception would be thrown from the context manager itself. I'd like to be able to catch the exception, log a warning, and not enter the context if the resource is locked.
This comes down to finding some way of closing the context early, so that __exit__ is called and the context code isn't executed. Is there some way to tweak either of the ideas above to do this? Or is there another way?
Yes, you can't manually call
__exit__like this. One other alternative is simplyraisethe exception and let another construct manage it. You could either use atry-exceptor whip up another context manager to log these:and change your original context manager to:
And call it with:
Of course you could simply use a
try-exceptand nestwithinside that or use anifclause alternatively.