Skip to content

Commit 5798b4c

Browse files
committed
Only set parent and ident from _execute_request_loop.
1 parent 19ee3e2 commit 5798b4c

File tree

6 files changed

+58
-97
lines changed

6 files changed

+58
-97
lines changed

ipykernel/comm/comm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys):
3939
msg_type,
4040
content,
4141
metadata=json_clean(metadata),
42-
parent=self.kernel.get_parent(),
42+
parent=self.kernel.parent_msg,
4343
ident=self.topic,
4444
buffers=buffers,
4545
)

ipykernel/inprocess/ipkernel.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def stop(self):
9595
def _abort_queues(self):
9696
"""The in-process kernel doesn't abort requests."""
9797

98-
def _input_request(self, prompt, ident, parent, password=False):
98+
def _input_request(self, prompt, *, password=False):
9999
# Flush output before making the request.
100100
self.raw_input_str = None
101101
if sys.stdout is not None:
@@ -106,10 +106,10 @@ def _input_request(self, prompt, ident, parent, password=False):
106106
# Send the input request.
107107
content = json_clean(dict(prompt=prompt, password=password))
108108
assert self.session is not None
109-
msg = self.session.msg("input_request", content, parent)
109+
msg = self.session.msg("input_request", content, self.parent_msg)
110110
for frontend in self.frontends:
111111
assert frontend is not None
112-
if frontend.session.session == parent["header"]["session"]:
112+
if frontend.session.session == self.parent_msg["header"]["session"]:
113113
frontend.stdin_channel.call_handlers(msg)
114114
break
115115
else:

ipykernel/ipkernel.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,12 +286,9 @@ def stop(self):
286286
if self.debugpy_socket is not None:
287287
self.debugpy_stop.set()
288288

289-
def set_parent(self, ident, parent, channel="shell"):
290-
"""Overridden from parent to tell the display hook and output streams
291-
about the parent message.
292-
"""
293-
super().set_parent(ident, parent, channel)
294-
if channel == "shell" and self.shell:
289+
def _set_parent_ident(self, parent, ident):
290+
super()._set_parent_ident(parent, ident)
291+
if self.shell:
295292
self.shell.set_parent(parent)
296293

297294
def _forward_input(self, allow_stdin=False):

ipykernel/kernelbase.py

Lines changed: 47 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
from functools import partial
2323
from signal import SIGINT, SIGTERM, Signals
2424

25-
from .thread import CONTROL_THREAD_NAME
26-
2725
if sys.platform != "win32":
2826
from signal import SIGKILL
2927
else:
@@ -174,17 +172,6 @@ def _default_ident(self):
174172

175173
# track associations with current request
176174
_allow_stdin = Bool(False)
177-
_parents: Dict[str, t.Any] = Dict({"shell": {}, "control": {}})
178-
_parent_ident = Dict({"shell": b"", "control": b""})
179-
180-
@property
181-
def _parent_header(self):
182-
warnings.warn(
183-
"Kernel._parent_header is deprecated in ipykernel 6. Use .get_parent()",
184-
DeprecationWarning,
185-
stacklevel=2,
186-
)
187-
return self.get_parent()
188175

189176
# Time to sleep after flushing the stdout/err buffers in each execute
190177
# cycle. While this introduces a hard limit on the minimal latency of the
@@ -303,11 +290,7 @@ async def process_control_message(self, msg=None):
303290
return
304291

305292
self.log.debug("Control received: %s", msg)
306-
307-
# Set the parent message for side effects.
308-
self.set_parent(idents, msg, channel="control")
309-
self._publish_status("busy", "control", parent=msg)
310-
293+
self._publish_status("busy", msg)
311294
header = msg["header"]
312295
msg_type = header["msg_type"]
313296

@@ -329,7 +312,7 @@ async def process_control_message(self, msg=None):
329312
sys.stdout.flush()
330313
if sys.stderr is not None:
331314
sys.stderr.flush()
332-
self._publish_status("idle", "control")
315+
self._publish_status("idle", msg)
333316

