Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 184bdfb

Browse files
committed
Merged revisions 78136 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r78136 | ezio.melotti | 2010-02-10 23:40:33 +0200 (Wed, 10 Feb 2010) | 1 line #7712: add a temp_cwd context manager to test_support and use it in regrtest to run all the tests in a temporary directory, saving the original CWD in test_support.SAVEDCWD. Thanks to Florent Xicluna who helped with the patch. ........
1 parent a3211ee commit 184bdfb

4 files changed

Lines changed: 98 additions & 27 deletions

File tree

Lib/test/regrtest.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,24 @@
158158
import warnings
159159
import unittest
160160
from inspect import isabstract
161+
import tempfile
162+
163+
# Some times __path__ and __file__ are not absolute (e.g. while running from
164+
# Lib/) and, if we change the CWD to run the tests in a temporary dir, some
165+
# imports might fail. This affects only the modules imported before os.chdir().
166+
# These modules are searched first in sys.path[0] (so '' -- the CWD) and if
167+
# they are found in the CWD their __file__ and __path__ will be relative (this
168+
# happens before the chdir). All the modules imported after the chdir, are
169+
# not found in the CWD, and since the other paths in sys.path[1:] are absolute
170+
# (site.py absolutize them), the __file__ and __path__ will be absolute too.
171+
# Therefore it is necessary to absolutize manually the __file__ and __path__ of
172+
# the packages to prevent later imports to fail when the CWD is different.
173+
for module in sys.modules.values():
174+
if hasattr(module, '__path__'):
175+
module.__path__ = [os.path.abspath(path) for path in module.__path__]
176+
if hasattr(module, '__file__'):
177+
module.__file__ = os.path.abspath(module.__file__)
178+
161179

162180
# Ignore ImportWarnings that only occur in the source tree,
163181
# (because of modules with the same name as source-directories in Modules/)
@@ -375,6 +393,9 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
375393
resource_denieds = []
376394
environment_changed = []
377395

396+
if verbose:
397+
print('The CWD is now', os.getcwd())
398+
378399
if findleaks:
379400
try:
380401
import gc
@@ -389,8 +410,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
389410
found_garbage = []
390411

391412
if single:
392-
from tempfile import gettempdir
393-
filename = os.path.join(gettempdir(), 'pynexttest')
413+
filename = 'pynexttest'
394414
try:
395415
fp = open(filename, 'r')
396416
next_test = fp.read().strip()
@@ -401,7 +421,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
401421

402422
if fromfile:
403423
tests = []
404-
fp = open(fromfile)
424+
fp = open(os.path.join(support.SAVEDCWD, fromfile))
405425
for line in fp:
406426
guts = line.split() # assuming no test has whitespace in its name
407427
if guts and not guts[0].startswith('#'):
@@ -966,6 +986,7 @@ def run_the_test():
966986

967987
deltas = []
968988
nwarmup, ntracked, fname = huntrleaks
989+
fname = os.path.join(support.SAVEDCWD, fname)
969990
repcount = nwarmup + ntracked
970991
print("beginning", repcount, "repetitions", file=sys.stderr)
971992
print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr)
@@ -1412,4 +1433,23 @@ def getexpected(self):
14121433
i -= 1
14131434
if os.path.abspath(os.path.normpath(sys.path[i])) == mydir:
14141435
del sys.path[i]
1415-
main()
1436+
1437+
# findtestdir() gets the dirname out of sys.argv[0], so we have to make it
1438+
# absolute before changing the CWD.
1439+
if sys.argv[0]:
1440+
sys.argv[0] = os.path.abspath(sys.argv[0])
1441+
1442+
1443+
# Define a writable temp dir that will be used as cwd while running
1444+
# the tests. The name of the dir includes the pid to allow parallel
1445+
# testing (see the -j option).
1446+
TESTCWD = 'test_python_{}'.format(os.getpid())
1447+
1448+
TESTCWD = os.path.abspath(os.path.join(tempfile.gettempdir(), TESTCWD))
1449+
1450+
# Run the tests in a context manager that temporary changes the CWD to a
1451+
# temporary and writable directory. If it's not possible to create or
1452+
# change the CWD, the original CWD will be used. The original CWD is
1453+
# available from support.SAVEDCWD.
1454+
with support.temp_cwd(TESTCWD, quiet=True):
1455+
main()

Lib/test/support.py

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
"verbose", "use_resources", "max_memuse", "record_original_stdout",
2222
"get_original_stdout", "unload", "unlink", "rmtree", "forget",
2323
"is_resource_enabled", "requires", "find_unused_port", "bind_port",
24-
"fcmp", "is_jython", "TESTFN", "HOST", "FUZZ", "findfile",
25-
"sortdict", "check_syntax_error", "open_urlresource",
24+
"fcmp", "is_jython", "TESTFN", "HOST", "FUZZ", "SAVEDCWD", "temp_cwd",
25+
"findfile", "sortdict", "check_syntax_error", "open_urlresource",
2626
"check_warnings", "CleanImport", "EnvironmentVarGuard",
2727
"TransientResource", "captured_output", "captured_stdout",
2828
"time_out", "socket_peer_reset", "ioerror_peer_reset",
@@ -338,7 +338,7 @@ def fcmp(x, y): # fuzzy comparison function
338338

