Index: Lib/test/regrtest.py =================================================================== --- Lib/test/regrtest.py (revision 77942) +++ Lib/test/regrtest.py (working copy) @@ -159,6 +159,7 @@ import traceback import warnings import unittest +import tempfile import imp @@ -201,6 +202,19 @@ 'xpickle') +# Define a writable temp dir that will be used as cwd while running +# the tests. The name of the dir includes the pid to allow parallel +# testing (see the -j option). +TESTCWD = "{0}_{1}_cwd".format(test_support.TESTFN, os.getpid()) + +TESTCWD = os.path.abspath(os.path.join(tempfile.gettempdir(), TESTCWD)) + +# Create a context manager that temporary sets TESTCWD as current working +# directory. This context manager is used to run the tests, and provides +# a writable cwd. The original cwd is saved in test_support.SAVEDCWD. +temporary_cwd = test_support.temp_cwd(TESTCWD, quiet=True) + + def usage(code, msg=''): print __doc__ if msg: print msg @@ -328,7 +342,8 @@ elif o == '--slaveargs': args, kwargs = json.loads(a) try: - result = runtest(*args, **kwargs) + with temporary_cwd: + result = runtest(*args, **kwargs) except BaseException, e: result = INTERRUPTED, e.__class__.__name__ print # Force a newline (just in case) @@ -365,8 +380,7 @@ found_garbage = [] if single: - from tempfile import gettempdir - filename = os.path.join(gettempdir(), 'pynexttest') + filename = os.path.join(tempfile.gettempdir(), 'pynexttest') try: fp = open(filename, 'r') next_test = fp.read().strip() @@ -514,42 +528,43 @@ for worker in workers: worker.join() else: - for test in tests: - if not quiet: - print test - sys.stdout.flush() - if trace: - # If we're tracing code coverage, then we don't exit with status - # if on a false return value from main. - tracer.runctx('runtest(test, verbose, quiet, testdir)', - globals=globals(), locals=vars()) - else: - try: - result = runtest(test, verbose, quiet, - testdir, huntrleaks) - accumulate_result(test, result) - if verbose3 and result[0] == FAILED: - print "Re-running test %r in verbose mode" % test - runtest(test, True, quiet, testdir, huntrleaks) - except KeyboardInterrupt: - # print a newline separate from the ^C - print - break - except: - raise - if findleaks: - gc.collect() - if gc.garbage: - print "Warning: test created", len(gc.garbage), - print "uncollectable object(s)." - # move the uncollectable objects somewhere so we don't see - # them again - found_garbage.extend(gc.garbage) - del gc.garbage[:] - # Unload the newly imported modules (best effort finalization) - for module in sys.modules.keys(): - if module not in save_modules and module.startswith("test."): - test_support.unload(module) + with temporary_cwd: + for test in tests: + if not quiet: + print test + sys.stdout.flush() + if trace: + # If we're tracing code coverage, then we don't exit with + # status if on a false return value from main. + tracer.runctx('runtest(test, verbose, quiet, testdir)', + globals=globals(), locals=vars()) + else: + try: + result = runtest(test, verbose, quiet, + testdir, huntrleaks) + accumulate_result(test, result) + if verbose3 and result[0] == FAILED: + print "Re-running test %r in verbose mode" % test + runtest(test, True, quiet, testdir, huntrleaks) + except KeyboardInterrupt: + # print a newline separate from the ^C + print + break + except: + raise + if findleaks: + gc.collect() + if gc.garbage: + print "Warning: test created", len(gc.garbage), + print "uncollectable object(s)." + # move the uncollectable objects somewhere so we don't + # see them again + found_garbage.extend(gc.garbage) + del gc.garbage[:] + # Unload the newly imported modules (best effort finalization) + for module in sys.modules.keys(): + if module not in save_modules and module.startswith("test."): + test_support.unload(module) # The lists won't be sorted if running with -r good.sort() @@ -595,19 +610,20 @@ if verbose2 and bad: print "Re-running failed tests in verbose mode" - for test in bad: - print "Re-running test %r in verbose mode" % test - sys.stdout.flush() - try: - test_support.verbose = True - ok = runtest(test, True, quiet, testdir, - huntrleaks) - except KeyboardInterrupt: - # print a newline separate from the ^C - print - break - except: - raise + with temporary_cwd: + for test in bad: + print "Re-running test %r in verbose mode" % test + sys.stdout.flush() + try: + test_support.verbose = True + ok = runtest(test, True, quiet, testdir, + huntrleaks) + except KeyboardInterrupt: + # print a newline separate from the ^C + print + break + except: + raise if single: if next_single_test: Index: Lib/test/test_subprocess.py =================================================================== --- Lib/test/test_subprocess.py (revision 77941) +++ Lib/test/test_subprocess.py (working copy) @@ -32,12 +32,17 @@ # doesn't crash on some buildbots (Alphas in particular). if hasattr(test_support, "reap_children"): test_support.reap_children() + # This test should be run from the original working directory + self.save_cwd = os.getcwd() + os.chdir(test_support.SAVECWD) def tearDown(self): # Try to minimize the number of children we have so this test # doesn't crash on some buildbots (Alphas in particular). if hasattr(test_support, "reap_children"): test_support.reap_children() + # Restore the working directory + os.chdir(self.save_cwd) def mkstemp(self): """wrapper for mkstemp, calling mktemp if mkstemp is not available""" Index: Lib/test/test_support.py =================================================================== --- Lib/test/test_support.py (revision 77941) +++ Lib/test/test_support.py (working copy) @@ -17,6 +17,7 @@ import importlib import UserDict + __all__ = ["Error", "TestFailed", "ResourceDenied", "import_module", "verbose", "use_resources", "max_memuse", "record_original_stdout", "get_original_stdout", "unload", "unlink", "rmtree", "forget", @@ -24,6 +25,7 @@ "fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ", "findfile", "sortdict", "check_syntax_error", "open_urlresource", "check_warnings", "CleanImport", + "SAVEDCWD", "temp_cwd", "EnvironmentVarGuard", "captured_output", "captured_stdout", "TransientResource", "transient_internet", "run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest", @@ -379,28 +381,31 @@ 'Unicode filename tests may not be effective' \ % TESTFN_UNICODE_UNENCODEABLE -# Disambiguate TESTFN for parallel testing, while letting it remain a valid -# module name. -TESTFN = "{0}_{1}_tmp".format(TESTFN, os.getpid()) +# Save the initial cwd +SAVEDCWD = os.getcwd() -# Make sure we can write to TESTFN, try in /tmp if we can't -fp = None -try: - fp = open(TESTFN, 'w+') -except IOError: - TMP_TESTFN = os.path.join('/tmp', TESTFN) +@contextlib.contextmanager +def temp_cwd(name='tempcwd', quiet=False): + """Create a temporary directory. Set it as current directory.""" + saved_dir = os.getcwd() + is_temporary = False try: - fp = open(TMP_TESTFN, 'w+') - TESTFN = TMP_TESTFN - del TMP_TESTFN - except IOError: - print ('WARNING: tests will fail, unable to write to: %s or %s' % - (TESTFN, TMP_TESTFN)) -if fp is not None: - fp.close() - unlink(TESTFN) -del fp + os.mkdir(name) + os.chdir(name) + is_temporary = True + print 'the cwd is now', os.getcwd() + except OSError: + if not quiet: + raise + warnings.warn('WARNING: tests may fail, unable to switch to ' + name) + try: + yield os.getcwd() + finally: + os.chdir(saved_dir) + if is_temporary: + rmtree(name) + def findfile(file, here=__file__): """Try to find a file on sys.path and the working directory. If it is not found the argument passed to the function is returned (this does not