Skip to content

Commit 683e8dd

Browse files
authored
Merge pull request #760 from blink1073/filter-warnings-2
2 parents 8c16b0f + bd6efdc commit 683e8dd

20 files changed

+125
-58
lines changed

.github/workflows/downstream.yml

+11-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ concurrency:
1212
jobs:
1313
tests:
1414
runs-on: ubuntu-latest
15+
timeout-minutes: 20
1516
strategy:
1617
matrix:
1718
python-version: ["3.9"]
19+
fail-fast: false
1820
steps:
1921
- name: Checkout
2022
uses: actions/checkout@v2
@@ -50,7 +52,15 @@ jobs:
5052
with:
5153
package_name: jupyter_server
5254

53-
# Test using jupyter_kernel_test
55+
jupyter_kernel_test:
56+
runs-on: ubuntu-latest
57+
timeout-minutes: 10
58+
steps:
59+
- name: Checkout
60+
uses: actions/checkout@v2
61+
62+
- name: Base Setup
63+
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
5464

5565
- name: Setup conda ${{ matrix.python-version }}
5666
uses: conda-incubator/setup-miniconda@v2

.github/workflows/main.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ jobs:
4545
4646
build-n-test-n-coverage:
4747
name: Build, test and code coverage
48-
4948
runs-on: ${{ matrix.os }}
49+
timeout-minutes: 15
5050

5151
strategy:
5252
fail-fast: false
@@ -94,6 +94,7 @@ jobs:
9494

9595
docs:
9696
runs-on: ubuntu-latest
97+
timeout-minutes: 10
9798
steps:
9899
- name: Checkout
99100
uses: actions/checkout@v2
@@ -111,6 +112,7 @@ jobs:
111112
test_miniumum_verisons:
112113
name: Test Minimum Versions
113114
runs-on: ubuntu-latest
115+
timeout-minutes: 10
114116
steps:
115117
- uses: actions/checkout@v2
116118
- name: Base Setup
@@ -124,6 +126,7 @@ jobs:
124126

125127
test_prereleases:
126128
name: Test Prereleases
129+
timeout-minutes: 10
127130
runs-on: ubuntu-latest
128131
steps:
129132
- name: Checkout
@@ -144,7 +147,7 @@ jobs:
144147
make_sdist:
145148
name: Make SDist
146149
runs-on: ubuntu-latest
147-
timeout-minutes: 20
150+
timeout-minutes: 10
148151
steps:
149152
- uses: actions/checkout@v2
150153
- name: Base Setup

jupyter_client/client.py

+10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import zmq.asyncio
1313
from traitlets import Any # type: ignore
14+
from traitlets import Bool
1415
from traitlets import Instance
1516
from traitlets import Type
1617

@@ -92,7 +93,10 @@ class KernelClient(ConnectionFileMixin):
9293
# The PyZMQ Context to use for communication with the kernel.
9394
context = Instance(zmq.asyncio.Context)
9495

96+
_created_context: Bool = Bool(False)
97+
9598
def _context_default(self) -> zmq.asyncio.Context:
99+
self._created_context = True
96100
return zmq.asyncio.Context()
97101

