test_completer.py
1274 lines
| 46.0 KiB
| text/x-python
|
PythonLexer
MinRK
|
r16564 | # encoding: utf-8 | ||
"""Tests for the IPython tab-completion machinery.""" | ||||
# Copyright (c) IPython Development Team. | ||||
# Distributed under the terms of the Modified BSD License. | ||||
Fernando Perez
|
r2365 | |||
Fernando Perez
|
r3184 | import os | ||
Fernando Perez
|
r2365 | import sys | ||
Matthias Bussonnier
|
r23358 | import textwrap | ||
Fernando Perez
|
r2855 | import unittest | ||
Fernando Perez
|
r2365 | |||
MinRK
|
r16564 | from contextlib import contextmanager | ||
Min RK
|
r21253 | from traitlets.config.loader import Config | ||
Min RK
|
r21718 | from IPython import get_ipython | ||
Fernando Perez
|
r2365 | from IPython.core import completer | ||
Laurent Gautier
|
r24878 | from IPython.external import decorators | ||
Thomas Kluyver
|
r16767 | from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory | ||
Thomas Kluyver
|
r5155 | from IPython.utils.generics import complete_object | ||
Joel Nothman
|
r15766 | from IPython.testing import decorators as dec | ||
Fernando Perez
|
r2365 | |||
Matthias Bussonnier
|
r23358 | from IPython.core.completer import ( | ||
Matthias Bussonnier
|
r25101 | Completion, | ||
provisionalcompleter, | ||||
match_dict_keys, | ||||
_deduplicate_completions, | ||||
) | ||||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25101 | # ----------------------------------------------------------------------------- | ||
Fernando Perez
|
r2365 | # Test functions | ||
Matthias Bussonnier
|
r25101 | # ----------------------------------------------------------------------------- | ||
Matthias Bussonnier
|
r25729 | def recompute_unicode_ranges(): | ||
""" | ||||
utility to recompute the largest unicode range without any characters | ||||
use to recompute the gap in the global _UNICODE_RANGES of completer.py | ||||
""" | ||||
import itertools | ||||
import unicodedata | ||||
valid = [] | ||||
for c in range(0,0x10FFFF + 1): | ||||
try: | ||||
unicodedata.name(chr(c)) | ||||
except ValueError: | ||||
continue | ||||
valid.append(c) | ||||
def ranges(i): | ||||
for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]): | ||||
b = list(b) | ||||
yield b[0][1], b[-1][1] | ||||
rg = list(ranges(valid)) | ||||
lens = [] | ||||
gap_lens = [] | ||||
pstart, pstop = 0,0 | ||||
for start, stop in rg: | ||||
lens.append(stop-start) | ||||
gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%')) | ||||
pstart, pstop = start, stop | ||||
return sorted(gap_lens)[-1] | ||||
Matthias Bussonnier
|
r25711 | def test_unicode_range(): | ||
""" | ||||
Test that the ranges we test for unicode names give the same number of | ||||
results than testing the full length. | ||||
""" | ||||
from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES | ||||
expected_list = _unicode_name_compute([(0, 0x110000)]) | ||||
test = _unicode_name_compute(_UNICODE_RANGES) | ||||
Matthias Bussonnier
|
r25712 | len_exp = len(expected_list) | ||
len_test = len(test) | ||||
Matthias Bussonnier
|
r25711 | |||
Matthias Bussonnier
|
r25712 | # do not inline the len() or on error pytest will try to print the 130 000 + | ||
# elements. | ||||
Matthias Bussonnier
|
r25729 | message = None | ||
if len_exp != len_test or len_exp > 131808: | ||||
size, start, stop, prct = recompute_unicode_ranges() | ||||
message = f"""_UNICODE_RANGES likely wrong and need updating. This is | ||||
likely due to a new release of Python. We've find that the biggest gap | ||||
Dimitri Papadopoulos
|
r26875 | in unicode characters has reduces in size to be {size} characters | ||
Matthias Bussonnier
|
r25729 | ({prct}), from {start}, to {stop}. In completer.py likely update to | ||
_UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)] | ||||
And update the assertion below to use | ||||
len_exp <= {len_exp} | ||||
""" | ||||
assert len_exp == len_test, message | ||||
Matthias Bussonnier
|
r25712 | |||
# fail if new unicode symbols have been added. | ||||
Matthias Bussonnier
|
r25729 | assert len_exp <= 137714, message | ||
Matthias Bussonnier
|
r25711 | |||
MinRK
|
r16564 | |||
@contextmanager | ||||
def greedy_completion(): | ||||
ip = get_ipython() | ||||
greedy_original = ip.Completer.greedy | ||||
try: | ||||
ip.Completer.greedy = True | ||||
yield | ||||
finally: | ||||
ip.Completer.greedy = greedy_original | ||||
Matthias Bussonnier
|
r25101 | |||
Fernando Perez
|
r2365 | def test_protect_filename(): | ||
Matthias Bussonnier
|
r25101 | if sys.platform == "win32": | ||
pairs = [ | ||||
("abc", "abc"), | ||||
(" abc", '" abc"'), | ||||
("a bc", '"a bc"'), | ||||
("a bc", '"a bc"'), | ||||
(" bc", '" bc"'), | ||||
] | ||||
Antony Lee
|
r22418 | else: | ||
Matthias Bussonnier
|
r25101 | pairs = [ | ||
("abc", "abc"), | ||||
(" abc", r"\ abc"), | ||||
("a bc", r"a\ bc"), | ||||
("a bc", r"a\ \ bc"), | ||||
(" bc", r"\ \ bc"), | ||||
# On posix, we also protect parens and other special characters. | ||||
("a(bc", r"a\(bc"), | ||||
("a)bc", r"a\)bc"), | ||||
("a( )bc", r"a\(\ \)bc"), | ||||
("a[1]bc", r"a\[1\]bc"), | ||||
("a{1}bc", r"a\{1\}bc"), | ||||
("a#bc", r"a\#bc"), | ||||
("a?bc", r"a\?bc"), | ||||
("a=bc", r"a\=bc"), | ||||
("a\\bc", r"a\\bc"), | ||||
("a|bc", r"a\|bc"), | ||||
("a;bc", r"a\;bc"), | ||||
("a:bc", r"a\:bc"), | ||||
("a'bc", r"a\'bc"), | ||||
("a*bc", r"a\*bc"), | ||||
('a"bc', r"a\"bc"), | ||||
("a^bc", r"a\^bc"), | ||||
("a&bc", r"a\&bc"), | ||||
] | ||||
Fernando Perez
|
r2365 | # run the actual tests | ||
for s1, s2 in pairs: | ||||
s1p = completer.protect_filename(s1) | ||||
Samuel Gaist
|
r26888 | assert s1p == s2 | ||
Fernando Perez
|
r2855 | |||
def check_line_split(splitter, test_specs): | ||||
for part1, part2, split in test_specs: | ||||
cursor_pos = len(part1) | ||||
Matthias Bussonnier
|
r25101 | line = part1 + part2 | ||
Fernando Perez
|
r2855 | out = splitter.split_line(line, cursor_pos) | ||
Samuel Gaist
|
r26888 | assert out == split | ||
Fernando Perez
|
r2855 | |||
def test_line_split(): | ||||
Thomas Kluyver
|
r13375 | """Basic line splitter test with default specs.""" | ||
Fernando Perez
|
r2855 | sp = completer.CompletionSplitter() | ||
# The format of the test specs is: part1, part2, expected answer. Parts 1 | ||||
# and 2 are joined into the 'line' sent to the splitter, as if the cursor | ||||
# was at the end of part1. So an empty part2 represents someone hitting | ||||
# tab at the end of the line, the most common case. | ||||
Matthias Bussonnier
|
r25101 | t = [ | ||
("run some/scrip", "", "some/scrip"), | ||||
("run scripts/er", "ror.py foo", "scripts/er"), | ||||
("echo $HOM", "", "HOM"), | ||||
("print sys.pa", "", "sys.pa"), | ||||
("print(sys.pa", "", "sys.pa"), | ||||
("execfile('scripts/er", "", "scripts/er"), | ||||
("a[x.", "", "x."), | ||||
("a[x.", "y", "x."), | ||||
('cd "some_file/', "", "some_file/"), | ||||
] | ||||
Fernando Perez
|
r2855 | check_line_split(sp, t) | ||
Fernando Perez
|
r3074 | # Ensure splitting works OK with unicode by re-running the tests with | ||
# all inputs turned into unicode | ||||
Matthias Bussonnier
|
r25101 | check_line_split(sp, [map(str, p) for p in t]) | ||
Piti Ongmongkolkul
|
r6511 | |||
Fernando Perez
|
r3074 | |||
Matthias Bussonnier
|
r25099 | class NamedInstanceMetaclass(type): | ||
def __getitem__(cls, item): | ||||
return cls.get_instance(item) | ||||
Matthias Bussonnier
|
r21103 | |||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25100 | class NamedInstanceClass(metaclass=NamedInstanceMetaclass): | ||
Matthias Bussonnier
|
r25099 | def __init__(self, name): | ||
Matthias Bussonnier
|
r25101 | if not hasattr(self.__class__, "instances"): | ||
Matthias Bussonnier
|
r25099 | self.__class__.instances = {} | ||
self.__class__.instances[name] = self | ||||
Matthias Bussonnier
|
r21103 | |||
Matthias Bussonnier
|
r25099 | @classmethod | ||
def _ipython_key_completions_(cls): | ||||
return cls.instances.keys() | ||||
Matthias Bussonnier
|
r21103 | |||
Matthias Bussonnier
|
r25099 | @classmethod | ||
def get_instance(cls, name): | ||||
return cls.instances[name] | ||||
Matthias Bussonnier
|
r21103 | |||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25100 | class KeyCompletable: | ||
Matthias Bussonnier
|
r25099 | def __init__(self, things=()): | ||
self.things = things | ||||
Matthias Bussonnier
|
r21103 | |||
Matthias Bussonnier
|
r25099 | def _ipython_key_completions_(self): | ||
return list(self.things) | ||||
Matthias Bussonnier
|
r21103 | |||
Matthias Bussonnier
|
r25099 | class TestCompleter(unittest.TestCase): | ||
Fernando Perez
|
r2855 | def setUp(self): | ||
Matthias Bussonnier
|
r25099 | """ | ||
We want to silence all PendingDeprecationWarning when testing the completer | ||||
""" | ||||
self._assertwarns = self.assertWarns(PendingDeprecationWarning) | ||||
self._assertwarns.__enter__() | ||||
def tearDown(self): | ||||
try: | ||||
self._assertwarns.__exit__(None, None, None) | ||||
except AssertionError: | ||||
pass | ||||
def test_custom_completion_error(self): | ||||
"""Test that errors from custom attribute completers are silenced.""" | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | |||
class A: | ||||
pass | ||||
ip.user_ns["x"] = A() | ||||
Matthias Bussonnier
|
r25099 | @complete_object.register(A) | ||
def complete_A(a, existing_completions): | ||||
raise TypeError("this should be silenced") | ||||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | ip.complete("x.") | ||
Tony Fast
|
r25168 | def test_custom_completion_ordering(self): | ||
"""Test that errors from custom attribute completers are silenced.""" | ||||
ip = get_ipython() | ||||
_, matches = ip.complete('in') | ||||
assert matches.index('input') < matches.index('int') | ||||
def complete_example(a): | ||||
return ['example2', 'example1'] | ||||
ip.Completer.custom_completers.add_re('ex*', complete_example) | ||||
_, matches = ip.complete('ex') | ||||
assert matches.index('example2') < matches.index('example1') | ||||
Matthias Bussonnier
|
r25099 | def test_unicode_completions(self): | ||
ip = get_ipython() | ||||
# Some strings that trigger different types of completion. Check them both | ||||
# in str and unicode forms | ||||
Matthias Bussonnier
|
r25101 | s = ["ru", "%ru", "cd /", "floa", "float(x)/"] | ||
Matthias Bussonnier
|
r25099 | for t in s + list(map(str, s)): | ||
# We don't need to check exact completion values (they may change | ||||
# depending on the state of the namespace, but at least no exceptions | ||||
# should be thrown and the return value should be a pair of text, list | ||||
# values. | ||||
text, matches = ip.complete(t) | ||||
Samuel Gaist
|
r26888 | self.assertIsInstance(text, str) | ||
self.assertIsInstance(matches, list) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_latex_completions(self): | ||||
from IPython.core.latex_symbols import latex_symbols | ||||
import random | ||||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | ip = get_ipython() | ||
# Test some random unicode symbols | ||||
keys = random.sample(latex_symbols.keys(), 10) | ||||
for k in keys: | ||||
text, matches = ip.complete(k) | ||||
Samuel Gaist
|
r26888 | self.assertEqual(text, k) | ||
self.assertEqual(matches, [latex_symbols[k]]) | ||||
Matthias Bussonnier
|
r25099 | # Test a more complex line | ||
Matthias Bussonnier
|
r25101 | text, matches = ip.complete("print(\\alpha") | ||
Samuel Gaist
|
r26888 | self.assertEqual(text, "\\alpha") | ||
self.assertEqual(matches[0], latex_symbols["\\alpha"]) | ||||
Matthias Bussonnier
|
r25099 | # Test multiple matching latex symbols | ||
Matthias Bussonnier
|
r25101 | text, matches = ip.complete("\\al") | ||
Samuel Gaist
|
r26888 | self.assertIn("\\alpha", matches) | ||
self.assertIn("\\aleph", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
Matthias Bussonnier
|
r25686 | def test_latex_no_results(self): | ||
""" | ||||
forward latex should really return nothing in either field if nothing is found. | ||||
""" | ||||
ip = get_ipython() | ||||
text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(text, "") | ||
self.assertEqual(matches, ()) | ||||
Matthias Bussonnier
|
r25686 | |||
Matthias Bussonnier
|
r25099 | def test_back_latex_completion(self): | ||
ip = get_ipython() | ||||
Dimitri Papadopoulos
|
r26875 | # do not return more than 1 matches for \beta, only the latex one. | ||
Matthias Bussonnier
|
r25101 | name, matches = ip.complete("\\β") | ||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["\\beta"]) | ||
Matthias Bussonnier
|
r25099 | |||
def test_back_unicode_completion(self): | ||||
ip = get_ipython() | ||||
Thomas Kluyver
|
r16767 | |||
Matthias Bussonnier
|
r25101 | name, matches = ip.complete("\\â…¤") | ||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",)) | ||
Thomas Kluyver
|
r16767 | |||
Matthias Bussonnier
|
r25099 | def test_forward_unicode_completion(self): | ||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | |||
name, matches = ip.complete("\\ROMAN NUMERAL FIVE") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["â…¤"]) # This is not a V | ||
self.assertEqual(matches, ["\u2164"]) # same as above but explicit. | ||||
Matthias Bussonnier
|
r25099 | |||
Samuel Gaist
|
r26888 | @unittest.skip("now we have a completion for \jmath") | ||
Matthias Bussonnier
|
r25101 | @decorators.knownfailureif( | ||
sys.platform == "win32", "Fails if there is a C:\\j... path" | ||||
) | ||||
Matthias Bussonnier
|
r25099 | def test_no_ascii_back_completion(self): | ||
ip = get_ipython() | ||||
with TemporaryWorkingDirectory(): # Avoid any filename completions | ||||
# single ascii letter that don't have yet completions | ||||
Matthias Bussonnier
|
r25101 | for letter in "jJ": | ||
name, matches = ip.complete("\\" + letter) | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, []) | ||
Matthias Bussonnier
|
r25099 | |||
class CompletionSplitterTestCase(unittest.TestCase): | ||||
def setUp(self): | ||||
self.sp = completer.CompletionSplitter() | ||||
def test_delim_setting(self): | ||||
Matthias Bussonnier
|
r25101 | self.sp.delims = " " | ||
Samuel Gaist
|
r26888 | self.assertEqual(self.sp.delims, " ") | ||
self.assertEqual(self.sp._delim_expr, r"[\ ]") | ||||
Matthias Bussonnier
|
r25099 | |||
def test_spaces(self): | ||||
"""Test with only spaces as split chars.""" | ||||
Matthias Bussonnier
|
r25101 | self.sp.delims = " " | ||
t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")] | ||||
Matthias Bussonnier
|
r25099 | check_line_split(self.sp, t) | ||
MinRK
|
r4825 | |||
Matthias Bussonnier
|
r25099 | def test_has_open_quotes1(self): | ||
for s in ["'", "'''", "'hi' '"]: | ||||
Samuel Gaist
|
r26888 | self.assertEqual(completer.has_open_quotes(s), "'") | ||
Matthias Bussonnier
|
r25099 | |||
def test_has_open_quotes2(self): | ||||
for s in ['"', '"""', '"hi" "']: | ||||
Samuel Gaist
|
r26888 | self.assertEqual(completer.has_open_quotes(s), '"') | ||
Matthias Bussonnier
|
r25099 | |||
def test_has_open_quotes3(self): | ||||
for s in ["''", "''' '''", "'hi' 'ipython'"]: | ||||
Samuel Gaist
|
r26888 | self.assertFalse(completer.has_open_quotes(s)) | ||
Matthias Bussonnier
|
r25099 | |||
def test_has_open_quotes4(self): | ||||
for s in ['""', '""" """', '"hi" "ipython"']: | ||||
Samuel Gaist
|
r26888 | self.assertFalse(completer.has_open_quotes(s)) | ||
Matthias Bussonnier
|
r25099 | |||
Matthias Bussonnier
|
r25101 | @decorators.knownfailureif( | ||
sys.platform == "win32", "abspath completions fail on Windows" | ||||
) | ||||
Matthias Bussonnier
|
r25099 | def test_abspath_file_completions(self): | ||
ip = get_ipython() | ||||
with TemporaryDirectory() as tmpdir: | ||||
Matthias Bussonnier
|
r25101 | prefix = os.path.join(tmpdir, "foo") | ||
suffixes = ["1", "2"] | ||||
names = [prefix + s for s in suffixes] | ||||
Matthias Bussonnier
|
r25099 | for n in names: | ||
Matthias Bussonnier
|
r25101 | open(n, "w").close() | ||
Matthias Bussonnier
|
r25099 | |||
# Check simple completion | ||||
c = ip.complete(prefix)[1] | ||||
Samuel Gaist
|
r26888 | self.assertEqual(c, names) | ||
Matthias Bussonnier
|
r25099 | |||
# Now check with a function call | ||||
cmd = 'a = f("%s' % prefix | ||||
c = ip.complete(prefix, cmd)[1] | ||||
Matthias Bussonnier
|
r25101 | comp = [prefix + s for s in suffixes] | ||
Samuel Gaist
|
r26888 | self.assertEqual(c, comp) | ||
Matthias Bussonnier
|
r25099 | |||
def test_local_file_completions(self): | ||||
ip = get_ipython() | ||||
with TemporaryWorkingDirectory(): | ||||
Matthias Bussonnier
|
r25101 | prefix = "./foo" | ||
suffixes = ["1", "2"] | ||||
names = [prefix + s for s in suffixes] | ||||
Matthias Bussonnier
|
r25099 | for n in names: | ||
Matthias Bussonnier
|
r25101 | open(n, "w").close() | ||
Matthias Bussonnier
|
r25099 | |||
# Check simple completion | ||||
c = ip.complete(prefix)[1] | ||||
Samuel Gaist
|
r26888 | self.assertEqual(c, names) | ||
Matthias Bussonnier
|
r25099 | |||
# Now check with a function call | ||||
cmd = 'a = f("%s' % prefix | ||||
c = ip.complete(prefix, cmd)[1] | ||||
Matthias Bussonnier
|
r25101 | comp = {prefix + s for s in suffixes} | ||
Samuel Gaist
|
r26888 | self.assertTrue(comp.issubset(set(c))) | ||
Matthias Bussonnier
|
r25099 | |||
def test_quoted_file_completions(self): | ||||
ip = get_ipython() | ||||
with TemporaryWorkingDirectory(): | ||||
name = "foo'bar" | ||||
Matthias Bussonnier
|
r25101 | open(name, "w").close() | ||
Matthias Bussonnier
|
r25099 | |||
# Don't escape Windows | ||||
escaped = name if sys.platform == "win32" else "foo\\'bar" | ||||
# Single quote matches embedded single quote | ||||
text = "open('foo" | ||||
Matthias Bussonnier
|
r25101 | c = ip.Completer._complete( | ||
cursor_line=0, cursor_pos=len(text), full_text=text | ||||
)[1] | ||||
Samuel Gaist
|
r26888 | self.assertEqual(c, [escaped]) | ||
Matthias Bussonnier
|
r25099 | |||
# Double quote requires no escape | ||||
text = 'open("foo' | ||||
Matthias Bussonnier
|
r25101 | c = ip.Completer._complete( | ||
cursor_line=0, cursor_pos=len(text), full_text=text | ||||
)[1] | ||||
Samuel Gaist
|
r26888 | self.assertEqual(c, [name]) | ||
Matthias Bussonnier
|
r25099 | |||
# No quote requires an escape | ||||
Matthias Bussonnier
|
r25101 | text = "%ls foo" | ||
c = ip.Completer._complete( | ||||
cursor_line=0, cursor_pos=len(text), full_text=text | ||||
)[1] | ||||
Samuel Gaist
|
r26888 | self.assertEqual(c, [escaped]) | ||
Matthias Bussonnier
|
r25099 | |||
Brandon T. Willard
|
r25122 | def test_all_completions_dups(self): | ||
""" | ||||
Make sure the output of `IPCompleter.all_completions` does not have | ||||
duplicated prefixes. | ||||
""" | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
ip.ex("class TestClass():\n\ta=1\n\ta1=2") | ||||
for jedi_status in [True, False]: | ||||
with provisionalcompleter(): | ||||
ip.Completer.use_jedi = jedi_status | ||||
matches = c.all_completions("TestCl") | ||||
assert matches == ['TestClass'], jedi_status | ||||
matches = c.all_completions("TestClass.") | ||||
assert len(matches) > 2, jedi_status | ||||
matches = c.all_completions("TestClass.a") | ||||
assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status | ||||
Matthias Bussonnier
|
r25099 | def test_jedi(self): | ||
""" | ||||
A couple of issue we had with Jedi | ||||
""" | ||||
ip = get_ipython() | ||||
def _test_complete(reason, s, comp, start=None, end=None): | ||||
l = len(s) | ||||
start = start if start is not None else l | ||||
end = end if end is not None else l | ||||
with provisionalcompleter(): | ||||
ip.Completer.use_jedi = True | ||||
completions = set(ip.Completer.completions(s, l)) | ||||
ip.Completer.use_jedi = False | ||||
assert_in(Completion(start, end, comp), completions, reason) | ||||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | def _test_not_complete(reason, s, comp): | ||
l = len(s) | ||||
with provisionalcompleter(): | ||||
ip.Completer.use_jedi = True | ||||
completions = set(ip.Completer.completions(s, l)) | ||||
ip.Completer.use_jedi = False | ||||
assert_not_in(Completion(l, l, comp), completions, reason) | ||||
import jedi | ||||
Matthias Bussonnier
|
r25101 | |||
jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3]) | ||||
Matthias Bussonnier
|
r25099 | if jedi_version > (0, 10): | ||
Matthias Bussonnier
|
r25101 | yield _test_complete, "jedi >0.9 should complete and not crash", "a=1;a.", "real" | ||
yield _test_complete, "can infer first argument", 'a=(1,"foo");a[0].', "real" | ||||
yield _test_complete, "can infer second argument", 'a=(1,"foo");a[1].', "capitalize" | ||||
yield _test_complete, "cover duplicate completions", "im", "import", 0, 2 | ||||
Matthias Bussonnier
|
r25099 | |||
Matthias Bussonnier
|
r25101 | yield _test_not_complete, "does not mix types", 'a=(1,"foo");a[0].', "capitalize" | ||
Matthias Bussonnier
|
r25099 | |||
def test_completion_have_signature(self): | ||||
""" | ||||
Lets make sure jedi is capable of pulling out the signature of the function we are completing. | ||||
""" | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r23284 | with provisionalcompleter(): | ||
Thomas Kluyver
|
r24281 | ip.Completer.use_jedi = True | ||
Matthias Bussonnier
|
r25101 | completions = ip.Completer.completions("ope", 3) | ||
Matthias Bussonnier
|
r25099 | c = next(completions) # should be `open` | ||
Thomas Kluyver
|
r24281 | ip.Completer.use_jedi = False | ||
Matthias Bussonnier
|
r25101 | assert "file" in c.signature, "Signature of function was not found by completer" | ||
assert ( | ||||
"encoding" in c.signature | ||||
), "Signature of function was not found by completer" | ||||
Matthias Bussonnier
|
r25099 | |||
def test_deduplicate_completions(self): | ||||
""" | ||||
Test that completions are correctly deduplicated (even if ranges are not the same) | ||||
""" | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | ip.ex( | ||
textwrap.dedent( | ||||
""" | ||||
Matthias Bussonnier
|
r25099 | class Z: | ||
zoo = 1 | ||||
Matthias Bussonnier
|
r25101 | """ | ||
) | ||||
) | ||||
Matthias Bussonnier
|
r23284 | with provisionalcompleter(): | ||
Thomas Kluyver
|
r24281 | ip.Completer.use_jedi = True | ||
Matthias Bussonnier
|
r25101 | l = list( | ||
_deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3)) | ||||
) | ||||
Thomas Kluyver
|
r24281 | ip.Completer.use_jedi = False | ||
Matthias Bussonnier
|
r23753 | |||
Matthias Bussonnier
|
r25101 | assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l | ||
assert l[0].text == "zoo" # and not `it.accumulate` | ||||
Matthias Bussonnier
|
r23358 | |||
Matthias Bussonnier
|
r25099 | def test_greedy_completions(self): | ||
""" | ||||
Test the capability of the Greedy completer. | ||||
Matthias Bussonnier
|
r23358 | |||
Matthias Bussonnier
|
r25099 | Most of the test here does not really show off the greedy completer, for proof | ||
each of the text below now pass with Jedi. The greedy completer is capable of more. | ||||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | See the :any:`test_dict_key_completion_contexts` | ||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | """ | ||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | ip.ex("a=list(range(5))") | ||
_, c = ip.complete(".", line="a[0].") | ||||
Samuel Gaist
|
r26888 | self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c) | ||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | def _(line, cursor_pos, expect, message, completion): | ||
with greedy_completion(), provisionalcompleter(): | ||||
ip.Completer.use_jedi = False | ||||
Matthias Bussonnier
|
r25101 | _, c = ip.complete(".", line=line, cursor_pos=cursor_pos) | ||
Samuel Gaist
|
r26888 | self.assertIn(expect, c, message % c) | ||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | ip.Completer.use_jedi = True | ||
with provisionalcompleter(): | ||||
completions = ip.Completer.completions(line, cursor_pos) | ||||
Samuel Gaist
|
r26888 | self.assertIn(completion, completions) | ||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | with provisionalcompleter(): | ||
Matthias Bussonnier
|
r25101 | yield _, "a[0].", 5, "a[0].real", "Should have completed on a[0].: %s", Completion( | ||
5, 5, "real" | ||||
) | ||||
yield _, "a[0].r", 6, "a[0].real", "Should have completed on a[0].r: %s", Completion( | ||||
5, 6, "real" | ||||
) | ||||
Matthias Bussonnier
|
r25099 | |||
kousik
|
r25246 | yield _, "a[0].from_", 10, "a[0].from_bytes", "Should have completed on a[0].from_: %s", Completion( | ||
5, 10, "from_bytes" | ||||
) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_omit__names(self): | ||||
# also happens to test IPCompleter as a configurable | ||||
ip = get_ipython() | ||||
ip._hidden_attr = 1 | ||||
ip._x = {} | ||||
c = ip.Completer | ||||
Matthias Bussonnier
|
r25101 | ip.ex("ip=get_ipython()") | ||
Matthias Bussonnier
|
r25099 | cfg = Config() | ||
cfg.IPCompleter.omit__names = 0 | ||||
c.update_config(cfg) | ||||
with provisionalcompleter(): | ||||
c.use_jedi = False | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete("ip.") | ||
Samuel Gaist
|
r26888 | self.assertIn("ip.__str__", matches) | ||
self.assertIn("ip._hidden_attr", matches) | ||||
Kelly Liu
|
r22292 | |||
Matthias Bussonnier
|
r25099 | # c.use_jedi = True | ||
# completions = set(c.completions('ip.', 3)) | ||||
Samuel Gaist
|
r26888 | # self.assertIn(Completion(3, 3, '__str__'), completions) | ||
# self.assertIn(Completion(3,3, "_hidden_attr"), completions) | ||||
Kelly Liu
|
r22292 | |||
Matthias Bussonnier
|
r25099 | cfg = Config() | ||
cfg.IPCompleter.omit__names = 1 | ||||
c.update_config(cfg) | ||||
with provisionalcompleter(): | ||||
c.use_jedi = False | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete("ip.") | ||
Samuel Gaist
|
r26888 | self.assertNotIn("ip.__str__", matches) | ||
# self.assertIn('ip._hidden_attr', matches) | ||||
Matthias Bussonnier
|
r25099 | |||
# c.use_jedi = True | ||||
# completions = set(c.completions('ip.', 3)) | ||||
Samuel Gaist
|
r26888 | # self.assertNotIn(Completion(3,3,'__str__'), completions) | ||
# self.assertIn(Completion(3,3, "_hidden_attr"), completions) | ||||
Matthias Bussonnier
|
r25099 | |||
cfg = Config() | ||||
cfg.IPCompleter.omit__names = 2 | ||||
c.update_config(cfg) | ||||
with provisionalcompleter(): | ||||
c.use_jedi = False | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete("ip.") | ||
Samuel Gaist
|
r26888 | self.assertNotIn("ip.__str__", matches) | ||
self.assertNotIn("ip._hidden_attr", matches) | ||||
Piti Ongmongkolkul
|
r6511 | |||
Matthias Bussonnier
|
r25099 | # c.use_jedi = True | ||
# completions = set(c.completions('ip.', 3)) | ||||
Samuel Gaist
|
r26888 | # self.assertNotIn(Completion(3,3,'__str__'), completions) | ||
# self.assertNotIn(Completion(3,3, "_hidden_attr"), completions) | ||||
Thomas Kluyver
|
r24128 | |||
Matthias Bussonnier
|
r25099 | with provisionalcompleter(): | ||
c.use_jedi = False | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete("ip._x.") | ||
Samuel Gaist
|
r26888 | self.assertIn("ip._x.keys", matches) | ||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | # c.use_jedi = True | ||
# completions = set(c.completions('ip._x.', 6)) | ||||
Samuel Gaist
|
r26888 | # self.assertIn(Completion(6,6, "keys"), completions) | ||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | del ip._hidden_attr | ||
del ip._x | ||||
Thomas Kluyver
|
r24128 | |||
Matthias Bussonnier
|
r25099 | def test_limit_to__all__False_ok(self): | ||
""" | ||||
Limit to all is deprecated, once we remove it this test can go away. | ||||
""" | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
Thomas Kluyver
|
r24128 | c.use_jedi = False | ||
Matthias Bussonnier
|
r25101 | ip.ex("class D: x=24") | ||
ip.ex("d=D()") | ||||
Matthias Bussonnier
|
r25099 | cfg = Config() | ||
cfg.IPCompleter.limit_to__all__ = False | ||||
c.update_config(cfg) | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete("d.") | ||
Samuel Gaist
|
r26888 | self.assertIn("d.x", matches) | ||
Matthias Bussonnier
|
r23284 | |||
Matthias Bussonnier
|
r25099 | def test_get__all__entries_ok(self): | ||
Matthias Bussonnier
|
r25100 | class A: | ||
Matthias Bussonnier
|
r25101 | __all__ = ["x", 1] | ||
Tim Couper
|
r6308 | |||
Matthias Bussonnier
|
r25101 | words = completer.get__all__entries(A()) | ||
Samuel Gaist
|
r26888 | self.assertEqual(words, ["x"]) | ||
Tim Couper
|
r6312 | |||
Matthias Bussonnier
|
r25099 | def test_get__all__entries_no__all__ok(self): | ||
Matthias Bussonnier
|
r25100 | class A: | ||
Matthias Bussonnier
|
r25099 | pass | ||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | words = completer.get__all__entries(A()) | ||
Samuel Gaist
|
r26888 | self.assertEqual(words, []) | ||
Tim Couper
|
r6312 | |||
Matthias Bussonnier
|
r25099 | def test_func_kw_completions(self): | ||
ip = get_ipython() | ||||
c = ip.Completer | ||||
c.use_jedi = False | ||||
Matthias Bussonnier
|
r25101 | ip.ex("def myfunc(a=1,b=2): return a+b") | ||
s, matches = c.complete(None, "myfunc(1,b") | ||||
Samuel Gaist
|
r26888 | self.assertIn("b=", matches) | ||
Matthias Bussonnier
|
r25099 | # Simulate completing with cursor right after b (pos==10): | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "myfunc(1,b)", 10) | ||
Samuel Gaist
|
r26888 | self.assertIn("b=", matches) | ||
Matthias Bussonnier
|
r25099 | s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b') | ||
Samuel Gaist
|
r26888 | self.assertIn("b=", matches) | ||
Matthias Bussonnier
|
r25101 | # builtin function | ||
s, matches = c.complete(None, "min(k, k") | ||||
Samuel Gaist
|
r26888 | self.assertIn("key=", matches) | ||
Matthias Bussonnier
|
r25099 | |||
def test_default_arguments_from_docstring(self): | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
Matthias Bussonnier
|
r25101 | kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value") | ||
Samuel Gaist
|
r26888 | self.assertEqual(kwd, ["key"]) | ||
Matthias Bussonnier
|
r25101 | # with cython type etc | ||
Matthias Bussonnier
|
r25099 | kwd = c._default_arguments_from_docstring( | ||
Matthias Bussonnier
|
r25101 | "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n" | ||
) | ||||
Samuel Gaist
|
r26888 | self.assertEqual(kwd, ["ncall", "resume", "nsplit"]) | ||
Matthias Bussonnier
|
r25101 | # white spaces | ||
Matthias Bussonnier
|
r25099 | kwd = c._default_arguments_from_docstring( | ||
Matthias Bussonnier
|
r25101 | "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n" | ||
) | ||||
Samuel Gaist
|
r26888 | self.assertEqual(kwd, ["ncall", "resume", "nsplit"]) | ||
Matthias Bussonnier
|
r25099 | |||
def test_line_magics(self): | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "lsmag") | ||
Samuel Gaist
|
r26888 | self.assertIn("%lsmagic", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%lsmag") | ||
Samuel Gaist
|
r26888 | self.assertIn("%lsmagic", matches) | ||
Matthias Bussonnier
|
r25099 | |||
def test_cell_magics(self): | ||||
from IPython.core.magic import register_cell_magic | ||||
@register_cell_magic | ||||
def _foo_cellm(line, cell): | ||||
pass | ||||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | ip = get_ipython() | ||
c = ip.Completer | ||||
Piti Ongmongkolkul
|
r6511 | |||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "_foo_ce") | ||
Samuel Gaist
|
r26888 | self.assertIn("%%_foo_cellm", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%%_foo_ce") | ||
Samuel Gaist
|
r26888 | self.assertIn("%%_foo_cellm", matches) | ||
Piti Ongmongkolkul
|
r6511 | |||
Matthias Bussonnier
|
r25099 | def test_line_cell_magics(self): | ||
from IPython.core.magic import register_line_cell_magic | ||||
Piti Ongmongkolkul
|
r6511 | |||
Matthias Bussonnier
|
r25099 | @register_line_cell_magic | ||
def _bar_cellm(line, cell): | ||||
pass | ||||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | ip = get_ipython() | ||
c = ip.Completer | ||||
# The policy here is trickier, see comments in completion code. The | ||||
# returned values depend on whether the user passes %% or not explicitly, | ||||
# and this will show a difference if the same name is both a line and cell | ||||
# magic. | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "_bar_ce") | ||
Samuel Gaist
|
r26888 | self.assertIn("%_bar_cellm", matches) | ||
self.assertIn("%%_bar_cellm", matches) | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%_bar_ce") | ||
Samuel Gaist
|
r26888 | self.assertIn("%_bar_cellm", matches) | ||
self.assertIn("%%_bar_cellm", matches) | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%%_bar_ce") | ||
Samuel Gaist
|
r26888 | self.assertNotIn("%_bar_cellm", matches) | ||
self.assertIn("%%_bar_cellm", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_magic_completion_order(self): | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
# Test ordering of line and cell magics. | ||||
text, matches = c.complete("timeit") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["%timeit", "%%timeit"]) | ||
Matthias Bussonnier
|
r25099 | |||
def test_magic_completion_shadowing(self): | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
c.use_jedi = False | ||||
Fernando Perez
|
r6991 | |||
Matthias Bussonnier
|
r25099 | # Before importing matplotlib, %matplotlib magic should be the only option. | ||
text, matches = c.complete("mat") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["%matplotlib"]) | ||
Matthias Bussonnier
|
r25099 | |||
# The newly introduced name should shadow the magic. | ||||
ip.run_cell("matplotlib = 1") | ||||
text, matches = c.complete("mat") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["matplotlib"]) | ||
Matthias Bussonnier
|
r25099 | |||
# After removing matplotlib from namespace, the magic should again be | ||||
# the only option. | ||||
del ip.user_ns["matplotlib"] | ||||
text, matches = c.complete("mat") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["%matplotlib"]) | ||
Matthias Bussonnier
|
r25099 | |||
def test_magic_completion_shadowing_explicit(self): | ||||
""" | ||||
If the user try to complete a shadowed magic, and explicit % start should | ||||
still return the completions. | ||||
""" | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
# Before importing matplotlib, %matplotlib magic should be the only option. | ||||
text, matches = c.complete("%mat") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["%matplotlib"]) | ||
Matthias Bussonnier
|
r25099 | |||
ip.run_cell("matplotlib = 1") | ||||
# After removing matplotlib from namespace, the magic should still be | ||||
# the only option. | ||||
text, matches = c.complete("%mat") | ||||
Samuel Gaist
|
r26888 | self.assertEqual(matches, ["%matplotlib"]) | ||
Matthias Bussonnier
|
r25099 | |||
def test_magic_config(self): | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "conf") | ||
Samuel Gaist
|
r26888 | self.assertIn("%config", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "conf") | ||
Samuel Gaist
|
r26888 | self.assertNotIn("AliasManager", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "config ") | ||
Samuel Gaist
|
r26888 | self.assertIn("AliasManager", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%config ") | ||
Samuel Gaist
|
r26888 | self.assertIn("AliasManager", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "config Ali") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["AliasManager"], matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%config Ali") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["AliasManager"], matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "config AliasManager") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["AliasManager"], matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%config AliasManager") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["AliasManager"], matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "config AliasManager.") | ||
Samuel Gaist
|
r26888 | self.assertIn("AliasManager.default_aliases", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%config AliasManager.") | ||
Samuel Gaist
|
r26888 | self.assertIn("AliasManager.default_aliases", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "config AliasManager.de") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["AliasManager.default_aliases"], matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "config AliasManager.de") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["AliasManager.default_aliases"], matches) | ||
Matthias Bussonnier
|
r25099 | |||
def test_magic_color(self): | ||||
ip = get_ipython() | ||||
c = ip.Completer | ||||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "colo") | ||
Samuel Gaist
|
r26888 | self.assertIn("%colors", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "colo") | ||
Samuel Gaist
|
r26888 | self.assertNotIn("NoColor", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%colors") # No trailing space | ||
Samuel Gaist
|
r26888 | self.assertNotIn("NoColor", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "colors ") | ||
Samuel Gaist
|
r26888 | self.assertIn("NoColor", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%colors ") | ||
Samuel Gaist
|
r26888 | self.assertIn("NoColor", matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "colors NoCo") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["NoColor"], matches) | ||
Matthias Bussonnier
|
r25101 | s, matches = c.complete(None, "%colors NoCo") | ||
Samuel Gaist
|
r26888 | self.assertListEqual(["NoColor"], matches) | ||
Matthias Bussonnier
|
r25099 | |||
def test_match_dict_keys(self): | ||||
""" | ||||
Test that match_dict_keys works on a couple of use case does return what | ||||
expected, and does not crash | ||||
""" | ||||
Matthias Bussonnier
|
r25101 | delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?" | ||
Matthias Bussonnier
|
r25099 | |||
Matthias Bussonnier
|
r25101 | 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"]) | ||||
Matthias Bussonnier
|
r25099 | |||
Matthias Bussonnier
|
r25101 | 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"]) | ||||
Matthias Bussonnier
|
r25099 | |||
match_dict_keys | ||||
Fernando Perez
|
r6991 | |||
Corentin Cadiou
|
r25851 | def test_match_dict_keys_tuple(self): | ||
""" | ||||
Test that match_dict_keys called with extra prefix works on a couple of use case, | ||||
does return what expected, and does not crash. | ||||
""" | ||||
delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?" | ||||
keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')] | ||||
# Completion on first key == "foo" | ||||
assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"]) | ||||
assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"]) | ||||
assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"]) | ||||
assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"]) | ||||
assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"]) | ||||
assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"]) | ||||
assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"]) | ||||
assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"]) | ||||
# No Completion | ||||
assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, []) | ||||
assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, []) | ||||
keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')] | ||||
assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"]) | ||||
assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"]) | ||||
assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"]) | ||||
assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, []) | ||||
Matthias Bussonnier
|
r25099 | def test_dict_key_completion_string(self): | ||
"""Test dictionary key completion for string keys""" | ||||
ip = get_ipython() | ||||
complete = ip.Completer.complete | ||||
Fernando Perez
|
r6991 | |||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = {"abc": None} | ||
Fernando Perez
|
r6991 | |||
Matthias Bussonnier
|
r25099 | # check completion at different stages | ||
_, matches = complete(line_buffer="d[") | ||||
Samuel Gaist
|
r26888 | self.assertIn("'abc'", matches) | ||
self.assertNotIn("'abc']", matches) | ||||
Fernando Perez
|
r6991 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['") | ||
Samuel Gaist
|
r26888 | self.assertIn("abc", matches) | ||
self.assertNotIn("abc']", matches) | ||||
Fernando Perez
|
r6991 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['a") | ||
Samuel Gaist
|
r26888 | self.assertIn("abc", matches) | ||
self.assertNotIn("abc']", matches) | ||||
David P. Sanders
|
r13344 | |||
Matthias Bussonnier
|
r25099 | # check use of different quoting | ||
Matthias Bussonnier
|
r25101 | _, matches = complete(line_buffer='d["') | ||
Samuel Gaist
|
r26888 | self.assertIn("abc", matches) | ||
self.assertNotIn('abc"]', matches) | ||||
David P. Sanders
|
r13344 | |||
Matthias Bussonnier
|
r25101 | _, matches = complete(line_buffer='d["a') | ||
Samuel Gaist
|
r26888 | self.assertIn("abc", matches) | ||
self.assertNotIn('abc"]', matches) | ||||
David P. Sanders
|
r13344 | |||
Matthias Bussonnier
|
r25099 | # check sensitivity to following context | ||
_, matches = complete(line_buffer="d[]", cursor_pos=2) | ||||
Samuel Gaist
|
r26888 | self.assertIn("'abc'", matches) | ||
Matthias Bussonnier
|
r23898 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['']", cursor_pos=3) | ||
Samuel Gaist
|
r26888 | self.assertIn("abc", matches) | ||
self.assertNotIn("abc'", matches) | ||||
self.assertNotIn("abc']", matches) | ||||
Matthias Bussonnier
|
r23898 | |||
Matthias Bussonnier
|
r25099 | # check multiple solutions are correctly returned and that noise is not | ||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = { | ||
"abc": None, | ||||
"abd": None, | ||||
"bad": None, | ||||
object(): None, | ||||
5: None, | ||||
Corentin Cadiou
|
r25852 | ("abe", None): None, | ||
(None, "abf"): None | ||||
Matthias Bussonnier
|
r25101 | } | ||
Matthias Bussonnier
|
r23898 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['a") | ||
Samuel Gaist
|
r26888 | self.assertIn("abc", matches) | ||
self.assertIn("abd", matches) | ||||
self.assertNotIn("bad", matches) | ||||
self.assertNotIn("abe", matches) | ||||
self.assertNotIn("abf", matches) | ||||
Matthias Bussonnier
|
r25101 | assert not any(m.endswith(("]", '"', "'")) for m in matches), matches | ||
Matthias Bussonnier
|
r25099 | |||
# check escaping and whitespace | ||||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None} | ||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['a") | ||
Samuel Gaist
|
r26888 | self.assertIn("a\\nb", matches) | ||
self.assertIn("a\\'b", matches) | ||||
self.assertIn('a"b', matches) | ||||
self.assertIn("a word", matches) | ||||
Matthias Bussonnier
|
r25101 | assert not any(m.endswith(("]", '"', "'")) for m in matches), matches | ||
Matthias Bussonnier
|
r25099 | |||
# - can complete on non-initial word of the string | ||||
_, matches = complete(line_buffer="d['a w") | ||||
Samuel Gaist
|
r26888 | self.assertIn("word", matches) | ||
Matthias Bussonnier
|
r25099 | |||
# - understands quote escaping | ||||
_, matches = complete(line_buffer="d['a\\'") | ||||
Samuel Gaist
|
r26888 | self.assertIn("b", matches) | ||
Matthias Bussonnier
|
r25099 | |||
# - default quoting should work like repr | ||||
_, matches = complete(line_buffer="d[") | ||||
Samuel Gaist
|
r26888 | self.assertIn('"a\'b"', matches) | ||
Matthias Bussonnier
|
r25099 | |||
# - when opening quote with ", possible to match with unescaped apostrophe | ||||
_, matches = complete(line_buffer="d[\"a'") | ||||
Samuel Gaist
|
r26888 | self.assertIn("b", matches) | ||
Matthias Bussonnier
|
r25099 | |||
# need to not split at delims that readline won't split at | ||||
Matthias Bussonnier
|
r25101 | if "-" not in ip.Completer.splitter.delims: | ||
ip.user_ns["d"] = {"before-after": None} | ||||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['before-af") | ||
Samuel Gaist
|
r26888 | self.assertIn("before-after", matches) | ||
Matthias Bussonnier
|
r25099 | |||
Corentin Cadiou
|
r25853 | # check completion on tuple-of-string keys at different stage - on first key | ||
ip.user_ns["d"] = {('foo', 'bar'): None} | ||||
_, matches = complete(line_buffer="d[") | ||||
Samuel Gaist
|
r26888 | self.assertIn("'foo'", matches) | ||
self.assertNotIn("'foo']", matches) | ||||
self.assertNotIn("'bar'", matches) | ||||
self.assertNotIn("foo", matches) | ||||
self.assertNotIn("bar", matches) | ||||
Corentin Cadiou
|
r25853 | |||
# - match the prefix | ||||
_, matches = complete(line_buffer="d['f") | ||||
Samuel Gaist
|
r26888 | self.assertIn("foo", matches) | ||
self.assertNotIn("foo']", matches) | ||||
self.assertNotIn('foo"]', matches) | ||||
Corentin Cadiou
|
r25853 | _, matches = complete(line_buffer="d['foo") | ||
Samuel Gaist
|
r26888 | self.assertIn("foo", matches) | ||
Corentin Cadiou
|
r25853 | |||
# - can complete on second key | ||||
_, matches = complete(line_buffer="d['foo', ") | ||||
Samuel Gaist
|
r26888 | self.assertIn("'bar'", matches) | ||
Corentin Cadiou
|
r25853 | _, matches = complete(line_buffer="d['foo', 'b") | ||
Samuel Gaist
|
r26888 | self.assertIn("bar", matches) | ||
self.assertNotIn("foo", matches) | ||||
Corentin Cadiou
|
r25853 | |||
# - does not propose missing keys | ||||
_, matches = complete(line_buffer="d['foo', 'f") | ||||
Samuel Gaist
|
r26888 | self.assertNotIn("bar", matches) | ||
self.assertNotIn("foo", matches) | ||||
Corentin Cadiou
|
r25853 | |||
# check sensitivity to following context | ||||
_, matches = complete(line_buffer="d['foo',]", cursor_pos=8) | ||||
Samuel Gaist
|
r26888 | self.assertIn("'bar'", matches) | ||
self.assertNotIn("bar", matches) | ||||
self.assertNotIn("'foo'", matches) | ||||
self.assertNotIn("foo", matches) | ||||
Corentin Cadiou
|
r25853 | |||
_, matches = complete(line_buffer="d['']", cursor_pos=3) | ||||
Samuel Gaist
|
r26888 | self.assertIn("foo", matches) | ||
Corentin Cadiou
|
r25853 | assert not any(m.endswith(("]", '"', "'")) for m in matches), matches | ||
_, matches = complete(line_buffer='d[""]', cursor_pos=3) | ||||
Samuel Gaist
|
r26888 | self.assertIn("foo", matches) | ||
Corentin Cadiou
|
r25853 | assert not any(m.endswith(("]", '"', "'")) for m in matches), matches | ||
_, matches = complete(line_buffer='d["foo","]', cursor_pos=9) | ||||
Samuel Gaist
|
r26888 | self.assertIn("bar", matches) | ||
Corentin Cadiou
|
r25853 | assert not any(m.endswith(("]", '"', "'")) for m in matches), matches | ||
_, matches = complete(line_buffer='d["foo",]', cursor_pos=8) | ||||
Samuel Gaist
|
r26888 | self.assertIn("'bar'", matches) | ||
self.assertNotIn("bar", matches) | ||||
Corentin Cadiou
|
r25853 | |||
# Can complete with longer tuple keys | ||||
ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None} | ||||
# - can complete second key | ||||
_, matches = complete(line_buffer="d['foo', 'b") | ||||
Samuel Gaist
|
r26888 | self.assertIn("bar", matches) | ||
self.assertNotIn("foo", matches) | ||||
self.assertNotIn("foobar", matches) | ||||
Corentin Cadiou
|
r25853 | |||
# - can complete third key | ||||
_, matches = complete(line_buffer="d['foo', 'bar', 'fo") | ||||
Samuel Gaist
|
r26888 | self.assertIn("foobar", matches) | ||
self.assertNotIn("foo", matches) | ||||
self.assertNotIn("bar", matches) | ||||
Corentin Cadiou
|
r25853 | |||
Matthias Bussonnier
|
r25099 | def test_dict_key_completion_contexts(self): | ||
"""Test expression contexts in which dict key completion occurs""" | ||||
ip = get_ipython() | ||||
complete = ip.Completer.complete | ||||
Matthias Bussonnier
|
r25101 | d = {"abc": None} | ||
ip.user_ns["d"] = d | ||||
Matthias Bussonnier
|
r25099 | |||
class C: | ||||
data = d | ||||
Matthias Bussonnier
|
r25101 | |||
ip.user_ns["C"] = C | ||||
ip.user_ns["get"] = lambda: d | ||||
Matthias Bussonnier
|
r25099 | |||
def assert_no_completion(**kwargs): | ||||
_, matches = complete(**kwargs) | ||||
Samuel Gaist
|
r26888 | self.assertNotIn("abc", matches) | ||
self.assertNotIn("abc'", matches) | ||||
self.assertNotIn("abc']", matches) | ||||
self.assertNotIn("'abc'", matches) | ||||
self.assertNotIn("'abc']", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def assert_completion(**kwargs): | ||||
_, matches = complete(**kwargs) | ||||
Samuel Gaist
|
r26888 | self.assertIn("'abc'", matches) | ||
self.assertNotIn("'abc']", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
# no completion after string closed, even if reopened | ||||
assert_no_completion(line_buffer="d['a'") | ||||
Matthias Bussonnier
|
r25101 | assert_no_completion(line_buffer='d["a"') | ||
Matthias Bussonnier
|
r25099 | assert_no_completion(line_buffer="d['a' + ") | ||
assert_no_completion(line_buffer="d['a' + '") | ||||
# completion in non-trivial expressions | ||||
assert_completion(line_buffer="+ d[") | ||||
assert_completion(line_buffer="(d[") | ||||
assert_completion(line_buffer="C.data[") | ||||
# greedy flag | ||||
def assert_completion(**kwargs): | ||||
_, matches = complete(**kwargs) | ||||
Samuel Gaist
|
r26888 | self.assertIn("get()['abc']", matches) | ||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | assert_no_completion(line_buffer="get()[") | ||
with greedy_completion(): | ||||
assert_completion(line_buffer="get()[") | ||||
assert_completion(line_buffer="get()['") | ||||
assert_completion(line_buffer="get()['a") | ||||
assert_completion(line_buffer="get()['ab") | ||||
assert_completion(line_buffer="get()['abc") | ||||
Matthias Bussonnier
|
r23322 | |||
Matthias Bussonnier
|
r25099 | def test_dict_key_completion_bytes(self): | ||
"""Test handling of bytes in dict key completion""" | ||||
ip = get_ipython() | ||||
complete = ip.Completer.complete | ||||
Joel Nothman
|
r15766 | |||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = {"abc": None, b"abd": None} | ||
Joel Nothman
|
r15766 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d[") | ||
Samuel Gaist
|
r26888 | self.assertIn("'abc'", matches) | ||
self.assertIn("b'abd'", matches) | ||||
Joel Nothman
|
r15766 | |||
Matthias Bussonnier
|
r25099 | if False: # not currently implemented | ||
_, matches = complete(line_buffer="d[b") | ||||
Samuel Gaist
|
r26888 | self.assertIn("b'abd'", matches) | ||
self.assertNotIn("b'abc'", matches) | ||||
Joel Nothman
|
r15766 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d[b'") | ||
Samuel Gaist
|
r26888 | self.assertIn("abd", matches) | ||
self.assertNotIn("abc", matches) | ||||
Joel Nothman
|
r15766 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d[B'") | ||
Samuel Gaist
|
r26888 | self.assertIn("abd", matches) | ||
self.assertNotIn("abc", matches) | ||||
Joel Nothman
|
r15766 | |||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['") | ||
Samuel Gaist
|
r26888 | self.assertIn("abc", matches) | ||
self.assertNotIn("abd", matches) | ||||
Joel Nothman
|
r15766 | |||
Matthias Bussonnier
|
r25099 | def test_dict_key_completion_unicode_py3(self): | ||
"""Test handling of unicode in dict key completion""" | ||||
ip = get_ipython() | ||||
complete = ip.Completer.complete | ||||
Joel Nothman
|
r15773 | |||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = {"a\u05d0": None} | ||
Joel Nothman
|
r15773 | |||
MinRK
|
r16564 | # query using escape | ||
Matthias Bussonnier
|
r25101 | if sys.platform != "win32": | ||
Matthias Bussonnier
|
r25099 | # Known failure on Windows | ||
_, matches = complete(line_buffer="d['a\\u05d0") | ||||
Samuel Gaist
|
r26888 | self.assertIn("u05d0", matches) # tokenized after \\ | ||
MinRK
|
r16564 | |||
# query using character | ||||
_, matches = complete(line_buffer="d['a\u05d0") | ||||
Samuel Gaist
|
r26888 | self.assertIn("a\u05d0", matches) | ||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | with greedy_completion(): | ||
# query using escape | ||||
_, matches = complete(line_buffer="d['a\\u05d0") | ||||
Samuel Gaist
|
r26888 | self.assertIn("d['a\\u05d0']", matches) # tokenized after \\ | ||
Matthias Bussonnier
|
r25099 | |||
# query using character | ||||
_, matches = complete(line_buffer="d['a\u05d0") | ||||
Samuel Gaist
|
r26888 | self.assertIn("d['a\u05d0']", matches) | ||
Matthias Bussonnier
|
r25099 | |||
Matthias Bussonnier
|
r25101 | @dec.skip_without("numpy") | ||
Matthias Bussonnier
|
r25099 | def test_struct_array_key_completion(self): | ||
"""Test dict key completion applies to numpy struct arrays""" | ||||
import numpy | ||||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | ip = get_ipython() | ||
complete = ip.Completer.complete | ||||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")]) | ||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['") | ||
Samuel Gaist
|
r26888 | self.assertIn("hello", matches) | ||
self.assertIn("world", matches) | ||||
Matthias Bussonnier
|
r25099 | # complete on the numpy struct itself | ||
Matthias Bussonnier
|
r25101 | dt = numpy.dtype( | ||
[("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)] | ||||
) | ||||
Matthias Bussonnier
|
r25099 | x = numpy.zeros(2, dtype=dt) | ||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = x[1] | ||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['") | ||
Samuel Gaist
|
r26888 | self.assertIn("my_head", matches) | ||
self.assertIn("my_data", matches) | ||||
Matthias Bussonnier
|
r25099 | # complete on a nested level | ||
with greedy_completion(): | ||||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = numpy.zeros(2, dtype=dt) | ||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d[1]['my_head']['") | ||
Samuel Gaist
|
r26888 | self.assertTrue(any(["my_dt" in m for m in matches])) | ||
self.assertTrue(any(["my_df" in m for m in matches])) | ||||
Matthias Bussonnier
|
r25099 | |||
Matthias Bussonnier
|
r25101 | @dec.skip_without("pandas") | ||
Matthias Bussonnier
|
r25099 | def test_dataframe_key_completion(self): | ||
"""Test dict key completion applies to pandas DataFrames""" | ||||
import pandas | ||||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | ip = get_ipython() | ||
complete = ip.Completer.complete | ||||
Matthias Bussonnier
|
r25101 | ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]}) | ||
Matthias Bussonnier
|
r25099 | _, matches = complete(line_buffer="d['") | ||
Samuel Gaist
|
r26888 | self.assertIn("hello", matches) | ||
self.assertIn("world", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_dict_key_completion_invalids(self): | ||||
"""Smoke test cases dict key completion can't handle""" | ||||
ip = get_ipython() | ||||
complete = ip.Completer.complete | ||||
Matthias Bussonnier
|
r25101 | ip.user_ns["no_getitem"] = None | ||
ip.user_ns["no_keys"] = [] | ||||
ip.user_ns["cant_call_keys"] = dict | ||||
ip.user_ns["empty"] = {} | ||||
ip.user_ns["d"] = {"abc": 5} | ||||
Matthias Bussonnier
|
r25099 | |||
_, matches = complete(line_buffer="no_getitem['") | ||||
_, matches = complete(line_buffer="no_keys['") | ||||
_, matches = complete(line_buffer="cant_call_keys['") | ||||
_, matches = complete(line_buffer="empty['") | ||||
_, matches = complete(line_buffer="name_error['") | ||||
_, matches = complete(line_buffer="d['\\") # incomplete escape | ||||
def test_object_key_completion(self): | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"]) | ||
Matthias Bussonnier
|
r25099 | |||
_, matches = ip.Completer.complete(line_buffer="key_completable['qw") | ||||
Samuel Gaist
|
r26888 | self.assertIn("qwerty", matches) | ||
self.assertIn("qwick", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_class_key_completion(self): | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | NamedInstanceClass("qwerty") | ||
NamedInstanceClass("qwick") | ||||
ip.user_ns["named_instance_class"] = NamedInstanceClass | ||||
Matthias Bussonnier
|
r25099 | |||
_, matches = ip.Completer.complete(line_buffer="named_instance_class['qw") | ||||
Samuel Gaist
|
r26888 | self.assertIn("qwerty", matches) | ||
self.assertIn("qwick", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_tryimport(self): | ||||
""" | ||||
Test that try-import don't crash on trailing dot, and import modules before | ||||
""" | ||||
from IPython.core.completerlib import try_import | ||||
Matthias Bussonnier
|
r25101 | assert try_import("IPython.") | ||
Matthias Bussonnier
|
r25099 | |||
def test_aimport_module_completer(self): | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | _, matches = ip.complete("i", "%aimport i") | ||
Samuel Gaist
|
r26888 | self.assertIn("io", matches) | ||
self.assertNotIn("int", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_nested_import_module_completer(self): | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | _, matches = ip.complete(None, "import IPython.co", 17) | ||
Samuel Gaist
|
r26888 | self.assertIn("IPython.core", matches) | ||
self.assertNotIn("import IPython.core", matches) | ||||
self.assertNotIn("IPython.display", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_import_module_completer(self): | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | _, matches = ip.complete("i", "import i") | ||
Samuel Gaist
|
r26888 | self.assertIn("io", matches) | ||
self.assertNotIn("int", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_from_module_completer(self): | ||||
ip = get_ipython() | ||||
Matthias Bussonnier
|
r25101 | _, matches = ip.complete("B", "from io import B", 16) | ||
Samuel Gaist
|
r26888 | self.assertIn("BytesIO", matches) | ||
self.assertNotIn("BaseException", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_snake_case_completion(self): | ||||
ip = get_ipython() | ||||
ip.Completer.use_jedi = False | ||||
Matthias Bussonnier
|
r25101 | ip.user_ns["some_three"] = 3 | ||
ip.user_ns["some_four"] = 4 | ||||
Matthias Bussonnier
|
r25099 | _, matches = ip.complete("s_", "print(s_f") | ||
Samuel Gaist
|
r26888 | self.assertIn("some_three", matches) | ||
self.assertIn("some_four", matches) | ||||
Matthias Bussonnier
|
r25099 | |||
def test_mix_terms(self): | ||||
ip = get_ipython() | ||||
from textwrap import dedent | ||||
Matthias Bussonnier
|
r25101 | |||
Matthias Bussonnier
|
r25099 | ip.Completer.use_jedi = False | ||
Matthias Bussonnier
|
r25101 | ip.ex( | ||
dedent( | ||||
""" | ||||
Matthias Bussonnier
|
r25099 | class Test: | ||
def meth(self, meth_arg1): | ||||
print("meth") | ||||
def meth_1(self, meth1_arg1, meth1_arg2): | ||||
print("meth1") | ||||
def meth_2(self, meth2_arg1, meth2_arg2): | ||||
print("meth2") | ||||
test = Test() | ||||
Matthias Bussonnier
|
r25101 | """ | ||
) | ||||
) | ||||
Matthias Bussonnier
|
r25099 | _, matches = ip.complete(None, "test.meth(") | ||
Samuel Gaist
|
r26888 | self.assertIn("meth_arg1=", matches) | ||
self.assertNotIn("meth2_arg1=", matches) | ||||