Was going to comment but things turn out to be too complicated to leave there, but I do have an answer.
The corrected version of code can be reduced to essentially this
@contextmanager
def myopen(path):
try:
yield open(path)
except Exception as e:
print(e.__traceback__)
Before we try, let's get a count of open file handles using this:
>>> os.listdir('/proc/self/fd')
['0', '1', '2', '3']
Now use our context manager
>>> with myopen('/tmp/a_file') as f:
... print(f.read())
... print(os.listdir('/proc/self/fd'))
...
Contents of file
['0', '1', '2', '3', '4']
Yup, file descriptor count increased, but now that we are out of our context manager, let's see
>>> print(os.listdir('/proc/self/fd'))
['0', '1', '2', '3', '4']
Uh that defeats the purpose of having a context manager for the file (we want to use the default autoclosing function, so restart the interpreter, and try this.
@contextmanager
def myopen(path):
try:
with open(path) as f:
yield f
except Exception as e:
print(e.__traceback__)
Rerun our tests
>>> with myopen('/tmp/a_file') as f:
... print(f.read())
... print(os.listdir('/proc/self/fd'))
...
Contents of file
['0', '1', '2', '3', '4']
Now outside the context manager
>>> print(os.listdir('/proc/self/fd'))
['0', '1', '2', '3']
Yay, looks like it worked (file is successfully closed), but what about a path that does not exist to see that exception handling?
>>> with myopen('/tmp/no_path') as f:
... print(f.read())
...
<traceback object at 0x7f6b64b618c8>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/contextlib.py", line 61, in __enter__
raise RuntimeError("generator didn't yield") from None
RuntimeError: generator didn't yield
The exception block did fire, note that traceback object, but then since the context manager did not correctly yield, a different exception is raised like what you saw before. I don't know what to recommend, but what I recommend is log the error (using a logger) and then reraise the exception. You could consider returning a dummy object of some kind that will then raise the exception when read, or return nothing, but you need to decide on what exactly is best for your case.
opento avoid confusion