98102
# The classes to use for the various channels
@@ -282,6 +286,9 @@ def start_channels(
282286
:meth:`start_kernel`. If the channels have been stopped and you
283287
call this, :class:`RuntimeError` will be raised.
284288
"""
289+
# Create the context if needed.
290+
if not self._created_context:
291+
self.context = self._context_default()
285292
if iopub:
286293
self.iopub_channel.start()
287294
if shell:
@@ -311,6 +318,9 @@ def stop_channels(self) -> None:
311318
self.hb_channel.stop()
312319
if self.control_channel.is_alive():
313320
self.control_channel.stop()
321+
if self._created_context:
322+
self._created_context = False
323+
self.context.destroy()
314324

315325
@property
316326
def channels_running(self) -> bool:

jupyter_client/kernelspec.py

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
class KernelSpec(HasTraits):
3333
argv = List()
34+
name = Unicode()
35+
mimetype = Unicode()
3436
display_name = Unicode()
3537
language = Unicode()
3638
env = Dict()

jupyter_client/kernelspecapp.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def _kernel_spec_manager_default(self):
182182
return KernelSpecManager(data_dir=self.data_dir, parent=self)
183183

184184
flags = {
185-
"f": ({"RemoveKernelSpec": {"force": True}}, force.get_metadata("help")),
185+
"f": ({"RemoveKernelSpec": {"force": True}}, force.help),
186186
}
187187
flags.update(JupyterApp.flags)
188188

jupyter_client/manager.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def __init__(self, *args, **kwargs):
9292
self._shutdown_status = _ShutdownStatus.Unset
9393
# Create a place holder future.
9494
try:
95+
asyncio.get_running_loop()
9596
self._ready = Future()
9697
except RuntimeError:
9798
# No event loop running, use concurrent future
@@ -476,7 +477,8 @@ async def _async_shutdown_kernel(self, now: bool = False, restart: bool = False)
476477
# Stop monitoring for restarting while we shutdown.
477478
self.stop_restarter()
478479

479-
await ensure_async(self.interrupt_kernel())
480+
if self.has_kernel:
481+
await ensure_async(self.interrupt_kernel())
480482

481483
if now:
482484
await ensure_async(self._kill_kernel())

jupyter_client/provisioning/local_provisioner.py

+5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ async def wait(self) -> Optional[int]:
6060

6161
# Process is no longer alive, wait and clear
6262
ret = self.process.wait()
63+
# Make sure all the fds get closed.
64+
for attr in ['stdout', 'stderr', 'stdin']:
65+
fid = getattr(self.process, attr)
66+
if fid:
67+
fid.close()
6368
self.process = None # allow has_process to now return False
6469
return ret
6570

jupyter_client/ssh/tunnel.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ class SSHException(Exception): # type: ignore
3636
except ImportError:
3737
pexpect = None
3838

39-
from zmq.utils.strtypes import b
40-
4139

4240
def select_random_ports(n):
4341
"""Select and return n random ports that are available."""
@@ -56,7 +54,7 @@ def select_random_ports(n):
5654
# -----------------------------------------------------------------------------
5755
# Check for passwordless login
5856
# -----------------------------------------------------------------------------
59-
_password_pat = re.compile(b(r"pass(word|phrase):"), re.IGNORECASE)
57+
_password_pat = re.compile((r"pass(word|phrase):".encode("utf8")), re.IGNORECASE)
6058

6159

6260
def try_passwordless_ssh(server, keyfile, paramiko=None):

jupyter_client/tests/conftest.py

+21
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,30 @@
77

88
from .utils import test_env
99

10+
try:
11+
import resource
12+
except ImportError:
13+
# Windows
14+
resource = None
15+
1016
pjoin = os.path.join
1117

1218

19+
# Handle resource limit
20+
# Ensure a minimal soft limit of DEFAULT_SOFT if the current hard limit is at least that much.
21+
if resource is not None:
22+
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
23+
24+
DEFAULT_SOFT = 4096
25+
if hard >= DEFAULT_SOFT:
26+
soft = DEFAULT_SOFT
27+
28+
if hard < soft:
29+
hard = soft
30+
31+
resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard))
32+
33+
1334
if os.name == "nt" and sys.version_info >= (3, 7):
1435
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
1536

jupyter_client/tests/test_client.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ def setUp(self):
2828
except NoSuchKernel:
2929
pytest.skip()
3030
self.km, self.kc = start_new_kernel(kernel_name=NATIVE_KERNEL_NAME)
31-
self.addCleanup(self.kc.stop_channels)
32-
self.addCleanup(self.km.shutdown_kernel)
31+
32+
def tearDown(self):
33+
self.env_patch.stop()
34+
self.km.shutdown_kernel()
35+
self.kc.stop_channels()
36+
return super().tearDown()
3337

3438
def test_execute_interactive(self):
3539
kc = self.kc

jupyter_client/tests/test_kernelmanager.py

+1
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ def execute(cmd):
440440

441441
km.shutdown_kernel()
442442
assert km.context.closed
443+
kc.stop_channels()
443444

444445

445446
@pytest.mark.asyncio

jupyter_client/tests/test_multikernelmanager.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ def setUp(self):
4444
self.env_patch.start()
4545
super().setUp()
4646

47+
def tearDown(self) -> None:
48+
self.env_patch.stop()
49+
return super().tearDown()
50+
4751
# static so picklable for multiprocessing on Windows
4852
@staticmethod
4953
def _get_tcp_km():
@@ -243,6 +247,10 @@ def setUp(self):
243247
self.env_patch.start()
244248
super().setUp()
245249

250+
def tearDown(self) -> None:
251+
self.env_patch.stop()
252+
return super().tearDown()
253+
246254
# static so picklable for multiprocessing on Windows
247255
@staticmethod
248256
def _get_tcp_km():
@@ -465,8 +473,9 @@ async def test_start_sequence_ipc_kernels(self):
465473

466474
def tcp_lifecycle_with_loop(self):
467475
# Ensure each thread has an event loop
468-
asyncio.set_event_loop(asyncio.new_event_loop())
469-
asyncio.get_event_loop().run_until_complete(self.raw_tcp_lifecycle())
476+
loop = asyncio.new_event_loop()
477+
asyncio.set_event_loop(loop)
478+
loop.run_until_complete(self.raw_tcp_lifecycle())
470479

471480
# static so picklable for multiprocessing on Windows
472481
@classmethod
@@ -479,11 +488,8 @@ async def raw_tcp_lifecycle(cls, test_kid=None):
479488
# static so picklable for multiprocessing on Windows
480489
@classmethod
481490
def raw_tcp_lifecycle_sync(cls, test_kid=None):
482-
loop = asyncio.get_event_loop()
483-
if loop.is_running():
484-
# Forked MP, make new loop
485-
loop = asyncio.new_event_loop()
486-
asyncio.set_event_loop(loop)
491+
loop = asyncio.new_event_loop()
492+
asyncio.set_event_loop(loop)
487493
loop.run_until_complete(cls.raw_tcp_lifecycle(test_kid=test_kid))
488494

489495
@gen_test

jupyter_client/tests/test_provisioning.py

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ async def wait(self) -> Optional[int]:
6666

6767
# Process is no longer alive, wait and clear
6868
ret = self.process.wait()
69+
# Make sure all the fds get closed.
70+
for attr in ['stdout', 'stderr', 'stdin']:
71+
fid = getattr(self.process, attr)
72+
if fid:
73+
fid.close()
6974
self.process = None
7075
return ret
7176

jupyter_client/tests/test_session.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import pytest
1212
import zmq
13+
from tornado import ioloop
1314
from zmq.eventloop.zmqstream import ZMQStream
1415
from zmq.tests import BaseZMQTestCase
1516

@@ -171,7 +172,8 @@ def test_tracking(self):
171172
a, b = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
172173
s = self.session
173174
s.copy_threshold = 1
174-
ZMQStream(a)
175+
loop = ioloop.IOLoop(make_current=False)
176+
ZMQStream(a, io_loop=loop)
175177
msg = s.send(a, "hello", track=False)
176178
self.assertTrue(msg["tracker"] is ss.DONE)
177179
msg = s.send(a, "hello", track=True)

jupyter_client/tests/test_utils.py

-30
This file was deleted.

jupyter_client/tests/utils.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ def start(self):
6262

6363
def stop(self):
6464
self.env_patch.stop()
65-
self.test_dir.cleanup()
65+
try:
66+
self.test_dir.cleanup()
67+
except (PermissionError, NotADirectoryError):
68+
if os.name != 'nt':
69+
raise
6670

6771
def __enter__(self):
6872
self.start()

jupyter_client/utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
def run_sync(coro):
1212
def wrapped(*args, **kwargs):
1313
try:
14-
loop = asyncio.get_event_loop()
14+
loop = asyncio.get_running_loop()
1515
except RuntimeError:
1616
loop = asyncio.new_event_loop()
1717
asyncio.set_event_loop(loop)
1818
import nest_asyncio # type: ignore
1919

2020
nest_asyncio.apply(loop)
21-
future = asyncio.ensure_future(coro(*args, **kwargs))
21+
future = asyncio.ensure_future(coro(*args, **kwargs), loop=loop)
2222
try:
2323
return loop.run_until_complete(future)
2424
except BaseException as e:

pyproject.toml

+25
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,28 @@ testpaths = [
3636
timeout = 300
3737
# Restore this setting to debug failures
3838
# timeout_method = "thread"
39+
asyncio_mode = "auto"
40+
filterwarnings= [
41+
# Fail on warnings
42+
"error",
43+
44+
# Workarounds for https://github.com/pytest-dev/pytest-asyncio/issues/77
45+
"ignore:unclosed <socket.socket:ResourceWarning",
46+
"ignore:unclosed event loop:ResourceWarning",
47+
48+
# Workaround for https://github.com/tornadoweb/tornado/issues/3106
49+
# (To be fixed in Tornado 6.2)
50+
"ignore:There is no current event loop:DeprecationWarning:tornado",
51+
52+
# Workaround for distutils.Version used in ipykernel
53+
"ignore:The distutils package is deprecated and slated for removal:DeprecationWarning:ipykernel",
54+
55+
# ZMQ uses Future internally, which raises a DeprecationWarning
56+
# When there is no loop running.
57+
# We could eventually find a way to make sure these are only created
58+
# when there is a running event loop.
59+
"ignore:There is no current event loop:DeprecationWarning:zmq",
60+
61+
# Workaround for imp used in ipykernel
62+
"ignore:the imp module is deprecated in favour of importlib:DeprecationWarning"
63+
]

0 commit comments

Comments
 (0)