339339
# Disambiguate TESTFN for parallel testing, while letting it remain a valid
340340
# module name.
341-
TESTFN = "{0}_{1}_tmp".format(TESTFN, os.getpid())
341+
TESTFN = "{}_{}_tmp".format(TESTFN, os.getpid())
342342

343343
# Assuming sys.getfilesystemencoding()!=sys.getdefaultencoding()
344344
# TESTFN_UNICODE is a filename that can be encoded using the
@@ -369,23 +369,37 @@ def fcmp(x, y): # fuzzy comparison function
369369
'Unicode filename tests may not be effective'
370370
% TESTFN_UNICODE_UNENCODEABLE)
371371

372-
# Make sure we can write to TESTFN, try in /tmp if we can't
373-
fp = None
374-
try:
375-
fp = open(TESTFN, 'w+')
376-
except IOError:
377-
TMP_TESTFN = os.path.join('/tmp', TESTFN)
372+
# Save the initial cwd
373+
SAVEDCWD = os.getcwd()
374+
375+
@contextlib.contextmanager
376+
def temp_cwd(name='tempcwd', quiet=False):
377+
"""
378+
Context manager that creates a temporary directory and set it as CWD.
379+
380+
The new CWD is created in the current directory and it's named *name*.
381+
If *quiet* is False (default) and it's not possible to create or change
382+
the CWD, an error is raised. If it's True, only a warning is raised
383+
and the original CWD is used.
384+
"""
385+
saved_dir = os.getcwd()
386+
is_temporary = False
378387
try:
379-
fp = open(TMP_TESTFN, 'w+')
380-
TESTFN = TMP_TESTFN
381-
del TMP_TESTFN
382-
except IOError:
383-
print(('WARNING: tests will fail, unable to write to: %s or %s' %
384-
(TESTFN, TMP_TESTFN)))
385-
if fp is not None:
386-
fp.close()
387-
unlink(TESTFN)
388-
del fp
388+
os.mkdir(name)
389+
os.chdir(name)
390+
is_temporary = True
391+
except OSError:
392+
if not quiet:
393+
raise
394+
warnings.warn('tests may fail, unable to change the CWD to ' + name,
395+
RuntimeWarning, stacklevel=3)
396+
try:
397+
yield os.getcwd()
398+
finally:
399+
os.chdir(saved_dir)
400+
if is_temporary:
401+
rmtree(name)
402+
389403

390404
def findfile(file, here=__file__):
391405
"""Try to find a file on sys.path and the working directory. If it is not

Lib/test/test_subprocess.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import tempfile
88
import time
99
import re
10+
import sysconfig
1011

1112
mswindows = (sys.platform == "win32")
1213

@@ -141,10 +142,21 @@ def test_stderr_none(self):
141142
p.wait()
142143
self.assertEqual(p.stderr, None)
143144

144-
def test_executable(self):
145-
arg0 = os.path.join(os.path.dirname(sys.executable),
146-
"somethingyoudonthave")
147-
p = subprocess.Popen([arg0, "-c", "import sys; sys.exit(47)"],
145+
def test_executable_with_cwd(self):
146+
python_dir = os.path.dirname(os.path.realpath(sys.executable))
147+
p = subprocess.Popen(["somethingyoudonthave", "-c",
148+
"import sys; sys.exit(47)"],
149+
executable=sys.executable, cwd=python_dir)
150+
p.wait()
151+
self.assertEqual(p.returncode, 47)
152+
153+
@unittest.skipIf(sysconfig.is_python_build(),
154+
"need an installed Python. See #7774")
155+
def test_executable_without_cwd(self):
156+
# For a normal installation, it should work without 'cwd'
157+
# argument. For test runs in the build directory, see #7774.
158+
p = subprocess.Popen(["somethingyoudonthave", "-c",
159+
"import sys; sys.exit(47)"],
148160
executable=sys.executable)
149161
p.wait()
150162
self.assertEqual(p.returncode, 47)

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,11 @@ Documentation
740740
Tests
741741
-----
742742

743+
- Issue #7712: test.support gained a new `temp_cwd` context manager which is
744+
now also used by regrtest to run all the tests in a temporary directory.
745+
The original CWD is saved in `support.SAVEDCWD`.
746+
Thanks to Florent Xicluna who helped with the patch.
747+
743748
- Issue #7924: Fix an intermittent 'XXX undetected error' failure in
744749
test_capi (only seen so far on platforms where the curses module
745750
wasn't built), due to an uncleared exception.

0 commit comments

Comments
 (0)