I'd like to make a program which saves intermediate results to be able to reuse them is case of crash.
In this regard, I wanted to try to open the intermediate results file with a context manager. However basic context manager do not include error handling and basic error handling do not include context management. So I was forced to write my own context manager - which works fairly well, but I do not feel like the result is very pythonicly satifying
import subprocess
import contextlib
import sys
@contextlib.contextmanager
def myopen(cmd, filename):
try: f = open(filename, 'r')
except FileNotFoundError: pass
# I didn't put the file creation here to prevent the risk of
# causing an exception during the handling of the previous one
else:
yield f
f.close()
return
print(f'creating new {filename}', file=sys.stderr, flush=True)
sp = subprocess.run(cmd, shell=True, executable='/bin/bash')
try: f = open(filename, 'r')
except: raise
else:
yield f
f.close()
Which I test with
filename = "./context_exception.data"
print(f'removing {filename}', file=sys.stderr, flush=True)
sp = subprocess.run("rm "+filename, shell=True, executable='/bin/bash')
cmd = "echo -e 'spam\\neggs' >"+filename
with myopen(cmd, filename) as f:
lines=f.readlines()
for i, line in enumerate(lines):
print(f'line{i:02}={line}', end='')
cmd = "echo -e 'ham\\nbanana' >"+filename
with myopen(cmd, filename) as f:
lines=f.readlines()
for i, line in enumerate(lines):
print(f'line{i:02}={line}', end='')
print(f'removing {filename}', file=sys.stderr, flush=True)
sp = subprocess.run("rm "+filename, shell=True, executable='/bin/bash')
with myopen(cmd, filename) as f:
lines=f.readlines()
for i, line in enumerate(lines):
print(f'line{i:02}={line}', end='')
Is there any nicer way to combine context manager and exception handling, without having to manually rewrite the context manager ? And by the way, I'm not very satisfied of the bulkiness of my context manager. Any idea about how to make it more compact would be welcome.
EDIT (Addendum)
Obviously, as @PeterWood noticed, I could, just test the existence beforehand, and then wouldn't even need neither to rewrite a context manager nor any exception handling:
import subprocess
import os
import sys
def create_if_nonexistent(cmd, filename):
if not os.path.isfile(filename):
print(f'creating new {filename}', file=sys.stderr, flush=True)
sp = subprocess.run(cmd, shell=True, executable='/bin/bash')
filename = "./context_exception.data"
print(f'removing {filename}', file=sys.stderr, flush=True)
sp = subprocess.run("rm "+filename, shell=True, executable='/bin/bash')
cmd = "echo -e 'spam\\neggs' >"+filename
create_if_nonexistent(cmd, filename)
with open(filename) as f:
lines=f.readlines()
for i, line in enumerate(lines):
print(f'line{i:02}={line}', end='')
cmd = "echo -e 'ham\\nbanana' >"+filename
create_if_nonexistent(cmd, filename)
with open(filename) as f:
lines=f.readlines()
for i, line in enumerate(lines):
print(f'line{i:02}={line}', end='')
print(f'removing {filename}', file=sys.stderr, flush=True)
sp = subprocess.run("rm "+filename, shell=True, executable='/bin/bash')
create_if_nonexistent(cmd, filename)
with open(filename) as f:
lines=f.readlines()
for i, line in enumerate(lines):
print(f'line{i:02}={line}', end='')
However
- I wanted to try this, because using error handling is the generally considered pythonic way of doing those things and
- the question is about how to properly combine both of them in order to learn more about python and not about how to work around the example without actually solving the problem.