mirror of https://github.com/python/cpython
Close #15415: Factor out temp dir helpers to test.support
Patch by Chris Jerdonek
This commit is contained in:
parent
69e3bda310
commit
5517596c04
|
@ -387,18 +387,40 @@ The :mod:`test.support` module defines the following functions:
|
|||
self.assertEqual(captured, "hello")
|
||||
|
||||
|
||||
.. function:: temp_cwd(name='tempcwd', quiet=False, path=None)
|
||||
.. function:: temp_dir(path=None, quiet=False)
|
||||
|
||||
A context manager that creates a temporary directory at *path* and
|
||||
yields the directory.
|
||||
|
||||
If *path* is None, the temporary directory is created using
|
||||
:func:`tempfile.mkdtemp`. If *quiet* is ``False``, the context manager
|
||||
raises an exception on error. Otherwise, if *path* is specified and
|
||||
cannot be created, only a warning is issued.
|
||||
|
||||
|
||||
.. function:: change_cwd(path, quiet=False)
|
||||
|
||||
A context manager that temporarily changes the current working
|
||||
directory (CWD).
|
||||
directory to *path* and yields the directory.
|
||||
|
||||
An existing path may be provided as *path*, in which case this function
|
||||
makes no changes to the file system.
|
||||
If *quiet* is ``False``, the context manager raises an exception
|
||||
on error. Otherwise, it issues only a warning and keeps the current
|
||||
working directory the same.
|
||||
|
||||
Otherwise, the new CWD is created in the current directory and it's named
|
||||
*name*. If *quiet* is ``False`` and it's not possible to create or
|
||||
change the CWD, an error is raised. If it's ``True``, only a warning
|
||||
is raised and the original CWD is used.
|
||||
|
||||
.. function:: temp_cwd(name='tempcwd', quiet=False)
|
||||
|
||||
A context manager that temporarily creates a new directory and
|
||||
changes the current working directory (CWD).
|
||||
|
||||
The context manager creates a temporary directory in the current
|
||||
directory with name *name* before temporarily changing the current
|
||||
working directory. If *name* is None, the temporary directory is
|
||||
created using :func:`tempfile.mkdtemp`.
|
||||
|
||||
If *quiet* is ``False`` and it is not possible to create or change
|
||||
the CWD, an error is raised. Otherwise, only a warning is raised
|
||||
and the original CWD is used.
|
||||
|
||||
|
||||
.. function:: temp_umask(umask)
|
||||
|
|
|
@ -13,7 +13,7 @@ import shutil
|
|||
import zipfile
|
||||
|
||||
from imp import source_from_cache
|
||||
from test.support import make_legacy_pyc, strip_python_stderr
|
||||
from test.support import make_legacy_pyc, strip_python_stderr, temp_dir
|
||||
|
||||
# Executing the interpreter in a subprocess
|
||||
def _assert_python(expected_success, *args, **env_vars):
|
||||
|
@ -77,16 +77,6 @@ def kill_python(p):
|
|||
subprocess._cleanup()
|
||||
return data
|
||||
|
||||
# Script creation utilities
|
||||
@contextlib.contextmanager
|
||||
def temp_dir():
|
||||
dirname = tempfile.mkdtemp()
|
||||
dirname = os.path.realpath(dirname)
|
||||
try:
|
||||
yield dirname
|
||||
finally:
|
||||
shutil.rmtree(dirname)
|
||||
|
||||
def make_script(script_dir, script_basename, source):
|
||||
script_filename = script_basename+os.extsep+'py'
|
||||
script_name = os.path.join(script_dir, script_filename)
|
||||
|
|
|
@ -738,45 +738,85 @@ else:
|
|||
SAVEDCWD = os.getcwd()
|
||||
|
||||
@contextlib.contextmanager
|
||||
def temp_cwd(name='tempcwd', quiet=False, path=None):
|
||||
"""
|
||||
Context manager that temporarily changes the CWD.
|
||||
def temp_dir(path=None, quiet=False):
|
||||
"""Return a context manager that creates a temporary directory.
|
||||
|
||||
An existing path may be provided as *path*, in which case this
|
||||
function makes no changes to the file system.
|
||||
Arguments:
|
||||
|
||||
path: the directory to create temporarily. If omitted or None,
|
||||
defaults to creating a temporary directory using tempfile.mkdtemp.
|
||||
|
||||
quiet: if False (the default), the context manager raises an exception
|
||||
on error. Otherwise, if the path is specified and cannot be
|
||||
created, only a warning is issued.
|
||||
|
||||
Otherwise, the new CWD is created in the current directory and it's
|
||||
named *name*. If *quiet* is False (default) and it's not possible to
|
||||
create or change the CWD, an error is raised. If it's True, only a
|
||||
warning is raised and the original CWD is used.
|
||||
"""
|
||||
saved_dir = os.getcwd()
|
||||
is_temporary = False
|
||||
dir_created = False
|
||||
if path is None:
|
||||
path = name
|
||||
path = tempfile.mkdtemp()
|
||||
dir_created = True
|
||||
path = os.path.realpath(path)
|
||||
else:
|
||||
try:
|
||||
os.mkdir(name)
|
||||
is_temporary = True
|
||||
os.mkdir(path)
|
||||
dir_created = True
|
||||
except OSError:
|
||||
if not quiet:
|
||||
raise
|
||||
warnings.warn('tests may fail, unable to create temp CWD ' + name,
|
||||
warnings.warn('tests may fail, unable to create temp dir: ' + path,
|
||||
RuntimeWarning, stacklevel=3)
|
||||
try:
|
||||
yield path
|
||||
finally:
|
||||
if dir_created:
|
||||
shutil.rmtree(path)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def change_cwd(path, quiet=False):
|
||||
"""Return a context manager that changes the current working directory.
|
||||
|
||||
Arguments:
|
||||
|
||||
path: the directory to use as the temporary current working directory.
|
||||
|
||||
quiet: if False (the default), the context manager raises an exception
|
||||
on error. Otherwise, it issues only a warning and keeps the current
|
||||
working directory the same.
|
||||
|
||||
"""
|
||||
saved_dir = os.getcwd()
|
||||
try:
|
||||
os.chdir(path)
|
||||
except OSError:
|
||||
if not quiet:
|
||||
raise
|
||||
warnings.warn('tests may fail, unable to change the CWD to ' + path,
|
||||
warnings.warn('tests may fail, unable to change CWD to: ' + path,
|
||||
RuntimeWarning, stacklevel=3)
|
||||
try:
|
||||
yield os.getcwd()
|
||||
finally:
|
||||
os.chdir(saved_dir)
|
||||
if is_temporary:
|
||||
rmtree(name)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def temp_cwd(name='tempcwd', quiet=False):
|
||||
"""
|
||||
Context manager that temporarily creates and changes the CWD.
|
||||
|
||||
The function temporarily changes the current working directory
|
||||
after creating a temporary directory in the current directory with
|
||||
name *name*. If *name* is None, the temporary directory is
|
||||
created using tempfile.mkdtemp.
|
||||
|
||||
If *quiet* is False (default) and it is not possible to
|
||||
create or change the CWD, an error is raised. If *quiet* is True,
|
||||
only a warning is raised and the original CWD is used.
|
||||
|
||||
"""
|
||||
with temp_dir(path=name, quiet=quiet) as temp_path:
|
||||
with change_cwd(temp_path, quiet=quiet) as cwd_dir:
|
||||
yield cwd_dir
|
||||
|
||||
if hasattr(os, "umask"):
|
||||
@contextlib.contextmanager
|
||||
def temp_umask(umask):
|
||||
|
|
|
@ -290,7 +290,7 @@ class CmdLineTest(unittest.TestCase):
|
|||
# Make sure package __init__ modules see "-m" in sys.argv0 while
|
||||
# searching for the module to execute
|
||||
with temp_dir() as script_dir:
|
||||
with support.temp_cwd(path=script_dir):
|
||||
with support.change_cwd(path=script_dir):
|
||||
pkg_dir = os.path.join(script_dir, 'test_pkg')
|
||||
make_pkg(pkg_dir, "import sys; print('init_argv0==%r' % sys.argv[0])")
|
||||
script_name = _make_test_script(pkg_dir, 'script')
|
||||
|
@ -307,7 +307,7 @@ class CmdLineTest(unittest.TestCase):
|
|||
# Make sure a "-c" file in the current directory
|
||||
# does not alter the value of sys.path[0]
|
||||
with temp_dir() as script_dir:
|
||||
with support.temp_cwd(path=script_dir):
|
||||
with support.change_cwd(path=script_dir):
|
||||
with open("-c", "w") as f:
|
||||
f.write("data")
|
||||
rc, out, err = assert_python_ok('-c',
|
||||
|
@ -322,7 +322,7 @@ class CmdLineTest(unittest.TestCase):
|
|||
# does not alter the value of sys.path[0]
|
||||
with temp_dir() as script_dir:
|
||||
script_name = _make_test_script(script_dir, 'other')
|
||||
with support.temp_cwd(path=script_dir):
|
||||
with support.change_cwd(path=script_dir):
|
||||
with open("-m", "w") as f:
|
||||
f.write("data")
|
||||
rc, out, err = assert_python_ok('-m', 'other', *example_args)
|
||||
|
@ -335,7 +335,7 @@ class CmdLineTest(unittest.TestCase):
|
|||
# and results in an error that the return code to the
|
||||
# shell is '1'
|
||||
with temp_dir() as script_dir:
|
||||
with support.temp_cwd(path=script_dir):
|
||||
with support.change_cwd(path=script_dir):
|
||||
pkg_dir = os.path.join(script_dir, 'test_pkg')
|
||||
make_pkg(pkg_dir)
|
||||
script_name = _make_test_script(pkg_dir, 'other',
|
||||
|
|
|
@ -1307,18 +1307,18 @@ class TestWhich(unittest.TestCase):
|
|||
# that exists, it should be returned.
|
||||
base_dir, tail_dir = os.path.split(self.dir)
|
||||
relpath = os.path.join(tail_dir, self.file)
|
||||
with support.temp_cwd(path=base_dir):
|
||||
with support.change_cwd(path=base_dir):
|
||||
rv = shutil.which(relpath, path=self.temp_dir)
|
||||
self.assertEqual(rv, relpath)
|
||||
# But it shouldn't be searched in PATH directories (issue #16957).
|
||||
with support.temp_cwd(path=self.dir):
|
||||
with support.change_cwd(path=self.dir):
|
||||
rv = shutil.which(relpath, path=base_dir)
|
||||
self.assertIsNone(rv)
|
||||
|
||||
def test_cwd(self):
|
||||
# Issue #16957
|
||||
base_dir = os.path.dirname(self.dir)
|
||||
with support.temp_cwd(path=self.dir):
|
||||
with support.change_cwd(path=self.dir):
|
||||
rv = shutil.which(self.file, path=base_dir)
|
||||
if sys.platform == "win32":
|
||||
# Windows: current directory implicitly on PATH
|
||||
|
@ -1339,7 +1339,7 @@ class TestWhich(unittest.TestCase):
|
|||
|
||||
def test_relative_path(self):
|
||||
base_dir, tail_dir = os.path.split(self.dir)
|
||||
with support.temp_cwd(path=base_dir):
|
||||
with support.change_cwd(path=base_dir):
|
||||
rv = shutil.which(self.file, path=tail_dir)
|
||||
self.assertEqual(rv, os.path.join(tail_dir, self.file))
|
||||
|
||||
|
@ -1364,7 +1364,7 @@ class TestWhich(unittest.TestCase):
|
|||
|
||||
def test_empty_path(self):
|
||||
base_dir = os.path.dirname(self.dir)
|
||||
with support.temp_cwd(path=self.dir), \
|
||||
with support.change_cwd(path=self.dir), \
|
||||
support.EnvironmentVarGuard() as env:
|
||||
env['PATH'] = self.dir
|
||||
rv = shutil.which(self.file, path='')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import importlib
|
||||
import shutil
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
|
@ -88,6 +89,118 @@ class TestSupport(unittest.TestCase):
|
|||
s.listen(1)
|
||||
s.close()
|
||||
|
||||
# Tests for temp_dir()
|
||||
|
||||
def test_temp_dir(self):
|
||||
"""Test that temp_dir() creates and destroys its directory."""
|
||||
parent_dir = tempfile.mkdtemp()
|
||||
parent_dir = os.path.realpath(parent_dir)
|
||||
|
||||
try:
|
||||
path = os.path.join(parent_dir, 'temp')
|
||||
self.assertFalse(os.path.isdir(path))
|
||||
with support.temp_dir(path) as temp_path:
|
||||
self.assertEqual(temp_path, path)
|
||||
self.assertTrue(os.path.isdir(path))
|
||||
self.assertFalse(os.path.isdir(path))
|
||||
finally:
|
||||
shutil.rmtree(parent_dir)
|
||||
|
||||
def test_temp_dir__path_none(self):
|
||||
"""Test passing no path."""
|
||||
with support.temp_dir() as temp_path:
|
||||
self.assertTrue(os.path.isdir(temp_path))
|
||||
self.assertFalse(os.path.isdir(temp_path))
|
||||
|
||||
def test_temp_dir__existing_dir__quiet_default(self):
|
||||
"""Test passing a directory that already exists."""
|
||||
def call_temp_dir(path):
|
||||
with support.temp_dir(path) as temp_path:
|
||||
raise Exception("should not get here")
|
||||
|
||||
path = tempfile.mkdtemp()
|
||||
path = os.path.realpath(path)
|
||||
try:
|
||||
self.assertTrue(os.path.isdir(path))
|
||||
self.assertRaises(FileExistsError, call_temp_dir, path)
|
||||
# Make sure temp_dir did not delete the original directory.
|
||||
self.assertTrue(os.path.isdir(path))
|
||||
finally:
|
||||
shutil.rmtree(path)
|
||||
|
||||
def test_temp_dir__existing_dir__quiet_true(self):
|
||||
"""Test passing a directory that already exists with quiet=True."""
|
||||
path = tempfile.mkdtemp()
|
||||
path = os.path.realpath(path)
|
||||
|
||||
try:
|
||||
with support.check_warnings() as recorder:
|
||||
with support.temp_dir(path, quiet=True) as temp_path:
|
||||
self.assertEqual(path, temp_path)
|
||||
warnings = [str(w.message) for w in recorder.warnings]
|
||||
# Make sure temp_dir did not delete the original directory.
|
||||
self.assertTrue(os.path.isdir(path))
|
||||
finally:
|
||||
shutil.rmtree(path)
|
||||
|
||||
expected = ['tests may fail, unable to create temp dir: ' + path]
|
||||
self.assertEqual(warnings, expected)
|
||||
|
||||
# Tests for change_cwd()
|
||||
|
||||
def test_change_cwd(self):
|
||||
original_cwd = os.getcwd()
|
||||
|
||||
with support.temp_dir() as temp_path:
|
||||
with support.change_cwd(temp_path) as new_cwd:
|
||||
self.assertEqual(new_cwd, temp_path)
|
||||
self.assertEqual(os.getcwd(), new_cwd)
|
||||
|
||||
self.assertEqual(os.getcwd(), original_cwd)
|
||||
|
||||
def test_change_cwd__non_existent_dir(self):
|
||||
"""Test passing a non-existent directory."""
|
||||
original_cwd = os.getcwd()
|
||||
|
||||
def call_change_cwd(path):
|
||||
with support.change_cwd(path) as new_cwd:
|
||||
raise Exception("should not get here")
|
||||
|
||||
with support.temp_dir() as parent_dir:
|
||||
non_existent_dir = os.path.join(parent_dir, 'does_not_exist')
|
||||
self.assertRaises(FileNotFoundError, call_change_cwd,
|
||||
non_existent_dir)
|
||||
|
||||
self.assertEqual(os.getcwd(), original_cwd)
|
||||
|
||||
def test_change_cwd__non_existent_dir__quiet_true(self):
|
||||
"""Test passing a non-existent directory with quiet=True."""
|
||||
original_cwd = os.getcwd()
|
||||
|
||||
with support.temp_dir() as parent_dir:
|
||||
bad_dir = os.path.join(parent_dir, 'does_not_exist')
|
||||
with support.check_warnings() as recorder:
|
||||
with support.change_cwd(bad_dir, quiet=True) as new_cwd:
|
||||
self.assertEqual(new_cwd, original_cwd)
|
||||
self.assertEqual(os.getcwd(), new_cwd)
|
||||
warnings = [str(w.message) for w in recorder.warnings]
|
||||
|
||||
expected = ['tests may fail, unable to change CWD to: ' + bad_dir]
|
||||
self.assertEqual(warnings, expected)
|
||||
|
||||
# Tests for change_cwd()
|
||||
|
||||
def test_change_cwd__chdir_warning(self):
|
||||
"""Check the warning message when os.chdir() fails."""
|
||||
path = TESTFN + '_does_not_exist'
|
||||
with support.check_warnings() as recorder:
|
||||
with support.change_cwd(path=path, quiet=True):
|
||||
pass
|
||||
messages = [str(w.message) for w in recorder.warnings]
|
||||
self.assertEqual(messages, ['tests may fail, unable to change CWD to: ' + path])
|
||||
|
||||
# Tests for temp_cwd()
|
||||
|
||||
def test_temp_cwd(self):
|
||||
here = os.getcwd()
|
||||
with support.temp_cwd(name=TESTFN):
|
||||
|
@ -95,14 +208,15 @@ class TestSupport(unittest.TestCase):
|
|||
self.assertFalse(os.path.exists(TESTFN))
|
||||
self.assertTrue(os.path.basename(os.getcwd()), here)
|
||||
|
||||
def test_temp_cwd__chdir_warning(self):
|
||||
"""Check the warning message when os.chdir() fails."""
|
||||
path = TESTFN + '_does_not_exist'
|
||||
with support.check_warnings() as recorder:
|
||||
with support.temp_cwd(path=path, quiet=True):
|
||||
pass
|
||||
messages = [str(w.message) for w in recorder.warnings]
|
||||
self.assertEqual(messages, ['tests may fail, unable to change the CWD to ' + path])
|
||||
|
||||
def test_temp_cwd__name_none(self):
|
||||
"""Test passing None to temp_cwd()."""
|
||||
original_cwd = os.getcwd()
|
||||
with support.temp_cwd(name=None) as new_cwd:
|
||||
self.assertNotEqual(new_cwd, original_cwd)
|
||||
self.assertTrue(os.path.isdir(new_cwd))
|
||||
self.assertEqual(os.getcwd(), new_cwd)
|
||||
self.assertEqual(os.getcwd(), original_cwd)
|
||||
|
||||
def test_sortdict(self):
|
||||
self.assertEqual(support.sortdict({3:3, 2:2, 1:1}), "{1: 1, 2: 2, 3: 3}")
|
||||
|
|
|
@ -222,6 +222,9 @@ IDLE
|
|||
Tests
|
||||
-----
|
||||
|
||||
- Issue #15415: Add new temp_dir() and change_cwd() context managers to
|
||||
test.support, and refactor temp_cwd() to use them. Patch by Chris Jerdonek.
|
||||
|
||||
- Issue #15494: test.support is now a package rather than a module (Initial
|
||||
patch by Indra Talip)
|
||||
|
||||
|
|
Loading…
Reference in New Issue