Show More
@@ -34,11 +34,6 b' before_install:' | |||||
34 | install: |
|
34 | install: | |
35 | - pip install pip --upgrade |
|
35 | - pip install pip --upgrade | |
36 | - pip install setuptools --upgrade |
|
36 | - pip install setuptools --upgrade | |
37 | - if [[ "$TRAVIS_PYTHON_VERSION" == "3.6" ]]; then |
|
|||
38 | echo "for the time being still test on 3.6"; |
|
|||
39 | sed -ibkp s/7/6/g setup.py; |
|
|||
40 | git diff; |
|
|||
41 | fi |
|
|||
42 | - pip install -e file://$PWD#egg=ipython[test] --upgrade |
|
37 | - pip install -e file://$PWD#egg=ipython[test] --upgrade | |
43 | - pip install trio curio --upgrade --upgrade-strategy eager |
|
38 | - pip install trio curio --upgrade --upgrade-strategy eager | |
44 | - pip install 'pytest' 'matplotlib !=3.2.0' |
|
39 | - pip install 'pytest' 'matplotlib !=3.2.0' | |
@@ -73,9 +68,6 b' after_success:' | |||||
73 | matrix: |
|
68 | matrix: | |
74 | include: |
|
69 | include: | |
75 | - arch: amd64 |
|
70 | - arch: amd64 | |
76 | python: "3.6" |
|
|||
77 | dist: xenial |
|
|||
78 | - arch: amd64 |
|
|||
79 | python: "3.7" |
|
71 | python: "3.7" | |
80 | dist: xenial |
|
72 | dist: xenial | |
81 | - arch: amd64 |
|
73 | - arch: amd64 |
@@ -8,7 +8,7 b' import os' | |||||
8 | import sys |
|
8 | import sys | |
9 | import signal |
|
9 | import signal | |
10 | import time |
|
10 | import time | |
11 | from subprocess import Popen, PIPE, CalledProcessError |
|
11 | import asyncio | |
12 | import atexit |
|
12 | import atexit | |
13 |
|
13 | |||
14 | from IPython.core import magic_arguments |
|
14 | from IPython.core import magic_arguments | |
@@ -175,11 +175,44 b' class ScriptMagics(Magics):' | |||||
175 | 2 |
|
175 | 2 | |
176 | 3 |
|
176 | 3 | |
177 | """ |
|
177 | """ | |
178 | argv = arg_split(line, posix = not sys.platform.startswith('win')) |
|
178 | ||
|
179 | async def _handle_stream(stream, stream_arg, file_object): | |||
|
180 | while True: | |||
|
181 | line = (await stream.readline()).decode("utf8") | |||
|
182 | if not line: | |||
|
183 | break | |||
|
184 | if stream_arg: | |||
|
185 | self.shell.user_ns[stream_arg] = line | |||
|
186 | else: | |||
|
187 | file_object.write(line) | |||
|
188 | file_object.flush() | |||
|
189 | ||||
|
190 | async def _stream_communicate(process, cell): | |||
|
191 | process.stdin.write(cell) | |||
|
192 | process.stdin.close() | |||
|
193 | stdout_task = asyncio.create_task( | |||
|
194 | _handle_stream(process.stdout, args.out, sys.stdout) | |||
|
195 | ) | |||
|
196 | stderr_task = asyncio.create_task( | |||
|
197 | _handle_stream(process.stderr, args.err, sys.stderr) | |||
|
198 | ) | |||
|
199 | await asyncio.wait([stdout_task, stderr_task]) | |||
|
200 | ||||
|
201 | if sys.platform.startswith("win"): | |||
|
202 | asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) | |||
|
203 | loop = asyncio.get_event_loop() | |||
|
204 | ||||
|
205 | argv = arg_split(line, posix=not sys.platform.startswith("win")) | |||
179 | args, cmd = self.shebang.parser.parse_known_args(argv) |
|
206 | args, cmd = self.shebang.parser.parse_known_args(argv) | |
180 |
|
||||
181 | try: |
|
207 | try: | |
182 | p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE) |
|
208 | p = loop.run_until_complete( | |
|
209 | asyncio.create_subprocess_exec( | |||
|
210 | *cmd, | |||
|
211 | stdout=asyncio.subprocess.PIPE, | |||
|
212 | stderr=asyncio.subprocess.PIPE, | |||
|
213 | stdin=asyncio.subprocess.PIPE | |||
|
214 | ) | |||
|
215 | ) | |||
183 | except OSError as e: |
|
216 | except OSError as e: | |
184 | if e.errno == errno.ENOENT: |
|
217 | if e.errno == errno.ENOENT: | |
185 | print("Couldn't find program: %r" % cmd[0]) |
|
218 | print("Couldn't find program: %r" % cmd[0]) | |
@@ -208,17 +241,17 b' class ScriptMagics(Magics):' | |||||
208 | return |
|
241 | return | |
209 |
|
242 | |||
210 | try: |
|
243 | try: | |
211 | out, err = p.communicate(cell) |
|
244 | loop.run_until_complete(_stream_communicate(p, cell)) | |
212 | except KeyboardInterrupt: |
|
245 | except KeyboardInterrupt: | |
213 | try: |
|
246 | try: | |
214 | p.send_signal(signal.SIGINT) |
|
247 | p.send_signal(signal.SIGINT) | |
215 | time.sleep(0.1) |
|
248 | time.sleep(0.1) | |
216 |
if p. |
|
249 | if p.returncode is not None: | |
217 | print("Process is interrupted.") |
|
250 | print("Process is interrupted.") | |
218 | return |
|
251 | return | |
219 | p.terminate() |
|
252 | p.terminate() | |
220 | time.sleep(0.1) |
|
253 | time.sleep(0.1) | |
221 |
if p. |
|
254 | if p.returncode is not None: | |
222 | print("Process is terminated.") |
|
255 | print("Process is terminated.") | |
223 | return |
|
256 | return | |
224 | p.kill() |
|
257 | p.kill() | |
@@ -229,20 +262,8 b' class ScriptMagics(Magics):' | |||||
229 | print("Error while terminating subprocess (pid=%i): %s" \ |
|
262 | print("Error while terminating subprocess (pid=%i): %s" \ | |
230 | % (p.pid, e)) |
|
263 | % (p.pid, e)) | |
231 | return |
|
264 | return | |
232 | out = py3compat.decode(out) |
|
|||
233 | err = py3compat.decode(err) |
|
|||
234 | if args.out: |
|
|||
235 | self.shell.user_ns[args.out] = out |
|
|||
236 | else: |
|
|||
237 | sys.stdout.write(out) |
|
|||
238 | sys.stdout.flush() |
|
|||
239 | if args.err: |
|
|||
240 | self.shell.user_ns[args.err] = err |
|
|||
241 | else: |
|
|||
242 | sys.stderr.write(err) |
|
|||
243 | sys.stderr.flush() |
|
|||
244 | if args.raise_error and p.returncode!=0: |
|
265 | if args.raise_error and p.returncode!=0: | |
245 |
raise CalledProcessError(p.returncode, cell |
|
266 | raise CalledProcessError(p.returncode, cell) | |
246 |
|
267 | |||
247 | def _run_script(self, p, cell, to_close): |
|
268 | def _run_script(self, p, cell, to_close): | |
248 | """callback for running the script in the background""" |
|
269 | """callback for running the script in the background""" | |
@@ -263,7 +284,7 b' class ScriptMagics(Magics):' | |||||
263 | if not self.bg_processes: |
|
284 | if not self.bg_processes: | |
264 | return |
|
285 | return | |
265 | for p in self.bg_processes: |
|
286 | for p in self.bg_processes: | |
266 |
if p. |
|
287 | if p.returncode is None: | |
267 | try: |
|
288 | try: | |
268 | p.send_signal(signal.SIGINT) |
|
289 | p.send_signal(signal.SIGINT) | |
269 | except: |
|
290 | except: | |
@@ -273,7 +294,7 b' class ScriptMagics(Magics):' | |||||
273 | if not self.bg_processes: |
|
294 | if not self.bg_processes: | |
274 | return |
|
295 | return | |
275 | for p in self.bg_processes: |
|
296 | for p in self.bg_processes: | |
276 |
if p. |
|
297 | if p.returncode is None: | |
277 | try: |
|
298 | try: | |
278 | p.terminate() |
|
299 | p.terminate() | |
279 | except: |
|
300 | except: | |
@@ -283,7 +304,7 b' class ScriptMagics(Magics):' | |||||
283 | if not self.bg_processes: |
|
304 | if not self.bg_processes: | |
284 | return |
|
305 | return | |
285 | for p in self.bg_processes: |
|
306 | for p in self.bg_processes: | |
286 |
if p. |
|
307 | if p.returncode is None: | |
287 | try: |
|
308 | try: | |
288 | p.kill() |
|
309 | p.kill() | |
289 | except: |
|
310 | except: | |
@@ -291,4 +312,4 b' class ScriptMagics(Magics):' | |||||
291 | self._gc_bg_processes() |
|
312 | self._gc_bg_processes() | |
292 |
|
313 | |||
293 | def _gc_bg_processes(self): |
|
314 | def _gc_bg_processes(self): | |
294 |
self.bg_processes = [p for p in self.bg_processes if p. |
|
315 | self.bg_processes = [p for p in self.bg_processes if p.returncode is None] |
@@ -948,28 +948,32 b' def test_script_out_err():' | |||||
948 | nt.assert_equal(ip.user_ns['error'], 'hello\n') |
|
948 | nt.assert_equal(ip.user_ns['error'], 'hello\n') | |
949 |
|
949 | |||
950 | @dec.skip_win32 |
|
950 | @dec.skip_win32 | |
951 | def test_script_bg_out(): |
|
951 | async def test_script_bg_out(): | |
952 | ip = get_ipython() |
|
952 | ip = get_ipython() | |
953 | ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'") |
|
953 | ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'") | |
954 |
|
954 | nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n") | ||
955 | nt.assert_equal(ip.user_ns['output'].read(), b'hi\n') |
|
|||
956 | ip.user_ns['output'].close() |
|
955 | ip.user_ns['output'].close() | |
957 |
|
956 | |||
|
957 | ||||
958 | @dec.skip_win32 |
|
958 | @dec.skip_win32 | |
959 | def test_script_bg_err(): |
|
959 | async def test_script_bg_err(): | |
960 | ip = get_ipython() |
|
960 | ip = get_ipython() | |
961 | ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2") |
|
961 | ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2") | |
962 |
nt.assert_equal(ip.user_ns[ |
|
962 | nt.assert_equal((await ip.user_ns["error"].read()), b"hello\n") | |
963 |
ip.user_ns[ |
|
963 | ip.user_ns["error"].close() | |
|
964 | ||||
964 |
|
965 | |||
965 | @dec.skip_win32 |
|
966 | @dec.skip_win32 | |
966 | def test_script_bg_out_err(): |
|
967 | async def test_script_bg_out_err(): | |
967 | ip = get_ipython() |
|
968 | ip = get_ipython() | |
968 | ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2") |
|
969 | ip.run_cell_magic( | |
969 | nt.assert_equal(ip.user_ns['output'].read(), b'hi\n') |
|
970 | "script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2" | |
970 | nt.assert_equal(ip.user_ns['error'].read(), b'hello\n') |
|
971 | ) | |
971 | ip.user_ns['output'].close() |
|
972 | nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n") | |
972 | ip.user_ns['error'].close() |
|
973 | nt.assert_equal((await ip.user_ns["error"].read()), b"hello\n") | |
|
974 | ip.user_ns["output"].close() | |||
|
975 | ip.user_ns["error"].close() | |||
|
976 | ||||
973 |
|
977 | |||
974 | def test_script_defaults(): |
|
978 | def test_script_defaults(): | |
975 | ip = get_ipython() |
|
979 | ip = get_ipython() |
General Comments 0
You need to be logged in to leave comments.
Login now