You were right about the TemporaryDirectory. There is also an interesting issue with BaseExceptions that's leading to an AttributeError. I filed two bugs: http://bugs.python.org/issue22427 http://bugs.python.org/issue22428
On Sat, Sep 6, 2014 at 9:39 PM, Guido van Rossum <[email protected]> wrote: > Wow. Good catch! I had four different theories about this, and none of > them held up. Two things are suspect: the logic in TemporaryDirectory to > ensure cleanup (there are two separate mechanisms), and the fact that > KeyboardError is not a subclass of Exception (only of BaseException). > > The latter means that many try/except clauses in asyncio don't get > triggered, because (intentionally) it uses "except Exception:" instead of a > bare except clause. This probably causes the main() generator to be > abandoned by the asyncio scheduler, so the context manager's __exit__ isn't > called, and instead the cleanup path via the weak reference removes the > directory during some GC step. But then at a later GC step the main() > generator is finalized, which throws GeneratorExit into the generator, > which causes __exit__ to be called -- and it attempts to clean up a second > time. I think. > > I suspect that the real bug is that TemporaryDirectory assumes that the > __exit__ clause is always reached before the finalizer cleans up, and > apparently that is violated here, during end-of-program GC. You can put > some print calls in to debug this further. > > Please do file this as a bug on bugs.python.org! > > --Guido > > > On Sat, Sep 6, 2014 at 5:49 PM, Jack O'Connor <[email protected]> > wrote: > >> I have the following test script: >> >> import asyncio >> import tempfile >> >> @asyncio.coroutine >> def error(): >> raise KeyboardInterrupt() >> >> @asyncio.coroutine >> def main(): >> with tempfile.TemporaryDirectory(): >> yield from asyncio.gather(error()) # gather() is important here >> >> loop = asyncio.get_event_loop() >> loop.run_until_complete(main()) >> >> >> When I run that, I get several tracebacks in a row, and one of them is >> inexplicable to me: >> >> Exception ignored in: <generator object main at 0x7fccf7a48ee8> >> Traceback (most recent call last): >> File "test.py", line 11, in main >> File "/usr/lib/python3.4/tempfile.py", line 691, in __exit__ >> File "/usr/lib/python3.4/tempfile.py", line 697, in cleanup >> File "/usr/lib/python3.4/shutil.py", line 454, in rmtree >> File "/usr/lib/python3.4/shutil.py", line 452, in rmtree >> FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpl2z0vwdy' >> >> >> When the TemporaryDirectory context manager exits, it tries to clean up >> the directory it created. In this case, something appears to have already >> deleted that directory. There's no other rmdir() or anything like that in >> the script, so I'm confused. This part of the traceback goes away if I >> remove the gather() in there and instead yield directly from my error() >> coro. This also doesn't repro if I throw a RuntimeError instead of a >> KeyboardInterrupt. >> >> Could gather() be removing a directory? Or maybe making my context >> manager exit twice? >> > > > > -- > --Guido van Rossum (python.org/~guido) >
