From ab60d3197788b943db0cf81d9279c28e52ec9225 2022-09-24 20:39:35 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: 2022-09-24 20:39:35 Subject: [PATCH] Switch `CompletionContext` to `dataclass`, use `cached_property` Data class has narrower API than named tuple (does not expose item getters) which means it is less likely that the downstream code would be broken in the future if we introduce new attributes. Also, compared to other places where memory-efficient named tuple is used, `CompletionContext` is only created once per completion and thus does not require as low overhead. For the same reason we can forgo slightly more memory-efficient `@property @cache` stack and just use `@cached_property`. --- diff --git a/IPython/core/completer.py b/IPython/core/completer.py index ef99c97..fc3aea7 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -191,7 +191,8 @@ import unicodedata import uuid import warnings from contextlib import contextmanager -from functools import lru_cache, partial +from dataclasses import dataclass +from functools import cached_property, partial from importlib import import_module from types import SimpleNamespace from typing import ( @@ -597,7 +598,8 @@ class _JediMatcherResult(_MatcherResultBase): completions: Iterable[_JediCompletionLike] -class CompletionContext(NamedTuple): +@dataclass +class CompletionContext: """Completion context provided as an argument to matchers in the Matcher API v2.""" # rationale: many legacy matchers relied on completer state (`self.text_until_cursor`) @@ -626,13 +628,11 @@ class CompletionContext(NamedTuple): # If not given, return all possible completions. limit: Optional[int] - @property - @lru_cache(maxsize=None) # TODO change to @cache after dropping Python 3.7 + @cached_property def text_until_cursor(self) -> str: return self.line_with_cursor[: self.cursor_position] - @property - @lru_cache(maxsize=None) # TODO change to @cache after dropping Python 3.7 + @cached_property def line_with_cursor(self) -> str: return self.full_text.split("\n")[self.cursor_line]