Refactor tmpdir directory removal process

This commit is contained in:
Yusuke Kadowaki 2022-11-27 01:39:21 +09:00
parent f513d33d5a
commit 5ae5efc332
3 changed files with 24 additions and 2 deletions

16
src/_pytest/callback.py Normal file
View File

@ -0,0 +1,16 @@
from typing import Any
from typing import Callable
from typing import List
from typing import Tuple
class Callback:
def __init__(self) -> None:
self._funcs: List[Tuple[Callable[..., Any], Any, Any]] = []
def register(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> None:
self._funcs.append((func, args, kwargs))
def execute(self) -> None:
for func, args, kwargs in reversed(self._funcs):
func(*args, **kwargs)

View File

@ -362,6 +362,7 @@ def make_numbered_dir_with_cleanup(
keep: int, keep: int,
lock_timeout: float, lock_timeout: float,
mode: int, mode: int,
register=atexit.register,
) -> Path: ) -> Path:
"""Create a numbered dir with a cleanup lock and remove old ones.""" """Create a numbered dir with a cleanup lock and remove old ones."""
e = None e = None
@ -371,13 +372,13 @@ def make_numbered_dir_with_cleanup(
# Only lock the current dir when keep is not 0 # Only lock the current dir when keep is not 0
if keep != 0: if keep != 0:
lock_path = create_cleanup_lock(p) lock_path = create_cleanup_lock(p)
register_cleanup_lock_removal(lock_path) register_cleanup_lock_removal(lock_path, register=register)
except Exception as exc: except Exception as exc:
e = exc e = exc
else: else:
consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout
# Register a cleanup for program exit # Register a cleanup for program exit
atexit.register( register(
cleanup_numbered_dir, cleanup_numbered_dir,
root, root,
prefix, prefix,

View File

@ -37,6 +37,7 @@ from _pytest.deprecated import check_ispytest
from _pytest.fixtures import fixture from _pytest.fixtures import fixture
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from _pytest.callback import Callback
tmppath_result_key = StashKey[Dict[str, bool]]() tmppath_result_key = StashKey[Dict[str, bool]]()
@ -77,6 +78,7 @@ class TempPathFactory:
self._retention_count = retention_count self._retention_count = retention_count
self._retention_policy = retention_policy self._retention_policy = retention_policy
self._basetemp = basetemp self._basetemp = basetemp
self._lock_and_dir_removal_callback = Callback()
@classmethod @classmethod
def from_config( def from_config(
@ -196,6 +198,7 @@ class TempPathFactory:
keep=keep, keep=keep,
lock_timeout=LOCK_TIMEOUT, lock_timeout=LOCK_TIMEOUT,
mode=0o700, mode=0o700,
register=self._lock_and_dir_removal_callback.register,
) )
assert basetemp is not None, basetemp assert basetemp is not None, basetemp
self._basetemp = basetemp self._basetemp = basetemp
@ -315,6 +318,8 @@ def pytest_sessionfinish(session, exitstatus: Union[int, ExitCode]):
# permissions, etc, in which case we ignore it. # permissions, etc, in which case we ignore it.
rmtree(passed_dir, ignore_errors=True) rmtree(passed_dir, ignore_errors=True)
tmp_path_factory._lock_and_dir_removal_callback.execute()
@hookimpl(tryfirst=True, hookwrapper=True) @hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item: Item, call): def pytest_runtest_makereport(item: Item, call):