diff --git a/IPython/core/completer.py b/IPython/core/completer.py index d2637c4..80aafee 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -622,8 +622,27 @@ def get__all__entries(obj): return [cast_unicode_py2(w) for w in words if isinstance(w, str)] -def match_dict_keys(keys, prefix, delims): - """Used by dict_key_matches, matching the prefix to a list of keys""" +def match_dict_keys(keys: List[str], prefix: str, delims: str): + """Used by dict_key_matches, matching the prefix to a list of keys + + Parameters + ========== + keys: + list of keys in dictionary currently being completed. + prefix: + Part of the text already typed by the user. e.g. `mydict[b'fo` + delims: + String of delimiters to consider when finding the current key. + + Returns + ======= + + A tuple of three elements: ``quote``, ``token_start``, ``matched``, with + ``quote`` being the quote that need to be used to close current string. + ``token_start`` the position where the replacement should start occurring, + ``matches`` a list of replacement/completion + + """ if not prefix: return None, 0, [repr(k) for k in keys if isinstance(k, (str, bytes))] @@ -639,7 +658,6 @@ def match_dict_keys(keys, prefix, delims): token_start = token_match.start() token_prefix = token_match.group() - # TODO: support bytes in Py3k matched = [] for key in keys: try: @@ -652,7 +670,7 @@ def match_dict_keys(keys, prefix, delims): # reformat remainder of key to begin with prefix rem = key[len(prefix_str):] # force repr wrapped in ' - rem_repr = repr(rem + '"') + rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"') if rem_repr.startswith('u') and prefix[0] not in 'uU': # Found key is unicode, but prefix is Py2 string. # Therefore attempt to interpret key as string. diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index dab79ec..cd193b9 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -20,7 +20,7 @@ from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory from IPython.utils.generics import complete_object from IPython.testing import decorators as dec -from IPython.core.completer import Completion, provisionalcompleter +from IPython.core.completer import Completion, provisionalcompleter, match_dict_keys from nose.tools import assert_in, assert_not_in #----------------------------------------------------------------------------- @@ -526,7 +526,28 @@ def test_magic_completion_order(): # Order of user variable and line and cell magics with same name: text, matches = c.complete('timeit') - nt.assert_equal(matches, ["timeit", "%timeit","%%timeit"]) + nt.assert_equal(matches, ["timeit", "%timeit", "%%timeit"]) + +def test_match_dict_keys(): + """ + Test that match_dict_keys works on a couple of use case does return what + expected, and does not crash + """ + delims = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' + + + keys = ['foo', b'far'] + assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2 ,['far']) + assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2 ,['far']) + assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2 ,['far']) + assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2 ,['far']) + + assert match_dict_keys(keys, "'", delims=delims) == ("'", 1 ,['foo']) + assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1 ,['foo']) + assert match_dict_keys(keys, '"', delims=delims) == ('"', 1 ,['foo']) + assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1 ,['foo']) + + match_dict_keys def test_dict_key_completion_string():