summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/symlink_support.py100
-rw-r--r--Lib/test/test_import.py81
2 files changed, 105 insertions, 76 deletions
diff --git a/Lib/test/symlink_support.py b/Lib/test/symlink_support.py
new file mode 100644
index 0000000..301d0f9
--- /dev/null
+++ b/Lib/test/symlink_support.py
@@ -0,0 +1,100 @@
+import os
+import unittest
+import platform
+
+from test.test_support import TESTFN
+
+def can_symlink():
+ # cache the result in can_symlink.prev_val
+ prev_val = getattr(can_symlink, 'prev_val', None)
+ if prev_val is not None:
+ return prev_val
+ symlink_path = TESTFN + "can_symlink"
+ try:
+ symlink(TESTFN, symlink_path)
+ can = True
+ except (OSError, NotImplementedError, AttributeError):
+ can = False
+ else:
+ os.remove(symlink_path)
+ can_symlink.prev_val = can
+ return can
+
+def skip_unless_symlink(test):
+ """Skip decorator for tests that require functional symlink"""
+ ok = can_symlink()
+ msg = "Requires functional symlink implementation"
+ return test if ok else unittest.skip(msg)(test)
+
+def _symlink_win32(target, link, target_is_directory=False):
+ """
+ Ctypes symlink implementation since Python doesn't support
+ symlinks in windows yet. Borrowed from jaraco.windows project.
+ """
+ import ctypes.wintypes
+ CreateSymbolicLink = ctypes.windll.kernel32.CreateSymbolicLinkW
+ CreateSymbolicLink.argtypes = (
+ ctypes.wintypes.LPWSTR,
+ ctypes.wintypes.LPWSTR,
+ ctypes.wintypes.DWORD,
+ )
+ CreateSymbolicLink.restype = ctypes.wintypes.BOOLEAN
+
+ def format_system_message(errno):
+ """
+ Call FormatMessage with a system error number to retrieve
+ the descriptive error message.
+ """
+ # first some flags used by FormatMessageW
+ ALLOCATE_BUFFER = 0x100
+ ARGUMENT_ARRAY = 0x2000
+ FROM_HMODULE = 0x800
+ FROM_STRING = 0x400
+ FROM_SYSTEM = 0x1000
+ IGNORE_INSERTS = 0x200
+
+ # Let FormatMessageW allocate the buffer (we'll free it below)
+ # Also, let it know we want a system error message.
+ flags = ALLOCATE_BUFFER | FROM_SYSTEM
+ source = None
+ message_id = errno
+ language_id = 0
+ result_buffer = ctypes.wintypes.LPWSTR()
+ buffer_size = 0
+ arguments = None
+ bytes = ctypes.windll.kernel32.FormatMessageW(
+ flags,
+ source,
+ message_id,
+ language_id,
+ ctypes.byref(result_buffer),
+ buffer_size,
+ arguments,
+ )
+ # note the following will cause an infinite loop if GetLastError
+ # repeatedly returns an error that cannot be formatted, although
+ # this should not happen.
+ handle_nonzero_success(bytes)
+ message = result_buffer.value
+ ctypes.windll.kernel32.LocalFree(result_buffer)
+ return message
+
+ def handle_nonzero_success(result):
+ if result == 0:
+ value = ctypes.windll.kernel32.GetLastError()
+ strerror = format_system_message(value)
+ raise WindowsError(value, strerror)
+
+ target_is_directory = target_is_directory or os.path.isdir(target)
+ handle_nonzero_success(CreateSymbolicLink(link, target, target_is_directory))
+
+symlink = os.symlink if hasattr(os, 'symlink') else (
+ _symlink_win32 if platform.system() == 'Windows' else None
+)
+
+def remove_symlink(name):
+ # On Windows, to remove a directory symlink, one must use rmdir
+ try:
+ os.rmdir(name)
+ except OSError:
+ os.remove(name)
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
index 8878659..1612a47 100644
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -12,6 +12,7 @@ import shutil
from test.test_support import (unlink, TESTFN, unload, run_unittest, rmtree,
is_jython, check_warnings, EnvironmentVarGuard)
+from test import symlink_support
from test import script_helper
def remove_files(name):
@@ -497,11 +498,9 @@ class TestSymbolicallyLinkedPackage(unittest.TestCase):
if os.path.exists(self.tagged):
shutil.rmtree(self.tagged)
if os.path.exists(self.package_name):
- self.remove_symlink(self.package_name)
+ symlink_support.remove_symlink(self.package_name)
self.orig_sys_path = sys.path[:]
- symlink = getattr(os, 'symlink', None) or self._symlink_win32
-
# create a sample package; imagine you have a package with a tag and
# you want to symbolically link it from its untagged name.
os.mkdir(self.tagged)
@@ -511,7 +510,7 @@ class TestSymbolicallyLinkedPackage(unittest.TestCase):
# now create a symlink to the tagged package
# sample -> sample-tagged
- symlink(self.tagged, self.package_name)
+ symlink_support.symlink(self.tagged, self.package_name)
assert os.path.isdir(self.package_name)
assert os.path.isfile(os.path.join(self.package_name, '__init__.py'))
@@ -520,74 +519,12 @@ class TestSymbolicallyLinkedPackage(unittest.TestCase):
def tagged(self):
return self.package_name + '-tagged'
- @classmethod
- def _symlink_win32(cls, target, link, target_is_directory=False):
- """
- Ctypes symlink implementation since Python doesn't support
- symlinks in windows yet. Borrowed from jaraco.windows project.
- """
- import ctypes.wintypes
- CreateSymbolicLink = ctypes.windll.kernel32.CreateSymbolicLinkW
- CreateSymbolicLink.argtypes = (
- ctypes.wintypes.LPWSTR,
- ctypes.wintypes.LPWSTR,
- ctypes.wintypes.DWORD,
- )
- CreateSymbolicLink.restype = ctypes.wintypes.BOOLEAN
-
- def format_system_message(errno):
- """
- Call FormatMessage with a system error number to retrieve
- the descriptive error message.
- """
- # first some flags used by FormatMessageW
- ALLOCATE_BUFFER = 0x100
- ARGUMENT_ARRAY = 0x2000
- FROM_HMODULE = 0x800
- FROM_STRING = 0x400
- FROM_SYSTEM = 0x1000
- IGNORE_INSERTS = 0x200
-
- # Let FormatMessageW allocate the buffer (we'll free it below)
- # Also, let it know we want a system error message.
- flags = ALLOCATE_BUFFER | FROM_SYSTEM
- source = None
- message_id = errno
- language_id = 0
- result_buffer = ctypes.wintypes.LPWSTR()
- buffer_size = 0
- arguments = None
- bytes = ctypes.windll.kernel32.FormatMessageW(
- flags,
- source,
- message_id,
- language_id,
- ctypes.byref(result_buffer),
- buffer_size,
- arguments,
- )
- # note the following will cause an infinite loop if GetLastError
- # repeatedly returns an error that cannot be formatted, although
- # this should not happen.
- handle_nonzero_success(bytes)
- message = result_buffer.value
- ctypes.windll.kernel32.LocalFree(result_buffer)
- return message
-
- def handle_nonzero_success(result):
- if result == 0:
- value = ctypes.windll.kernel32.GetLastError()
- strerror = format_system_message(value)
- raise WindowsError(value, strerror)
-
- target_is_directory = target_is_directory or os.path.isdir(target)
- handle_nonzero_success(CreateSymbolicLink(link, target, target_is_directory))
-
# regression test for issue6727
@unittest.skipUnless(
not hasattr(sys, 'getwindowsversion')
or sys.getwindowsversion() >= (6, 0),
"Windows Vista or later required")
+ @symlink_support.skip_unless_symlink
def test_symlinked_dir_importable(self):
# make sure sample can only be imported from the current directory.
sys.path[:] = ['.']
@@ -598,19 +535,11 @@ class TestSymbolicallyLinkedPackage(unittest.TestCase):
def tearDown(self):
# now cleanup
if os.path.exists(self.package_name):
- self.remove_symlink(self.package_name)
+ symlink_support.remove_symlink(self.package_name)
if os.path.exists(self.tagged):
shutil.rmtree(self.tagged)
sys.path[:] = self.orig_sys_path
- @staticmethod
- def remove_symlink(name):
- # On Windows, to remove a directory symlink, one must use rmdir
- try:
- os.rmdir(name)
- except OSError:
- os.remove(name)
-
def test_main(verbose=None):
run_unittest(ImportTests, PycRewritingTests, PathsTests,
RelativeImportTests, TestSymbolicallyLinkedPackage)