Custom 'with Open()' Statement In Python: Generator Didn't Yield Error
Solution 1:
Try this:
@contextmanagerdefopen(self):
try:
yieldopen(os.path.join(self.directory, self.name), self.flags)
except Exception as e:
print(e.__traceback__)
Context managers are generators, not functions.
Solution 2:
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
@contextmanagerdefmyopen(path):
try:
yieldopen(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.
@contextmanagerdefmyopen(path):
try:
withopen(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.
Post a Comment for "Custom 'with Open()' Statement In Python: Generator Didn't Yield Error"