Skip to content

Commit 6fdb97f

Browse files
committed
Suggest to make implementations of some function always return awaitable.
See discussion in ipython#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 4cc832e commit 6fdb97f

File tree

1 file changed

+52
-2
lines changed

1 file changed

+52
-2
lines changed

ipykernel/kernelbase.py

+52-2
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,11 +816,17 @@ 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

809-
def do_complete(self, code, cursor_pos):
829+
async def do_complete(self, code, cursor_pos):
810830
"""Override in subclasses to find completions."""
811831
return {
812832
"matches": [],
@@ -830,6 +850,12 @@ async def inspect_request(self, socket, ident, parent):
830850
)
831851
if inspect.isawaitable(reply_content):
832852
reply_content = await reply_content
853+
else:
854+
warnings.warn(
855+
_AWAITABLE_MESSAGE.format(func_name="inspect_request"),
856+
PendingDeprecationWarning,
857+
stacklevel=1,
858+
)
833859

834860
# Before we send this object over, we scrub it for JSON usage
835861
reply_content = json_clean(reply_content)
@@ -849,6 +875,12 @@ async def history_request(self, socket, ident, parent):
849875
reply_content = self.do_history(**content)
850876
if inspect.isawaitable(reply_content):
851877
reply_content = await reply_content
878+
else:
879+
warnings.warn(
880+
_AWAITABLE_MESSAGE.format(func_name="history_request"),
881+
PendingDeprecationWarning,
882+
stacklevel=1,
883+
)
852884

853885
reply_content = json_clean(reply_content)
854886
msg = self.session.send(socket, "history_reply", reply_content, parent, ident)
@@ -966,6 +998,12 @@ async def shutdown_request(self, socket, ident, parent):
966998
content = self.do_shutdown(parent["content"]["restart"])
967999
if inspect.isawaitable(content):
9681000
content = await content
1001+
else:
1002+
warnings.warn(
1003+
_AWAITABLE_MESSAGE.format(func_name="do_shutdown"),
1004+
PendingDeprecationWarning,
1005+
stacklevel=1,
1006+
)
9691007
self.session.send(socket, "shutdown_reply", content, parent, ident=ident)
9701008
# same content, but different msg_id for broadcasting on IOPub
9711009
self._shutdown_message = self.session.msg("shutdown_reply", content, parent)
@@ -974,7 +1012,7 @@ async def shutdown_request(self, socket, ident, parent):
9741012

9751013
self.stop()
9761014

977-
def do_shutdown(self, restart):
1015+
async def do_shutdown(self, restart):
9781016
"""Override in subclasses to do things when the frontend shuts down the
9791017
kernel.
9801018
"""
@@ -990,6 +1028,12 @@ async def is_complete_request(self, socket, ident, parent):
9901028
reply_content = self.do_is_complete(code)
9911029
if inspect.isawaitable(reply_content):
9921030
reply_content = await reply_content
1031+
else:
1032+
warnings.warn(
1033+
_AWAITABLE_MESSAGE.format(func_name="do_execute"),
1034+
PendingDeprecationWarning,
1035+
stacklevel=1,
1036+
)
9931037
reply_content = json_clean(reply_content)
9941038
reply_msg = self.session.send(socket, "is_complete_reply", reply_content, parent, ident)
9951039
self.log.debug("%s", reply_msg)
@@ -1006,6 +1050,12 @@ async def debug_request(self, socket, ident, parent):
10061050
reply_content = self.do_debug_request(content)
10071051
if inspect.isawaitable(reply_content):
10081052
reply_content = await reply_content
1053+
else:
1054+
warnings.warn(
1055+
_AWAITABLE_MESSAGE.format(func_name="debug_request"),
1056+
PendingDeprecationWarning,
1057+
stacklevel=1,
1058+
)
10091059
reply_content = json_clean(reply_content)
10101060
reply_msg = self.session.send(socket, "debug_reply", reply_content, parent, ident)
10111061
self.log.debug("%s", reply_msg)

0 commit comments

Comments
 (0)