Show More
@@ -1,125 +1,122 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-2011 The IPython Development Team |
|
7 | # Copyright (C) 2008-2011 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 | from __future__ import print_function |
|
16 | from __future__ import print_function | |
17 |
|
17 | |||
18 | # Stdlib |
|
18 | # Stdlib | |
19 | import os |
|
19 | import os | |
20 | import sys |
|
20 | import sys | |
21 | import shlex |
|
21 | 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, arg_split |
|
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, arg_split |
|
27 | from ._process_posix import _find_cmd, system, getoutput, arg_split | |
28 |
|
28 | |||
29 |
|
29 | |||
30 | from ._process_common import getoutputerror |
|
30 | from ._process_common import getoutputerror | |
31 |
|
31 | |||
32 | #----------------------------------------------------------------------------- |
|
32 | #----------------------------------------------------------------------------- | |
33 | # Code |
|
33 | # Code | |
34 | #----------------------------------------------------------------------------- |
|
34 | #----------------------------------------------------------------------------- | |
35 |
|
35 | |||
36 |
|
36 | |||
37 | class FindCmdError(Exception): |
|
37 | class FindCmdError(Exception): | |
38 | pass |
|
38 | pass | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | def find_cmd(cmd): |
|
41 | def find_cmd(cmd): | |
42 | """Find absolute path to executable cmd in a cross platform manner. |
|
42 | """Find absolute path to executable cmd in a cross platform manner. | |
43 |
|
43 | |||
44 | This function tries to determine the full path to a command line program |
|
44 | This function tries to determine the full path to a command line program | |
45 | using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the |
|
45 | using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the | |
46 |
time it will use the version that is first on the users `PATH`. |
|
46 | time it will use the version that is first on the users `PATH`. | |
47 | cmd is `python` return `sys.executable`. |
|
|||
48 |
|
47 | |||
49 | Warning, don't use this to find IPython command line programs as there |
|
48 | Warning, don't use this to find IPython command line programs as there | |
50 | is a risk you will find the wrong one. Instead find those using the |
|
49 | is a risk you will find the wrong one. Instead find those using the | |
51 | following code and looking for the application itself:: |
|
50 | following code and looking for the application itself:: | |
52 |
|
51 | |||
53 | from IPython.utils.path import get_ipython_module_path |
|
52 | from IPython.utils.path import get_ipython_module_path | |
54 | from IPython.utils.process import pycmd2argv |
|
53 | from IPython.utils.process import pycmd2argv | |
55 | argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp')) |
|
54 | argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp')) | |
56 |
|
55 | |||
57 | Parameters |
|
56 | Parameters | |
58 | ---------- |
|
57 | ---------- | |
59 | cmd : str |
|
58 | cmd : str | |
60 | The command line program to look for. |
|
59 | The command line program to look for. | |
61 | """ |
|
60 | """ | |
62 | if cmd in ('python', os.path.basename(sys.executable)): |
|
|||
63 | return os.path.abspath(sys.executable) |
|
|||
64 | try: |
|
61 | try: | |
65 | path = _find_cmd(cmd).rstrip() |
|
62 | path = _find_cmd(cmd).rstrip() | |
66 | except OSError: |
|
63 | except OSError: | |
67 | raise FindCmdError('command could not be found: %s' % cmd) |
|
64 | raise FindCmdError('command could not be found: %s' % cmd) | |
68 | # which returns empty if not found |
|
65 | # which returns empty if not found | |
69 | if path == '': |
|
66 | if path == '': | |
70 | raise FindCmdError('command could not be found: %s' % cmd) |
|
67 | raise FindCmdError('command could not be found: %s' % cmd) | |
71 | return os.path.abspath(path) |
|
68 | return os.path.abspath(path) | |
72 |
|
69 | |||
73 |
|
70 | |||
74 | def is_cmd_found(cmd): |
|
71 | def is_cmd_found(cmd): | |
75 | """Check whether executable `cmd` exists or not and return a bool.""" |
|
72 | """Check whether executable `cmd` exists or not and return a bool.""" | |
76 | try: |
|
73 | try: | |
77 | find_cmd(cmd) |
|
74 | find_cmd(cmd) | |
78 | return True |
|
75 | return True | |
79 | except FindCmdError: |
|
76 | except FindCmdError: | |
80 | return False |
|
77 | return False | |
81 |
|
78 | |||
82 |
|
79 | |||
83 | def pycmd2argv(cmd): |
|
80 | def pycmd2argv(cmd): | |
84 | r"""Take the path of a python command and return a list (argv-style). |
|
81 | r"""Take the path of a python command and return a list (argv-style). | |
85 |
|
82 | |||
86 | This only works on Python based command line programs and will find the |
|
83 | This only works on Python based command line programs and will find the | |
87 | location of the ``python`` executable using ``sys.executable`` to make |
|
84 | location of the ``python`` executable using ``sys.executable`` to make | |
88 | sure the right version is used. |
|
85 | sure the right version is used. | |
89 |
|
86 | |||
90 | For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe, |
|
87 | For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe, | |
91 | .com or .bat, and [, cmd] otherwise. |
|
88 | .com or .bat, and [, cmd] otherwise. | |
92 |
|
89 | |||
93 | Parameters |
|
90 | Parameters | |
94 | ---------- |
|
91 | ---------- | |
95 | cmd : string |
|
92 | cmd : string | |
96 | The path of the command. |
|
93 | The path of the command. | |
97 |
|
94 | |||
98 | Returns |
|
95 | Returns | |
99 | ------- |
|
96 | ------- | |
100 | argv-style list. |
|
97 | argv-style list. | |
101 | """ |
|
98 | """ | |
102 | ext = os.path.splitext(cmd)[1] |
|
99 | ext = os.path.splitext(cmd)[1] | |
103 | if ext in ['.exe', '.com', '.bat']: |
|
100 | if ext in ['.exe', '.com', '.bat']: | |
104 | return [cmd] |
|
101 | return [cmd] | |
105 | else: |
|
102 | else: | |
106 | return [sys.executable, cmd] |
|
103 | return [sys.executable, cmd] | |
107 |
|
104 | |||
108 |
|
105 | |||
109 | def abbrev_cwd(): |
|
106 | def abbrev_cwd(): | |
110 | """ Return abbreviated version of cwd, e.g. d:mydir """ |
|
107 | """ Return abbreviated version of cwd, e.g. d:mydir """ | |
111 | cwd = os.getcwdu().replace('\\','/') |
|
108 | cwd = os.getcwdu().replace('\\','/') | |
112 | drivepart = '' |
|
109 | drivepart = '' | |
113 | tail = cwd |
|
110 | tail = cwd | |
114 | if sys.platform == 'win32': |
|
111 | if sys.platform == 'win32': | |
115 | if len(cwd) < 4: |
|
112 | if len(cwd) < 4: | |
116 | return cwd |
|
113 | return cwd | |
117 | drivepart,tail = os.path.splitdrive(cwd) |
|
114 | drivepart,tail = os.path.splitdrive(cwd) | |
118 |
|
115 | |||
119 |
|
116 | |||
120 | parts = tail.split('/') |
|
117 | parts = tail.split('/') | |
121 | if len(parts) > 2: |
|
118 | if len(parts) > 2: | |
122 | tail = '/'.join(parts[-2:]) |
|
119 | tail = '/'.join(parts[-2:]) | |
123 |
|
120 | |||
124 | return (drivepart + ( |
|
121 | return (drivepart + ( | |
125 | cwd == '/' and '/' or tail)) |
|
122 | cwd == '/' and '/' or tail)) |
@@ -1,138 +1,134 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-2011 The IPython Development Team |
|
7 | # Copyright (C) 2008-2011 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 | import os |
|
18 | import os | |
19 | from unittest import TestCase |
|
19 | from unittest import TestCase | |
20 |
|
20 | |||
21 | import nose.tools as nt |
|
21 | import nose.tools as nt | |
22 |
|
22 | |||
23 | from IPython.utils.process import (find_cmd, FindCmdError, arg_split, |
|
23 | from IPython.utils.process import (find_cmd, FindCmdError, arg_split, | |
24 | system, getoutput, getoutputerror) |
|
24 | system, getoutput, getoutputerror) | |
25 | from IPython.testing import decorators as dec |
|
25 | from IPython.testing import decorators as dec | |
26 | from IPython.testing import tools as tt |
|
26 | from IPython.testing import tools as tt | |
27 |
|
27 | |||
28 | python = os.path.basename(sys.executable) |
|
28 | python = os.path.basename(sys.executable) | |
29 |
|
29 | |||
30 | #----------------------------------------------------------------------------- |
|
30 | #----------------------------------------------------------------------------- | |
31 | # Tests |
|
31 | # Tests | |
32 | #----------------------------------------------------------------------------- |
|
32 | #----------------------------------------------------------------------------- | |
33 |
|
33 | |||
34 | def test_find_cmd_python(): |
|
|||
35 | """Make sure we find sys.exectable for python.""" |
|
|||
36 | nt.assert_equal(find_cmd(python), sys.executable) |
|
|||
37 |
|
34 | |||
38 |
|
||||
39 | @dec.skip_win32 |
|
35 | @dec.skip_win32 | |
40 | def test_find_cmd_ls(): |
|
36 | def test_find_cmd_ls(): | |
41 | """Make sure we can find the full path to ls.""" |
|
37 | """Make sure we can find the full path to ls.""" | |
42 | path = find_cmd('ls') |
|
38 | path = find_cmd('ls') | |
43 | nt.assert_true(path.endswith('ls')) |
|
39 | nt.assert_true(path.endswith('ls')) | |
44 |
|
40 | |||
45 |
|
41 | |||
46 | def has_pywin32(): |
|
42 | def has_pywin32(): | |
47 | try: |
|
43 | try: | |
48 | import win32api |
|
44 | import win32api | |
49 | except ImportError: |
|
45 | except ImportError: | |
50 | return False |
|
46 | return False | |
51 | return True |
|
47 | return True | |
52 |
|
48 | |||
53 |
|
49 | |||
54 | @dec.onlyif(has_pywin32, "This test requires win32api to run") |
|
50 | @dec.onlyif(has_pywin32, "This test requires win32api to run") | |
55 | def test_find_cmd_pythonw(): |
|
51 | def test_find_cmd_pythonw(): | |
56 | """Try to find pythonw on Windows.""" |
|
52 | """Try to find pythonw on Windows.""" | |
57 | path = find_cmd('pythonw') |
|
53 | path = find_cmd('pythonw') | |
58 | nt.assert_true(path.endswith('pythonw.exe')) |
|
54 | nt.assert_true(path.endswith('pythonw.exe')) | |
59 |
|
55 | |||
60 |
|
56 | |||
61 | @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(), |
|
57 | @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(), | |
62 | "This test runs on posix or in win32 with win32api installed") |
|
58 | "This test runs on posix or in win32 with win32api installed") | |
63 | def test_find_cmd_fail(): |
|
59 | def test_find_cmd_fail(): | |
64 | """Make sure that FindCmdError is raised if we can't find the cmd.""" |
|
60 | """Make sure that FindCmdError is raised if we can't find the cmd.""" | |
65 | nt.assert_raises(FindCmdError,find_cmd,'asdfasdf') |
|
61 | nt.assert_raises(FindCmdError,find_cmd,'asdfasdf') | |
66 |
|
62 | |||
67 |
|
63 | |||
68 | @dec.skip_win32 |
|
64 | @dec.skip_win32 | |
69 | def test_arg_split(): |
|
65 | def test_arg_split(): | |
70 | """Ensure that argument lines are correctly split like in a shell.""" |
|
66 | """Ensure that argument lines are correctly split like in a shell.""" | |
71 | tests = [['hi', ['hi']], |
|
67 | tests = [['hi', ['hi']], | |
72 | [u'hi', [u'hi']], |
|
68 | [u'hi', [u'hi']], | |
73 | ['hello there', ['hello', 'there']], |
|
69 | ['hello there', ['hello', 'there']], | |
74 | # \u01ce == \N{LATIN SMALL LETTER A WITH CARON} |
|
70 | # \u01ce == \N{LATIN SMALL LETTER A WITH CARON} | |
75 | # Do not use \N because the tests crash with syntax error in |
|
71 | # Do not use \N because the tests crash with syntax error in | |
76 | # some cases, for example windows python2.6. |
|
72 | # some cases, for example windows python2.6. | |
77 | [u'h\u01cello', [u'h\u01cello']], |
|
73 | [u'h\u01cello', [u'h\u01cello']], | |
78 | ['something "with quotes"', ['something', '"with quotes"']], |
|
74 | ['something "with quotes"', ['something', '"with quotes"']], | |
79 | ] |
|
75 | ] | |
80 | for argstr, argv in tests: |
|
76 | for argstr, argv in tests: | |
81 | nt.assert_equal(arg_split(argstr), argv) |
|
77 | nt.assert_equal(arg_split(argstr), argv) | |
82 |
|
78 | |||
83 | @dec.skip_if_not_win32 |
|
79 | @dec.skip_if_not_win32 | |
84 | def test_arg_split_win32(): |
|
80 | def test_arg_split_win32(): | |
85 | """Ensure that argument lines are correctly split like in a shell.""" |
|
81 | """Ensure that argument lines are correctly split like in a shell.""" | |
86 | tests = [['hi', ['hi']], |
|
82 | tests = [['hi', ['hi']], | |
87 | [u'hi', [u'hi']], |
|
83 | [u'hi', [u'hi']], | |
88 | ['hello there', ['hello', 'there']], |
|
84 | ['hello there', ['hello', 'there']], | |
89 | [u'h\u01cello', [u'h\u01cello']], |
|
85 | [u'h\u01cello', [u'h\u01cello']], | |
90 | ['something "with quotes"', ['something', 'with quotes']], |
|
86 | ['something "with quotes"', ['something', 'with quotes']], | |
91 | ] |
|
87 | ] | |
92 | for argstr, argv in tests: |
|
88 | for argstr, argv in tests: | |
93 | nt.assert_equal(arg_split(argstr), argv) |
|
89 | nt.assert_equal(arg_split(argstr), argv) | |
94 |
|
90 | |||
95 |
|
91 | |||
96 | class SubProcessTestCase(TestCase, tt.TempFileMixin): |
|
92 | class SubProcessTestCase(TestCase, tt.TempFileMixin): | |
97 | def setUp(self): |
|
93 | def setUp(self): | |
98 | """Make a valid python temp file.""" |
|
94 | """Make a valid python temp file.""" | |
99 | lines = ["from __future__ import print_function", |
|
95 | lines = ["from __future__ import print_function", | |
100 | "import sys", |
|
96 | "import sys", | |
101 | "print('on stdout', end='', file=sys.stdout)", |
|
97 | "print('on stdout', end='', file=sys.stdout)", | |
102 | "print('on stderr', end='', file=sys.stderr)", |
|
98 | "print('on stderr', end='', file=sys.stderr)", | |
103 | "sys.stdout.flush()", |
|
99 | "sys.stdout.flush()", | |
104 | "sys.stderr.flush()"] |
|
100 | "sys.stderr.flush()"] | |
105 | self.mktmp('\n'.join(lines)) |
|
101 | self.mktmp('\n'.join(lines)) | |
106 |
|
102 | |||
107 | def test_system(self): |
|
103 | def test_system(self): | |
108 | status = system('%s "%s"' % (python, self.fname)) |
|
104 | status = system('%s "%s"' % (python, self.fname)) | |
109 | self.assertEqual(status, 0) |
|
105 | self.assertEqual(status, 0) | |
110 |
|
106 | |||
111 | def test_system_quotes(self): |
|
107 | def test_system_quotes(self): | |
112 | status = system('%s -c "import sys"' % python) |
|
108 | status = system('%s -c "import sys"' % python) | |
113 | self.assertEqual(status, 0) |
|
109 | self.assertEqual(status, 0) | |
114 |
|
110 | |||
115 | def test_getoutput(self): |
|
111 | def test_getoutput(self): | |
116 | out = getoutput('%s "%s"' % (python, self.fname)) |
|
112 | out = getoutput('%s "%s"' % (python, self.fname)) | |
117 | # we can't rely on the order the line buffered streams are flushed |
|
113 | # we can't rely on the order the line buffered streams are flushed | |
118 | try: |
|
114 | try: | |
119 | self.assertEqual(out, 'on stderron stdout') |
|
115 | self.assertEqual(out, 'on stderron stdout') | |
120 | except AssertionError: |
|
116 | except AssertionError: | |
121 | self.assertEqual(out, 'on stdouton stderr') |
|
117 | self.assertEqual(out, 'on stdouton stderr') | |
122 |
|
118 | |||
123 | def test_getoutput_quoted(self): |
|
119 | def test_getoutput_quoted(self): | |
124 | out = getoutput('%s -c "print (1)"' % python) |
|
120 | out = getoutput('%s -c "print (1)"' % python) | |
125 | self.assertEqual(out.strip(), '1') |
|
121 | self.assertEqual(out.strip(), '1') | |
126 |
|
122 | |||
127 | #Invalid quoting on windows |
|
123 | #Invalid quoting on windows | |
128 | @dec.skip_win32 |
|
124 | @dec.skip_win32 | |
129 | def test_getoutput_quoted2(self): |
|
125 | def test_getoutput_quoted2(self): | |
130 | out = getoutput("%s -c 'print (1)'" % python) |
|
126 | out = getoutput("%s -c 'print (1)'" % python) | |
131 | self.assertEqual(out.strip(), '1') |
|
127 | self.assertEqual(out.strip(), '1') | |
132 | out = getoutput("%s -c 'print (\"1\")'" % python) |
|
128 | out = getoutput("%s -c 'print (\"1\")'" % python) | |
133 | self.assertEqual(out.strip(), '1') |
|
129 | self.assertEqual(out.strip(), '1') | |
134 |
|
130 | |||
135 | def test_getoutput_error(self): |
|
131 | def test_getoutput_error(self): | |
136 | out, err = getoutputerror('%s "%s"' % (python, self.fname)) |
|
132 | out, err = getoutputerror('%s "%s"' % (python, self.fname)) | |
137 | self.assertEqual(out, 'on stdout') |
|
133 | self.assertEqual(out, 'on stdout') | |
138 | self.assertEqual(err, 'on stderr') |
|
134 | self.assertEqual(err, 'on stderr') |
General Comments 0
You need to be logged in to leave comments.
Login now