Show More
@@ -13,6 +13,7 b' jobs:' | |||
|
13 | 13 | build: |
|
14 | 14 | |
|
15 | 15 | runs-on: ubuntu-latest |
|
16 | timeout-minutes: 10 | |
|
16 | 17 | strategy: |
|
17 | 18 | matrix: |
|
18 | 19 | python-version: [3.8] |
@@ -45,6 +45,6 b' jobs:' | |||
|
45 | 45 | cp /tmp/.coverage ./ |
|
46 | 46 | - name: pytest |
|
47 | 47 | run: | |
|
48 | pytest | |
|
48 | pytest -v | |
|
49 | 49 | - name: Upload coverage to Codecov |
|
50 | 50 | uses: codecov/codecov-action@v1 |
@@ -3,24 +3,24 b'' | |||
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | import asyncio | |
|
7 | import atexit | |
|
6 | 8 | import errno |
|
9 | import functools | |
|
7 | 10 | import os |
|
8 | import sys | |
|
9 | 11 | import signal |
|
12 | import sys | |
|
10 | 13 | import time |
|
11 | import asyncio | |
|
12 | import atexit | |
|
13 | ||
|
14 | from asyncio import SafeChildWatcher | |
|
15 | from contextlib import contextmanager | |
|
14 | 16 | from subprocess import CalledProcessError |
|
15 | 17 | |
|
18 | from traitlets import Dict, List, default | |
|
19 | ||
|
16 | 20 | from IPython.core import magic_arguments |
|
17 | from IPython.core.magic import ( | |
|
18 | Magics, magics_class, line_magic, cell_magic | |
|
19 | ) | |
|
21 | from IPython.core.magic import Magics, cell_magic, line_magic, magics_class | |
|
20 | 22 | from IPython.lib.backgroundjobs import BackgroundJobManager |
|
21 | 23 | from IPython.utils.process import arg_split |
|
22 | from traitlets import List, Dict, default | |
|
23 | ||
|
24 | 24 | |
|
25 | 25 | #----------------------------------------------------------------------------- |
|
26 | 26 | # Magic implementation classes |
@@ -67,6 +67,39 b' def script_args(f):' | |||
|
67 | 67 | f = arg(f) |
|
68 | 68 | return f |
|
69 | 69 | |
|
70 | ||
|
71 | @contextmanager | |
|
72 | def safe_watcher(): | |
|
73 | if sys.platform == "win32": | |
|
74 | yield | |
|
75 | return | |
|
76 | ||
|
77 | policy = asyncio.get_event_loop_policy() | |
|
78 | old_watcher = policy.get_child_watcher() | |
|
79 | if isinstance(old_watcher, SafeChildWatcher): | |
|
80 | yield | |
|
81 | return | |
|
82 | ||
|
83 | loop = asyncio.get_event_loop() | |
|
84 | try: | |
|
85 | watcher = asyncio.SafeChildWatcher() | |
|
86 | watcher.attach_loop(loop) | |
|
87 | policy.set_child_watcher(watcher) | |
|
88 | yield | |
|
89 | finally: | |
|
90 | watcher.close() | |
|
91 | policy.set_child_watcher(old_watcher) | |
|
92 | ||
|
93 | ||
|
94 | def dec_safe_watcher(fun): | |
|
95 | @functools.wraps(fun) | |
|
96 | def _inner(*args, **kwargs): | |
|
97 | with safe_watcher(): | |
|
98 | return fun(*args, **kwargs) | |
|
99 | ||
|
100 | return _inner | |
|
101 | ||
|
102 | ||
|
70 | 103 | @magics_class |
|
71 | 104 | class ScriptMagics(Magics): |
|
72 | 105 | """Magics for talking to scripts |
@@ -157,6 +190,7 b' class ScriptMagics(Magics):' | |||
|
157 | 190 | @magic_arguments.magic_arguments() |
|
158 | 191 | @script_args |
|
159 | 192 | @cell_magic("script") |
|
193 | @dec_safe_watcher | |
|
160 | 194 | def shebang(self, line, cell): |
|
161 | 195 | """Run a cell via a shell command |
|
162 | 196 | |
@@ -204,7 +238,6 b' class ScriptMagics(Magics):' | |||
|
204 | 238 | if sys.platform.startswith("win"): |
|
205 | 239 | asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) |
|
206 | 240 | loop = asyncio.get_event_loop() |
|
207 | ||
|
208 | 241 | argv = arg_split(line, posix=not sys.platform.startswith("win")) |
|
209 | 242 | args, cmd = self.shebang.parser.parse_known_args(argv) |
|
210 | 243 | try: |
@@ -4,38 +4,40 b'' | |||
|
4 | 4 | Needs to be run by nose (to make ipython session available). |
|
5 | 5 | """ |
|
6 | 6 | |
|
7 | import asyncio | |
|
7 | 8 | import io |
|
8 | 9 | import os |
|
9 | 10 | import re |
|
11 | import shlex | |
|
10 | 12 | import sys |
|
11 | 13 | import warnings |
|
12 | from textwrap import dedent | |
|
13 | from unittest import TestCase | |
|
14 | from unittest import mock | |
|
15 | 14 | from importlib import invalidate_caches |
|
16 | 15 | from io import StringIO |
|
17 | 16 | from pathlib import Path |
|
17 | from textwrap import dedent | |
|
18 | from unittest import TestCase, mock | |
|
18 | 19 | |
|
19 | 20 | import nose.tools as nt |
|
20 | 21 | |
|
21 | import shlex | |
|
22 | ||
|
23 | 22 | from IPython import get_ipython |
|
24 | 23 | from IPython.core import magic |
|
25 | 24 | from IPython.core.error import UsageError |
|
26 |
from IPython.core.magic import ( |
|
|
27 | cell_magic, | |
|
28 | register_line_magic, register_cell_magic) | |
|
29 | from IPython.core.magics import execution, script, code, logging, osm | |
|
25 | from IPython.core.magic import ( | |
|
26 | Magics, | |
|
27 | cell_magic, | |
|
28 | line_magic, | |
|
29 | magics_class, | |
|
30 | register_cell_magic, | |
|
31 | register_line_magic, | |
|
32 | ) | |
|
33 | from IPython.core.magics import code, execution, logging, osm, script | |
|
30 | 34 | from IPython.testing import decorators as dec |
|
31 | 35 | from IPython.testing import tools as tt |
|
32 | 36 | from IPython.utils.io import capture_output |
|
33 | from IPython.utils.tempdir import (TemporaryDirectory, | |
|
34 | TemporaryWorkingDirectory) | |
|
35 | 37 | from IPython.utils.process import find_cmd |
|
36 | from .test_debugger import PdbTestInput | |
|
38 | from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory | |
|
37 | 39 | |
|
38 | import pytest | |
|
40 | from .test_debugger import PdbTestInput | |
|
39 | 41 | |
|
40 | 42 | |
|
41 | 43 | @magic.magics_class |
@@ -947,32 +949,48 b' def test_script_config():' | |||
|
947 | 949 | sm = script.ScriptMagics(shell=ip) |
|
948 | 950 | nt.assert_in('whoda', sm.magics['cell']) |
|
949 | 951 | |
|
952 | @dec.skip_iptest_but_not_pytest | |
|
950 | 953 | @dec.skip_win32 |
|
951 | 954 | def test_script_out(): |
|
955 | assert asyncio.get_event_loop().is_running() is False | |
|
956 | ||
|
952 | 957 | ip = get_ipython() |
|
953 | 958 | ip.run_cell_magic("script", "--out output sh", "echo 'hi'") |
|
959 | assert asyncio.get_event_loop().is_running() is False | |
|
954 | 960 | nt.assert_equal(ip.user_ns['output'], 'hi\n') |
|
955 | 961 | |
|
962 | @dec.skip_iptest_but_not_pytest | |
|
956 | 963 | @dec.skip_win32 |
|
957 | 964 | def test_script_err(): |
|
958 | 965 | ip = get_ipython() |
|
966 | assert asyncio.get_event_loop().is_running() is False | |
|
959 | 967 | ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2") |
|
968 | assert asyncio.get_event_loop().is_running() is False | |
|
960 | 969 | nt.assert_equal(ip.user_ns['error'], 'hello\n') |
|
961 | 970 | |
|
971 | ||
|
972 | @dec.skip_iptest_but_not_pytest | |
|
962 | 973 | @dec.skip_win32 |
|
963 | 974 | def test_script_out_err(): |
|
975 | ||
|
964 | 976 | ip = get_ipython() |
|
965 | ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2") | |
|
966 | nt.assert_equal(ip.user_ns['output'], 'hi\n') | |
|
967 | nt.assert_equal(ip.user_ns['error'], 'hello\n') | |
|
977 | ip.run_cell_magic( | |
|
978 | "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2" | |
|
979 | ) | |
|
980 | nt.assert_equal(ip.user_ns["output"], "hi\n") | |
|
981 | nt.assert_equal(ip.user_ns["error"], "hello\n") | |
|
968 | 982 | |
|
983 | ||
|
984 | @dec.skip_iptest_but_not_pytest | |
|
969 | 985 | @dec.skip_win32 |
|
970 | 986 | async def test_script_bg_out(): |
|
971 | 987 | ip = get_ipython() |
|
972 | 988 | ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'") |
|
973 | 989 | nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n") |
|
974 |
ip.user_ns[ |
|
|
990 | ip.user_ns["output"].close() | |
|
991 | asyncio.get_event_loop().stop() | |
|
975 | 992 | |
|
993 | @dec.skip_iptest_but_not_pytest | |
|
976 | 994 | @dec.skip_win32 |
|
977 | 995 | async def test_script_bg_err(): |
|
978 | 996 | ip = get_ipython() |
@@ -981,6 +999,7 b' async def test_script_bg_err():' | |||
|
981 | 999 | ip.user_ns["error"].close() |
|
982 | 1000 | |
|
983 | 1001 | |
|
1002 | @dec.skip_iptest_but_not_pytest | |
|
984 | 1003 | @dec.skip_win32 |
|
985 | 1004 | async def test_script_bg_out_err(): |
|
986 | 1005 | ip = get_ipython() |
General Comments 0
You need to be logged in to leave comments.
Login now