##// END OF EJS Templates
Work around a bug in Python's shlex module with unicode input....
Fernando Perez -
Show More
@@ -1,274 +1,301 b''
1 """Tests for various magic functions.
1 """Tests for various magic functions.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5 from __future__ import absolute_import
5 from __future__ import absolute_import
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Imports
8 # Imports
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 import os
11 import os
12 import sys
12 import sys
13 import tempfile
13 import tempfile
14 import types
14 import types
15 from cStringIO import StringIO
15 from cStringIO import StringIO
16
16
17 import nose.tools as nt
17 import nose.tools as nt
18
18
19 from IPython.utils.path import get_long_path_name
19 from IPython.utils.path import get_long_path_name
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21 from IPython.testing import tools as tt
21 from IPython.testing import tools as tt
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Test functions begin
24 # Test functions begin
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 def test_rehashx():
26 def test_rehashx():
27 # clear up everything
27 # clear up everything
28 _ip = get_ipython()
28 _ip = get_ipython()
29 _ip.alias_manager.alias_table.clear()
29 _ip.alias_manager.alias_table.clear()
30 del _ip.db['syscmdlist']
30 del _ip.db['syscmdlist']
31
31
32 _ip.magic('rehashx')
32 _ip.magic('rehashx')
33 # Practically ALL ipython development systems will have more than 10 aliases
33 # Practically ALL ipython development systems will have more than 10 aliases
34
34
35 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
35 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
36 for key, val in _ip.alias_manager.alias_table.items():
36 for key, val in _ip.alias_manager.alias_table.items():
37 # we must strip dots from alias names
37 # we must strip dots from alias names
38 nt.assert_true('.' not in key)
38 nt.assert_true('.' not in key)
39
39
40 # rehashx must fill up syscmdlist
40 # rehashx must fill up syscmdlist
41 scoms = _ip.db['syscmdlist']
41 scoms = _ip.db['syscmdlist']
42 yield (nt.assert_true, len(scoms) > 10)
42 yield (nt.assert_true, len(scoms) > 10)
43
43
44
44
45 def test_magic_parse_options():
45 def test_magic_parse_options():
46 """Test that we don't mangle paths when parsing magic options."""
46 """Test that we don't mangle paths when parsing magic options."""
47 ip = get_ipython()
47 ip = get_ipython()
48 path = 'c:\\x'
48 path = 'c:\\x'
49 opts = ip.parse_options('-f %s' % path,'f:')[0]
49 opts = ip.parse_options('-f %s' % path,'f:')[0]
50 # argv splitting is os-dependent
50 # argv splitting is os-dependent
51 if os.name == 'posix':
51 if os.name == 'posix':
52 expected = 'c:x'
52 expected = 'c:x'
53 else:
53 else:
54 expected = path
54 expected = path
55 nt.assert_equals(opts['f'], expected)
55 nt.assert_equals(opts['f'], expected)
56
56
57
57
58 def doctest_hist_f():
58 def doctest_hist_f():
59 """Test %hist -f with temporary filename.
59 """Test %hist -f with temporary filename.
60
60
61 In [9]: import tempfile
61 In [9]: import tempfile
62
62
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
64
64
65 In [11]: %hist -n -f $tfile 3
65 In [11]: %hist -n -f $tfile 3
66
66
67 In [13]: import os; os.unlink(tfile)
67 In [13]: import os; os.unlink(tfile)
68 """
68 """
69
69
70
70
71 def doctest_hist_r():
71 def doctest_hist_r():
72 """Test %hist -r
72 """Test %hist -r
73
73
74 XXX - This test is not recording the output correctly. For some reason, in
74 XXX - This test is not recording the output correctly. For some reason, in
75 testing mode the raw history isn't getting populated. No idea why.
75 testing mode the raw history isn't getting populated. No idea why.
76 Disabling the output checking for now, though at least we do run it.
76 Disabling the output checking for now, though at least we do run it.
77
77
78 In [1]: 'hist' in _ip.lsmagic()
78 In [1]: 'hist' in _ip.lsmagic()
79 Out[1]: True
79 Out[1]: True
80
80
81 In [2]: x=1
81 In [2]: x=1
82
82
83 In [3]: %hist -r 2
83 In [3]: %hist -r 2
84 x=1 # random
84 x=1 # random
85 %hist -r 2
85 %hist -r 2
86 """
86 """
87
87
88 def doctest_hist_op():
88 def doctest_hist_op():
89 """Test %hist -op
89 """Test %hist -op
90
90
91 In [1]: class b:
91 In [1]: class b:
92 ...: pass
92 ...: pass
93 ...:
93 ...:
94
94
95 In [2]: class s(b):
95 In [2]: class s(b):
96 ...: def __str__(self):
96 ...: def __str__(self):
97 ...: return 's'
97 ...: return 's'
98 ...:
98 ...:
99
99
100 In [3]:
100 In [3]:
101
101
102 In [4]: class r(b):
102 In [4]: class r(b):
103 ...: def __repr__(self):
103 ...: def __repr__(self):
104 ...: return 'r'
104 ...: return 'r'
105 ...:
105 ...:
106
106
107 In [5]: class sr(s,r): pass
107 In [5]: class sr(s,r): pass
108 ...:
108 ...:
109
109
110 In [6]:
110 In [6]:
111
111
112 In [7]: bb=b()
112 In [7]: bb=b()
113
113
114 In [8]: ss=s()
114 In [8]: ss=s()
115
115
116 In [9]: rr=r()
116 In [9]: rr=r()
117
117
118 In [10]: ssrr=sr()
118 In [10]: ssrr=sr()
119
119
120 In [11]: bb
120 In [11]: bb
121 Out[11]: <...b instance at ...>
121 Out[11]: <...b instance at ...>
122
122
123 In [12]: ss
123 In [12]: ss
124 Out[12]: <...s instance at ...>
124 Out[12]: <...s instance at ...>
125
125
126 In [13]:
126 In [13]:
127
127
128 In [14]: %hist -op
128 In [14]: %hist -op
129 >>> class b:
129 >>> class b:
130 ... pass
130 ... pass
131 ...
131 ...
132 >>> class s(b):
132 >>> class s(b):
133 ... def __str__(self):
133 ... def __str__(self):
134 ... return 's'
134 ... return 's'
135 ...
135 ...
136 >>>
136 >>>
137 >>> class r(b):
137 >>> class r(b):
138 ... def __repr__(self):
138 ... def __repr__(self):
139 ... return 'r'
139 ... return 'r'
140 ...
140 ...
141 >>> class sr(s,r): pass
141 >>> class sr(s,r): pass
142 >>>
142 >>>
143 >>> bb=b()
143 >>> bb=b()
144 >>> ss=s()
144 >>> ss=s()
145 >>> rr=r()
145 >>> rr=r()
146 >>> ssrr=sr()
146 >>> ssrr=sr()
147 >>> bb
147 >>> bb
148 <...b instance at ...>
148 <...b instance at ...>
149 >>> ss
149 >>> ss
150 <...s instance at ...>
150 <...s instance at ...>
151 >>>
151 >>>
152 """
152 """
153
153
154 def test_shist():
154 def test_shist():
155 # Simple tests of ShadowHist class - test generator.
155 # Simple tests of ShadowHist class - test generator.
156 import os, shutil, tempfile
156 import os, shutil, tempfile
157
157
158 from IPython.utils import pickleshare
158 from IPython.utils import pickleshare
159 from IPython.core.history import ShadowHist
159 from IPython.core.history import ShadowHist
160
160
161 tfile = tempfile.mktemp('','tmp-ipython-')
161 tfile = tempfile.mktemp('','tmp-ipython-')
162
162
163 db = pickleshare.PickleShareDB(tfile)
163 db = pickleshare.PickleShareDB(tfile)
164 s = ShadowHist(db)
164 s = ShadowHist(db)
165 s.add('hello')
165 s.add('hello')
166 s.add('world')
166 s.add('world')
167 s.add('hello')
167 s.add('hello')
168 s.add('hello')
168 s.add('hello')
169 s.add('karhu')
169 s.add('karhu')
170
170
171 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
171 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
172
172
173 yield nt.assert_equal,s.get(2),'world'
173 yield nt.assert_equal,s.get(2),'world'
174
174
175 shutil.rmtree(tfile)
175 shutil.rmtree(tfile)
176
176
177
177
178 # XXX failing for now, until we get clearcmd out of quarantine. But we should
178 # XXX failing for now, until we get clearcmd out of quarantine. But we should
179 # fix this and revert the skip to happen only if numpy is not around.
179 # fix this and revert the skip to happen only if numpy is not around.
180 #@dec.skipif_not_numpy
180 #@dec.skipif_not_numpy
181 @dec.skipknownfailure
181 @dec.skipknownfailure
182 def test_numpy_clear_array_undec():
182 def test_numpy_clear_array_undec():
183 from IPython.extensions import clearcmd
183 from IPython.extensions import clearcmd
184
184
185 _ip.ex('import numpy as np')
185 _ip.ex('import numpy as np')
186 _ip.ex('a = np.empty(2)')
186 _ip.ex('a = np.empty(2)')
187 yield (nt.assert_true, 'a' in _ip.user_ns)
187 yield (nt.assert_true, 'a' in _ip.user_ns)
188 _ip.magic('clear array')
188 _ip.magic('clear array')
189 yield (nt.assert_false, 'a' in _ip.user_ns)
189 yield (nt.assert_false, 'a' in _ip.user_ns)
190
190
191
191
192 # Multiple tests for clipboard pasting
192 # Multiple tests for clipboard pasting
193 @dec.parametric
193 @dec.parametric
194 def test_paste():
194 def test_paste():
195 _ip = get_ipython()
195 _ip = get_ipython()
196 def paste(txt, flags='-q'):
196 def paste(txt, flags='-q'):
197 """Paste input text, by default in quiet mode"""
197 """Paste input text, by default in quiet mode"""
198 hooks.clipboard_get = lambda : txt
198 hooks.clipboard_get = lambda : txt
199 _ip.magic('paste '+flags)
199 _ip.magic('paste '+flags)
200
200
201 # Inject fake clipboard hook but save original so we can restore it later
201 # Inject fake clipboard hook but save original so we can restore it later
202 hooks = _ip.hooks
202 hooks = _ip.hooks
203 user_ns = _ip.user_ns
203 user_ns = _ip.user_ns
204 original_clip = hooks.clipboard_get
204 original_clip = hooks.clipboard_get
205
205
206 try:
206 try:
207 # This try/except with an emtpy except clause is here only because
207 # This try/except with an emtpy except clause is here only because
208 # try/yield/finally is invalid syntax in Python 2.4. This will be
208 # try/yield/finally is invalid syntax in Python 2.4. This will be
209 # removed when we drop 2.4-compatibility, and the emtpy except below
209 # removed when we drop 2.4-compatibility, and the emtpy except below
210 # will be changed to a finally.
210 # will be changed to a finally.
211
211
212 # Run tests with fake clipboard function
212 # Run tests with fake clipboard function
213 user_ns.pop('x', None)
213 user_ns.pop('x', None)
214 paste('x=1')
214 paste('x=1')
215 yield nt.assert_equal(user_ns['x'], 1)
215 yield nt.assert_equal(user_ns['x'], 1)
216
216
217 user_ns.pop('x', None)
217 user_ns.pop('x', None)
218 paste('>>> x=2')
218 paste('>>> x=2')
219 yield nt.assert_equal(user_ns['x'], 2)
219 yield nt.assert_equal(user_ns['x'], 2)
220
220
221 paste("""
221 paste("""
222 >>> x = [1,2,3]
222 >>> x = [1,2,3]
223 >>> y = []
223 >>> y = []
224 >>> for i in x:
224 >>> for i in x:
225 ... y.append(i**2)
225 ... y.append(i**2)
226 ...
226 ...
227 """)
227 """)
228 yield nt.assert_equal(user_ns['x'], [1,2,3])
228 yield nt.assert_equal(user_ns['x'], [1,2,3])
229 yield nt.assert_equal(user_ns['y'], [1,4,9])
229 yield nt.assert_equal(user_ns['y'], [1,4,9])
230
230
231 # Now, test that paste -r works
231 # Now, test that paste -r works
232 user_ns.pop('x', None)
232 user_ns.pop('x', None)
233 yield nt.assert_false('x' in user_ns)
233 yield nt.assert_false('x' in user_ns)
234 _ip.magic('paste -r')
234 _ip.magic('paste -r')
235 yield nt.assert_equal(user_ns['x'], [1,2,3])
235 yield nt.assert_equal(user_ns['x'], [1,2,3])
236
236
237 # Also test paste echoing, by temporarily faking the writer
237 # Also test paste echoing, by temporarily faking the writer
238 w = StringIO()
238 w = StringIO()
239 writer = _ip.write
239 writer = _ip.write
240 _ip.write = w.write
240 _ip.write = w.write
241 code = """
241 code = """
242 a = 100
242 a = 100
243 b = 200"""
243 b = 200"""
244 try:
244 try:
245 paste(code,'')
245 paste(code,'')
246 out = w.getvalue()
246 out = w.getvalue()
247 finally:
247 finally:
248 _ip.write = writer
248 _ip.write = writer
249 yield nt.assert_equal(user_ns['a'], 100)
249 yield nt.assert_equal(user_ns['a'], 100)
250 yield nt.assert_equal(user_ns['b'], 200)
250 yield nt.assert_equal(user_ns['b'], 200)
251 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
251 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
252
252
253 finally:
253 finally:
254 # This should be in a finally clause, instead of the bare except above.
254 # This should be in a finally clause, instead of the bare except above.
255 # Restore original hook
255 # Restore original hook
256 hooks.clipboard_get = original_clip
256 hooks.clipboard_get = original_clip
257
257
258
258
259 def test_time():
259 def test_time():
260 _ip.magic('time None')
260 _ip.magic('time None')
261
261
262
262
263 def doctest_time():
263 def doctest_time():
264 """
264 """
265 In [10]: %time None
265 In [10]: %time None
266 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
266 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
267 Wall time: 0.00 s
267 Wall time: 0.00 s
268 """
268 """
269
269
270
270 def test_doctest_mode():
271 def test_doctest_mode():
271 "Toggle doctest_mode twice, it should be a no-op and run without error"
272 "Toggle doctest_mode twice, it should be a no-op and run without error"
272 _ip.magic('doctest_mode')
273 _ip.magic('doctest_mode')
273 _ip.magic('doctest_mode')
274 _ip.magic('doctest_mode')
274
275
276
277 def test_parse_options():
278 """Tests for basic options parsing in magics."""
279 # These are only the most minimal of tests, more should be added later. At
280 # the very least we check that basic text/unicode calls work OK.
281 nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo')
282 nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo')
283
284
285 def test_dirops():
286 """Test various directory handling operations."""
287 curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
288
289 startdir = os.getcwd()
290 ipdir = _ip.ipython_dir
291 try:
292 _ip.magic('cd "%s"' % ipdir)
293 nt.assert_equal(curpath(), ipdir)
294 _ip.magic('cd -')
295 nt.assert_equal(curpath(), startdir)
296 _ip.magic('pushd "%s"' % ipdir)
297 nt.assert_equal(curpath(), ipdir)
298 _ip.magic('popd')
299 nt.assert_equal(curpath(), startdir)
300 finally:
301 os.chdir(startdir)
@@ -1,368 +1,367 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with external processes.
3 Utilities for working with external processes.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import sys
18 import sys
19 import shlex
19 import shlex
20 import subprocess
20 import subprocess
21
21
22 from IPython.utils.terminal import set_term_title
22 from IPython.utils.terminal import set_term_title
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Code
25 # Code
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 class FindCmdError(Exception):
29 class FindCmdError(Exception):
30 pass
30 pass
31
31
32
32
33 def _find_cmd(cmd):
33 def _find_cmd(cmd):
34 """Find the full path to a command using which."""
34 """Find the full path to a command using which."""
35 return os.popen('which %s' % cmd).read().strip()
35 return os.popen('which %s' % cmd).read().strip()
36
36
37
37
38 if os.name == 'posix':
38 if os.name == 'posix':
39 def _find_cmd(cmd):
39 def _find_cmd(cmd):
40 """Find the full path to a command using which."""
40 """Find the full path to a command using which."""
41 return getoutputerror('/usr/bin/env which %s' % cmd)[0]
41 return getoutputerror('/usr/bin/env which %s' % cmd)[0]
42
42
43
43
44 if sys.platform == 'win32':
44 if sys.platform == 'win32':
45 def _find_cmd(cmd):
45 def _find_cmd(cmd):
46 """Find the full path to a .bat or .exe using the win32api module."""
46 """Find the full path to a .bat or .exe using the win32api module."""
47 try:
47 try:
48 from win32api import SearchPath
48 from win32api import SearchPath
49 except ImportError:
49 except ImportError:
50 raise ImportError('you need to have pywin32 installed for this to work')
50 raise ImportError('you need to have pywin32 installed for this to work')
51 else:
51 else:
52 PATH = os.environ['PATH']
52 PATH = os.environ['PATH']
53 extensions = ['.exe', '.com', '.bat', '.py']
53 extensions = ['.exe', '.com', '.bat', '.py']
54 path = None
54 path = None
55 for ext in extensions:
55 for ext in extensions:
56 try:
56 try:
57 path = SearchPath(PATH,cmd + ext)[0]
57 path = SearchPath(PATH,cmd + ext)[0]
58 except:
58 except:
59 pass
59 pass
60 if path is None:
60 if path is None:
61 raise OSError("command %r not found" % cmd)
61 raise OSError("command %r not found" % cmd)
62 else:
62 else:
63 return path
63 return path
64
64
65
65
66 def find_cmd(cmd):
66 def find_cmd(cmd):
67 """Find absolute path to executable cmd in a cross platform manner.
67 """Find absolute path to executable cmd in a cross platform manner.
68
68
69 This function tries to determine the full path to a command line program
69 This function tries to determine the full path to a command line program
70 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
70 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
71 time it will use the version that is first on the users `PATH`. If
71 time it will use the version that is first on the users `PATH`. If
72 cmd is `python` return `sys.executable`.
72 cmd is `python` return `sys.executable`.
73
73
74 Warning, don't use this to find IPython command line programs as there
74 Warning, don't use this to find IPython command line programs as there
75 is a risk you will find the wrong one. Instead find those using the
75 is a risk you will find the wrong one. Instead find those using the
76 following code and looking for the application itself::
76 following code and looking for the application itself::
77
77
78 from IPython.utils.path import get_ipython_module_path
78 from IPython.utils.path import get_ipython_module_path
79 from IPython.utils.process import pycmd2argv
79 from IPython.utils.process import pycmd2argv
80 argv = pycmd2argv(get_ipython_module_path('IPython.core.ipapp'))
80 argv = pycmd2argv(get_ipython_module_path('IPython.core.ipapp'))
81
81
82 Parameters
82 Parameters
83 ----------
83 ----------
84 cmd : str
84 cmd : str
85 The command line program to look for.
85 The command line program to look for.
86 """
86 """
87 if cmd == 'python':
87 if cmd == 'python':
88 return os.path.abspath(sys.executable)
88 return os.path.abspath(sys.executable)
89 try:
89 try:
90 path = _find_cmd(cmd)
90 path = _find_cmd(cmd)
91 except OSError:
91 except OSError:
92 raise FindCmdError('command could not be found: %s' % cmd)
92 raise FindCmdError('command could not be found: %s' % cmd)
93 # which returns empty if not found
93 # which returns empty if not found
94 if path == '':
94 if path == '':
95 raise FindCmdError('command could not be found: %s' % cmd)
95 raise FindCmdError('command could not be found: %s' % cmd)
96 return os.path.abspath(path)
96 return os.path.abspath(path)
97
97
98
98
99 def pycmd2argv(cmd):
99 def pycmd2argv(cmd):
100 r"""Take the path of a python command and return a list (argv-style).
100 r"""Take the path of a python command and return a list (argv-style).
101
101
102 This only works on Python based command line programs and will find the
102 This only works on Python based command line programs and will find the
103 location of the ``python`` executable using ``sys.executable`` to make
103 location of the ``python`` executable using ``sys.executable`` to make
104 sure the right version is used.
104 sure the right version is used.
105
105
106 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
106 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
107 .com or .bat, and [, cmd] otherwise.
107 .com or .bat, and [, cmd] otherwise.
108
108
109 Parameters
109 Parameters
110 ----------
110 ----------
111 cmd : string
111 cmd : string
112 The path of the command.
112 The path of the command.
113
113
114 Returns
114 Returns
115 -------
115 -------
116 argv-style list.
116 argv-style list.
117 """
117 """
118 ext = os.path.splitext(cmd)[1]
118 ext = os.path.splitext(cmd)[1]
119 if ext in ['.exe', '.com', '.bat']:
119 if ext in ['.exe', '.com', '.bat']:
120 return [cmd]
120 return [cmd]
121 else:
121 else:
122 if sys.platform == 'win32':
122 if sys.platform == 'win32':
123 # The -u option here turns on unbuffered output, which is required
123 # The -u option here turns on unbuffered output, which is required
124 # on Win32 to prevent wierd conflict and problems with Twisted.
124 # on Win32 to prevent wierd conflict and problems with Twisted.
125 # Also, use sys.executable to make sure we are picking up the
125 # Also, use sys.executable to make sure we are picking up the
126 # right python exe.
126 # right python exe.
127 return [sys.executable, '-u', cmd]
127 return [sys.executable, '-u', cmd]
128 else:
128 else:
129 return [sys.executable, cmd]
129 return [sys.executable, cmd]
130
130
131
131
132 def arg_split(s, posix=False):
132 def arg_split(s, posix=False):
133 """Split a command line's arguments in a shell-like manner.
133 """Split a command line's arguments in a shell-like manner.
134
134
135 This is a modified version of the standard library's shlex.split()
135 This is a modified version of the standard library's shlex.split()
136 function, but with a default of posix=False for splitting, so that quotes
136 function, but with a default of posix=False for splitting, so that quotes
137 in inputs are respected."""
137 in inputs are respected."""
138
138
139 # XXX - there may be unicode-related problems here!!! I'm not sure that
139 # Unfortunately, python's shlex module is buggy with unicode input:
140 # shlex is truly unicode-safe, so it might be necessary to do
140 # http://bugs.python.org/issue1170
141 #
141 # At least encoding the input when it's unicode seems to help, but there
142 # s = s.encode(sys.stdin.encoding)
142 # may be more problems lurking. Apparently this is fixed in python3.
143 #
143 if isinstance(s, unicode):
144 # first, to ensure that shlex gets a normal string. Input from anyone who
144 s = s.encode(sys.stdin.encoding)
145 # knows more about unicode and shlex than I would be good to have here...
146 lex = shlex.shlex(s, posix=posix)
145 lex = shlex.shlex(s, posix=posix)
147 lex.whitespace_split = True
146 lex.whitespace_split = True
148 return list(lex)
147 return list(lex)
149
148
150
149
151 def system(cmd, verbose=0, debug=0, header=''):
150 def system(cmd, verbose=0, debug=0, header=''):
152 """Execute a system command, return its exit status.
151 """Execute a system command, return its exit status.
153
152
154 Options:
153 Options:
155
154
156 - verbose (0): print the command to be executed.
155 - verbose (0): print the command to be executed.
157
156
158 - debug (0): only print, do not actually execute.
157 - debug (0): only print, do not actually execute.
159
158
160 - header (''): Header to print on screen prior to the executed command (it
159 - header (''): Header to print on screen prior to the executed command (it
161 is only prepended to the command, no newlines are added).
160 is only prepended to the command, no newlines are added).
162
161
163 Note: a stateful version of this function is available through the
162 Note: a stateful version of this function is available through the
164 SystemExec class."""
163 SystemExec class."""
165
164
166 stat = 0
165 stat = 0
167 if verbose or debug: print header+cmd
166 if verbose or debug: print header+cmd
168 sys.stdout.flush()
167 sys.stdout.flush()
169 if not debug: stat = os.system(cmd)
168 if not debug: stat = os.system(cmd)
170 return stat
169 return stat
171
170
172
171
173 def abbrev_cwd():
172 def abbrev_cwd():
174 """ Return abbreviated version of cwd, e.g. d:mydir """
173 """ Return abbreviated version of cwd, e.g. d:mydir """
175 cwd = os.getcwd().replace('\\','/')
174 cwd = os.getcwd().replace('\\','/')
176 drivepart = ''
175 drivepart = ''
177 tail = cwd
176 tail = cwd
178 if sys.platform == 'win32':
177 if sys.platform == 'win32':
179 if len(cwd) < 4:
178 if len(cwd) < 4:
180 return cwd
179 return cwd
181 drivepart,tail = os.path.splitdrive(cwd)
180 drivepart,tail = os.path.splitdrive(cwd)
182
181
183
182
184 parts = tail.split('/')
183 parts = tail.split('/')
185 if len(parts) > 2:
184 if len(parts) > 2:
186 tail = '/'.join(parts[-2:])
185 tail = '/'.join(parts[-2:])
187
186
188 return (drivepart + (
187 return (drivepart + (
189 cwd == '/' and '/' or tail))
188 cwd == '/' and '/' or tail))
190
189
191
190
192 # This function is used by ipython in a lot of places to make system calls.
191 # This function is used by ipython in a lot of places to make system calls.
193 # We need it to be slightly different under win32, due to the vagaries of
192 # We need it to be slightly different under win32, due to the vagaries of
194 # 'network shares'. A win32 override is below.
193 # 'network shares'. A win32 override is below.
195
194
196 def shell(cmd, verbose=0, debug=0, header=''):
195 def shell(cmd, verbose=0, debug=0, header=''):
197 """Execute a command in the system shell, always return None.
196 """Execute a command in the system shell, always return None.
198
197
199 Options:
198 Options:
200
199
201 - verbose (0): print the command to be executed.
200 - verbose (0): print the command to be executed.
202
201
203 - debug (0): only print, do not actually execute.
202 - debug (0): only print, do not actually execute.
204
203
205 - header (''): Header to print on screen prior to the executed command (it
204 - header (''): Header to print on screen prior to the executed command (it
206 is only prepended to the command, no newlines are added).
205 is only prepended to the command, no newlines are added).
207
206
208 Note: this is similar to system(), but it returns None so it can
207 Note: this is similar to system(), but it returns None so it can
209 be conveniently used in interactive loops without getting the return value
208 be conveniently used in interactive loops without getting the return value
210 (typically 0) printed many times."""
209 (typically 0) printed many times."""
211
210
212 stat = 0
211 stat = 0
213 if verbose or debug: print header+cmd
212 if verbose or debug: print header+cmd
214 # flush stdout so we don't mangle python's buffering
213 # flush stdout so we don't mangle python's buffering
215 sys.stdout.flush()
214 sys.stdout.flush()
216
215
217 if not debug:
216 if not debug:
218 set_term_title("IPy " + cmd)
217 set_term_title("IPy " + cmd)
219 os.system(cmd)
218 os.system(cmd)
220 set_term_title("IPy " + abbrev_cwd())
219 set_term_title("IPy " + abbrev_cwd())
221
220
222 # override shell() for win32 to deal with network shares
221 # override shell() for win32 to deal with network shares
223 if os.name in ('nt','dos'):
222 if os.name in ('nt','dos'):
224
223
225 shell_ori = shell
224 shell_ori = shell
226
225
227 def shell(cmd, verbose=0, debug=0, header=''):
226 def shell(cmd, verbose=0, debug=0, header=''):
228 if os.getcwd().startswith(r"\\"):
227 if os.getcwd().startswith(r"\\"):
229 path = os.getcwd()
228 path = os.getcwd()
230 # change to c drive (cannot be on UNC-share when issuing os.system,
229 # change to c drive (cannot be on UNC-share when issuing os.system,
231 # as cmd.exe cannot handle UNC addresses)
230 # as cmd.exe cannot handle UNC addresses)
232 os.chdir("c:")
231 os.chdir("c:")
233 # issue pushd to the UNC-share and then run the command
232 # issue pushd to the UNC-share and then run the command
234 try:
233 try:
235 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
234 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
236 finally:
235 finally:
237 os.chdir(path)
236 os.chdir(path)
238 else:
237 else:
239 shell_ori(cmd,verbose,debug,header)
238 shell_ori(cmd,verbose,debug,header)
240
239
241 shell.__doc__ = shell_ori.__doc__
240 shell.__doc__ = shell_ori.__doc__
242
241
243
242
244 def getoutput(cmd, verbose=0, debug=0, header='', split=0):
243 def getoutput(cmd, verbose=0, debug=0, header='', split=0):
245 """Dummy substitute for perl's backquotes.
244 """Dummy substitute for perl's backquotes.
246
245
247 Executes a command and returns the output.
246 Executes a command and returns the output.
248
247
249 Accepts the same arguments as system(), plus:
248 Accepts the same arguments as system(), plus:
250
249
251 - split(0): if true, the output is returned as a list split on newlines.
250 - split(0): if true, the output is returned as a list split on newlines.
252
251
253 Note: a stateful version of this function is available through the
252 Note: a stateful version of this function is available through the
254 SystemExec class.
253 SystemExec class.
255
254
256 This is pretty much deprecated and rarely used, getoutputerror may be
255 This is pretty much deprecated and rarely used, getoutputerror may be
257 what you need.
256 what you need.
258
257
259 """
258 """
260
259
261 if verbose or debug: print header+cmd
260 if verbose or debug: print header+cmd
262 if not debug:
261 if not debug:
263 pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout
262 pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout
264 output = pipe.read()
263 output = pipe.read()
265 # stipping last \n is here for backwards compat.
264 # stipping last \n is here for backwards compat.
266 if output.endswith('\n'):
265 if output.endswith('\n'):
267 output = output[:-1]
266 output = output[:-1]
268 if split:
267 if split:
269 return output.split('\n')
268 return output.split('\n')
270 else:
269 else:
271 return output
270 return output
272
271
273
272
274 # for compatibility with older naming conventions
273 # for compatibility with older naming conventions
275 xsys = system
274 xsys = system
276
275
277
276
278 def getoutputerror(cmd, verbose=0, debug=0, header='', split=0):
277 def getoutputerror(cmd, verbose=0, debug=0, header='', split=0):
279 """Return (standard output,standard error) of executing cmd in a shell.
278 """Return (standard output,standard error) of executing cmd in a shell.
280
279
281 Accepts the same arguments as system(), plus:
280 Accepts the same arguments as system(), plus:
282
281
283 - split(0): if true, each of stdout/err is returned as a list split on
282 - split(0): if true, each of stdout/err is returned as a list split on
284 newlines.
283 newlines.
285
284
286 Note: a stateful version of this function is available through the
285 Note: a stateful version of this function is available through the
287 SystemExec class."""
286 SystemExec class."""
288
287
289 if verbose or debug: print header+cmd
288 if verbose or debug: print header+cmd
290 if not cmd:
289 if not cmd:
291 if split:
290 if split:
292 return [],[]
291 return [],[]
293 else:
292 else:
294 return '',''
293 return '',''
295 if not debug:
294 if not debug:
296 p = subprocess.Popen(cmd, shell=True,
295 p = subprocess.Popen(cmd, shell=True,
297 stdin=subprocess.PIPE,
296 stdin=subprocess.PIPE,
298 stdout=subprocess.PIPE,
297 stdout=subprocess.PIPE,
299 stderr=subprocess.PIPE,
298 stderr=subprocess.PIPE,
300 close_fds=True)
299 close_fds=True)
301 pin, pout, perr = (p.stdin, p.stdout, p.stderr)
300 pin, pout, perr = (p.stdin, p.stdout, p.stderr)
302
301
303 tout = pout.read().rstrip()
302 tout = pout.read().rstrip()
304 terr = perr.read().rstrip()
303 terr = perr.read().rstrip()
305 pin.close()
304 pin.close()
306 pout.close()
305 pout.close()
307 perr.close()
306 perr.close()
308 if split:
307 if split:
309 return tout.split('\n'),terr.split('\n')
308 return tout.split('\n'),terr.split('\n')
310 else:
309 else:
311 return tout,terr
310 return tout,terr
312
311
313
312
314 class SystemExec:
313 class SystemExec:
315 """Access the system and getoutput functions through a stateful interface.
314 """Access the system and getoutput functions through a stateful interface.
316
315
317 Note: here we refer to the system and getoutput functions from this
316 Note: here we refer to the system and getoutput functions from this
318 library, not the ones from the standard python library.
317 library, not the ones from the standard python library.
319
318
320 This class offers the system and getoutput functions as methods, but the
319 This class offers the system and getoutput functions as methods, but the
321 verbose, debug and header parameters can be set for the instance (at
320 verbose, debug and header parameters can be set for the instance (at
322 creation time or later) so that they don't need to be specified on each
321 creation time or later) so that they don't need to be specified on each
323 call.
322 call.
324
323
325 For efficiency reasons, there's no way to override the parameters on a
324 For efficiency reasons, there's no way to override the parameters on a
326 per-call basis other than by setting instance attributes. If you need
325 per-call basis other than by setting instance attributes. If you need
327 local overrides, it's best to directly call system() or getoutput().
326 local overrides, it's best to directly call system() or getoutput().
328
327
329 The following names are provided as alternate options:
328 The following names are provided as alternate options:
330 - xsys: alias to system
329 - xsys: alias to system
331 - bq: alias to getoutput
330 - bq: alias to getoutput
332
331
333 An instance can then be created as:
332 An instance can then be created as:
334 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
333 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
335 """
334 """
336
335
337 def __init__(self, verbose=0, debug=0, header='', split=0):
336 def __init__(self, verbose=0, debug=0, header='', split=0):
338 """Specify the instance's values for verbose, debug and header."""
337 """Specify the instance's values for verbose, debug and header."""
339 self.verbose = verbose
338 self.verbose = verbose
340 self.debug = debug
339 self.debug = debug
341 self.header = header
340 self.header = header
342 self.split = split
341 self.split = split
343
342
344 def system(self, cmd):
343 def system(self, cmd):
345 """Stateful interface to system(), with the same keyword parameters."""
344 """Stateful interface to system(), with the same keyword parameters."""
346
345
347 system(cmd, self.verbose, self.debug, self.header)
346 system(cmd, self.verbose, self.debug, self.header)
348
347
349 def shell(self, cmd):
348 def shell(self, cmd):
350 """Stateful interface to shell(), with the same keyword parameters."""
349 """Stateful interface to shell(), with the same keyword parameters."""
351
350
352 shell(cmd, self.verbose, self.debug, self.header)
351 shell(cmd, self.verbose, self.debug, self.header)
353
352
354 xsys = system # alias
353 xsys = system # alias
355
354
356 def getoutput(self, cmd):
355 def getoutput(self, cmd):
357 """Stateful interface to getoutput()."""
356 """Stateful interface to getoutput()."""
358
357
359 return getoutput(cmd, self.verbose, self.debug, self.header, self.split)
358 return getoutput(cmd, self.verbose, self.debug, self.header, self.split)
360
359
361 def getoutputerror(self, cmd):
360 def getoutputerror(self, cmd):
362 """Stateful interface to getoutputerror()."""
361 """Stateful interface to getoutputerror()."""
363
362
364 return getoutputerror(cmd, self.verbose, self.debug, self.header, self.split)
363 return getoutputerror(cmd, self.verbose, self.debug, self.header, self.split)
365
364
366 bq = getoutput # alias
365 bq = getoutput # alias
367
366
368
367
@@ -1,62 +1,68 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for platutils.py
3 Tests for platutils.py
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import sys
17 import sys
18
18
19 import nose.tools as nt
19 import nose.tools as nt
20
20
21 from IPython.utils.process import find_cmd, FindCmdError
21 from IPython.utils.process import find_cmd, FindCmdError, arg_split
22 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Tests
25 # Tests
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 def test_find_cmd_python():
28 def test_find_cmd_python():
29 """Make sure we find sys.exectable for python."""
29 """Make sure we find sys.exectable for python."""
30 nt.assert_equals(find_cmd('python'), sys.executable)
30 nt.assert_equals(find_cmd('python'), sys.executable)
31
31
32
32
33 @dec.skip_win32
33 @dec.skip_win32
34 def test_find_cmd_ls():
34 def test_find_cmd_ls():
35 """Make sure we can find the full path to ls."""
35 """Make sure we can find the full path to ls."""
36 path = find_cmd('ls')
36 path = find_cmd('ls')
37 nt.assert_true(path.endswith('ls'))
37 nt.assert_true(path.endswith('ls'))
38
38
39
39
40 def has_pywin32():
40 def has_pywin32():
41 try:
41 try:
42 import win32api
42 import win32api
43 except ImportError:
43 except ImportError:
44 return False
44 return False
45 return True
45 return True
46
46
47
47
48 @dec.onlyif(has_pywin32, "This test requires win32api to run")
48 @dec.onlyif(has_pywin32, "This test requires win32api to run")
49 def test_find_cmd_pythonw():
49 def test_find_cmd_pythonw():
50 """Try to find pythonw on Windows."""
50 """Try to find pythonw on Windows."""
51 path = find_cmd('pythonw')
51 path = find_cmd('pythonw')
52 nt.assert_true(path.endswith('pythonw.exe'))
52 nt.assert_true(path.endswith('pythonw.exe'))
53
53
54
54
55 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
55 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
56 "This test runs on posix or in win32 with win32api installed")
56 "This test runs on posix or in win32 with win32api installed")
57 def test_find_cmd_fail():
57 def test_find_cmd_fail():
58 """Make sure that FindCmdError is raised if we can't find the cmd."""
58 """Make sure that FindCmdError is raised if we can't find the cmd."""
59 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
59 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
60
60
61
61
62
62 def test_arg_split():
63 """Ensure that argument lines are correctly split like in a shell."""
64 tests = [['hi', ['hi']],
65 [u'hi', [u'hi']],
66 ]
67 for argstr, argv in tests:
68 nt.assert_equal(arg_split(argstr), argv)
General Comments 0
You need to be logged in to leave comments. Login now