Skip to content

Commit f2af7df

Browse files
committed
Use tempdir_registry to control auto-deleted files globally
Next we can actually transition some files to be globally-managed that are only deleted conditionally.
1 parent 45991bc commit f2af7df

File tree

3 files changed

+90
-6
lines changed

3 files changed

+90
-6
lines changed

src/pip/_internal/cli/base_command.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,21 @@
3434
from pip._internal.utils.filesystem import check_path_owner
3535
from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
3636
from pip._internal.utils.misc import get_prog, normalize_path
37-
from pip._internal.utils.temp_dir import global_tempdir_manager
37+
from pip._internal.utils.temp_dir import (
38+
global_tempdir_manager,
39+
tempdir_registry,
40+
)
3841
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
3942
from pip._internal.utils.virtualenv import running_under_virtualenv
4043

4144
if MYPY_CHECK_RUNNING:
42-
from typing import List, Tuple, Any
45+
from typing import List, Optional, Tuple, Any
4346
from optparse import Values
4447

48+
from pip._internal.utils.temp_dir import (
49+
TempDirectoryTypeRegistry as TempDirRegistry
50+
)
51+
4552
__all__ = ['Command']
4653

4754
logger = logging.getLogger(__name__)
@@ -68,6 +75,8 @@ def __init__(self, name, summary, isolated=False):
6875
self.summary = summary
6976
self.parser = ConfigOptionParser(**parser_kw)
7077

78+
self.tempdir_registry = None # type: Optional[TempDirRegistry]
79+
7180
# Commands should add options to this option group
7281
optgroup_name = '%s Options' % self.name.capitalize()
7382
self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)
@@ -108,6 +117,10 @@ def main(self, args):
108117

109118
def _main(self, args):
110119
# type: (List[str]) -> int
120+
# We must initialize this before the tempdir manager, otherwise the
121+
# configuration would not be accessible by the time we clean up the
122+
# tempdir manager.
123+
self.tempdir_registry = self.enter_context(tempdir_registry())
111124
# Intentionally set as early as possible so globally-managed temporary
112125
# directories are available to the rest of the code.
113126
self.enter_context(global_tempdir_manager())

tests/conftest.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import pytest
1212
import six
13-
from pip._vendor.contextlib2 import ExitStack
13+
from pip._vendor.contextlib2 import ExitStack, nullcontext
1414
from setuptools.wheel import Wheel
1515

1616
from pip._internal.cli.main import main as pip_entry_point
@@ -188,13 +188,18 @@ def isolate(tmpdir):
188188

189189

190190
@pytest.fixture(autouse=True)
191-
def scoped_global_tempdir_manager():
191+
def scoped_global_tempdir_manager(request):
192192
"""Make unit tests with globally-managed tempdirs easier
193193
194194
Each test function gets its own individual scope for globally-managed
195195
temporary directories in the application.
196196
"""
197-
with global_tempdir_manager():
197+
if "no_auto_tempdir_manager" in request.keywords:
198+
ctx = nullcontext
199+
else:
200+
ctx = global_tempdir_manager
201+
202+
with ctx():
198203
yield
199204

200205

tests/unit/test_base_command.py

+67-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
import os
33
import time
44

5-
from mock import patch
5+
import pytest
6+
from mock import Mock, patch
67

78
from pip._internal.cli.base_command import Command
9+
from pip._internal.cli.status_codes import SUCCESS
10+
from pip._internal.utils import temp_dir
811
from pip._internal.utils.logging import BrokenStdoutLoggingError
12+
from pip._internal.utils.temp_dir import TempDirectory
913

1014

1115
class FakeCommand(Command):
@@ -145,3 +149,65 @@ def test_unicode_messages(self, tmpdir):
145149
cmd = FakeCommandWithUnicode()
146150
log_path = tmpdir.joinpath('log')
147151
cmd.main(['fake_unicode', '--log', log_path])
152+
153+
154+
@pytest.mark.no_auto_tempdir_manager
155+
def test_base_command_provides_tempdir_helpers():
156+
assert temp_dir._tempdir_manager is None
157+
assert temp_dir._tempdir_registry is None
158+
159+
def assert_helpers_set(options, args):
160+
assert temp_dir._tempdir_manager is not None
161+
assert temp_dir._tempdir_registry is not None
162+
163+
c = Command("fake", "fake")
164+
c.run = Mock(side_effect=assert_helpers_set)
165+
assert c.main(["fake"]) == SUCCESS
166+
c.run.assert_called_once()
167+
168+
169+
not_deleted = "not_deleted"
170+
171+
172+
@pytest.mark.parametrize("kind,exists", [
173+
(not_deleted, True), ("deleted", False)
174+
])
175+
@pytest.mark.no_auto_tempdir_manager
176+
def test_base_command_global_tempdir_cleanup(kind, exists):
177+
assert temp_dir._tempdir_manager is None
178+
assert temp_dir._tempdir_registry is None
179+
180+
class Holder(object):
181+
value = None
182+
183+
def create_temp_dirs(options, args):
184+
c.tempdir_registry.set_delete(not_deleted, False)
185+
Holder.value = TempDirectory(kind=kind, globally_managed=True).path
186+
187+
c = Command("fake", "fake")
188+
c.run = Mock(side_effect=create_temp_dirs)
189+
assert c.main(["fake"]) == SUCCESS
190+
c.run.assert_called_once()
191+
assert os.path.exists(Holder.value) == exists
192+
193+
194+
@pytest.mark.parametrize("kind,exists", [
195+
(not_deleted, True), ("deleted", False)
196+
])
197+
@pytest.mark.no_auto_tempdir_manager
198+
def test_base_command_local_tempdir_cleanup(kind, exists):
199+
assert temp_dir._tempdir_manager is None
200+
assert temp_dir._tempdir_registry is None
201+
202+
def create_temp_dirs(options, args):
203+
c.tempdir_registry.set_delete(not_deleted, False)
204+
205+
with TempDirectory(kind=kind) as d:
206+
path = d.path
207+
assert os.path.exists(path)
208+
assert os.path.exists(path) == exists
209+
210+
c = Command("fake", "fake")
211+
c.run = Mock(side_effect=create_temp_dirs)
212+
assert c.main(["fake"]) == SUCCESS
213+
c.run.assert_called_once()

0 commit comments

Comments
 (0)