Skip to content

Commit 194a825

Browse files
authored
Merge pull request #450 from jupyter/5.xZmqContextIsolation
Backport #488 5.x zmq context isolation
2 parents 08b13c1 + ed4a75b commit 194a825

File tree

7 files changed

+64
-21
lines changed

7 files changed

+64
-21
lines changed

.travis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ language: python
22
python:
33
- 3.6
44
- 3.5
5-
- 3.4
6-
- 3.3
75
- 2.7
86
sudo: false
97
install:

jupyter_client/manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class KernelManager(ConnectionFileMixin):
3939
# The PyZMQ Context to use for communication with the kernel.
4040
context = Instance(zmq.Context)
4141
def _context_default(self):
42-
return zmq.Context.instance()
42+
return zmq.Context()
4343

4444
# the class to create with our `client` method
4545
client_class = DottedObjectName('jupyter_client.blocking.BlockingKernelClient')

jupyter_client/multikernelmanager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class MultiKernelManager(LoggingConfigurable):
4747
)
4848

4949
kernel_spec_manager = Instance(KernelSpecManager, allow_none=True)
50-
50+
5151
kernel_manager_class = DottedObjectName(
5252
"jupyter_client.ioloop.IOLoopKernelManager", config=True,
5353
help="""The kernel manager class. This is configurable to allow
@@ -63,7 +63,7 @@ def _kernel_manager_factory_default(self):
6363

6464
context = Instance('zmq.Context')
6565
def _context_default(self):
66-
return zmq.Context.instance()
66+
return zmq.Context()
6767

6868
connection_dir = Unicode('')
6969

jupyter_client/session.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def _logname_changed(self, name, old, new):
186186
# not configurable:
187187
context = Instance('zmq.Context')
188188
def _context_default(self):
189-
return zmq.Context.instance()
189+
return zmq.Context()
190190

191191
session = Instance('jupyter_client.session.Session',
192192
allow_none=True)
@@ -300,10 +300,10 @@ class Session(Configurable):
300300
"""
301301

302302
debug = Bool(False, config=True, help="""Debug output in the Session""")
303-
303+
304304
check_pid = Bool(True, config=True,
305305
help="""Whether to check PID to protect against calls after fork.
306-
306+
307307
This check can be disabled if fork-safety is handled elsewhere.
308308
""")
309309

@@ -387,9 +387,9 @@ def _signature_scheme_changed(self, name, old, new):
387387
digest_mod = Any()
388388
def _digest_mod_default(self):
389389
return hashlib.sha256
390-
390+
391391
auth = Instance(hmac.HMAC, allow_none=True)
392-
392+
393393
def _new_auth(self):
394394
if self.key:
395395
self.auth = hmac.HMAC(self.key, digestmod=self.digest_mod)

jupyter_client/tests/test_multikernelmanager.py

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
"""Tests for the notebook kernel and session manager."""
22

3-
from subprocess import PIPE
3+
import os
44
import time
5-
from unittest import TestCase
5+
import threading
6+
import multiprocessing as mp
67

8+
from subprocess import PIPE
9+
from unittest import TestCase
710
from traitlets.config.loader import Config
8-
from ..localinterfaces import localhost
911
from jupyter_client import KernelManager
1012
from jupyter_client.multikernelmanager import MultiKernelManager
13+
1114
from .utils import skip_win32
15+
from ..localinterfaces import localhost
16+
17+
TIMEOUT = 30
18+
1219

1320
class TestKernelManager(TestCase):
1421

@@ -83,3 +90,43 @@ def test_ipc_lifecycle(self):
8390
def test_ipc_cinfo(self):
8491
km = self._get_ipc_km()
8592
self._run_cinfo(km, 'ipc', 'test')
93+
94+
def test_start_sequence_tcp_kernels(self):
95+
"""Ensure that a sequence of kernel startups doesn't break anything."""
96+
self._run_lifecycle(self._get_tcp_km())
97+
self._run_lifecycle(self._get_tcp_km())
98+
self._run_lifecycle(self._get_tcp_km())
99+
100+
101+
def test_start_sequence_tcp_kernels(self):
102+
"""Ensure that a sequence of kernel startups doesn't break anything."""
103+
self._run_lifecycle(self._get_ipc_km())
104+
self._run_lifecycle(self._get_ipc_km())
105+
self._run_lifecycle(self._get_ipc_km())
106+
107+
def test_start_parallel_thread_kernels(self):
108+
self.test_tcp_lifecycle()
109+
110+
thread = threading.Thread(target=self.test_tcp_lifecycle)
111+
thread2 = threading.Thread(target=self.test_tcp_lifecycle)
112+
try:
113+
thread.start()
114+
thread2.start()
115+
finally:
116+
thread.join()
117+
thread2.join()
118+
119+
def test_start_parallel_process_kernels(self):
120+
self.test_tcp_lifecycle()
121+
122+
thread = threading.Thread(target=self.test_tcp_lifecycle)
123+
proc = mp.Process(target=self.test_tcp_lifecycle)
124+
125+
try:
126+
thread.start()
127+
proc.start()
128+
finally:
129+
thread.join()
130+
proc.join()
131+
132+
assert proc.exitcode == 0

jupyter_client/tests/test_session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def test_default_secure(self):
8383
self.assertIsInstance(self.session.auth, hmac.HMAC)
8484

8585
def test_send(self):
86-
ctx = zmq.Context.instance()
86+
ctx = zmq.Context()
8787
A = ctx.socket(zmq.PAIR)
8888
B = ctx.socket(zmq.PAIR)
8989
A.bind("inproc://test")
@@ -316,7 +316,7 @@ def test_datetimes_msgpack(self):
316316
self._datetime_test(session)
317317

318318
def test_send_raw(self):
319-
ctx = zmq.Context.instance()
319+
ctx = zmq.Context()
320320
A = ctx.socket(zmq.PAIR)
321321
B = ctx.socket(zmq.PAIR)
322322
A.bind("inproc://test")

setup.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import sys
1717

1818
v = sys.version_info
19-
if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
20-
error = "ERROR: %s requires Python version 2.7 or 3.3 or above." % name
19+
if v[:2] < (2, 7) or (v[0] >= 3 and v[:2] < (3, 5)):
20+
error = "ERROR: %s requires Python version 2.7 or 3.5 or above." % name
2121
print(error, file=sys.stderr)
2222
sys.exit(1)
2323

@@ -93,11 +93,9 @@ def run(self):
9393
'python-dateutil>=2.1',
9494
'tornado>=4.1',
9595
],
96-
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*',
96+
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
9797
extras_require = {
98-
'test': ['ipykernel', 'ipython', 'mock'],
99-
'test:python_version == "3.3"': ['pytest<3.3.0'],
100-
'test:(python_version >= "3.4" or python_version == "2.7")': ['pytest'],
98+
'test': ['ipykernel', 'ipython', 'mock', 'pytest'],
10199
},
102100
cmdclass = {
103101
'bdist_egg': bdist_egg if 'bdist_egg' in sys.argv else bdist_egg_disabled,

0 commit comments

Comments
 (0)