Skip to content

Commit 5a1d46c

Browse files
committed
add Session.clone
and use it when instantiating new Clients with Manager.client() If multiple Clients are instantiated against the same kernel, they mustn’t share a digest_history because they could all be receiving the same iopub messages which would cause hash collisions.
1 parent 0278382 commit 5a1d46c

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

jupyter_client/connect.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,9 @@ def get_connection_info(self, session=False):
371371
control_port=self.control_port,
372372
)
373373
if session:
374-
# add session
375-
info['session'] = self.session
374+
# add *clone* of my session,
375+
# so that state such as digest_history is not shared.
376+
info['session'] = self.session.clone()
376377
else:
377378
# add session info
378379
info.update(dict(

jupyter_client/session.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,24 @@ def __init__(self, **kwargs):
488488
if not self.key:
489489
get_logger().warning("Message signing is disabled. This is insecure and not recommended!")
490490

491+
def clone(self):
492+
"""Create a copy of this Session
493+
494+
Useful when connecting multiple times to a given kernel.
495+
This prevents a shared digest_history warning about duplicate digests
496+
due to multiple connections to IOPub in the same process.
497+
498+
.. versionadded:: 5.1
499+
"""
500+
# make a copy
501+
new_session = type(self)()
502+
for name in self.traits():
503+
setattr(new_session, name, getattr(self, name))
504+
# fork digest_history
505+
new_session.digest_history = set()
506+
new_session.digest_history.update(self.digest_history)
507+
return new_session
508+
491509
@property
492510
def msg_id(self):
493511
"""always return new uuid"""

jupyter_client/tests/test_session.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,15 @@ def test_send_raw(self):
320320
A.close()
321321
B.close()
322322
ctx.term()
323+
324+
def test_clone(self):
325+
s = self.session
326+
s._add_digest('initial')
327+
s2 = s.clone()
328+
assert s2.session == s.session
329+
assert s2.digest_history == s.digest_history
330+
assert s2.digest_history is not s.digest_history
331+
digest = 'abcdef'
332+
s._add_digest(digest)
333+
assert digest in s.digest_history
334+
assert digest not in s2.digest_history

0 commit comments

Comments
 (0)