334317
def should_handle(self, stream, msg, idents):
335318
"""Check whether a shell-channel message should be handled
@@ -472,8 +455,8 @@ async def shell_main(self, subshell_id: str | None):
472455
async def _execute_request_loop(self, receive_stream: MemoryObjectReceiveStream):
473456
async with receive_stream:
474457
async for handler, (received_time, socket, idents, msg) in receive_stream:
475-
self.set_parent(idents, msg, channel="shell")
476-
self._publish_status("busy", "shell", parent=msg)
458+
self._set_parent_ident(msg, idents)
459+
self._publish_status("busy", msg)
477460
try:
478461
if received_time < self._aborted_time:
479462
await self._send_abort_reply(socket, msg, idents)
@@ -484,7 +467,7 @@ async def _execute_request_loop(self, receive_stream: MemoryObjectReceiveStream)
484467
except BaseException as e:
485468
self.log.exception("Execute request", exc_info=e)
486469
finally:
487-
self._publish_status("idle", "shell", parent=msg)
470+
self._publish_status("idle", msg)
488471

489472
async def _process_shell(self, socket):
490473
# socket=None is valid if kernel subshells are not supported.
@@ -522,7 +505,7 @@ async def process_shell_message(self, msg=None, socket=None):
522505

523506
msg_type = msg["header"]["msg_type"]
524507
if msg_type != "execute_request":
525-
self._publish_status("busy", "shell", parent=msg)
508+
self._publish_status("busy", msg)
526509

527510
# Print some info about this message and leave a '--->' marker, so it's
528511
# easier to trace visually the message chain when debugging. Each
@@ -565,7 +548,7 @@ async def process_shell_message(self, msg=None, socket=None):
565548
except Exception:
566549
self.log.debug("Unable to signal in post_handler_hook:", exc_info=True)
567550
if msg_type != "execute_request":
568-
self._publish_status("idle", "shell", parent=msg)
551+
self._publish_status("idle", msg)
569552

570553
async def control_main(self):
571554
assert self.control_socket is not None
@@ -651,15 +634,15 @@ def _publish_execute_input(self, code, parent, execution_count):
651634
ident=self._topic("execute_input"),
652635
)
653636

654-
def _publish_status(self, status, channel, parent=None):
637+
def _publish_status(self, status: str, parent):
655638
"""send status (busy/idle) on IOPub"""
656639
if not self.session:
657640
return
658641
self.session.send(
659642
self.iopub_socket,
660643
"status",
661644
{"execution_state": status},
662-
parent=parent or self.get_parent(channel),
645+
parent=parent,
663646
ident=self._topic("status"),
664647
)
665648

@@ -670,46 +653,35 @@ def _publish_debug_event(self, event):
670653
self.iopub_socket,
671654
"debug_event",
672655
event,
673-
parent=self.get_parent(),
656+
parent=self.parent_msg,
674657
ident=self._topic("debug_event"),
675658
)
676659

677-
def set_parent(self, ident, parent, channel="shell"):
678-
"""Set the current parent request
660+
def _set_parent_ident(self, parent, ident):
661+
self._parent_msg = parent
662+
self._parent_ident = ident
679663

