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