##// END OF EJS Templates
only get the default encoding one time...
Brandon Parsons -
Show More
@@ -1,184 +1,185 b''
1 1 """Windows-specific implementation of process utilities.
2 2
3 3 This file is only meant to be imported by process.py, not by end-users.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2010-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # stdlib
19 19 import os
20 20 import sys
21 21 import ctypes
22 22 import msvcrt
23 23
24 24 from ctypes import c_int, POINTER
25 25 from ctypes.wintypes import LPCWSTR, HLOCAL
26 26 from subprocess import STDOUT
27 27
28 28 # our own imports
29 29 from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split
30 30 from . import py3compat
31 31 from . import text
32 from .encoding import getdefaultencoding
32 33
33 34 #-----------------------------------------------------------------------------
34 35 # Function definitions
35 36 #-----------------------------------------------------------------------------
36 37
37 38 class AvoidUNCPath(object):
38 39 """A context manager to protect command execution from UNC paths.
39 40
40 41 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
41 42 This context manager temporarily changes directory to the 'C:' drive on
42 43 entering, and restores the original working directory on exit.
43 44
44 45 The context manager returns the starting working directory *if* it made a
45 46 change and None otherwise, so that users can apply the necessary adjustment
46 47 to their system calls in the event of a change.
47 48
48 49 Example
49 50 -------
50 51 ::
51 52 cmd = 'dir'
52 53 with AvoidUNCPath() as path:
53 54 if path is not None:
54 55 cmd = '"pushd %s &&"%s' % (path, cmd)
55 56 os.system(cmd)
56 57 """
57 58 def __enter__(self):
58 59 self.path = os.getcwdu()
59 60 self.is_unc_path = self.path.startswith(r"\\")
60 61 if self.is_unc_path:
61 62 # change to c drive (as cmd.exe cannot handle UNC addresses)
62 63 os.chdir("C:")
63 64 return self.path
64 65 else:
65 66 # We return None to signal that there was no change in the working
66 67 # directory
67 68 return None
68 69
69 70 def __exit__(self, exc_type, exc_value, traceback):
70 71 if self.is_unc_path:
71 72 os.chdir(self.path)
72 73
73 74
74 75 def _find_cmd(cmd):
75 76 """Find the full path to a .bat or .exe using the win32api module."""
76 77 try:
77 78 from win32api import SearchPath
78 79 except ImportError:
79 80 raise ImportError('you need to have pywin32 installed for this to work')
80 81 else:
81 82 PATH = os.environ['PATH']
82 83 extensions = ['.exe', '.com', '.bat', '.py']
83 84 path = None
84 85 for ext in extensions:
85 86 try:
86 87 path = SearchPath(PATH, cmd + ext)[0]
87 88 except:
88 89 pass
89 90 if path is None:
90 91 raise OSError("command %r not found" % cmd)
91 92 else:
92 93 return path
93 94
94 95
95 96 def _system_body(p):
96 97 """Callback for _system."""
97 enc = py3compat.getdefaultencoding()
98 enc = getdefaultencoding()
98 99 for line in read_no_interrupt(p.stdout).splitlines():
99 100 line = line.decode(enc, 'replace')
100 101 print(line, file=sys.stdout)
101 102 for line in read_no_interrupt(p.stderr).splitlines():
102 103 line = line.decode(enc, 'replace')
103 104 print(line, file=sys.stderr)
104 105
105 106 # Wait to finish for returncode
106 107 return p.wait()
107 108
108 109
109 110 def system(cmd):
110 111 """Win32 version of os.system() that works with network shares.
111 112
112 113 Note that this implementation returns None, as meant for use in IPython.
113 114
114 115 Parameters
115 116 ----------
116 117 cmd : str
117 118 A command to be executed in the system shell.
118 119
119 120 Returns
120 121 -------
121 122 None : we explicitly do NOT return the subprocess status code, as this
122 123 utility is meant to be used extensively in IPython, where any return value
123 124 would trigger :func:`sys.displayhook` calls.
124 125 """
125 126 # The controller provides interactivity with both
126 127 # stdin and stdout
127 128 import _process_win32_controller
128 129 _process_win32_controller.system(cmd)
129 130
130 131
131 132 def getoutput(cmd):
132 133 """Return standard output of executing cmd in a shell.
133 134
134 135 Accepts the same arguments as os.system().
135 136
136 137 Parameters
137 138 ----------
138 139 cmd : str
139 140 A command to be executed in the system shell.
140 141
141 142 Returns
142 143 -------
143 144 stdout : str
144 145 """
145 146
146 147 with AvoidUNCPath() as path:
147 148 if path is not None:
148 149 cmd = '"pushd %s &&"%s' % (path, cmd)
149 150 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
150 151
151 152 if out is None:
152 153 out = ''
153 154 return out
154 155
155 156 try:
156 157 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
157 158 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
158 159 CommandLineToArgvW.res_types = [POINTER(LPCWSTR)]
159 160 LocalFree = ctypes.windll.kernel32.LocalFree
160 161 LocalFree.res_type = HLOCAL
161 162 LocalFree.arg_types = [HLOCAL]
162 163
163 164 def arg_split(commandline, posix=False, strict=True):
164 165 """Split a command line's arguments in a shell-like manner.
165 166
166 167 This is a special version for windows that use a ctypes call to CommandLineToArgvW
167 168 to do the argv splitting. The posix paramter is ignored.
168 169
169 170 If strict=False, process_common.arg_split(...strict=False) is used instead.
170 171 """
171 172 #CommandLineToArgvW returns path to executable if called with empty string.
172 173 if commandline.strip() == "":
173 174 return []
174 175 if not strict:
175 176 # not really a cl-arg, fallback on _process_common
176 177 return py_arg_split(commandline, posix=posix, strict=strict)
177 178 argvn = c_int()
178 179 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
179 180 result_array_type = LPCWSTR * argvn.value
180 181 result = [arg for arg in result_array_type.from_address(result_pointer)]
181 182 retval = LocalFree(result_pointer)
182 183 return result
183 184 except AttributeError:
184 185 arg_split = py_arg_split
@@ -1,178 +1,180 b''
1 1 # coding: utf-8
2 2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 3 import __builtin__
4 4 import functools
5 5 import sys
6 6 import re
7 7 import types
8 8
9 from IPython.utils.encoding import getdefaultencoding
9 from .encoding import getdefaultencoding
10
11 default_encoding = getdefaultencoding()
10 12
11 13 orig_open = open
12 14
13 15 def no_code(x, encoding=None):
14 16 return x
15 17
16 18 def decode(s, encoding=None):
17 encoding = encoding or getdefaultencoding()
19 encoding = encoding or default_encoding
18 20 return s.decode(encoding, "replace")
19 21
20 22 def encode(u, encoding=None):
21 encoding = encoding or getdefaultencoding()
23 encoding = encoding or default_encoding
22 24 return u.encode(encoding, "replace")
23 25
24 26
25 27 def cast_unicode(s, encoding=None):
26 28 if isinstance(s, bytes):
27 29 return decode(s, encoding)
28 30 return s
29 31
30 32 def cast_bytes(s, encoding=None):
31 33 if not isinstance(s, bytes):
32 34 return encode(s, encoding)
33 35 return s
34 36
35 37 def _modify_str_or_docstring(str_change_func):
36 38 @functools.wraps(str_change_func)
37 39 def wrapper(func_or_str):
38 40 if isinstance(func_or_str, basestring):
39 41 func = None
40 42 doc = func_or_str
41 43 else:
42 44 func = func_or_str
43 45 doc = func.__doc__
44 46
45 47 doc = str_change_func(doc)
46 48
47 49 if func:
48 50 func.__doc__ = doc
49 51 return func
50 52 return doc
51 53 return wrapper
52 54
53 55 if sys.version_info[0] >= 3:
54 56 PY3 = True
55 57
56 58 input = input
57 59 builtin_mod_name = "builtins"
58 60
59 61 str_to_unicode = no_code
60 62 unicode_to_str = no_code
61 63 str_to_bytes = encode
62 64 bytes_to_str = decode
63 65 cast_bytes_py2 = no_code
64 66
65 67 def isidentifier(s, dotted=False):
66 68 if dotted:
67 69 return all(isidentifier(a) for a in s.split("."))
68 70 return s.isidentifier()
69 71
70 72 open = orig_open
71 73
72 74 MethodType = types.MethodType
73 75
74 76 def execfile(fname, glob, loc=None):
75 77 loc = loc if (loc is not None) else glob
76 78 exec compile(open(fname, 'rb').read(), fname, 'exec') in glob, loc
77 79
78 80 # Refactor print statements in doctests.
79 81 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
80 82 def _print_statement_sub(match):
81 83 expr = match.groups('expr')
82 84 return "print(%s)" % expr
83 85
84 86 @_modify_str_or_docstring
85 87 def doctest_refactor_print(doc):
86 88 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
87 89 unfortunately doesn't pick up on our doctests.
88 90
89 91 Can accept a string or a function, so it can be used as a decorator."""
90 92 return _print_statement_re.sub(_print_statement_sub, doc)
91 93
92 94 # Abstract u'abc' syntax:
93 95 @_modify_str_or_docstring
94 96 def u_format(s):
95 97 """"{u}'abc'" --> "'abc'" (Python 3)
96 98
97 99 Accepts a string or a function, so it can be used as a decorator."""
98 100 return s.format(u='')
99 101
100 102 else:
101 103 PY3 = False
102 104
103 105 input = raw_input
104 106 builtin_mod_name = "__builtin__"
105 107
106 108 str_to_unicode = decode
107 109 unicode_to_str = encode
108 110 str_to_bytes = no_code
109 111 bytes_to_str = no_code
110 112 cast_bytes_py2 = cast_bytes
111 113
112 114 import re
113 115 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
114 116 def isidentifier(s, dotted=False):
115 117 if dotted:
116 118 return all(isidentifier(a) for a in s.split("."))
117 119 return bool(_name_re.match(s))
118 120
119 121 class open(object):
120 122 """Wrapper providing key part of Python 3 open() interface."""
121 123 def __init__(self, fname, mode="r", encoding="utf-8"):
122 124 self.f = orig_open(fname, mode)
123 125 self.enc = encoding
124 126
125 127 def write(self, s):
126 128 return self.f.write(s.encode(self.enc))
127 129
128 130 def read(self, size=-1):
129 131 return self.f.read(size).decode(self.enc)
130 132
131 133 def close(self):
132 134 return self.f.close()
133 135
134 136 def __enter__(self):
135 137 return self
136 138
137 139 def __exit__(self, etype, value, traceback):
138 140 self.f.close()
139 141
140 142 def MethodType(func, instance):
141 143 return types.MethodType(func, instance, type(instance))
142 144
143 145 # don't override system execfile on 2.x:
144 146 execfile = execfile
145 147
146 148 def doctest_refactor_print(func_or_str):
147 149 return func_or_str
148 150
149 151
150 152 # Abstract u'abc' syntax:
151 153 @_modify_str_or_docstring
152 154 def u_format(s):
153 155 """"{u}'abc'" --> "u'abc'" (Python 2)
154 156
155 157 Accepts a string or a function, so it can be used as a decorator."""
156 158 return s.format(u='u')
157 159
158 160 if sys.platform == 'win32':
159 161 def execfile(fname, glob=None, loc=None):
160 162 loc = loc if (loc is not None) else glob
161 163 # The rstrip() is necessary b/c trailing whitespace in files will
162 164 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
163 165 # but we still support 2.6). See issue 1027.
164 166 scripttext = __builtin__.open(fname).read().rstrip() + '\n'
165 167 # compile converts unicode filename to str assuming
166 168 # ascii. Let's do the conversion before calling compile
167 169 if isinstance(fname, unicode):
168 170 filename = unicode_to_str(fname)
169 171 else:
170 172 filename = fname
171 173 exec compile(scripttext, filename, 'exec') in glob, loc
172 174 else:
173 175 def execfile(fname, *where):
174 176 if isinstance(fname, unicode):
175 177 filename = fname.encode(sys.getfilesystemencoding())
176 178 else:
177 179 filename = fname
178 180 __builtin__.execfile(filename, *where)
General Comments 0
You need to be logged in to leave comments. Login now