mirror of https://github.com/pypa/pip
Add global TempDirectory manager
In cases where there is not a clear scope, or where enforcing a scope and passing a temp directory to callees creates unnecessary coupling between components, this will let us tie the lifetime of temporary directories to the lifetime of the application without using e.g. atexit or finalizers. This has the benefit of being easier to test and reason about.
This commit is contained in:
parent
cf743dd245
commit
0457826bd0
|
@ -8,17 +8,35 @@ import itertools
|
|||
import logging
|
||||
import os.path
|
||||
import tempfile
|
||||
from contextlib import contextmanager
|
||||
|
||||
from pip._vendor.contextlib2 import ExitStack
|
||||
|
||||
from pip._internal.utils.misc import rmtree
|
||||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
||||
|
||||
if MYPY_CHECK_RUNNING:
|
||||
from typing import Optional
|
||||
from typing import Iterator, Optional
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
_tempdir_manager = None # type: Optional[ExitStack]
|
||||
|
||||
|
||||
@contextmanager
|
||||
def global_tempdir_manager():
|
||||
# type: () -> Iterator[None]
|
||||
global _tempdir_manager
|
||||
with ExitStack() as stack:
|
||||
old_tempdir_manager, _tempdir_manager = _tempdir_manager, stack
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
_tempdir_manager = old_tempdir_manager
|
||||
|
||||
|
||||
class TempDirectory(object):
|
||||
"""Helper class that owns and cleans up a temporary directory.
|
||||
|
||||
|
@ -44,7 +62,8 @@ class TempDirectory(object):
|
|||
self,
|
||||
path=None, # type: Optional[str]
|
||||
delete=None, # type: Optional[bool]
|
||||
kind="temp"
|
||||
kind="temp", # type: str
|
||||
globally_managed=False, # type: bool
|
||||
):
|
||||
super(TempDirectory, self).__init__()
|
||||
|
||||
|
@ -61,6 +80,10 @@ class TempDirectory(object):
|
|||
self.delete = delete
|
||||
self.kind = kind
|
||||
|
||||
if globally_managed:
|
||||
assert _tempdir_manager is not None
|
||||
_tempdir_manager.enter_context(self)
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
# type: () -> str
|
||||
|
|
|
@ -5,8 +5,13 @@ import tempfile
|
|||
|
||||
import pytest
|
||||
|
||||
from pip._internal.utils import temp_dir
|
||||
from pip._internal.utils.misc import ensure_dir
|
||||
from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory
|
||||
from pip._internal.utils.temp_dir import (
|
||||
AdjacentTempDirectory,
|
||||
TempDirectory,
|
||||
global_tempdir_manager,
|
||||
)
|
||||
|
||||
|
||||
# No need to test symlinked directories on Windows
|
||||
|
@ -188,3 +193,17 @@ def test_adjacent_directory_permission_error(monkeypatch):
|
|||
with pytest.raises(OSError):
|
||||
with AdjacentTempDirectory(original):
|
||||
pass
|
||||
|
||||
|
||||
def test_global_tempdir_manager():
|
||||
with global_tempdir_manager():
|
||||
d = TempDirectory(globally_managed=True)
|
||||
path = d.path
|
||||
assert os.path.exists(path)
|
||||
assert not os.path.exists(path)
|
||||
|
||||
|
||||
def test_tempdirectory_asserts_global_tempdir(monkeypatch):
|
||||
monkeypatch.setattr(temp_dir, "_tempdir_manager", None)
|
||||
with pytest.raises(AssertionError):
|
||||
TempDirectory(globally_managed=True)
|
||||
|
|
Loading…
Reference in New Issue