##// 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 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 shlex
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 (Magics, magics_class, line_magic,
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['output'].close()
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