Skip to content

Commit

Permalink
Handle async do_complete.
Browse files Browse the repository at this point in the history
A number of methods of ipykernel can optinally return `awaitable[T]`
instead of just `T`, this is the case for `do_complete`.

I think it's a mistake ; see ipython/ipykernel#1295 ; in particular
because it's easy to forget / hard to properly type-check, and I'd like
to make it mandatory in the long term to have await.

Spyder seem to not handle the case where do_completer return an
awaitable (or more partiularly is `do_complete` is a coroutine function.

This tries to handle it – and as of course `do_completer` _can_ be
async, all caller _must_ be async. So I try to do all the required
updates.

Note: I also add explict imports in some test, to get better error
message in case those deps are not installed.
  • Loading branch information
Carreau committed Nov 13, 2024
1 parent 4e554db commit 2f295cd
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 8 deletions.
7 changes: 6 additions & 1 deletion spyder_kernels/console/tests/test_console_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,13 +875,15 @@ def test_matplotlib_inline(kernel):
assert 'inline' in value


def test_do_complete(kernel):
async def test_do_complete(kernel):
"""
Check do complete works in normal and debugging mode.
"""
asyncio.run(kernel.do_execute('abba = 1', True))
assert kernel.get_value('abba') == 1
match = kernel.do_complete('ab', 2)
if isawaitable(match):
match = await match
assert 'abba' in match['matches']

# test pdb
Expand All @@ -890,6 +892,8 @@ def test_do_complete(kernel):
pdb_obj.completenames = lambda *ignore: ['baba']
kernel.shell._namespace_stack = [pdb_obj]
match = kernel.do_complete('ba', 2)
if isawaitable(match):
match = await match
assert 'baba' in match['matches']
pdb_obj.curframe = None

Expand Down Expand Up @@ -1390,6 +1394,7 @@ def test_django_settings(kernel):
This is a regression test for issue spyder-ide/spyder#19516
"""
import django
asyncio.run(kernel.do_execute('from django.conf import settings', True))
nsview = repr(kernel.get_namespace_view())
assert "'settings':" in nsview
Expand Down
14 changes: 7 additions & 7 deletions spyder_kernels/customize/spyderpdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,16 +351,16 @@ def do_where(self, arg):
do_bt = do_where

# --- Method defined by us to respond to ipython complete protocol
def do_complete(self, code, cursor_pos):
async def do_complete(self, code, cursor_pos):
"""
Respond to a complete request.
"""
if self.pdb_use_exclamation_mark:
return self._complete_exclamation(code, cursor_pos)
return await self._complete_exclamation(code, cursor_pos)
else:
return self._complete_default(code, cursor_pos)
return await self._complete_default(code, cursor_pos)

def _complete_default(self, code, cursor_pos):
async def _complete_default(self, code, cursor_pos):
"""
Respond to a complete request if not pdb_use_exclamation_mark.
"""
Expand Down Expand Up @@ -422,7 +422,7 @@ def is_name_or_composed(text):
else:
frame = self.curframe
self.shell.set_completer_frame(frame)
result = self.shell.kernel._do_complete(code, cursor_pos)
result = await self.shell.kernel._do_complete(code, cursor_pos)
# Reset frame
self.shell.set_completer_frame()
# If there is no Pdb results to merge, return the result
Expand Down Expand Up @@ -450,7 +450,7 @@ def is_name_or_composed(text):
'metadata': {},
'status': 'ok'}

def _complete_exclamation(self, code, cursor_pos):
async def _complete_exclamation(self, code, cursor_pos):
"""
Respond to a complete request if pdb_use_exclamation_mark.
"""
Expand Down Expand Up @@ -529,7 +529,7 @@ def is_name_or_composed(text):
else:
frame = self.curframe
self.shell.set_completer_frame(frame)
result = self.shell.kernel._do_complete(code, cursor_pos)
result = await self.shell.kernel._do_complete(code, cursor_pos)
# Reset frame
self.shell.set_completer_frame()
return result
Expand Down
1 change: 1 addition & 0 deletions spyder_kernels/utils/tests/test_iofuncs.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ def test_spydata_export(input_namespace, expected_namespace,

def test_save_load_hdf5_files(tmp_path):
"""Simple test to check that we can save and load HDF5 files."""
import h5py
h5_file = tmp_path / "test.h5"
data = {'a' : [1, 2, 3, 4], 'b' : 4.5}
iofuncs.save_hdf5(data, h5_file)
Expand Down

0 comments on commit 2f295cd

Please sign in to comment.