Skip to content

Commit 55e482a

Browse files
disallow untyped defs in autocomplete.py
1 parent 3356afc commit 55e482a

File tree

1 file changed

+99
-52
lines changed

1 file changed

+99
-52
lines changed

bpython/autocomplete.py

Lines changed: 99 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2222
# THE SOFTWARE.
2323

24+
# To gradually migrate to mypy we aren't setting these globally yet
25+
# mypy: disallow_untyped_defs=True
2426

2527
import __main__
2628
import abc
@@ -35,10 +37,12 @@
3537
from enum import Enum
3638
from typing import (
3739
Any,
40+
cast,
3841
Dict,
3942
Iterator,
4043
List,
4144
Match,
45+
Optional,
4246
Set,
4347
Union,
4448
Tuple,
@@ -50,6 +54,7 @@
5054
from .line import LinePart
5155
from .lazyre import LazyReCompile
5256
from .simpleeval import safe_eval, evaluate_current_expression, EvaluationError
57+
from .importcompletion import ModuleGatherer
5358

5459

5560
# Autocomplete modes
@@ -60,7 +65,7 @@ class AutocompleteModes(Enum):
6065
FUZZY = "fuzzy"
6166

6267
@classmethod
63-
def from_string(cls, value) -> Union[Any, None]:
68+
def from_string(cls, value: str) -> Union[Any, None]:
6469
if value.upper() in cls.__members__:
6570
return cls.__members__[value.upper()]
6671
return None
@@ -177,7 +182,7 @@ def after_last_dot(name: str) -> str:
177182
return name.rstrip(".").rsplit(".")[-1]
178183

179184

180-
def few_enough_underscores(current, match) -> bool:
185+
def few_enough_underscores(current: str, match: str) -> bool:
181186
"""Returns whether match should be shown based on current
182187
183188
if current is _, True if match starts with 0 or 1 underscore
@@ -203,7 +208,7 @@ def method_match_substring(word: str, size: int, text: str) -> bool:
203208
return text in word
204209

205210

206-
def method_match_fuzzy(word, size, text) -> Union[Match, None]:
211+
def method_match_fuzzy(word: str, size: int, text: str) -> Union[Match, None]:
207212
s = r".*%s.*" % ".*".join(list(text))
208213
return re.search(s, word)
209214

@@ -220,14 +225,16 @@ class BaseCompletionType:
220225
"""Describes different completion types"""
221226

222227
def __init__(
223-
self, shown_before_tab: bool = True, mode=AutocompleteModes.SIMPLE
228+
self,
229+
shown_before_tab: bool = True,
230+
mode: AutocompleteModes = AutocompleteModes.SIMPLE,
224231
) -> None:
225232
self._shown_before_tab = shown_before_tab
226233
self.method_match = MODES_MAP[mode]
227234

228235
@abc.abstractmethod
229236
def matches(
230-
self, cursor_offset: int, line: str, **kwargs
237+
self, cursor_offset: int, line: str, **kwargs: Any
231238
) -> Union[Set[str], None]:
232239
"""Returns a list of possible matches given a line and cursor, or None
233240
if this completion type isn't applicable.
@@ -255,10 +262,12 @@ def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
255262
the cursor."""
256263
raise NotImplementedError
257264

258-
def format(self, word):
265+
def format(self, word: str) -> str:
259266
return word
260267

261-
def substitute(self, cursor_offset, line, match) -> Tuple[int, str]:
268+
def substitute(
269+
self, cursor_offset: int, line: str, match: str
270+
) -> Tuple[int, str]:
262271
"""Returns a cursor offset and line with match swapped in"""
263272
lpart = self.locate(cursor_offset, line)
264273
assert lpart
@@ -289,18 +298,18 @@ def __init__(
289298

290299
super().__init__(True, mode)
291300

292-
def locate(self, current_offset, line):
301+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
293302
for completer in self._completers:
294-
return_value = completer.locate(current_offset, line)
303+
return_value = completer.locate(cursor_offset, line)
295304
if return_value is not None:
296305
return return_value
297306
return None
298307

299-
def format(self, word):
308+
def format(self, word: str) -> str:
300309
return self._completers[0].format(word)
301310

302311
def matches(
303-
self, cursor_offset: int, line: str, **kwargs
312+
self, cursor_offset: int, line: str, **kwargs: Any
304313
) -> Union[None, Set]:
305314
return_value = None
306315
all_matches = set()
@@ -316,28 +325,36 @@ def matches(
316325

317326

318327
class ImportCompletion(BaseCompletionType):
319-
def __init__(self, module_gatherer, mode=AutocompleteModes.SIMPLE):
328+
def __init__(
329+
self,
330+
module_gatherer: ModuleGatherer,
331+
mode: AutocompleteModes = AutocompleteModes.SIMPLE,
332+
):
320333
super().__init__(False, mode)
321334
self.module_gatherer = module_gatherer
322335

323-
def matches(self, cursor_offset, line, **kwargs):
336+
def matches(
337+
self, cursor_offset: int, line: str, **kwargs: Any
338+
) -> Union[None, Set]:
324339
return self.module_gatherer.complete(cursor_offset, line)
325340

326-
def locate(self, current_offset, line):
327-
return lineparts.current_word(current_offset, line)
341+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
342+
return lineparts.current_word(cursor_offset, line)
328343

329-
def format(self, word):
344+
def format(self, word: str) -> str:
330345
return after_last_dot(word)
331346

332347

333348
class FilenameCompletion(BaseCompletionType):
334-
def __init__(self, mode=AutocompleteModes.SIMPLE):
349+
def __init__(self, mode: AutocompleteModes = AutocompleteModes.SIMPLE):
335350
super().__init__(False, mode)
336351

337-
def safe_glob(self, pathname) -> Iterator:
352+
def safe_glob(self, pathname: str) -> Iterator[str]:
338353
return glob.iglob(glob.escape(pathname) + "*")
339354

340-
def matches(self, cursor_offset, line, **kwargs) -> Union[None, set]:
355+
def matches(
356+
self, cursor_offset: int, line: str, **kwargs: Any
357+
) -> Union[None, Set]:
341358
cs = lineparts.current_string(cursor_offset, line)
342359
if cs is None:
343360
return None
@@ -352,10 +369,10 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[None, set]:
352369
matches.add(filename)
353370
return matches
354371

355-
def locate(self, current_offset, line):
356-
return lineparts.current_string(current_offset, line)
372+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
373+
return lineparts.current_string(cursor_offset, line)
357374

358-
def format(self, filename):
375+
def format(self, filename: str) -> str:
359376
filename.rstrip(os.sep).rsplit(os.sep)[-1]
360377
if os.sep in filename[:-1]:
361378
return filename[filename.rindex(os.sep, 0, -1) + 1 :]
@@ -367,10 +384,12 @@ class AttrCompletion(BaseCompletionType):
367384

368385
attr_matches_re = LazyReCompile(r"(\w+(\.\w+)*)\.(\w*)")
369386

370-
def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
387+
def matches(
388+
self, cursor_offset: int, line: str, **kwargs: Any
389+
) -> Union[None, Set]:
371390
if "locals_" not in kwargs:
372391
return None
373-
locals_ = kwargs["locals_"]
392+
locals_ = cast(Dict[str, Any], kwargs["locals_"])
374393

375394
r = self.locate(cursor_offset, line)
376395
if r is None:
@@ -397,13 +416,13 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
397416
if few_enough_underscores(r.word.split(".")[-1], m.split(".")[-1])
398417
}
399418

400-
def locate(self, current_offset, line):
401-
return lineparts.current_dotted_attribute(current_offset, line)
419+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
420+
return lineparts.current_dotted_attribute(cursor_offset, line)
402421

403-
def format(self, word):
422+
def format(self, word: str) -> str:
404423
return after_last_dot(word)
405424

406-
def attr_matches(self, text, namespace) -> List:
425+
def attr_matches(self, text: str, namespace: Dict[str, Any]) -> List:
407426
"""Taken from rlcompleter.py and bent to my will."""
408427

409428
m = self.attr_matches_re.match(text)
@@ -422,7 +441,7 @@ def attr_matches(self, text, namespace) -> List:
422441
matches = self.attr_lookup(obj, expr, attr)
423442
return matches
424443

425-
def attr_lookup(self, obj, expr, attr) -> List:
444+
def attr_lookup(self, obj: Any, expr: str, attr: str) -> List:
426445
"""Second half of attr_matches."""
427446
words = self.list_attributes(obj)
428447
if inspection.hasattr_safe(obj, "__class__"):
@@ -442,15 +461,17 @@ def attr_lookup(self, obj, expr, attr) -> List:
442461
matches.append(f"{expr}.{word}")
443462
return matches
444463

445-
def list_attributes(self, obj) -> List[str]:
464+
def list_attributes(self, obj: Any) -> List[str]:
446465
# TODO: re-implement dir using getattr_static to avoid using
447466
# AttrCleaner here?
448467
with inspection.AttrCleaner(obj):
449468
return dir(obj)
450469

451470

452471
class DictKeyCompletion(BaseCompletionType):
453-
def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
472+
def matches(
473+
self, cursor_offset: int, line: str, **kwargs: Any
474+
) -> Union[None, Set]:
454475
if "locals_" not in kwargs:
455476
return None
456477
locals_ = kwargs["locals_"]
@@ -473,15 +494,17 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
473494
else:
474495
return None
475496

476-
def locate(self, current_offset, line) -> Union[LinePart, None]:
477-
return lineparts.current_dict_key(current_offset, line)
497+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
498+
return lineparts.current_dict_key(cursor_offset, line)
478499

479-
def format(self, match):
500+
def format(self, match: str) -> str:
480501
return match[:-1]
481502

482503

483504
class MagicMethodCompletion(BaseCompletionType):
484-
def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
505+
def matches(
506+
self, cursor_offset: int, line: str, **kwargs: Any
507+
) -> Union[None, Set]:
485508
if "current_block" not in kwargs:
486509
return None
487510
current_block = kwargs["current_block"]
@@ -493,12 +516,14 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
493516
return None
494517
return {name for name in MAGIC_METHODS if name.startswith(r.word)}
495518

496-
def locate(self, current_offset, line) -> Union[LinePart, None]:
497-
return lineparts.current_method_definition_name(current_offset, line)
519+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
520+
return lineparts.current_method_definition_name(cursor_offset, line)
498521

499522

500523
class GlobalCompletion(BaseCompletionType):
501-
def matches(self, cursor_offset, line, **kwargs) -> Union[Set, None]:
524+
def matches(
525+
self, cursor_offset: int, line: str, **kwargs: Any
526+
) -> Union[None, Set]:
502527
"""Compute matches when text is a simple name.
503528
Return a list of all keywords, built-in functions and names currently
504529
defined in self.namespace that match.
@@ -528,12 +553,14 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[Set, None]:
528553
matches.add(_callable_postfix(val, word))
529554
return matches if matches else None
530555

531-
def locate(self, current_offset, line) -> Union[LinePart, None]:
532-
return lineparts.current_single_word(current_offset, line)
556+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
557+
return lineparts.current_single_word(cursor_offset, line)
533558

534559

535560
class ParameterNameCompletion(BaseCompletionType):
536-
def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
561+
def matches(
562+
self, cursor_offset: int, line: str, **kwargs: Any
563+
) -> Union[None, Set]:
537564
if "argspec" not in kwargs:
538565
return None
539566
argspec = kwargs["argspec"]
@@ -554,16 +581,18 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
554581
)
555582
return matches if matches else None
556583

