##// END OF EJS Templates
Merge branch 'win32-shlex'
Thomas Kluyver -
r5539:d1997d96 merge
parent child Browse files
Show More
@@ -15,6 +15,7 b' of subprocess utilities, and it contains tools that are common to all of them.'
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 import subprocess
17 import subprocess
18 import shlex
18 import sys
19 import sys
19
20
20 from IPython.utils import py3compat
21 from IPython.utils import py3compat
@@ -143,3 +144,27 b' def getoutputerror(cmd):'
143 return '', ''
144 return '', ''
144 out, err = out_err
145 out, err = out_err
145 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
146 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
147
148
149 def arg_split(s, posix=False):
150 """Split a command line's arguments in a shell-like manner.
151
152 This is a modified version of the standard library's shlex.split()
153 function, but with a default of posix=False for splitting, so that quotes
154 in inputs are respected."""
155
156 # Unfortunately, python's shlex module is buggy with unicode input:
157 # http://bugs.python.org/issue1170
158 # At least encoding the input when it's unicode seems to help, but there
159 # may be more problems lurking. Apparently this is fixed in python3.
160 is_unicode = False
161 if (not py3compat.PY3) and isinstance(s, unicode):
162 is_unicode = True
163 s = s.encode('utf-8')
164 lex = shlex.shlex(s, posix=posix)
165 lex.whitespace_split = True
166 tokens = list(lex)
167 if is_unicode:
168 # Convert the tokens back to unicode.
169 tokens = [x.decode('utf-8') for x in tokens]
170 return tokens
@@ -23,7 +23,7 b' from IPython.external import pexpect'
23
23
24 # Our own
24 # Our own
25 from .autoattr import auto_attr
25 from .autoattr import auto_attr
26 from ._process_common import getoutput
26 from ._process_common import getoutput, arg_split
27 from IPython.utils import text
27 from IPython.utils import text
28 from IPython.utils import py3compat
28 from IPython.utils import py3compat
29
29
@@ -192,3 +192,6 b' class ProcessHandler(object):'
192 # programs think they are talking to a tty and produce highly formatted output
192 # programs think they are talking to a tty and produce highly formatted output
193 # (ls is a good example) that makes them hard.
193 # (ls is a good example) that makes them hard.
194 system = ProcessHandler().system
194 system = ProcessHandler().system
195
196
197
@@ -18,11 +18,15 b' from __future__ import print_function'
18 # stdlib
18 # stdlib
19 import os
19 import os
20 import sys
20 import sys
21 import ctypes
21
22
23 from ctypes import c_int, POINTER
24 from ctypes.wintypes import LPCWSTR, HLOCAL
22 from subprocess import STDOUT
25 from subprocess import STDOUT
23
26
24 # our own imports
27 # our own imports
25 from ._process_common import read_no_interrupt, process_handler
28 from ._process_common import read_no_interrupt, process_handler
29 from . import py3compat
26 from . import text
30 from . import text
27
31
28 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
@@ -146,3 +150,29 b' def getoutput(cmd):'
146 if out is None:
150 if out is None:
147 out = ''
151 out = ''
148 return out
152 return out
153
154 try:
155 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
156 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
157 CommandLineToArgvW.res_types = [POINTER(LPCWSTR)]
158 LocalFree = ctypes.windll.kernel32.LocalFree
159 LocalFree.res_type = HLOCAL
160 LocalFree.arg_types = [HLOCAL]
161
162 def arg_split(commandline, posix=False):
163 """Split a command line's arguments in a shell-like manner.
164
165 This is a special version for windows that use a ctypes call to CommandLineToArgvW
166 to do the argv splitting. The posix paramter is ignored.
167 """
168 #CommandLineToArgvW returns path to executable if called with empty string.
169 if commandline.strip() == "":
170 return []
171 argvn = c_int()
172 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
173 result_array_type = LPCWSTR * argvn.value
174 result = [arg for arg in result_array_type.from_address(result_pointer)]
175 retval = LocalFree(result_pointer)
176 return result
177 except AttributeError:
178 from ._process_common import arg_split
@@ -22,9 +22,10 b' import shlex'
22
22
23 # Our own
23 # Our own
24 if sys.platform == 'win32':
24 if sys.platform == 'win32':
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath, arg_split
26 else:
26 else:
27 from ._process_posix import _find_cmd, system, getoutput
27 from ._process_posix import _find_cmd, system, getoutput, arg_split
28
28
29
29 from ._process_common import getoutputerror
30 from ._process_common import getoutputerror
30 from IPython.utils import py3compat
31 from IPython.utils import py3compat
@@ -103,31 +104,6 b' def pycmd2argv(cmd):'
103 else:
104 else:
104 return [sys.executable, cmd]
105 return [sys.executable, cmd]
105
106
106
107 def arg_split(s, posix=False):
108 """Split a command line's arguments in a shell-like manner.
109
110 This is a modified version of the standard library's shlex.split()
111 function, but with a default of posix=False for splitting, so that quotes
112 in inputs are respected."""
113
114 # Unfortunately, python's shlex module is buggy with unicode input:
115 # http://bugs.python.org/issue1170
116 # At least encoding the input when it's unicode seems to help, but there
117 # may be more problems lurking. Apparently this is fixed in python3.
118 is_unicode = False
119 if (not py3compat.PY3) and isinstance(s, unicode):
120 is_unicode = True
121 s = s.encode('utf-8')
122 lex = shlex.shlex(s, posix=posix)
123 lex.whitespace_split = True
124 tokens = list(lex)
125 if is_unicode:
126 # Convert the tokens back to unicode.
127 tokens = [x.decode('utf-8') for x in tokens]
128 return tokens
129
130
131 def abbrev_cwd():
107 def abbrev_cwd():
132 """ Return abbreviated version of cwd, e.g. d:mydir """
108 """ Return abbreviated version of cwd, e.g. d:mydir """
133 cwd = os.getcwdu().replace('\\','/')
109 cwd = os.getcwdu().replace('\\','/')
@@ -62,16 +62,32 b' def test_find_cmd_fail():'
62 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
62 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
63
63
64
64
65 @dec.skip_win32
65 def test_arg_split():
66 def test_arg_split():
66 """Ensure that argument lines are correctly split like in a shell."""
67 """Ensure that argument lines are correctly split like in a shell."""
67 tests = [['hi', ['hi']],
68 tests = [['hi', ['hi']],
68 [u'hi', [u'hi']],
69 [u'hi', [u'hi']],
69 ['hello there', ['hello', 'there']],
70 ['hello there', ['hello', 'there']],
70 [u'h\N{LATIN SMALL LETTER A WITH CARON}llo', [u'h\N{LATIN SMALL LETTER A WITH CARON}llo']],
71 # \u01ce == \N{LATIN SMALL LETTER A WITH CARON}
72 # Do not use \N because the tests crash with syntax error in
73 # some cases, for example windows python2.6.
74 [u'h\u01cello', [u'h\u01cello']],
71 ['something "with quotes"', ['something', '"with quotes"']],
75 ['something "with quotes"', ['something', '"with quotes"']],
72 ]
76 ]
73 for argstr, argv in tests:
77 for argstr, argv in tests:
74 nt.assert_equal(arg_split(argstr), argv)
78 nt.assert_equal(arg_split(argstr), argv)
79
80 @dec.skip_if_not_win32
81 def test_arg_split_win32():
82 """Ensure that argument lines are correctly split like in a shell."""
83 tests = [['hi', ['hi']],
84 [u'hi', [u'hi']],
85 ['hello there', ['hello', 'there']],
86 [u'h\u01cello', [u'h\u01cello']],
87 ['something "with quotes"', ['something', 'with quotes']],
88 ]
89 for argstr, argv in tests:
90 nt.assert_equal(arg_split(argstr), argv)
75
91
76
92
77 class SubProcessTestCase(TestCase, tt.TempFileMixin):
93 class SubProcessTestCase(TestCase, tt.TempFileMixin):
@@ -100,6 +116,10 b' class SubProcessTestCase(TestCase, tt.TempFileMixin):'
100 def test_getoutput_quoted(self):
116 def test_getoutput_quoted(self):
101 out = getoutput('python -c "print (1)"')
117 out = getoutput('python -c "print (1)"')
102 self.assertEquals(out.strip(), '1')
118 self.assertEquals(out.strip(), '1')
119
120 #Invalid quoting on windows
121 @dec.skip_win32
122 def test_getoutput_quoted2(self):
103 out = getoutput("python -c 'print (1)'")
123 out = getoutput("python -c 'print (1)'")
104 self.assertEquals(out.strip(), '1')
124 self.assertEquals(out.strip(), '1')
105 out = getoutput("python -c 'print (\"1\")'")
125 out = getoutput("python -c 'print (\"1\")'")
General Comments 0
You need to be logged in to leave comments. Login now