Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 25f92b9

Browse files
committed
Try to fix some of current failures.
See error found in CI below. Hopefully this fixes it. There are manycomplexity, we need to make sure the loop has no task after each tests, so we need to close and restore the subprocess watcher. We make it a context manager and provide a decorator. ====================================================================== ERROR: IPython.core.tests.test_magic.test_script_out ---------------------------------------------------------------------- Traceback (most recent call last): File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/nose/case.py", line 198, in runTest self.test(*self.arg) File "/home/runner/work/ipython/ipython/IPython/testing/decorators.py", line 223, in skipper_func return f(*args, **kwargs) File "/home/runner/work/ipython/ipython/IPython/core/tests/test_magic.py", line 953, in test_script_out ip.run_cell_magic("script", "--out output sh", "echo 'hi'") File "/home/runner/work/ipython/ipython/IPython/core/interactiveshell.py", line 2417, in run_cell_magic result = fn(*args, **kwargs) File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/decorator.py", line 232, in fun return caller(func, *(extras + args), **kw) File "/home/runner/work/ipython/ipython/IPython/core/magic.py", line 187, in <lambda> call = lambda f, *a, **k: f(*a, **k) File "/home/runner/work/ipython/ipython/IPython/core/magics/script.py", line 216, in shebang stdin=asyncio.subprocess.PIPE, File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/asyncio/base_events.py", line 587, in run_until_complete return future.result() File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/asyncio/subprocess.py", line 217, in create_subprocess_exec stderr=stderr, **kwds) File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/asyncio/base_events.py", line 1544, in subprocess_exec bufsize, **kwargs) File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/asyncio/unix_events.py", line 193, in _make_subprocess_transport self._child_watcher_callback, transp) File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/asyncio/unix_events.py", line 941, in add_child_handler "Cannot add child handler, " RuntimeError: Cannot add child handler, the child watcher does not have a loop attached
1 parent 98941e5 commit 25f92b9

4 files changed

Lines changed: 81 additions & 28 deletions

File tree

.github/workflows/python-package.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jobs:
1313
build:
1414

1515
runs-on: ubuntu-latest
16+
timeout-minutes: 10
1617
strategy:
1718
matrix:
1819
python-version: [3.8]

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ jobs:
4545
cp /tmp/.coverage ./
4646
- name: pytest
4747
run: |
48-
pytest
48+
pytest -v
4949
- name: Upload coverage to Codecov
5050
uses: codecov/codecov-action@v1

IPython/core/magics/script.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@
33
# Copyright (c) IPython Development Team.
44
# Distributed under the terms of the Modified BSD License.
55

6+
import asyncio
7+
import atexit
68
import errno
9+
import functools
710
import os
8-
import sys
911
import signal
12+
import sys
1013
import time
11-
import asyncio
12-
import atexit
13-
14+
from asyncio import SafeChildWatcher
15+
from contextlib import contextmanager
1416
from subprocess import CalledProcessError
1517

18+
from traitlets import Dict, List, default
19+
1620
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
2022
from IPython.lib.backgroundjobs import BackgroundJobManager
2123
from IPython.utils.process import arg_split
22-
from traitlets import List, Dict, default
23-
2424

2525
#-----------------------------------------------------------------------------
2626
# Magic implementation classes
@@ -67,6 +67,39 @@ def script_args(f):
6767
f = arg(f)
6868
return f
6969

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+
70103
@magics_class
71104
class ScriptMagics(Magics):
72105
"""Magics for talking to scripts
@@ -157,6 +190,7 @@ def named_script_magic(line, cell):
157190
@magic_arguments.magic_arguments()
158191
@script_args
159192
@cell_magic("script")
193+
@dec_safe_watcher
160194
def shebang(self, line, cell):
161195
"""Run a cell via a shell command
162196
@@ -204,7 +238,6 @@ async def _stream_communicate(process, cell):
204238
if sys.platform.startswith("win"):
205239
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
206240
loop = asyncio.get_event_loop()
207-
208241
argv = arg_split(line, posix=not sys.platform.startswith("win"))
209242
args, cmd = self.shebang.parser.parse_known_args(argv)
210243
try:

IPython/core/tests/test_magic.py

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,40 @@
44
Needs to be run by nose (to make ipython session available).
55
"""
66

7+
import asyncio
78
import io
89
import os
910
import re
11+
import shlex
1012
import sys
1113
import warnings
12-
from textwrap import dedent
13-
from unittest import TestCase
14-
from unittest import mock
1514
from importlib import invalidate_caches
1615
from io import StringIO
1716
from pathlib import Path
17+
from textwrap import dedent
18+
from unittest import TestCase, mock
1819

1920
import nose.tools as nt
2021

21-
import shlex
22-
2322
from IPython import get_ipython
2423
from IPython.core import magic
2524
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
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
3034
from IPython.testing import decorators as dec
3135
from IPython.testing import tools as tt
3236
from IPython.utils.io import capture_output
33-
from IPython.utils.tempdir import (TemporaryDirectory,
34-
TemporaryWorkingDirectory)
3537
from IPython.utils.process import find_cmd
36-
from .test_debugger import PdbTestInput
38+
from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
3739

38-
import pytest
40+
from .test_debugger import PdbTestInput
3941

4042

4143
@magic.magics_class
@@ -947,32 +949,48 @@ def test_script_config():
947949
sm = script.ScriptMagics(shell=ip)
948950
nt.assert_in('whoda', sm.magics['cell'])
949951

952+
@dec.skip_iptest_but_not_pytest
950953
@dec.skip_win32
951954
def test_script_out():
955+
assert asyncio.get_event_loop().is_running() is False
956+
952957
ip = get_ipython()
953958
ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
959+
assert asyncio.get_event_loop().is_running() is False
954960
nt.assert_equal(ip.user_ns['output'], 'hi\n')
955961

962+
@dec.skip_iptest_but_not_pytest
956963
@dec.skip_win32
957964
def test_script_err():
958965
ip = get_ipython()
966+
assert asyncio.get_event_loop().is_running() is False
959967
ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
968+
assert asyncio.get_event_loop().is_running() is False
960969
nt.assert_equal(ip.user_ns['error'], 'hello\n')
961970

971+
972+
@dec.skip_iptest_but_not_pytest
962973
@dec.skip_win32
963974
def test_script_out_err():
975+
964976
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")
968982

983+
984+
@dec.skip_iptest_but_not_pytest
969985
@dec.skip_win32
970986
async def test_script_bg_out():
971987
ip = get_ipython()
972988
ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
973989
nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n")
974-
ip.user_ns['output'].close()
990+
ip.user_ns["output"].close()
991+
asyncio.get_event_loop().stop()
975992

993+
@dec.skip_iptest_but_not_pytest
976994
@dec.skip_win32
977995
async def test_script_bg_err():
978996
ip = get_ipython()
@@ -981,6 +999,7 @@ async def test_script_bg_err():
981999
ip.user_ns["error"].close()
9821000

9831001

1002+
@dec.skip_iptest_but_not_pytest
9841003
@dec.skip_win32
9851004
async def test_script_bg_out_err():
9861005
ip = get_ipython()

0 commit comments

Comments
 (0)