680-
Side effects (IOPub messages) and replies are associated with
681-
the request that caused them via the parent_header.
664+
@property
665+
def parent_msg(self):
666+
"""The message of the most recent execution request.
682667
683-
The parent identity is used to route input_request messages
684-
on the stdin channel.
668+
.. versionadded:: 7
685669
"""
686-
self._parent_ident[channel] = ident
687-
self._parents[channel] = parent
688-
689-
def get_parent(self, channel=None):
690-
"""Get the parent request associated with a channel.
691-
692-
.. versionadded:: 6
670+
try:
671+
return self._parent_msg
672+
except AttributeError:
673+
return {}
693674

694-
Parameters
695-
----------
696-
channel : str
697-
the name of the channel ('shell' or 'control')
675+
@property
676+
def parent_ident(self):
677+
"""The ident of the most recent execution request.
698678
699-
Returns
700-
-------
701-
message : dict
702-
the parent message for the most recent request on the channel.
679+
.. versionadded:: 7
703680
"""
704-
705-
if channel is None:
706-
# If a channel is not specified, get information from current thread
707-
if threading.current_thread().name == CONTROL_THREAD_NAME:
708-
channel = "control"
709-
else:
710-
channel = "shell"
711-
712-
return self._parents.get(channel, {})
681+
try:
682+
return self._parent_ident
683+
except AttributeError:
684+
return []
713685

714686
def send_response(
715687
self,
@@ -721,28 +693,24 @@ def send_response(
721693
track=False,
722694
header=None,
723695
metadata=None,
724-
channel=None,
725696
):
726697
"""Send a response to the message we're currently processing.
727698
728699
This accepts all the parameters of :meth:`jupyter_client.session.Session.send`
729700
except ``parent``.
730-
731-
This relies on :meth:`set_parent` having been called for the current
732-
message.
733701
"""
734702
if not self.session:
735703
return None
736704
return self.session.send(
737705
socket,
738706
msg_or_type,
739-
content,
740-
self.get_parent(channel),
741-
ident,
742-
buffers,
743-
track,
744-
header,
745-
metadata,
707+
content=content,
708+
parent=self.parent_msg,
709+
ident=ident,
710+
buffers=buffers,
711+
track=track,
712+
header=header,
713+
metadata=metadata,
746714
)
747715

748716
async def execute_request(self, socket, ident, parent):
@@ -1265,12 +1233,7 @@ def getpass(self, prompt="", stream=None):
12651233
UserWarning,
12661234
stacklevel=2,
12671235
)
1268-
return self._input_request(
1269-
prompt,
1270-
self._parent_ident["shell"],
1271-
self.get_parent("shell"),
1272-
password=True,
1273-
)
1236+
return self._input_request(prompt, password=True)
12741237

12751238
def raw_input(self, prompt=""):
12761239
"""Forward raw_input to frontends
@@ -1282,14 +1245,9 @@ def raw_input(self, prompt=""):
12821245
if not self._allow_stdin:
12831246
msg = "raw_input was called, but this frontend does not support input requests."
12841247
raise StdinNotImplementedError(msg)
1285-
return self._input_request(
1286-
str(prompt),
1287-
self._parent_ident["shell"],
1288-
self.get_parent("shell"),
1289-
password=False,
1290-
)
1248+
return self._input_request(str(prompt), password=False)
12911249

1292-
def _input_request(self, prompt, ident, parent, password=False):
1250+
def _input_request(self, prompt, *, password=False):
12931251
# Flush output before making the request.
12941252
if sys.stdout is not None:
12951253
sys.stdout.flush()
@@ -1308,7 +1266,13 @@ def _input_request(self, prompt, ident, parent, password=False):
13081266
# Send the input request.
13091267
assert self.session is not None
13101268
content = json_clean(dict(prompt=prompt, password=password))
1311-
self.session.send(self.stdin_socket, "input_request", content, parent, ident=ident)
1269+
self.session.send(
1270+
self.stdin_socket,
1271+
"input_request",
1272+
content,
1273+
parent=self.parent_msg,
1274+
ident=self.parent_ident,
1275+
)
13121276

13131277
# Await a response.
13141278
while True:
@@ -1334,7 +1298,7 @@ def _input_request(self, prompt, ident, parent, password=False):
13341298
try:
13351299
value = reply["content"]["value"] # type:ignore[index]
13361300
except Exception:
1337-
self.log.error("Bad input_reply: %s", parent)
1301+
self.log.error("Bad input_reply: %s", self.parent_msg)
13381302
value = ""
13391303
if value == "\x04":
13401304
# EOF

tests/test_kernel.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,18 +601,18 @@ def test_control_thread_priority():
601601

602602
def test_sequential_control_messages():
603603
with new_kernel() as kc:
604-
msg_id = kc.execute("import anyio")
604+
msg_id = kc.execute("import time")
605605
get_reply(kc, msg_id)
606606

607607
# Send multiple messages on the control channel.
608608
# Using execute messages to vary duration.
609-
sleeps = [0.0, 0.6, 0.3, 0.1, 0.0, 0.0]
609+
sleeps = [0.0, 0.6, 0.3, 0.1, 0.0]
610610

611611
# Prepare messages
612612
msgs = [
613613
kc.session.msg(
614614
"execute_request",
615-
{"code": f"await anyio.sleep({sleep})", "user_expressions": {"i": str(i)}},
615+
{"code": f"time.sleep({sleep})", "user_expressions": {"i": str(i)}},
616616
)
617617
for i, sleep in enumerate(sleeps)
618618
]

tests/test_subshells.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ def test_execution_count():
259259
def test_create_while_execute():
260260
with new_kernel() as kc:
261261
# Send request to execute code on main subshell.
262-
msg = kc.session.msg("execute_request", {"code": "import time; time.sleep(0.05)"})
262+
msg = kc.session.msg("execute_request", {"code": "import time; time.sleep(0.5)"})
263263
kc.shell_channel.send(msg)
264264

265265
# Create subshell via control channel.

0 commit comments

Comments
 (0)