557-
def locate(self, current_offset, line) -> Union[LinePart, None]:
558-
return lineparts.current_word(current_offset, line)
584+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
585+
return lineparts.current_word(cursor_offset, line)
559586

560587

561588
class ExpressionAttributeCompletion(AttrCompletion):
562589
# could replace attr completion as a more general case with some work
563-
def locate(self, current_offset, line) -> Union[LinePart, None]:
564-
return lineparts.current_expression_attribute(current_offset, line)
590+
def locate(self, cursor_offset: int, line: str) -> Union[LinePart, None]:
591+
return lineparts.current_expression_attribute(cursor_offset, line)
565592

566-
def matches(self, cursor_offset, line, **kwargs) -> Union[Set, None]:
593+
def matches(
594+
self, cursor_offset: int, line: str, **kwargs: Any
595+
) -> Union[None, Set]:
567596
if "locals_" not in kwargs:
568597
return None
569598
locals_ = kwargs["locals_"]
@@ -589,7 +618,14 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[Set, None]:
589618
except ImportError:
590619

591620
class MultilineJediCompletion(BaseCompletionType): # type: ignore [no-redef]
592-
def matches(self, cursor_offset, line, **kwargs) -> None:
621+
def matches(
622+
self, cursor_offset: int, line: str, **kwargs: Any
623+
) -> Union[None, Set]:
624+
return None
625+
626+
def locate(
627+
self, cursor_offset: int, line: str
628+
) -> Union[LinePart, None]:
593629
return None
594630

