diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 5dd5f1a1776..7a79b5322f1 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -481,27 +481,28 @@ def normpath(path): # Return an absolute path. -def abspath(path): - """Return the absolute version of a path""" - try: - from nt import _getfullpathname - except ImportError: # Not running on Windows - mock up something sensible. - global abspath - def _abspath(path): - if not isabs(path): - path = join(os.getcwd(), path) - return normpath(path) - abspath = _abspath - return _abspath(path) +try: + from nt import _getfullpathname - if path: # Empty path must return current working directory. - try: - path = _getfullpathname(path) - except WindowsError: - pass # Bad path - return unchanged. - else: - path = os.getcwd() - return normpath(path) +except ImportError: # not running on Windows - mock up something sensible + def abspath(path): + """Return the absolute version of a path.""" + if not isabs(path): + path = join(os.getcwd(), path) + return normpath(path) + +else: # use native Windows method on Windows + def abspath(path): + """Return the absolute version of a path.""" + + if path: # Empty path must return current working directory. + try: + path = _getfullpathname(path) + except WindowsError: + pass # Bad path - return unchanged. + else: + path = os.getcwd() + return normpath(path) # realpath is a no-op on systems without islink support realpath = abspath diff --git a/Lib/test/test_threaded_import.py b/Lib/test/test_threaded_import.py index dc27d4e66a7..0642d25200e 100644 --- a/Lib/test/test_threaded_import.py +++ b/Lib/test/test_threaded_import.py @@ -6,7 +6,7 @@ # randrange, and then Python hangs. import thread -from test.test_support import verbose, TestSkipped +from test.test_support import verbose, TestSkipped, TestFailed critical_section = thread.allocate_lock() done = thread.allocate_lock() @@ -25,6 +25,23 @@ def task(): if finished: done.release() +def test_import_hangers(): + import sys + if verbose: + print "testing import hangers ...", + + from test import threaded_import_hangers + + try: + if threaded_import_hangers.errors: + raise TestFailed(threaded_import_hangers.errors) + elif verbose: + print "OK." + finally: + # In case this test is run again, make sure the helper module + # gets loaded from scratch again. + del sys.modules['test.threaded_import_hangers'] + # Tricky: When regrtest imports this module, the thread running regrtest # grabs the import lock and won't let go of it until this module returns. # All other threads attempting an import hang for the duration. Since @@ -53,5 +70,7 @@ def test_main(): # magic name! see above print "OK." done.release() + test_import_hangers() + if __name__ == "__main__": test_main() diff --git a/Lib/test/threaded_import_hangers.py b/Lib/test/threaded_import_hangers.py new file mode 100644 index 00000000000..b21c52f3cf7 --- /dev/null +++ b/Lib/test/threaded_import_hangers.py @@ -0,0 +1,42 @@ +# This is a helper module for test_threaded_import. The test imports this +# module, and this module tries to run various Python library functions in +# their own thread, as a side effect of being imported. If the spawned +# thread doesn't complete in TIMEOUT seconds, an "appeared to hang" message +# is appended to the module-global `errors` list. That list remains empty +# if (and only if) all functions tested complete. + +TIMEOUT = 10 + +import threading + +import tempfile +import os.path + +errors = [] + +# This class merely runs a function in its own thread T. The thread importing +# this module holds the import lock, so if the function called by T tries +# to do its own imports it will block waiting for this module's import +# to complete. +class Worker(threading.Thread): + def __init__(self, function, args): + threading.Thread.__init__(self) + self.function = function + self.args = args + + def run(self): + self.function(*self.args) + +for name, func, args in [ + # Bug 147376: TemporaryFile hung on Windows, starting in Python 2.4. + ("tempfile.TemporaryFile", tempfile.TemporaryFile, ()), + + # The real cause for bug 147376: ntpath.abspath() caused the hang. + ("os.path.abspath", os.path.abspath, ('.',)), + ]: + + t = Worker(func, args) + t.start() + t.join(TIMEOUT) + if t.isAlive(): + errors.append("%s appeared to hang" % name) diff --git a/Misc/NEWS b/Misc/NEWS index 03dc27ca4fe..b4351365ee0 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -86,6 +86,9 @@ Extension Modules Library ------- +- Bug #1473760: ``tempfile.TemporaryFile()`` could hang on Windows, when + called from a thread spawned as a side effect of importing a module. + - New modules: setuptools, easy_install, and pkg_resources, to support building, installing, and using Python eggs, respectively.