##// END OF EJS Templates
Cleanup and type annotate completer.py...
Matthias Bussonnier -
Show More
@@ -0,0 +1,4 b''
1 [mypy]
2 python_version = 3.6
3 ignore_missing_imports = True
4 follow_imports = silent
@@ -40,6 +40,7 b' install:'
40 - pip install trio curio --upgrade --upgrade-strategy eager
40 - pip install trio curio --upgrade --upgrade-strategy eager
41 - pip install pytest 'matplotlib !=3.2.0' mypy
41 - pip install pytest 'matplotlib !=3.2.0' mypy
42 - pip install codecov check-manifest --upgrade
42 - pip install codecov check-manifest --upgrade
43 - pip install mypy
43
44
44 script:
45 script:
45 - check-manifest
46 - check-manifest
@@ -50,7 +51,8 b' script:'
50 fi
51 fi
51 - cd /tmp && iptest --coverage xml && cd -
52 - cd /tmp && iptest --coverage xml && cd -
52 - pytest IPython
53 - pytest IPython
53 - mypy --ignore-missing-imports -m IPython.terminal.ptutils
54 - mypy IPython/terminal/ptutils.py
55 - mypy IPython/core/c*.py
54 # On the latest Python (on Linux) only, make sure that the docs build.
56 # On the latest Python (on Linux) only, make sure that the docs build.
55 - |
57 - |
56 if [[ "$TRAVIS_PYTHON_VERSION" == "3.7" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
58 if [[ "$TRAVIS_PYTHON_VERSION" == "3.7" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
@@ -126,7 +126,7 b' import warnings'
126 from contextlib import contextmanager
126 from contextlib import contextmanager
127 from importlib import import_module
127 from importlib import import_module
128 from types import SimpleNamespace
128 from types import SimpleNamespace
129 from typing import Iterable, Iterator, List, Tuple
129 from typing import Iterable, Iterator, List, Tuple, Union, Any, Sequence, Dict, NamedTuple, Pattern, Optional
130
130
131 from IPython.core.error import TryNext
131 from IPython.core.error import TryNext
132 from IPython.core.inputtransformer2 import ESC_MAGIC
132 from IPython.core.inputtransformer2 import ESC_MAGIC
@@ -745,7 +745,7 b' def get__all__entries(obj):'
745 return [w for w in words if isinstance(w, str)]
745 return [w for w in words if isinstance(w, str)]
746
746
747
747
748 def match_dict_keys(keys: List[str], prefix: str, delims: str):
748 def match_dict_keys(keys: List[Union[str, bytes]], prefix: str, delims: str) -> Tuple[str, int, List[str]]:
749 """Used by dict_key_matches, matching the prefix to a list of keys
749 """Used by dict_key_matches, matching the prefix to a list of keys
750
750
751 Parameters
751 Parameters
@@ -766,22 +766,25 b' def match_dict_keys(keys: List[str], prefix: str, delims: str):'
766 ``matches`` a list of replacement/completion
766 ``matches`` a list of replacement/completion
767
767
768 """
768 """
769 keys = [k for k in keys if isinstance(k, (str, bytes))]
769 if not prefix:
770 if not prefix:
770 return None, 0, [repr(k) for k in keys
771 return '', 0, [repr(k) for k in keys
771 if isinstance(k, (str, bytes))]
772 if isinstance(k, (str, bytes))]
772 quote_match = re.search('["\']', prefix)
773 quote_match = re.search('["\']', prefix)
774 assert quote_match is not None # silence mypy
773 quote = quote_match.group()
775 quote = quote_match.group()
774 try:
776 try:
775 prefix_str = eval(prefix + quote, {})
777 prefix_str = eval(prefix + quote, {})
776 except Exception:
778 except Exception:
777 return None, 0, []
779 return '', 0, []
778
780
779 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
781 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
780 token_match = re.search(pattern, prefix, re.UNICODE)
782 token_match = re.search(pattern, prefix, re.UNICODE)
783 assert token_match is not None # silence mypy
781 token_start = token_match.start()
784 token_start = token_match.start()
782 token_prefix = token_match.group()
785 token_prefix = token_match.group()
783
786
784 matched = []
787 matched:List[str] = []
785 for key in keys:
788 for key in keys:
786 try:
789 try:
787 if not key.startswith(prefix_str):
790 if not key.startswith(prefix_str):
@@ -794,14 +797,6 b' def match_dict_keys(keys: List[str], prefix: str, delims: str):'
794 rem = key[len(prefix_str):]
797 rem = key[len(prefix_str):]
795 # force repr wrapped in '
798 # force repr wrapped in '
796 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
799 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
797 if rem_repr.startswith('u') and prefix[0] not in 'uU':
798 # Found key is unicode, but prefix is Py2 string.
799 # Therefore attempt to interpret key as string.
800 try:
801 rem_repr = repr(rem.encode('ascii') + '"')
802 except UnicodeEncodeError:
803 continue
804
805 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
800 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
806 if quote == '"':
801 if quote == '"':
807 # The entered prefix is quoted with ",
802 # The entered prefix is quoted with ",
@@ -887,9 +882,8 b' def _safe_isinstance(obj, module, class_name):'
887 return (module in sys.modules and
882 return (module in sys.modules and
888 isinstance(obj, getattr(import_module(module), class_name)))
883 isinstance(obj, getattr(import_module(module), class_name)))
889
884
890
885 def back_unicode_name_matches(text:str) -> Tuple[str, Sequence[str]]:
891 def back_unicode_name_matches(text):
886 """Match unicode characters back to unicode name
892 u"""Match unicode characters back to unicode name
893
887
894 This does ``☃`` -> ``\\snowman``
888 This does ``☃`` -> ``\\snowman``
895
889
@@ -898,25 +892,29 b' def back_unicode_name_matches(text):'
898
892
899 This will not either back-complete standard sequences like \\n, \\b ...
893 This will not either back-complete standard sequences like \\n, \\b ...
900
894
901 Used on Python 3 only.
895 Returns
896 =======
897
898 Return a tuple of
899
902 """
900 """
903 if len(text)<2:
901 if len(text)<2:
904 return u'', ()
902 return '', ()
905 maybe_slash = text[-2]
903 maybe_slash = text[-2]
906 if maybe_slash != '\\':
904 if maybe_slash != '\\':
907 return u'', ()
905 return '', ()
908
906
909 char = text[-1]
907 char = text[-1]
910 # no expand on quote for completion in strings.
908 # no expand on quote for completion in strings.
911 # nor backcomplete standard ascii keys
909 # nor backcomplete standard ascii keys
912 if char in string.ascii_letters or char in ['"',"'"]:
910 if char in string.ascii_letters or char in ['"',"'"]:
913 return u'', ()
911 return '', ()
914 try :
912 try :
915 unic = unicodedata.name(char)
913 unic = unicodedata.name(char)
916 return '\\'+char,['\\'+unic]
914 return '\\'+char,['\\'+unic]
917 except KeyError:
915 except KeyError:
918 pass
916 pass
919 return u'', ()
917 return '', ()
920
918
921 def back_latex_name_matches(text:str):
919 def back_latex_name_matches(text:str):
922 """Match latex characters back to unicode name
920 """Match latex characters back to unicode name
@@ -1002,9 +1000,19 b' def _make_signature(completion)-> str:'
1002 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
1000 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
1003 for p in signature.defined_names()) if f])
1001 for p in signature.defined_names()) if f])
1004
1002
1003
1004 class _CompleteResult(NamedTuple):
1005 matched_text : str
1006 matches: Sequence[str]
1007 matches_origin: Sequence[str]
1008 jedi_matches: Any
1009
1010
1005 class IPCompleter(Completer):
1011 class IPCompleter(Completer):
1006 """Extension of the completer class with IPython-specific features"""
1012 """Extension of the completer class with IPython-specific features"""
1007
1013
1014 __dict_key_regexps: Optional[Dict[bool,Pattern]] = None
1015
1008 @observe('greedy')
1016 @observe('greedy')
1009 def _greedy_changed(self, change):
1017 def _greedy_changed(self, change):
1010 """update the splitter and readline delims when greedy is changed"""
1018 """update the splitter and readline delims when greedy is changed"""
@@ -1143,7 +1151,7 b' class IPCompleter(Completer):'
1143 self._unicode_names = None
1151 self._unicode_names = None
1144
1152
1145 @property
1153 @property
1146 def matchers(self):
1154 def matchers(self) -> List[Any]:
1147 """All active matcher routines for completion"""
1155 """All active matcher routines for completion"""
1148 if self.dict_keys_only:
1156 if self.dict_keys_only:
1149 return [self.dict_key_matches]
1157 return [self.dict_key_matches]
@@ -1165,7 +1173,7 b' class IPCompleter(Completer):'
1165 self.dict_key_matches,
1173 self.dict_key_matches,
1166 ]
1174 ]
1167
1175
1168 def all_completions(self, text) -> List[str]:
1176 def all_completions(self, text:str) -> List[str]:
1169 """
1177 """
1170 Wrapper around the completion methods for the benefit of emacs.
1178 Wrapper around the completion methods for the benefit of emacs.
1171 """
1179 """
@@ -1176,14 +1184,14 b' class IPCompleter(Completer):'
1176
1184
1177 return self.complete(text)[1]
1185 return self.complete(text)[1]
1178
1186
1179 def _clean_glob(self, text):
1187 def _clean_glob(self, text:str):
1180 return self.glob("%s*" % text)
1188 return self.glob("%s*" % text)
1181
1189
1182 def _clean_glob_win32(self,text):
1190 def _clean_glob_win32(self,text:str):
1183 return [f.replace("\\","/")
1191 return [f.replace("\\","/")
1184 for f in self.glob("%s*" % text)]
1192 for f in self.glob("%s*" % text)]
1185
1193
1186 def file_matches(self, text):
1194 def file_matches(self, text:str)->List[str]:
1187 """Match filenames, expanding ~USER type strings.
1195 """Match filenames, expanding ~USER type strings.
1188
1196
1189 Most of the seemingly convoluted logic in this completer is an
1197 Most of the seemingly convoluted logic in this completer is an
@@ -1265,7 +1273,7 b' class IPCompleter(Completer):'
1265 # Mark directories in input list by appending '/' to their names.
1273 # Mark directories in input list by appending '/' to their names.
1266 return [x+'/' if os.path.isdir(x) else x for x in matches]
1274 return [x+'/' if os.path.isdir(x) else x for x in matches]
1267
1275
1268 def magic_matches(self, text):
1276 def magic_matches(self, text:str):
1269 """Match magics"""
1277 """Match magics"""
1270 # Get all shell magics now rather than statically, so magics loaded at
1278 # Get all shell magics now rather than statically, so magics loaded at
1271 # runtime show up too.
1279 # runtime show up too.
@@ -1356,7 +1364,7 b' class IPCompleter(Completer):'
1356 if color.startswith(prefix) ]
1364 if color.startswith(prefix) ]
1357 return []
1365 return []
1358
1366
1359 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str):
1367 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str) -> Iterable[Any]:
1360 """
1368 """
1361
1369
1362 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
1370 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
@@ -1430,7 +1438,7 b' class IPCompleter(Completer):'
1430 else:
1438 else:
1431 return []
1439 return []
1432
1440
1433 def python_matches(self, text):
1441 def python_matches(self, text:str)->list[str]:
1434 """Match attributes or global python names"""
1442 """Match attributes or global python names"""
1435 if "." in text:
1443 if "." in text:
1436 try:
1444 try:
@@ -1512,7 +1520,7 b' class IPCompleter(Completer):'
1512
1520
1513 return list(set(ret))
1521 return list(set(ret))
1514
1522
1515 def python_func_kw_matches(self,text):
1523 def python_func_kw_matches(self, text):
1516 """Match named parameters (kwargs) of the last open function"""
1524 """Match named parameters (kwargs) of the last open function"""
1517
1525
1518 if "." in text: # a parameter cannot be dotted
1526 if "." in text: # a parameter cannot be dotted
@@ -1588,30 +1596,33 b' class IPCompleter(Completer):'
1588
1596
1589 return argMatches
1597 return argMatches
1590
1598
1591 def dict_key_matches(self, text):
1599 @staticmethod
1600 def _get_keys(obj: Any) -> List[Any]:
1601 # Objects can define their own completions by defining an
1602 # _ipy_key_completions_() method.
1603 method = get_real_method(obj, '_ipython_key_completions_')
1604 if method is not None:
1605 return method()
1606
1607 # Special case some common in-memory dict-like types
1608 if isinstance(obj, dict) or\
1609 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1610 try:
1611 return list(obj.keys())
1612 except Exception:
1613 return []
1614 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1615 _safe_isinstance(obj, 'numpy', 'void'):
1616 return obj.dtype.names or []
1617 return []
1618
1619 def dict_key_matches(self, text:str) -> List[str]:
1592 "Match string keys in a dictionary, after e.g. 'foo[' "
1620 "Match string keys in a dictionary, after e.g. 'foo[' "
1593 def get_keys(obj):
1594 # Objects can define their own completions by defining an
1595 # _ipy_key_completions_() method.
1596 method = get_real_method(obj, '_ipython_key_completions_')
1597 if method is not None:
1598 return method()
1599
1600 # Special case some common in-memory dict-like types
1601 if isinstance(obj, dict) or\
1602 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1603 try:
1604 return list(obj.keys())
1605 except Exception:
1606 return []
1607 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1608 _safe_isinstance(obj, 'numpy', 'void'):
1609 return obj.dtype.names or []
1610 return []
1611
1621
1612 try:
1622
1623 if self.__dict_key_regexps is not None:
1613 regexps = self.__dict_key_regexps
1624 regexps = self.__dict_key_regexps
1614 except AttributeError:
1625 else:
1615 dict_key_re_fmt = r'''(?x)
1626 dict_key_re_fmt = r'''(?x)
1616 ( # match dict-referring expression wrt greedy setting
1627 ( # match dict-referring expression wrt greedy setting
1617 %s
1628 %s
@@ -1651,7 +1662,7 b' class IPCompleter(Completer):'
1651 except Exception:
1662 except Exception:
1652 return []
1663 return []
1653
1664
1654 keys = get_keys(obj)
1665 keys = self._get_keys(obj)
1655 if not keys:
1666 if not keys:
1656 return keys
1667 return keys
1657 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims)
1668 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims)
@@ -1696,16 +1707,15 b' class IPCompleter(Completer):'
1696
1707
1697 return [leading + k + suf for k in matches]
1708 return [leading + k + suf for k in matches]
1698
1709
1699 def unicode_name_matches(self, text):
1710 @staticmethod
1700 u"""Match Latex-like syntax for unicode characters base
1711 def unicode_name_matches(text:str) -> Tuple[str, List[str]] :
1712 """Match Latex-like syntax for unicode characters base
1701 on the name of the character.
1713 on the name of the character.
1702
1714
1703 This does ``\\GREEK SMALL LETTER ETA`` -> ``η``
1715 This does ``\\GREEK SMALL LETTER ETA`` -> ``η``
1704
1716
1705 Works only on valid python 3 identifier, or on combining characters that
1717 Works only on valid python 3 identifier, or on combining characters that
1706 will combine to form a valid identifier.
1718 will combine to form a valid identifier.
1707
1708 Used on Python 3 only.
1709 """
1719 """
1710 slashpos = text.rfind('\\')
1720 slashpos = text.rfind('\\')
1711 if slashpos > -1:
1721 if slashpos > -1:
@@ -1717,7 +1727,7 b' class IPCompleter(Completer):'
1717 return '\\'+s,[unic]
1727 return '\\'+s,[unic]
1718 except KeyError:
1728 except KeyError:
1719 pass
1729 pass
1720 return u'', []
1730 return '', []
1721
1731
1722
1732
1723 def latex_matches(self, text):
1733 def latex_matches(self, text):
@@ -1839,6 +1849,7 b' class IPCompleter(Completer):'
1839 category=ProvisionalCompleterWarning, stacklevel=2)
1849 category=ProvisionalCompleterWarning, stacklevel=2)
1840
1850
1841 seen = set()
1851 seen = set()
1852 profiler:Optional[cProfile.Profile]
1842 try:
1853 try:
1843 if self.profile_completions:
1854 if self.profile_completions:
1844 import cProfile
1855 import cProfile
@@ -1864,7 +1875,7 b' class IPCompleter(Completer):'
1864 print("Writing profiler output to", output_path)
1875 print("Writing profiler output to", output_path)
1865 profiler.dump_stats(output_path)
1876 profiler.dump_stats(output_path)
1866
1877
1867 def _completions(self, full_text: str, offset: int, *, _timeout)->Iterator[Completion]:
1878 def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]:
1868 """
1879 """
1869 Core completion module.Same signature as :any:`completions`, with the
1880 Core completion module.Same signature as :any:`completions`, with the
1870 extra `timeout` parameter (in seconds).
1881 extra `timeout` parameter (in seconds).
@@ -1949,7 +1960,7 b' class IPCompleter(Completer):'
1949 yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
1960 yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
1950
1961
1951
1962
1952 def complete(self, text=None, line_buffer=None, cursor_pos=None):
1963 def complete(self, text=None, line_buffer=None, cursor_pos=None) -> Tuple[str, Sequence[str]]:
1953 """Find completions for the given text and line context.
1964 """Find completions for the given text and line context.
1954
1965
1955 Note that both the text and the line_buffer are optional, but at least
1966 Note that both the text and the line_buffer are optional, but at least
@@ -1973,9 +1984,9 b' class IPCompleter(Completer):'
1973
1984
1974 Returns
1985 Returns
1975 -------
1986 -------
1987 Tuple of two items:
1976 text : str
1988 text : str
1977 Text that was actually used in the completion.
1989 Text that was actually used in the completion.
1978
1979 matches : list
1990 matches : list
1980 A list of completion matches.
1991 A list of completion matches.
1981
1992
@@ -1995,7 +2006,7 b' class IPCompleter(Completer):'
1995 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
2006 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
1996
2007
1997 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
2008 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
1998 full_text=None) -> Tuple[str, List[str], List[str], Iterable[_FakeJediCompletion]]:
2009 full_text=None) -> _CompleteResult:
1999 """
2010 """
2000
2011
2001 Like complete but can also returns raw jedi completions as well as the
2012 Like complete but can also returns raw jedi completions as well as the
@@ -2008,8 +2019,19 b' class IPCompleter(Completer):'
2008 caller) as the offset in the ``text`` or ``line_buffer``, or as the
2019 caller) as the offset in the ``text`` or ``line_buffer``, or as the
2009 ``column`` when passing multiline strings this could/should be renamed
2020 ``column`` when passing multiline strings this could/should be renamed
2010 but would add extra noise.
2021 but would add extra noise.
2022
2023 Return
2024 ======
2025
2026 A tuple of N elements which are (likely):
2027
2028 matched_text: ? the text that the complete matched
2029 matches: list of completions ?
2030 matches_origin: ? list same lenght as matches, and where each completion came from
2031 jedi_matches: list of Jedi matches, have it's own structure.
2011 """
2032 """
2012
2033
2034
2013 # if the cursor position isn't given, the only sane assumption we can
2035 # if the cursor position isn't given, the only sane assumption we can
2014 # make is that it's at the end of the line (the common case)
2036 # make is that it's at the end of the line (the common case)
2015 if cursor_pos is None:
2037 if cursor_pos is None:
@@ -2027,17 +2049,16 b' class IPCompleter(Completer):'
2027 if self.backslash_combining_completions:
2049 if self.backslash_combining_completions:
2028 # allow deactivation of these on windows.
2050 # allow deactivation of these on windows.
2029 base_text = text if not line_buffer else line_buffer[:cursor_pos]
2051 base_text = text if not line_buffer else line_buffer[:cursor_pos]
2030 latex_text, latex_matches = self.latex_matches(base_text)
2052
2031 if latex_matches:
2053 for meth in (self.latex_matches,
2032 return latex_text, latex_matches, ['latex_matches']*len(latex_matches), ()
2054 self.unicode_name_matches,
2033 name_text = ''
2055 back_latex_name_matches,
2034 name_matches = []
2056 back_unicode_name_matches,
2035 # need to add self.fwd_unicode_match() function here when done
2057 self.fwd_unicode_match):
2036 for meth in (self.unicode_name_matches, back_latex_name_matches, back_unicode_name_matches, self.fwd_unicode_match):
2037 name_text, name_matches = meth(base_text)
2058 name_text, name_matches = meth(base_text)
2038 if name_text:
2059 if name_text:
2039 return name_text, name_matches[:MATCHES_LIMIT], \
2060 return _CompleteResult(name_text, name_matches[:MATCHES_LIMIT], \
2040 [meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ()
2061 [meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ())
2041
2062
2042
2063
2043 # If no line buffer is given, assume the input text is all there was
2064 # If no line buffer is given, assume the input text is all there was
@@ -2052,7 +2073,7 b' class IPCompleter(Completer):'
2052 matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
2073 matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
2053 if matches:
2074 if matches:
2054 origins = [matcher.__qualname__] * len(matches)
2075 origins = [matcher.__qualname__] * len(matches)
2055 return text, matches, origins, ()
2076 return _CompleteResult(text, matches, origins, ())
2056
2077
2057 # Start with a clean slate of completions
2078 # Start with a clean slate of completions
2058 matches = []
2079 matches = []
@@ -2061,7 +2082,7 b' class IPCompleter(Completer):'
2061 # different types of objects. The rlcomplete() method could then
2082 # different types of objects. The rlcomplete() method could then
2062 # simply collapse the dict into a list for readline, but we'd have
2083 # simply collapse the dict into a list for readline, but we'd have
2063 # richer completion semantics in other environments.
2084 # richer completion semantics in other environments.
2064 completions = ()
2085 completions:Iterable[Any] = []
2065 if self.use_jedi:
2086 if self.use_jedi:
2066 if not full_text:
2087 if not full_text:
2067 full_text = line_buffer
2088 full_text = line_buffer
@@ -2105,9 +2126,38 b' class IPCompleter(Completer):'
2105
2126
2106 self.matches = _matches
2127 self.matches = _matches
2107
2128
2108 return text, _matches, origins, completions
2129 return _CompleteResult(text, _matches, origins, completions)
2109
2130
2110 def fwd_unicode_match(self, text:str) -> Tuple[str, list]:
2131 def fwd_unicode_match(self, text:str) -> Tuple[str, Iterable[str]]:
2132 """
2133
2134 Forward match a string starting with a backslash with a list of
2135 potential Unicode completions.
2136
2137 Will compute list list of Unicode character names on first call and cache it.
2138
2139 Return
2140 ======
2141
2142 At tuple with:
2143 - matched text (empty if no matches)
2144 - list of potential completions, empty tuple otherwise)
2145 """
2146 # TODO: self.unicode_names is here a list we traverse each time with ~100k elements.
2147 # We could do a faster match using a Trie.
2148
2149 # Using pygtrie the follwing seem to work:
2150
2151 # s = PrefixSet()
2152
2153 # for c in range(0,0x10FFFF + 1):
2154 # try:
2155 # s.add(unicodedata.name(chr(c)))
2156 # except ValueError:
2157 # pass
2158 # [''.join(k) for k in s.iter(prefix)]
2159
2160 # But need to be timed and adds an extra dependency.
2111
2161
2112 slashpos = text.rfind('\\')
2162 slashpos = text.rfind('\\')
2113 # if text starts with slash
2163 # if text starts with slash
@@ -2126,7 +2176,7 b' class IPCompleter(Completer):'
2126
2176
2127 # if text does not start with slash
2177 # if text does not start with slash
2128 else:
2178 else:
2129 return u'', ()
2179 return '', ()
2130
2180
2131 @property
2181 @property
2132 def unicode_names(self) -> List[str]:
2182 def unicode_names(self) -> List[str]:
@@ -212,9 +212,8 b' class TestCompleter(unittest.TestCase):'
212 keys = random.sample(latex_symbols.keys(), 10)
212 keys = random.sample(latex_symbols.keys(), 10)
213 for k in keys:
213 for k in keys:
214 text, matches = ip.complete(k)
214 text, matches = ip.complete(k)
215 nt.assert_equal(len(matches), 1)
216 nt.assert_equal(text, k)
215 nt.assert_equal(text, k)
217 nt.assert_equal(matches[0], latex_symbols[k])
216 nt.assert_equal(matches, [latex_symbols[k]])
218 # Test a more complex line
217 # Test a more complex line
219 text, matches = ip.complete("print(\\alpha")
218 text, matches = ip.complete("print(\\alpha")
220 nt.assert_equal(text, "\\alpha")
219 nt.assert_equal(text, "\\alpha")
@@ -250,8 +249,8 b' class TestCompleter(unittest.TestCase):'
250 ip = get_ipython()
249 ip = get_ipython()
251
250
252 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
251 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
253 nt.assert_equal(len(matches), 1)
252 nt.assert_equal(matches, ["Ⅴ"] ) # This is not a V
254 nt.assert_equal(matches[0], "")
253 nt.assert_equal(matches, ["\u2164"] ) # same as above but explicit.
255
254
256 @nt.nottest # now we have a completion for \jmath
255 @nt.nottest # now we have a completion for \jmath
257 @decorators.knownfailureif(
256 @decorators.knownfailureif(
@@ -5,6 +5,7 b' include setupbase.py'
5 include setupegg.py
5 include setupegg.py
6 include MANIFEST.in
6 include MANIFEST.in
7 include pytest.ini
7 include pytest.ini
8 include mypy.ini
8 include .mailmap
9 include .mailmap
9
10
10 recursive-exclude tools *
11 recursive-exclude tools *
General Comments 0
You need to be logged in to leave comments. Login now