source: python/trunk/Lib/test/symlink_support.py

Last change on this file was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

  • Property svn:eol-style set to native
File size: 3.2 KB
Line 
1import os
2import unittest
3import platform
4
5from test.test_support import TESTFN
6
7def can_symlink():
8 # cache the result in can_symlink.prev_val
9 prev_val = getattr(can_symlink, 'prev_val', None)
10 if prev_val is not None:
11 return prev_val
12 symlink_path = TESTFN + "can_symlink"
13 try:
14 symlink(TESTFN, symlink_path)
15 can = True
16 except (OSError, NotImplementedError, AttributeError):
17 can = False
18 else:
19 os.remove(symlink_path)
20 can_symlink.prev_val = can
21 return can
22
23def skip_unless_symlink(test):
24 """Skip decorator for tests that require functional symlink"""
25 ok = can_symlink()
26 msg = "Requires functional symlink implementation"
27 return test if ok else unittest.skip(msg)(test)
28
29def _symlink_win32(target, link, target_is_directory=False):
30 """
31 Ctypes symlink implementation since Python doesn't support
32 symlinks in windows yet. Borrowed from jaraco.windows project.
33 """
34 import ctypes.wintypes
35 CreateSymbolicLink = ctypes.windll.kernel32.CreateSymbolicLinkW
36 CreateSymbolicLink.argtypes = (
37 ctypes.wintypes.LPWSTR,
38 ctypes.wintypes.LPWSTR,
39 ctypes.wintypes.DWORD,
40 )
41 CreateSymbolicLink.restype = ctypes.wintypes.BOOLEAN
42
43 def format_system_message(errno):
44 """
45 Call FormatMessage with a system error number to retrieve
46 the descriptive error message.
47 """
48 # first some flags used by FormatMessageW
49 ALLOCATE_BUFFER = 0x100
50 ARGUMENT_ARRAY = 0x2000
51 FROM_HMODULE = 0x800
52 FROM_STRING = 0x400
53 FROM_SYSTEM = 0x1000
54 IGNORE_INSERTS = 0x200
55
56 # Let FormatMessageW allocate the buffer (we'll free it below)
57 # Also, let it know we want a system error message.
58 flags = ALLOCATE_BUFFER | FROM_SYSTEM
59 source = None
60 message_id = errno
61 language_id = 0
62 result_buffer = ctypes.wintypes.LPWSTR()
63 buffer_size = 0
64 arguments = None
65 bytes = ctypes.windll.kernel32.FormatMessageW(
66 flags,
67 source,
68 message_id,
69 language_id,
70 ctypes.byref(result_buffer),
71 buffer_size,
72 arguments,
73 )
74 # note the following will cause an infinite loop if GetLastError
75 # repeatedly returns an error that cannot be formatted, although
76 # this should not happen.
77 handle_nonzero_success(bytes)
78 message = result_buffer.value
79 ctypes.windll.kernel32.LocalFree(result_buffer)
80 return message
81
82 def handle_nonzero_success(result):
83 if result == 0:
84 value = ctypes.windll.kernel32.GetLastError()
85 strerror = format_system_message(value)
86 raise WindowsError(value, strerror)
87
88 target_is_directory = target_is_directory or os.path.isdir(target)
89 handle_nonzero_success(CreateSymbolicLink(link, target, target_is_directory))
90
91symlink = os.symlink if hasattr(os, 'symlink') else (
92 _symlink_win32 if platform.system() == 'Windows' else None
93)
94
95def remove_symlink(name):
96 # On Windows, to remove a directory symlink, one must use rmdir
97 try:
98 os.rmdir(name)
99 except OSError:
100 os.remove(name)
Note: See TracBrowser for help on using the repository browser.