I am trying to achieve something similar to
from tempfile import TemporaryFile
def open_head(file_path):
with open(file_path, 'r') as f,
TemporaryFile() as tf:
for i in range(0,10):
tf.write(f.read_line())
return tf
such that the caller gets ownership of the temporary file.
In particular, I don't want the with
statement to close the TemporaryFile
. But if anything goes wrong before the return
, I still want the TemporaryFile
be closed by the with
statement.
Ideally, I would then want to write the caller as
with open_head(file_path):
# more code here
Is this possible somehow? E.g. by writing return do_not_close(tf)
or some other utility functionality?
Or am I approaching this completely wrong and there is a more Pythonic way to return a TemporaryFiles
or other resources, between functions while guaranteeing exception safety?
You don't. open_head
should take an already opened handle, which the caller is responsible for closing.
from tempfile import TemporaryFile
from itertools import islice
def head(file_path, fh):
with open(file_path) as f:
for line in islice(f, 10):
fh.write(line)
with TemporaryFile() as tf:
head(file_path, tf)
# Do other stuff with tf before it gets closed.
In general, anytime you are opening a file in an function, ask yourself if you can push the actual open up to the caller and accept a file-like object instead. Aside from making your code more reusable, it makes your code easier to test. head
doesn't have to be called with an actual file: it can be called with any file-like object, such as io.StringIO
.
Put another way: the with
statement enforces the advice
If you open the file, you are responsible for closing it as well.
The contrapositive of that advice is
If you aren't responsible for closing the file, you aren't responsible for opening the file, either.
Just move the TemporaryFile
outside the context manager and wrap it in a try except
block
from tempfile import TemporaryFile
def open_head(path: str):
try:
tf = TemporaryFile()
with open(path, "r") as f:
for _ in range(10):
tf.write(f.readline())
return tf
except Exception as e:
tf.close()
raise e
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