From the datamodel docs on context managers:
Note that
__exit__()
methods should not reraise the passed-in exception; this is the caller’s responsibility.
I have a temporary file, whose file descriptor I'd like to free with close
but without writing anything to disk. My intuitive solution was to pass on the exception, but that is discouraged in the docs - and surely for good reasons.
class Processor(object):
...
def write(self, *args, **kwargs):
if something_bad_happens:
raise RuntimeError('This format expects %s columns: %s, got %s.' % (
(len(self.cols), self.cols, len(args))))
self.writer.writerow(args)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
# the RuntimeError from write will be set as type, value and so on ..
# I'd like to close the stream here (release the file descriptor),
# but I do not leave a trace of the associated file -
# (one can always 'manually' delete with `os.remove` but maybe there's a
# better way ..?)
self.output_pipe.close()
Also I do not want in this particular case error handling in the caller for two reasons:
The context manager is used something like this:
class Worker(object):
...
def run(self):
# output setup so it will emit a three column CSV
with self.output().open('w') as output:
output.write('John', 'CA', 92101)
output.write('Jane', 'NY', 10304)
# should yield an error, since only three 'columns' are allowed
output.write('Hello', 'world')
update: My quesion was a bit ill-formulated as my problem really boiled down to this: In nested context managers, how can I pass an exception on to the outermost CM?
If an exception occurs during execution of the try clause, the exception may be handled by an except clause. If the exception is not handled by an except clause, the exception is re-raised after the finally clause has been executed.
Let's consider a situation where we want to raise an exception in response to catching a different exception but want to include information about both exceptions in the traceback. To chain exceptions, use the raise from statement instead of a simple raise statement. This will give you information about both errors.
A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. with open('/path/to/file.txt', 'r') as f: for line in f: print(line)
__exit__
returns True, any exception passed to it is swallowed.__exit__
returns False, the exception is reraised.def __exit__(self, type, value, traceback):
self.output_pipe.close() # always close the file
if type is not None: # an exception has occurred
os.unlink(...) # remove the file
return False # reraise the exception
You could of course omit the return False
since Python will return None
(which is Falsish) by default.
By the way, is self.output()
an instance of Processor
? If so,
with self.output().open('w') as output:
should be
with self.output() as output:
In any case, it would be nicer if you could arrange for the latter to be the correct syntax. You might have to change __enter__
to:
def __enter__(self):
return self.output_pipe.open('w')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With