Skip to content

Commit 97719e4

Browse files
committed
Suggest to make implementations of some function always return awaitable.
See discussion in #1272; It is not deprecated, but being able to always know you can (and must) await should be simpler in the long run. Deprecating now is not the point, but I want to cover our bases, so that we are more confident later when and if we want to enforce those await. In particular many of those branches are not covered in our tests – and I don't even know wether they were ever taken; I changed some of the base methods to be async, but I'm happy to move those back to sync. A few other things use the `if awaitable(...):` pattern but are a bit more complicted, and some do not dates from 2021, so those will be dealt with separately.
1 parent e64fb2e commit 97719e4

File tree

1 file changed

+66
-1
lines changed

1 file changed

+66
-1
lines changed

ipykernel/kernelbase.py

+66-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@
5757
from ._version import kernel_protocol_version
5858
from .iostream import OutStream
5959

60+
_AWAITABLE_MESSAGE: str = (
61+
"For consistency across implementations, it is recommended that `{func_name}`"
62+
" either be a coroutine function (`async def`) or return an awaitable object"
63+
" (like a Future). It might become a requirement in the future."
64+
" Coroutine functions and awaitables have been supported since"
65+
" ipykernel 6.0 (2021)."
66+
)
67+
6068

6169
def _accepts_parameters(meth, param_names):
6270
parameters = inspect.signature(meth).parameters
@@ -742,6 +750,12 @@ async def execute_request(self, socket, ident, parent):
742750

743751
if inspect.isawaitable(reply_content):
744752
reply_content = await reply_content
753+
else:
754+
warnings.warn(
755+
_AWAITABLE_MESSAGE.format(func_name="execute_request"),
756+
PendingDeprecationWarning,
757+
stacklevel=1,
758+
)
745759

746760
# Flush output before sending the reply.
747761
if sys.stdout is not None:
@@ -802,12 +816,27 @@ async def complete_request(self, socket, ident, parent):
802816
matches = self.do_complete(code, cursor_pos)
803817
if inspect.isawaitable(matches):
804818
matches = await matches
819+
else:
820+
warnings.warn(
821+
_AWAITABLE_MESSAGE.format(func_name="do_complete"),
822+
PendingDeprecationWarning,
823+
stacklevel=1,
824+
)
805825

806826
matches = json_clean(matches)
807827
self.session.send(socket, "complete_reply", matches, parent, ident)
808828

809829
def do_complete(self, code, cursor_pos):
810-
"""Override in subclasses to find completions."""
830+
"""Override in subclasses to find completions.
831+
832+
.. note::
833+
834+
Subclass should likely make this method return an awaitable,
835+
but the base class method will need to stay sync for a few versions
836+
to not break spyder-kernel and qtconsole.
837+
838+
839+
"""
811840
return {
812841
"matches": [],
813842
"cursor_end": cursor_pos,
@@ -830,6 +859,12 @@ async def inspect_request(self, socket, ident, parent):
830859
)
831860
if inspect.isawaitable(reply_content):
832861
reply_content = await reply_content
862+
else:
863+
warnings.warn(
864+
_AWAITABLE_MESSAGE.format(func_name="inspect_request"),
865+
PendingDeprecationWarning,
866+
stacklevel=1,
867+
)
833868

834869
# Before we send this object over, we scrub it for JSON usage
835870
reply_content = json_clean(reply_content)
@@ -849,6 +884,12 @@ async def history_request(self, socket, ident, parent):
849884
reply_content = self.do_history(**content)
850885
if inspect.isawaitable(reply_content):
851886
reply_content = await reply_content
887+
else:
888+
warnings.warn(
889+
_AWAITABLE_MESSAGE.format(func_name="history_request"),
890+
PendingDeprecationWarning,
891+
stacklevel=1,
892+
)
852893

853894
reply_content = json_clean(reply_content)
854895
msg = self.session.send(socket, "history_reply", reply_content, parent, ident)
@@ -966,6 +1007,12 @@ async def shutdown_request(self, socket, ident, parent):
9661007
content = self.do_shutdown(parent["content"]["restart"])
9671008
if inspect.isawaitable(content):
9681009
content = await content
1010+
else:
1011+
warnings.warn(
1012+
_AWAITABLE_MESSAGE.format(func_name="do_shutdown"),
1013+
PendingDeprecationWarning,
1014+
stacklevel=1,
1015+
)
9691016
self.session.send(socket, "shutdown_reply", content, parent, ident=ident)
9701017
# same content, but different msg_id for broadcasting on IOPub
9711018
self._shutdown_message = self.session.msg("shutdown_reply", content, parent)
@@ -977,6 +1024,12 @@ async def shutdown_request(self, socket, ident, parent):
9771024
def do_shutdown(self, restart):
9781025
"""Override in subclasses to do things when the frontend shuts down the
9791026
kernel.
1027+
1028+
.. note::
1029+
1030+
Subclass should likely make this method return an awaitable,
1031+
but the base class method will need to stay sync for a few versions
1032+
to not break spyder-kernel and qtconsole.
9801033
"""
9811034
return {"status": "ok", "restart": restart}
9821035

@@ -990,6 +1043,12 @@ async def is_complete_request(self, socket, ident, parent):
9901043
reply_content = self.do_is_complete(code)
9911044
if inspect.isawaitable(reply_content):
9921045
reply_content = await reply_content
1046+
else:
1047+
warnings.warn(
1048+
_AWAITABLE_MESSAGE.format(func_name="do_execute"),
1049+
PendingDeprecationWarning,
1050+
stacklevel=1,
1051+
)
9931052
reply_content = json_clean(reply_content)
9941053
reply_msg = self.session.send(socket, "is_complete_reply", reply_content, parent, ident)
9951054
self.log.debug("%s", reply_msg)
@@ -1006,6 +1065,12 @@ async def debug_request(self, socket, ident, parent):
10061065
reply_content = self.do_debug_request(content)
10071066
if inspect.isawaitable(reply_content):
10081067
reply_content = await reply_content
1068+
else:
1069+
warnings.warn(
1070+
_AWAITABLE_MESSAGE.format(func_name="debug_request"),
1071+
PendingDeprecationWarning,
1072+
stacklevel=1,
1073+
)
10091074
reply_content = json_clean(reply_content)
10101075
reply_msg = self.session.send(socket, "debug_reply", reply_content, parent, ident)
10111076
self.log.debug("%s", reply_msg)

0 commit comments

Comments
 (0)