##// END OF EJS Templates
Merge pull request #13191 from Carreau/fix-loop...
Matthias Bussonnier -
r26858:e6aab7f5 merge
parent child Browse files
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 shlex
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 (Magics, magics_class, line_magic,
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['output'].close()
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