Show More
@@ -1872,22 +1872,44 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||||
1872 | # Things related to the running of system commands |
|
1872 | # Things related to the running of system commands | |
1873 | #------------------------------------------------------------------------- |
|
1873 | #------------------------------------------------------------------------- | |
1874 |
|
1874 | |||
1875 | def system(self, cmd): |
|
1875 | def system_piped(self, cmd): | |
1876 |
"""Call the given cmd in a subprocess |
|
1876 | """Call the given cmd in a subprocess, piping stdout/err | |
1877 |
|
1877 | |||
1878 | Parameters |
|
1878 | Parameters | |
1879 | ---------- |
|
1879 | ---------- | |
1880 | cmd : str |
|
1880 | cmd : str | |
1881 | Command to execute (can not end in '&', as bacground processes are |
|
1881 | Command to execute (can not end in '&', as background processes are | |
1882 | not supported. |
|
1882 | not supported. Should not be a command that expects input | |
|
1883 | other than simple text. | |||
1883 | """ |
|
1884 | """ | |
|
1885 | if cmd.rstrip().endswith('&'): | |||
|
1886 | # this is *far* from a rigorous test | |||
1884 | # We do not support backgrounding processes because we either use |
|
1887 | # We do not support backgrounding processes because we either use | |
1885 | # pexpect or pipes to read from. Users can always just call |
|
1888 | # pexpect or pipes to read from. Users can always just call | |
1886 | # os.system() if they really want a background process. |
|
1889 | # os.system() or use ip.system=ip.system_raw | |
1887 | if cmd.endswith('&'): |
|
1890 | # if they really want a background process. | |
1888 | raise OSError("Background processes not supported.") |
|
1891 | raise OSError("Background processes not supported.") | |
1889 |
|
1892 | |||
1890 | return system(self.var_expand(cmd, depth=2)) |
|
1893 | # we explicitly do NOT return the subprocess status code, because | |
|
1894 | # a non-None value would trigger :func:`sys.displayhook` calls. | |||
|
1895 | # Instead, we store the exit_code in user_ns. | |||
|
1896 | self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=2)) | |||
|
1897 | ||||
|
1898 | def system_raw(self, cmd): | |||
|
1899 | """Call the given cmd in a subprocess using os.system | |||
|
1900 | ||||
|
1901 | Parameters | |||
|
1902 | ---------- | |||
|
1903 | cmd : str | |||
|
1904 | Command to execute. | |||
|
1905 | """ | |||
|
1906 | # We explicitly do NOT return the subprocess status code, because | |||
|
1907 | # a non-None value would trigger :func:`sys.displayhook` calls. | |||
|
1908 | # Instead, we store the exit_code in user_ns. | |||
|
1909 | self.user_ns['_exit_code'] = os.system(self.var_expand(cmd, depth=2)) | |||
|
1910 | ||||
|
1911 | # use piped system by default, because it is better behaved | |||
|
1912 | system = system_piped | |||
1891 |
|
1913 | |||
1892 | def getoutput(self, cmd, split=True): |
|
1914 | def getoutput(self, cmd, split=True): | |
1893 | """Get output (possibly including stderr) from a subprocess. |
|
1915 | """Get output (possibly including stderr) from a subprocess. | |
@@ -1905,7 +1927,8 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||||
1905 | manipulation of line-based output. You can use '?' on them for |
|
1927 | manipulation of line-based output. You can use '?' on them for | |
1906 | details. |
|
1928 | details. | |
1907 | """ |
|
1929 | """ | |
1908 | if cmd.endswith('&'): |
|
1930 | if cmd.rstrip().endswith('&'): | |
|
1931 | # this is *far* from a rigorous test | |||
1909 | raise OSError("Background processes not supported.") |
|
1932 | raise OSError("Background processes not supported.") | |
1910 | out = getoutput(self.var_expand(cmd, depth=2)) |
|
1933 | out = getoutput(self.var_expand(cmd, depth=2)) | |
1911 | if split: |
|
1934 | if split: | |
@@ -2172,7 +2195,9 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||||
2172 | prefilter_failed = False |
|
2195 | prefilter_failed = False | |
2173 | if len(cell.splitlines()) == 1: |
|
2196 | if len(cell.splitlines()) == 1: | |
2174 | try: |
|
2197 | try: | |
2175 | cell = self.prefilter_manager.prefilter_line(cell) |
|
2198 | # use prefilter_lines to handle trailing newlines | |
|
2199 | # restore trailing newline for ast.parse | |||
|
2200 | cell = self.prefilter_manager.prefilter_lines(cell) + '\n' | |||
2176 | except AliasError as e: |
|
2201 | except AliasError as e: | |
2177 | error(e) |
|
2202 | error(e) | |
2178 | prefilter_failed=True |
|
2203 | prefilter_failed=True |
@@ -107,3 +107,10 b' class InteractiveShellTestCase(unittest.TestCase):' | |||||
107 | io.stderr = save_err |
|
107 | io.stderr = save_err | |
108 | self.assertEquals(err.split(':')[0], 'ERROR') |
|
108 | self.assertEquals(err.split(':')[0], 'ERROR') | |
109 |
|
109 | |||
|
110 | def test_trailing_newline(self): | |||
|
111 | """test that running !(command) does not raise a SyntaxError""" | |||
|
112 | ip = get_ipython() | |||
|
113 | ip.run_cell('!(true)\n', False) | |||
|
114 | ip.run_cell('!(true)\n\n\n', False) | |||
|
115 | ||||
|
116 |
@@ -86,6 +86,12 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
86 | config=config, ipython_dir=ipython_dir, user_ns=user_ns, |
|
86 | config=config, ipython_dir=ipython_dir, user_ns=user_ns, | |
87 | user_global_ns=user_global_ns, custom_exceptions=custom_exceptions |
|
87 | user_global_ns=user_global_ns, custom_exceptions=custom_exceptions | |
88 | ) |
|
88 | ) | |
|
89 | # use os.system instead of utils.process.system by default, except on Windows | |||
|
90 | if os.name == 'nt': | |||
|
91 | self.system = self.system_piped | |||
|
92 | else: | |||
|
93 | self.system = self.system_raw | |||
|
94 | ||||
89 | self.init_term_title() |
|
95 | self.init_term_title() | |
90 | self.init_usage(usage) |
|
96 | self.init_usage(usage) | |
91 | self.init_banner(banner1, banner2, display_banner) |
|
97 | self.init_banner(banner1, banner2, display_banner) |
@@ -130,9 +130,7 b' class ProcessHandler(object):' | |||||
130 |
|
130 | |||
131 | Returns |
|
131 | Returns | |
132 | ------- |
|
132 | ------- | |
133 | None : we explicitly do NOT return the subprocess status code, as this |
|
133 | int : child's exitstatus | |
134 | utility is meant to be used extensively in IPython, where any return |
|
|||
135 | value would trigger :func:`sys.displayhook` calls. |
|
|||
136 | """ |
|
134 | """ | |
137 | pcmd = self._make_cmd(cmd) |
|
135 | pcmd = self._make_cmd(cmd) | |
138 | # Patterns to match on the output, for pexpect. We read input and |
|
136 | # Patterns to match on the output, for pexpect. We read input and | |
@@ -181,6 +179,7 b' class ProcessHandler(object):' | |||||
181 | finally: |
|
179 | finally: | |
182 | # Ensure the subprocess really is terminated |
|
180 | # Ensure the subprocess really is terminated | |
183 | child.terminate(force=True) |
|
181 | child.terminate(force=True) | |
|
182 | return child.exitstatus | |||
184 |
|
183 | |||
185 | def _make_cmd(self, cmd): |
|
184 | def _make_cmd(self, cmd): | |
186 | return '%s -c "%s"' % (self.sh, cmd) |
|
185 | return '%s -c "%s"' % (self.sh, cmd) |
@@ -96,6 +96,9 b' def _system_body(p):' | |||||
96 | line = line.decode(enc, 'replace') |
|
96 | line = line.decode(enc, 'replace') | |
97 | print(line, file=sys.stderr) |
|
97 | print(line, file=sys.stderr) | |
98 |
|
98 | |||
|
99 | # Wait to finish for returncode | |||
|
100 | return p.wait() | |||
|
101 | ||||
99 |
|
102 | |||
100 | def system(cmd): |
|
103 | def system(cmd): | |
101 | """Win32 version of os.system() that works with network shares. |
|
104 | """Win32 version of os.system() that works with network shares. | |
@@ -116,7 +119,7 b' def system(cmd):' | |||||
116 | with AvoidUNCPath() as path: |
|
119 | with AvoidUNCPath() as path: | |
117 | if path is not None: |
|
120 | if path is not None: | |
118 | cmd = '"pushd %s &&"%s' % (path, cmd) |
|
121 | cmd = '"pushd %s &&"%s' % (path, cmd) | |
119 | process_handler(cmd, _system_body) |
|
122 | return process_handler(cmd, _system_body) | |
120 |
|
123 | |||
121 |
|
124 | |||
122 | def getoutput(cmd): |
|
125 | def getoutput(cmd): |
General Comments 0
You need to be logged in to leave comments.
Login now