summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/ntpath.py43
-rw-r--r--Lib/test/test_threaded_import.py21
-rw-r--r--Lib/test/threaded_import_hangers.py42
-rw-r--r--Misc/NEWS3
4 files changed, 87 insertions, 22 deletions
diff --git a/Lib/ntpath.py b/Lib/ntpath.py
index 5dd5f1a..7a79b53 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)
-
- 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)
+try:
+ from nt import _getfullpathname
+
+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 dc27d4e..0642d25 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 0000000..b21c52f
--- /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 03dc27c..b435136 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.