Skip to content

Commit

Permalink
Use variable annotations instead of type comments on Python 3.8 (subl…
Browse files Browse the repository at this point in the history
…imelsp#2450)

* "Add .python-version file"

* remove pathlib from dependencies

* change import

* Revert "change import" (:

This reverts commit c70cd57.

* Fix failing unittests on MacOS (sublimelsp#2436)

This commit adopts `unittesting.ViewTestCase` to run view related test cases.

ViewTestCase ...

1. provides `view` and `window` members pointing to a dedicated view, being
   created for testing.
2. ensures not to close empty windows, which was probably the most likely
   reason for unittests failing before on MacOS.

* keep the same order as before

* rchlint

* add release notes

* tweak release message

* Be more descriptive of what the user expect, or what the user can do if things go wrong

* tweak words

* Use variable annotations instead of type comments

---------

Co-authored-by: Предраг Николић <[email protected]>
Co-authored-by: Rafal Chlodnicki <[email protected]>
Co-authored-by: deathaxe <[email protected]>
Co-authored-by: Raoul Wols <[email protected]>
  • Loading branch information
5 people authored Apr 20, 2024
1 parent 4b02dbd commit 0fabb7d
Show file tree
Hide file tree
Showing 57 changed files with 363 additions and 364 deletions.
2 changes: 1 addition & 1 deletion boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def _get_final_subclasses(derived: List[Type], results: List[Type]) -> None:


def _register_all_plugins() -> None:
plugin_classes = [] # type: List[Type[AbstractPlugin]]
plugin_classes: List[Type[AbstractPlugin]] = []
_get_final_subclasses(AbstractPlugin.__subclasses__(), plugin_classes)
for plugin_class in plugin_classes:
try:
Expand Down
22 changes: 11 additions & 11 deletions plugin/code_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ class CodeActionsManager:
"""Manager for per-location caching of code action responses."""

def __init__(self) -> None:
self._response_cache = None # type: Optional[Tuple[str, Promise[List[CodeActionsByConfigName]]]]
self.menu_actions_cache_key = None # type: Optional[str]
self.refactor_actions_cache = [] # type: List[Tuple[str, CodeAction]]
self.source_actions_cache = [] # type: List[Tuple[str, CodeAction]]
self._response_cache: Optional[Tuple[str, Promise[List[CodeActionsByConfigName]]]] = None
self.menu_actions_cache_key: Optional[str] = None
self.refactor_actions_cache: List[Tuple[str, CodeAction]] = []
self.source_actions_cache: List[Tuple[str, CodeAction]] = []

def request_for_region_async(
self,
Expand Down Expand Up @@ -74,7 +74,7 @@ def request_for_region_async(
self.source_actions_cache.clear()

def request_factory(sb: SessionBufferProtocol) -> Optional[Request]:
diagnostics = [] # type: List[Diagnostic]
diagnostics: List[Diagnostic] = []
for diag_sb, diags in session_buffer_diagnostics:
if diag_sb == sb:
diagnostics = diags
Expand Down Expand Up @@ -122,7 +122,7 @@ def request_factory(sb: SessionBufferProtocol) -> Optional[Request]:
matching_kinds = get_matching_on_save_kinds(on_save_actions, session_kinds)
if not matching_kinds:
return None
diagnostics = [] # type: List[Diagnostic]
diagnostics: List[Diagnostic] = []
for diag_sb, diags in session_buffer_diagnostics:
if diag_sb == sb:
diagnostics = diags
Expand Down Expand Up @@ -155,13 +155,13 @@ def on_response(
actions = response_filter(sb, response)
return (sb.session.config.name, actions)

tasks = [] # type: List[Promise[CodeActionsByConfigName]]
tasks: List[Promise[CodeActionsByConfigName]] = []
for sb in listener.session_buffers_async('codeActionProvider'):
session = sb.session
request = request_factory(sb)
if request:
response_handler = partial(on_response, sb)
task = session.send_request_task(request) # type: Promise[Optional[List[CodeActionOrCommand]]]
task: Promise[Optional[List[CodeActionOrCommand]]] = session.send_request_task(request)
tasks.append(task.then(response_handler))
# Return only results for non-empty lists.
return Promise.all(tasks) \
Expand All @@ -172,7 +172,7 @@ def on_response(


def get_session_kinds(sb: SessionBufferProtocol) -> List[CodeActionKind]:
session_kinds = sb.get_capability('codeActionProvider.codeActionKinds') # type: Optional[List[CodeActionKind]]
session_kinds: Optional[List[CodeActionKind]] = sb.get_capability('codeActionProvider.codeActionKinds')
return session_kinds or []


Expand Down Expand Up @@ -254,7 +254,7 @@ def _handle_response_async(self, responses: List[CodeActionsByConfigName]) -> No
if self._cancelled:
return
view = self._task_runner.view
tasks = [] # type: List[Promise]
tasks: List[Promise] = []
for config_name, code_actions in responses:
session = self._task_runner.session_by_name(config_name, 'codeActionProvider')
if session:
Expand Down Expand Up @@ -308,7 +308,7 @@ def _run_async(self, only_kinds: Optional[List[CodeActionKind]] = None) -> None:

def _handle_code_actions(self, response: List[CodeActionsByConfigName], run_first: bool = False) -> None:
# Flatten response to a list of (config_name, code_action) tuples.
actions = [] # type: List[Tuple[ConfigName, CodeActionOrCommand]]
actions: List[Tuple[ConfigName, CodeActionOrCommand]] = []
for config_name, session_actions in response:
actions.extend([(config_name, action) for action in session_actions])
if actions:
Expand Down
8 changes: 4 additions & 4 deletions plugin/code_lens.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def __init__(self, view: sublime.View) -> None:
self.view = view
self._init = False
self._phantom = sublime.PhantomSet(view, self.CODE_LENS_KEY)
self._code_lenses = {} # type: Dict[Tuple[int, int], List[CodeLensData]]
self._code_lenses: Dict[Tuple[int, int], List[CodeLensData]] = {}

def clear(self) -> None:
self._code_lenses.clear()
Expand All @@ -134,10 +134,10 @@ def handle_response(self, session_name: str, response: List[CodeLens]) -> None:
self._init = True
responses = [CodeLensData(data, self.view, session_name) for data in response]
responses.sort(key=lambda c: c.region)
result = {
result: Dict[Tuple[int, int], List[CodeLensData]] = {
region.to_tuple(): list(groups)
for region, groups in itertools.groupby(responses, key=lambda c: c.region)
} # type: Dict[Tuple[int, int], List[CodeLensData]]
}

# Fast path: no extra work to do
if self.is_empty():
Expand Down Expand Up @@ -215,7 +215,7 @@ def run(self, edit: sublime.Edit) -> None:
listener = windows.listener_for_view(self.view)
if not listener:
return
code_lenses = [] # type: List[CodeLensExtended]
code_lenses: List[CodeLensExtended] = []
for region in self.view.sel():
for sv in listener.session_views_async():
code_lenses.extend(sv.get_resolved_code_lenses_for_region(region))
Expand Down
6 changes: 3 additions & 3 deletions plugin/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ def run(self, edit: sublime.Edit, color_information: ColorInformation) -> None:
if session:
self._version = self.view.change_count()
self._range = color_information['range']
params = {
params: ColorPresentationParams = {
'textDocument': text_document_identifier(self.view),
'color': color_information['color'],
'range': self._range
} # type: ColorPresentationParams
}
session.send_request_async(Request.colorPresentation(params, self.view), self._handle_response_async)

def want_event(self) -> bool:
Expand All @@ -38,7 +38,7 @@ def _handle_response_async(self, response: List[ColorPresentation]) -> None:
if self._version != self.view.change_count():
return
old_text = self.view.substr(range_to_region(self._range, self.view))
self._filtered_response = [] # type: List[ColorPresentation]
self._filtered_response: List[ColorPresentation] = []
for item in response:
# Filter out items that would apply no change
text_edit = item.get('textEdit')
Expand Down
20 changes: 10 additions & 10 deletions plugin/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def format_completion(
lsp_detail = (item.get('detail') or "").replace("\n", " ")
completion_kind = item.get('kind')
kind = COMPLETION_KINDS.get(completion_kind, sublime.KIND_AMBIGUOUS) if completion_kind else sublime.KIND_AMBIGUOUS
details = [] # type: List[str]
details: List[str] = []
if can_resolve_completion_items or item.get('documentation'):
# Not using "make_command_link" in a hot path to avoid slow json.dumps.
args = '{{"view_id":{},"command":"lsp_resolve_docs","args":{{"index":{},"session_name":"{}"}}}}'.format(
Expand Down Expand Up @@ -132,7 +132,7 @@ def completion_with_defaults(item: CompletionItem, item_defaults: CompletionItem
""" Currently supports defaults for: ["editRange", "insertTextFormat", "data"] """
if not item_defaults:
return item
default_text_edit = None # type: Optional[Union[TextEdit, InsertReplaceEdit]]
default_text_edit: Optional[Union[TextEdit, InsertReplaceEdit]] = None
edit_range = item_defaults.get('editRange')
if edit_range:
# If textEditText is not provided and a list's default range is provided
Expand Down Expand Up @@ -182,7 +182,7 @@ def __init__(
self._triggered_manually = triggered_manually
self._on_done_async = on_done_async
self._resolved = False
self._pending_completion_requests = {} # type: Dict[int, weakref.ref[Session]]
self._pending_completion_requests: Dict[int, weakref.ref[Session]] = {}

def query_completions_async(self, sessions: List[Session]) -> None:
promises = [self._create_completion_request_async(session) for session in sessions]
Expand All @@ -206,10 +206,10 @@ def _resolve_completions_async(self, responses: List[ResolvedCompletions]) -> No
if self._resolved:
return
LspSelectCompletionCommand.completions = {}
items = [] # type: List[sublime.CompletionItem]
item_defaults = {} # type: CompletionItemDefaults
errors = [] # type: List[Error]
flags = 0 # int
items: List[sublime.CompletionItem] = []
item_defaults: CompletionItemDefaults = {}
errors: List[Error] = []
flags = 0
prefs = userprefs()
if prefs.inhibit_snippet_completions:
flags |= sublime.INHIBIT_EXPLICIT_COMPLETIONS
Expand All @@ -225,7 +225,7 @@ def _resolve_completions_async(self, responses: List[ResolvedCompletions]) -> No
session = weak_session()
if not session:
continue
response_items = [] # type: List[CompletionItem]
response_items: List[CompletionItem] = []
if isinstance(response, dict):
response_items = response["items"] or []
item_defaults = response.get('itemDefaults') or {}
Expand Down Expand Up @@ -291,7 +291,7 @@ def _handle_resolve_response_async(self, language_map: Optional[MarkdownLangMap]
detail = self._format_documentation(item.get('detail') or "", language_map)
documentation = self._format_documentation(item.get("documentation") or "", language_map)
if not documentation:
markdown = {"kind": MarkupKind.Markdown, "value": "*No documentation available.*"} # type: MarkupContent
markdown: MarkupContent = {"kind": MarkupKind.Markdown, "value": "*No documentation available.*"}
# No need for a language map here
documentation = self._format_documentation(markdown, None)
minihtml_content = ""
Expand Down Expand Up @@ -337,7 +337,7 @@ def run(self, edit: sublime.Edit, event: Optional[dict] = None) -> None:

class LspSelectCompletionCommand(LspTextCommand):

completions = {} # type: Dict[SessionName, CompletionsStore]
completions: Dict[SessionName, CompletionsStore] = {}

def run(self, edit: sublime.Edit, index: int, session_name: str) -> None:
items, item_defaults = LspSelectCompletionCommand.completions[session_name]
Expand Down
2 changes: 1 addition & 1 deletion plugin/core/active_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(self, sv: SessionViewProtocol, request_id: int, request: Request) -
self.weaksv = ref(sv)
self.request_id = request_id
self.request = request
self.progress = None # type: Optional[ProgressReporter]
self.progress: Optional[ProgressReporter] = None
# `request.progress` is either a boolean or a string. If it's a boolean, then that signals that the server does
# not support client-initiated progress. However, for some requests we still want to notify some kind of
# progress to the end-user. This is communicated by the boolean value being "True".
Expand Down
6 changes: 3 additions & 3 deletions plugin/core/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def __init__(self, d: Optional[Dict[str, Any]] = None) -> None:
:param d: An existing dictionary.
"""
self._d = {} # type: Dict[str, Any]
self._d: Dict[str, Any] = {}
if d is not None:
self.update(d)

Expand All @@ -40,7 +40,7 @@ def get(self, path: Optional[str] = None) -> Any:
"""
if path is None:
return self._d
current = self._d # type: Any
current: Any = self._d
keys = path.split('.')
for key in keys:
if isinstance(current, dict):
Expand All @@ -50,7 +50,7 @@ def get(self, path: Optional[str] = None) -> Any:
return current

def walk(self, path: str) -> Generator[Any, None, None]:
current = self._d # type: Any
current: Any = self._d
keys = path.split('.')
for key in keys:
if isinstance(current, dict):
Expand Down
8 changes: 4 additions & 4 deletions plugin/core/configurations.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ class WindowConfigManager(object):
def __init__(self, window: sublime.Window, global_configs: Dict[str, ClientConfig]) -> None:
self._window = window
self._global_configs = global_configs
self._disabled_for_session = set() # type: Set[str]
self._crashes = {} # type: Dict[str, Deque[datetime]]
self.all = {} # type: Dict[str, ClientConfig]
self._change_listeners = WeakSet() # type: WeakSet[WindowConfigChangeListener]
self._disabled_for_session: Set[str] = set()
self._crashes: Dict[str, Deque[datetime]] = {}
self.all: Dict[str, ClientConfig] = {}
self._change_listeners: WeakSet[WindowConfigChangeListener] = WeakSet()
self._reload_configs(notify_listeners=False)

def add_change_listener(self, listener: WindowConfigChangeListener) -> None:
Expand Down
28 changes: 14 additions & 14 deletions plugin/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
KIND_REFACTOR = (sublime.KIND_ID_COLOR_CYANISH, "r", "Refactor")
KIND_SOURCE = (sublime.KIND_ID_COLOR_PURPLISH, "s", "Source")

COMPLETION_KINDS = {
COMPLETION_KINDS: Dict[CompletionItemKind, SublimeKind] = {
CompletionItemKind.Text: KIND_TEXT,
CompletionItemKind.Method: KIND_METHOD,
CompletionItemKind.Function: KIND_FUNCTION,
Expand All @@ -97,9 +97,9 @@
CompletionItemKind.Event: KIND_EVENT,
CompletionItemKind.Operator: KIND_OPERATOR,
CompletionItemKind.TypeParameter: KIND_TYPEPARAMETER
} # type: Dict[CompletionItemKind, SublimeKind]
}

SYMBOL_KINDS = {
SYMBOL_KINDS: Dict[SymbolKind, SublimeKind] = {
SymbolKind.File: KIND_FILE,
SymbolKind.Module: KIND_MODULE,
SymbolKind.Namespace: KIND_NAMESPACE,
Expand All @@ -126,45 +126,45 @@
SymbolKind.Event: KIND_EVENT,
SymbolKind.Operator: KIND_OPERATOR,
SymbolKind.TypeParameter: KIND_TYPEPARAMETER
} # type: Dict[SymbolKind, SublimeKind]
}

DIAGNOSTIC_KINDS = {
DIAGNOSTIC_KINDS: Dict[DiagnosticSeverity, SublimeKind] = {
DiagnosticSeverity.Error: KIND_ERROR,
DiagnosticSeverity.Warning: KIND_WARNING,
DiagnosticSeverity.Information: KIND_INFORMATION,
DiagnosticSeverity.Hint: KIND_HINT
} # type: Dict[DiagnosticSeverity, SublimeKind]
}

CODE_ACTION_KINDS = {
CODE_ACTION_KINDS: Dict[CodeActionKind, SublimeKind] = {
CodeActionKind.QuickFix: KIND_QUICKFIX,
CodeActionKind.Refactor: KIND_REFACTOR,
CodeActionKind.Source: KIND_SOURCE
} # type: Dict[CodeActionKind, SublimeKind]
}


DOCUMENT_HIGHLIGHT_KIND_NAMES = {
DOCUMENT_HIGHLIGHT_KIND_NAMES: Dict[DocumentHighlightKind, str] = {
DocumentHighlightKind.Text: "text",
DocumentHighlightKind.Read: "read",
DocumentHighlightKind.Write: "write"
} # type: Dict[DocumentHighlightKind, str]
}


# Symbol scope to kind mapping, based on https://github.com/sublimetext-io/docs.sublimetext.io/issues/30
SUBLIME_KIND_SCOPES = {
SUBLIME_KIND_SCOPES: Dict[SublimeKind, str] = {
sublime.KIND_KEYWORD: "keyword | storage.modifier | storage.type | keyword.declaration | variable.language | constant.language", # noqa: E501
sublime.KIND_TYPE: "entity.name.type | entity.name.class | entity.name.enum | entity.name.trait | entity.name.struct | entity.name.impl | entity.name.interface | entity.name.union | support.type | support.class", # noqa: E501
sublime.KIND_FUNCTION: "entity.name.function | entity.name.method | entity.name.macro | meta.method entity.name.function | support.function | meta.function-call variable.function | meta.function-call support.function | support.method | meta.method-call variable.function", # noqa: E501
sublime.KIND_NAMESPACE: "entity.name.module | entity.name.namespace | support.module | support.namespace",
sublime.KIND_NAVIGATION: "entity.name.definition | entity.name.label | entity.name.section",
sublime.KIND_MARKUP: "entity.other.attribute-name | entity.name.tag | meta.toc-list.id.html",
sublime.KIND_VARIABLE: "entity.name.constant | constant.other | support.constant | variable.other | variable.parameter | variable.other.member | variable.other.readwrite.member" # noqa: E501
} # type: Dict[SublimeKind, str]
}

DOCUMENT_HIGHLIGHT_KIND_SCOPES = {
DOCUMENT_HIGHLIGHT_KIND_SCOPES: Dict[DocumentHighlightKind, str] = {
DocumentHighlightKind.Text: "region.bluish markup.highlight.text.lsp",
DocumentHighlightKind.Read: "region.greenish markup.highlight.read.lsp",
DocumentHighlightKind.Write: "region.yellowish markup.highlight.write.lsp"
} # type: Dict[DocumentHighlightKind, str]
}

SEMANTIC_TOKENS_MAP = {
"namespace": "variable.other.namespace.lsp",
Expand Down
2 changes: 1 addition & 1 deletion plugin/core/css.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __init__(self) -> None:
self.annotations_classname = "lsp_annotation"


_css = None # type: Optional[CSS]
_css: Optional[CSS] = None


def load() -> None:
Expand Down
2 changes: 1 addition & 1 deletion plugin/core/diagnostics_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def filter_map_diagnostics_async(
not more than once. Items and results are ordered as they came in from the server.
"""
for uri, diagnostics in self.items():
results = list(filter(None, map(functools.partial(f, uri), filter(pred, diagnostics)))) # type: List[T]
results: List[T] = list(filter(None, map(functools.partial(f, uri), filter(pred, diagnostics))))
if results:
yield uri, results

Expand Down
2 changes: 1 addition & 1 deletion plugin/core/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


def parse_workspace_edit(workspace_edit: WorkspaceEdit) -> WorkspaceChanges:
changes = {} # type: WorkspaceChanges
changes: WorkspaceChanges = {}
document_changes = workspace_edit.get('documentChanges')
if isinstance(document_changes, list):
for document_change in document_changes:
Expand Down
4 changes: 2 additions & 2 deletions plugin/core/file_watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@


def lsp_watch_kind_to_file_watcher_event_types(kind: WatchKind) -> List[FileWatcherEventType]:
event_types = [] # type: List[FileWatcherEventType]
event_types: List[FileWatcherEventType] = []
if kind & WatchKind.Create:
event_types.append('create')
if kind & WatchKind.Change:
Expand Down Expand Up @@ -78,7 +78,7 @@ def destroy(self) -> None:
pass


watcher_implementation = None # type: Optional[Type[FileWatcher]]
watcher_implementation: Optional[Type[FileWatcher]] = None


def register_file_watcher_implementation(file_watcher: Type[FileWatcher]) -> None:
Expand Down
4 changes: 2 additions & 2 deletions plugin/core/input_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ def __init__(self, command: sublime_plugin.WindowCommand, args: Dict[str, Any])
self.command = command
self.args = args
self.text = getattr(command, '_text', '')
self.listener = None # type: Optional[sublime_plugin.TextChangeListener]
self.input_view = None # type: Optional[sublime.View]
self.listener: Optional[sublime_plugin.TextChangeListener] = None
self.input_view: Optional[sublime.View] = None

def attach_listener(self) -> None:
for buffer in sublime._buffers(): # type: ignore
Expand Down
Loading

0 comments on commit 0fabb7d

Please sign in to comment.