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@v2 |
@@ -3,24 +3,23 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 contextlib import contextmanager | |
|
14 | 15 | from subprocess import CalledProcessError |
|
15 | 16 | |
|
17 | from traitlets import Dict, List, default | |
|
18 | ||
|
16 | 19 | from IPython.core import magic_arguments |
|
17 | from IPython.core.magic import ( | |
|
18 | Magics, magics_class, line_magic, cell_magic | |
|
19 | ) | |
|
20 | from IPython.core.magic import Magics, cell_magic, line_magic, magics_class | |
|
20 | 21 | from IPython.lib.backgroundjobs import BackgroundJobManager |
|
21 | 22 | from IPython.utils.process import arg_split |
|
22 | from traitlets import List, Dict, default | |
|
23 | ||
|
24 | 23 | |
|
25 | 24 | #----------------------------------------------------------------------------- |
|
26 | 25 | # Magic implementation classes |
@@ -67,6 +66,41 b' def script_args(f):' | |||
|
67 | 66 | f = arg(f) |
|
68 | 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 | 104 | @magics_class |
|
71 | 105 | class ScriptMagics(Magics): |
|
72 | 106 | """Magics for talking to scripts |
@@ -157,6 +191,7 b' class ScriptMagics(Magics):' | |||
|
157 | 191 | @magic_arguments.magic_arguments() |
|
158 | 192 | @script_args |
|
159 | 193 | @cell_magic("script") |
|
194 | @dec_safe_watcher | |
|
160 | 195 | def shebang(self, line, cell): |
|
161 | 196 | """Run a cell via a shell command |
|
162 | 197 | |
@@ -204,7 +239,6 b' class ScriptMagics(Magics):' | |||
|
204 | 239 | if sys.platform.startswith("win"): |
|
205 | 240 | asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) |
|
206 | 241 | loop = asyncio.get_event_loop() |
|
207 | ||
|
208 | 242 | argv = arg_split(line, posix=not sys.platform.startswith("win")) |
|
209 | 243 | args, cmd = self.shebang.parser.parse_known_args(argv) |
|
210 | 244 | try: |
@@ -4,38 +4,42 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 |
|
|
22 | import pytest | |
|
22 | 23 | |
|
23 | 24 | from IPython import get_ipython |
|
24 | 25 | from IPython.core import magic |
|
25 | 26 | 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 | |
|
27 | from IPython.core.magic import ( | |
|
28 | Magics, | |
|
29 | cell_magic, | |
|
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 | 36 | from IPython.testing import decorators as dec |
|
31 | 37 | from IPython.testing import tools as tt |
|
32 | 38 | from IPython.utils.io import capture_output |
|
33 | from IPython.utils.tempdir import (TemporaryDirectory, | |
|
34 | TemporaryWorkingDirectory) | |
|
35 | 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 | 45 | @magic.magics_class |
@@ -947,33 +951,64 b' def test_script_config():' | |||
|
947 | 951 | sm = script.ScriptMagics(shell=ip) |
|
948 | 952 | nt.assert_in('whoda', sm.magics['cell']) |
|
949 | 953 | |
|
954 | @dec.skip_iptest_but_not_pytest | |
|
950 | 955 | @dec.skip_win32 |
|
956 | @pytest.mark.skipif( | |
|
957 | sys.platform == "win32", reason="This test does not run under Windows" | |
|
958 | ) | |
|
951 | 959 | def test_script_out(): |
|
960 | assert asyncio.get_event_loop().is_running() is False | |
|
961 | ||
|
952 | 962 | ip = get_ipython() |
|
953 | 963 | ip.run_cell_magic("script", "--out output sh", "echo 'hi'") |
|
964 | assert asyncio.get_event_loop().is_running() is False | |
|
954 | 965 | nt.assert_equal(ip.user_ns['output'], 'hi\n') |
|
955 | 966 | |
|
967 | @dec.skip_iptest_but_not_pytest | |
|
956 | 968 | @dec.skip_win32 |
|
969 | @pytest.mark.skipif( | |
|
970 | sys.platform == "win32", reason="This test does not run under Windows" | |
|
971 | ) | |
|
957 | 972 | def test_script_err(): |
|
958 | 973 | ip = get_ipython() |
|
974 | assert asyncio.get_event_loop().is_running() is False | |
|
959 | 975 | ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2") |
|
976 | assert asyncio.get_event_loop().is_running() is False | |
|
960 | 977 | nt.assert_equal(ip.user_ns['error'], 'hello\n') |
|
961 | 978 | |
|
979 | ||
|
980 | @dec.skip_iptest_but_not_pytest | |
|
962 | 981 | @dec.skip_win32 |
|
982 | @pytest.mark.skipif( | |
|
983 | sys.platform == "win32", reason="This test does not run under Windows" | |
|
984 | ) | |
|
963 | 985 | def test_script_out_err(): |
|
986 | ||
|
964 | 987 | 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') | |
|
988 | ip.run_cell_magic( | |
|
989 | "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2" | |
|
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 | 996 | @dec.skip_win32 |
|
997 | @pytest.mark.skipif( | |
|
998 | sys.platform == "win32", reason="This test does not run under Windows" | |
|
999 | ) | |
|
970 | 1000 | async def test_script_bg_out(): |
|
971 | 1001 | ip = get_ipython() |
|
972 | 1002 | ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'") |
|
973 | 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 | 1008 | @dec.skip_win32 |
|
1009 | @pytest.mark.skipif( | |
|
1010 | sys.platform == "win32", reason="This test does not run under Windows" | |
|
1011 | ) | |
|
977 | 1012 | async def test_script_bg_err(): |
|
978 | 1013 | ip = get_ipython() |
|
979 | 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 | 1016 | ip.user_ns["error"].close() |
|
982 | 1017 | |
|
983 | 1018 | |
|
1019 | @dec.skip_iptest_but_not_pytest | |
|
984 | 1020 | @dec.skip_win32 |
|
1021 | @pytest.mark.skipif( | |
|
1022 | sys.platform == "win32", reason="This test does not run under Windows" | |
|
1023 | ) | |
|
985 | 1024 | async def test_script_bg_out_err(): |
|
986 | 1025 | ip = get_ipython() |
|
987 | 1026 | ip.run_cell_magic( |
General Comments 0
You need to be logged in to leave comments.
Login now