Skip to content

Commit 1ec2ef3

Browse files
authored
[ci] Try to fix Windows CI failures (#18145)
I often encounter test failures on Windows (failing tests are always related to `mypy` daemon). https://github.com/python/mypy/actions/runs/11783610549/job/32821129579 https://github.com/python/mypy/actions/runs/11767558564/job/32776369396 https://github.com/python/mypy/actions/runs/11763771676/job/32768172783 They always manifest as a `RecursionError` during test teardown, the following two frames are repeated many times: ``` ___________ ERROR at teardown of testDaemonRunIgnoreMissingImports ____________ [gw3] win32 -- Python 3.8.10 D:\a\mypy\mypy\.tox\py38\Scripts\python.EXE path = 'C:\Users\RUNNER~1\AppData\Local\Temp\mypy-test-6t6j6e1l\tmp' onerror = <function TemporaryDirectory._rmtree.<locals>.onerror at 0x00000250EE0F94C0> def _rmtree_unsafe(path, onerror): try: with os.scandir(path) as scandir_it: entries = list(scandir_it) except OSError: onerror(os.scandir, path, sys.exc_info()) entries = [] for entry in entries: fullname = entry.path if _rmtree_isdir(entry): try: if entry.is_symlink(): # This can only happen if someone replaces # a directory with a symlink after the call to # os.scandir or entry.is_dir above. raise OSError("Cannot call rmtree on a symbolic link") except OSError: onerror(os.path.islink, fullname, sys.exc_info()) continue _rmtree_unsafe(fullname, onerror) else: try: os.unlink(fullname) except OSError: onerror(os.unlink, fullname, sys.exc_info()) try: > os.rmdir(path) E PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\Users\RUNNER~1\AppData\Local\Temp\mypy-test-6t6j6e1l\tmp' C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\shutil.py:620: PermissionError During handling of the above exception, another exception occurred: func = <built-in function rmdir> path = 'C:\Users\RUNNER~1\AppData\Local\Temp\mypy-test-6t6j6e1l\tmp' exc_info = (<class 'PermissionError'>, PermissionError(13, 'The process cannot access the file because it is being used by another process'), <traceback object at 0x00000250EEB52A80>) def onerror(func, path, exc_info): if issubclass(exc_info[0], PermissionError): def resetperms(path): try: _os.chflags(path, 0) except AttributeError: pass _os.chmod(path, 0o700) try: if path != name: resetperms(_os.path.dirname(path)) resetperms(path) try: > _os.unlink(path) E PermissionError: [WinError 5] Access is denied: 'C:\Users\RUNNER~1\AppData\Local\Temp\mypy-test-6t6j6e1l\tmp' C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\tempfile.py:802: PermissionError ``` This likely can be solved by `TemporaryDirectory.ignore_cleanup_errors` but it is only available on 3.10+. I hope this PR does not mask any real deficiency - those failures are extremely annoying.
1 parent f067db4 commit 1ec2ef3

File tree

2 files changed

+10
-13
lines changed

2 files changed

+10
-13
lines changed

mypy/test/data.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def __init__(
304304
self.data = data
305305
self.line = line
306306
self.old_cwd: str | None = None
307-
self.tmpdir: tempfile.TemporaryDirectory[str] | None = None
307+
self.tmpdir: str | None = None
308308

309309
def runtest(self) -> None:
310310
if self.skip:
@@ -323,19 +323,19 @@ def runtest(self) -> None:
323323
save_dir: str | None = self.config.getoption("--save-failures-to", None)
324324
if save_dir:
325325
assert self.tmpdir is not None
326-
target_dir = os.path.join(save_dir, os.path.basename(self.tmpdir.name))
326+
target_dir = os.path.join(save_dir, os.path.basename(self.tmpdir))
327327
print(f"Copying data from test {self.name} to {target_dir}")
328328
if not os.path.isabs(target_dir):
329329
assert self.old_cwd
330330
target_dir = os.path.join(self.old_cwd, target_dir)
331-
shutil.copytree(self.tmpdir.name, target_dir)
331+
shutil.copytree(self.tmpdir, target_dir)
332332
raise
333333

334334
def setup(self) -> None:
335335
parse_test_case(case=self)
336336
self.old_cwd = os.getcwd()
337-
self.tmpdir = tempfile.TemporaryDirectory(prefix="mypy-test-")
338-
os.chdir(self.tmpdir.name)
337+
self.tmpdir = tempfile.mkdtemp(prefix="mypy-test-")
338+
os.chdir(self.tmpdir)
339339
os.mkdir(test_temp_dir)
340340

341341
# Precalculate steps for find_steps()
@@ -371,10 +371,7 @@ def teardown(self) -> None:
371371
if self.old_cwd is not None:
372372
os.chdir(self.old_cwd)
373373
if self.tmpdir is not None:
374-
try:
375-
self.tmpdir.cleanup()
376-
except OSError:
377-
pass
374+
shutil.rmtree(self.tmpdir, ignore_errors=True)
378375
self.old_cwd = None
379376
self.tmpdir = None
380377

mypy/test/testfinegrained.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ def run_case(self, testcase: DataDrivenTestCase) -> None:
101101
if messages:
102102
a.extend(normalize_messages(messages))
103103

104-
assert testcase.tmpdir
105-
a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir.name))
104+
assert testcase.tmpdir is not None
105+
a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir))
106106
a.extend(self.maybe_inspect(step, server, main_src))
107107

108108
if server.fine_grained_manager:
@@ -248,8 +248,8 @@ def perform_step(
248248
new_messages = normalize_messages(new_messages)
249249

250250
a = new_messages
251-
assert testcase.tmpdir
252-
a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir.name))
251+
assert testcase.tmpdir is not None
252+
a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir))
253253
a.extend(self.maybe_inspect(step, server, main_src))
254254

255255
return a, triggered

0 commit comments

Comments
 (0)