595631

@@ -598,7 +634,9 @@ def matches(self, cursor_offset, line, **kwargs) -> None:
598634
class JediCompletion(BaseCompletionType):
599635
_orig_start: Union[int, None]
600636

601-
def matches(self, cursor_offset, line, **kwargs) -> Union[None, Set]:
637+
def matches(
638+
self, cursor_offset: int, line: str, **kwargs: Any
639+
) -> Union[None, Set]:
602640
if "history" not in kwargs:
603641
return None
604642
history = kwargs["history"]
@@ -646,7 +684,9 @@ def locate(self, cursor_offset: int, line: str) -> LinePart:
646684
return LinePart(start, end, line[start:end])
647685

648686
class MultilineJediCompletion(JediCompletion): # type: ignore [no-redef]
649-
def matches(self, cursor_offset, line, **kwargs) -> Union[Set, None]:
687+
def matches(
688+
self, cursor_offset: int, line: str, **kwargs: Any
689+
) -> Union[None, Set]:
650690
if "current_block" not in kwargs or "history" not in kwargs:
651691
return None
652692
current_block = kwargs["current_block"]
@@ -663,7 +703,12 @@ def matches(self, cursor_offset, line, **kwargs) -> Union[Set, None]:
663703
return None
664704

665705

666-
def get_completer(completers, cursor_offset, line, **kwargs):
706+
def get_completer(
707+
completers: Sequence[BaseCompletionType],
708+
cursor_offset: int,
709+
line: str,
710+
**kwargs: Any,
711+
) -> Tuple[List[str], Optional[BaseCompletionType]]:
667712
"""Returns a list of matches and an applicable completer
668713
669714
If no matches available, returns a tuple of an empty list and None
@@ -698,7 +743,9 @@ def get_completer(completers, cursor_offset, line, **kwargs):
698743
return [], None
699744

700745

701-
def get_default_completer(mode=AutocompleteModes.SIMPLE, module_gatherer=None):
746+
def get_default_completer(
747+
mode: AutocompleteModes, module_gatherer: ModuleGatherer
748+
) -> Tuple[BaseCompletionType, ...]:
702749
return (
703750
(
704751
DictKeyCompletion(mode=mode),
@@ -721,7 +768,7 @@ def get_default_completer(mode=AutocompleteModes.SIMPLE, module_gatherer=None):
721768
)
722769

723770

724-
def _callable_postfix(value, word):
771+
def _callable_postfix(value: Any, word: str) -> str:
725772
"""rlcompleter's _callable_postfix done right."""
726773
if callable(value):
727774
word += "("

0 commit comments

Comments
 (0)