-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-29982: Add "ignore_cleanup_errors" param to tempfile.TemporaryDirectory() #24793
bpo-29982: Add "ignore_cleanup_errors" param to tempfile.TemporaryDirectory() #24793
Conversation
Not sure why |
Yeah, rumor has it that test_asyncio is flaky. |
Maybe on non Windows you can force failure by creating a subdirectory and set its permissions to zero? (Or at least x555.) |
Thanks @gvanrossum ! Actually, that was my first thought as well, but If there aren't any better ideas, I see two options:
Thoughts? |
You could use unittest.mock to patch unlink, but that would provide very limited value if it's as hard as you say to trigger this condition. So I am fine with just testing this on Windows. |
Thanks; I vaguely recalled I went ahead with the first option, setting the expected value of cleanup based on OS. If any other esoteric supported platforms still have errors attempting to clean up files locked by opening, it will show up when tested by the buildbot fleet, and we can revise the test accordingly to include them. Alternatively, we can explicitly limit the entire test to just Windows, which is cleaner but less comprehensive—but like you say, not sure it makes a huge difference either way. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, let's go with this.
Thanks @gvanrossum! |
We were getting errors like `PermissionError: [WinError 5] Access is denied: 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\resume.md_k098zhaj\\CrashpadMetrics-active.pma'` and `Exception ignored in: <finalize object at 0x16d9e039d60; dead> ... NotADirectoryError: [WinError 267] The directory name is invalid: 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\resume.md_3aoun3f2\\CrashpadMetrics-active.pma'` in CI on Windows. See e.g. https://github.com/mikepqr/resume.md/runs/5172290981 and https://github.com/mikepqr/resume.md/runs/5172234014. The root cause was that Chrome creates a file the python process does not have permission to delete. See puppeteer/puppeteer#2778. Because TemporaryDirectory is intended to be used as a context manager there is no way to prevent it logging an error when cleanup fails. The fix is to switch to the lower level tempfile.mkdtemp, and make a good faith attempt to clean it up manually, logging failure at the debug level (while adding a new --debug option). A more sophisticated fix would be to backport the new ignore_cleanup_errors option added in python 3.10 (python/cpython#24793), but this will do. Fixes #13
We were getting errors like `PermissionError: [WinError 5] Access is denied: 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\resume.md_k098zhaj\\CrashpadMetrics-active.pma'` and `Exception ignored in: <finalize object at 0x16d9e039d60; dead> ... NotADirectoryError: [WinError 267] The directory name is invalid: 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\resume.md_3aoun3f2\\CrashpadMetrics-active.pma'` in CI on Windows. See e.g. https://github.com/mikepqr/resume.md/runs/5172290981 and https://github.com/mikepqr/resume.md/runs/5172234014. The root cause was that Chrome creates a file the python process does not have permission to delete. See puppeteer/puppeteer#2778. Because TemporaryDirectory is intended to be used as a context manager there is no way to prevent it logging an error when cleanup fails. The fix is to switch to the lower level tempfile.mkdtemp, and make a good faith attempt to clean it up manually, logging failure at the debug level (while adding a new --debug option). A more sophisticated fix would be to backport the new ignore_cleanup_errors option added in python 3.10 (python/cpython#24793), but this will do. Fixes #13
We were getting errors like `PermissionError: [WinError 5] Access is denied: 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\resume.md_k098zhaj\\CrashpadMetrics-active.pma'` and `Exception ignored in: <finalize object at 0x16d9e039d60; dead> ... NotADirectoryError: [WinError 267] The directory name is invalid: 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\resume.md_3aoun3f2\\CrashpadMetrics-active.pma'` in CI on Windows. See e.g. https://github.com/mikepqr/resume.md/runs/5172290981 and https://github.com/mikepqr/resume.md/runs/5172234014. The root cause was that Chrome creates a file the python process does not have permission to delete. See puppeteer/puppeteer#2778. Because TemporaryDirectory is intended to be used as a context manager there is no way to prevent it logging an error when cleanup fails. The fix is to switch to the lower level tempfile.mkdtemp, and make a good faith attempt to clean it up manually, logging failure at the debug level (while adding a new --debug option). A more sophisticated fix would be to backport the new ignore_cleanup_errors option added in python 3.10 (python/cpython#24793), but this will do. Fixes #13
Resolves bpo-29982 by adding an
ignore_cleanup_errors
parameter totempfile.TemporaryDirectory()
, which allows for a best-effort cleanup without stopping on errors, such asPermissionError
s on Windows due to files being open, transient access failures or other runtime exceptions. This behavior matches that when passingignore_errors=True
toshutil.rmtree
, and allows using the nicer higher-level interface, context-manager support and more robust removal implementation oftempfile.TemporaryDirectory()
to clean up as much of the temporary directory as possible, without stopping and raising an exception mid-cleanup, which can otherwise potentially occur at a non-deterministic time when the directory is garbage-collected, or during interpreter shutdown.Additionally, as the other part of the issue described in bpo-29982 (and as required for the tests and many real-world use cases), ensures that
cleanup()
runs correctly on subsequent attempts if the directory was not completely cleaned up after the first call, instead of silently (and surprisingly to the user) failing to do anything at all.Example use cases for this include regebro/pyroma#28 (which prompted this proposal), the original scenario described in bpo-29982 , and one of the two use cases described by @asottile in bpo-25024 Since I assume everything will be squashed to one commit anyway, I've split this up into several to make it easier to review and modify.
Key implementation questions to draw reviewer attention to:
ignore_cleanup_errors
or something else? Its on the long side, but the shorter alternatives I considered (e.g.ignore_errors
) were not as clear and descriptive.ignore_errors
is whatshutil.rmtree
uses but given its in theTemporaryDirectory
constructor, it could otherwise mislead users into thinking that errors creating the temporary directory would be ignored, when in fact this is only the case for cleanup.ignore_errors
optional parameter tocleanup()
as well? This would be a simple but useful addition so calling code can explicitly specify at manual cleanup time whether they want an error to be returned, rather than being locked in to one or the other after object creation (and would allow for more robust unit tests), but I didn't add it yet to avoid it getting out of scope.ignore_errors=True
is tested with errors on Windows, and without them on Linux and macOS. Is there a straightforward way to ensure an error will occur on *nix, in a way that the existing cleanup code cannot handle? Maybe OS-specific locks?cleanup
), but I do see some other entries related to adding new parameters to callables, so I'm not sure.Thanks!
https://bugs.python.org/issue29982