')
for diagnostic in diagnostics:
by_severity.setdefault(diagnostic_severity(diagnostic), []).append(
@@ -270,7 +270,7 @@ def hover_content(self) -> str:
contents.append(minihtml(self.view, content, allowed_formats, language_map))
return '
'.join(contents)
- def hover_range(self) -> Optional[sublime.Region]:
+ def hover_range(self) -> sublime.Region | None:
for hover, _ in self._hover_responses:
hover_range = hover.get('range')
if hover_range:
@@ -357,7 +357,7 @@ def _on_navigate(self, href: str, point: int) -> None:
if window:
targets = [link["target"] for link in self._document_links] # pyright: ignore
- def on_select(targets: List[str], idx: int) -> None:
+ def on_select(targets: list[str], idx: int) -> None:
if idx > -1:
self._on_navigate(targets[idx], 0)
@@ -375,7 +375,7 @@ def on_select(targets: List[str], idx: int) -> None:
else:
sublime.set_timeout_async(partial(self.try_open_custom_uri_async, href))
- def handle_code_action_select(self, config_name: str, actions: List[CodeActionOrCommand], index: int) -> None:
+ def handle_code_action_select(self, config_name: str, actions: list[CodeActionOrCommand], index: int) -> None:
if index == -1:
return
diff --git a/plugin/inlay_hint.py b/plugin/inlay_hint.py
index c302d01b0..819e7a2b8 100644
--- a/plugin/inlay_hint.py
+++ b/plugin/inlay_hint.py
@@ -10,7 +10,6 @@
from .core.sessions import Session
from .core.settings import userprefs
from .core.views import position_to_offset
-from typing import Optional, Union
from typing import cast
import html
import sublime
@@ -20,12 +19,12 @@
class LspToggleInlayHintsCommand(LspWindowCommand):
capability = 'inlayHintProvider'
- def run(self, enable: Optional[bool] = None) -> None:
+ def run(self, enable: bool | None = None) -> None:
if not isinstance(enable, bool):
enable = not self.are_enabled(self.window)
self.window.settings().set('lsp_show_inlay_hints', enable)
status = 'on' if enable else 'off'
- sublime.status_message('Inlay Hints are {}'.format(status))
+ sublime.status_message(f'Inlay Hints are {status}')
for session in self.sessions():
for sv in session.session_views_async():
sv.session_buffer.do_inlay_hints_async(sv.view)
@@ -34,7 +33,7 @@ def is_checked(self) -> bool:
return self.are_enabled(self.window)
@classmethod
- def are_enabled(cls, window: Optional[sublime.Window]) -> bool:
+ def are_enabled(cls, window: sublime.Window | None) -> bool:
if not window:
return userprefs().show_inlay_hints
return bool(window.settings().get('lsp_show_inlay_hints', userprefs().show_inlay_hints))
@@ -44,7 +43,7 @@ class LspInlayHintClickCommand(LspTextCommand):
capability = 'inlayHintProvider'
def run(self, _edit: sublime.Edit, session_name: str, inlay_hint: InlayHint, phantom_uuid: str,
- event: Optional[dict] = None, label_part: Optional[InlayHintLabelPart] = None) -> None:
+ event: dict | None = None, label_part: InlayHintLabelPart | None = None) -> None:
# Insert textEdits for the given inlay hint.
# If a InlayHintLabelPart was clicked, label_part will be passed as an argument to the LspInlayHintClickCommand
# and InlayHintLabelPart.command will be executed.
@@ -58,7 +57,7 @@ def run(self, _edit: sublime.Edit, session_name: str, inlay_hint: InlayHint, pha
self.handle(session_name, inlay_hint, phantom_uuid, label_part)
def handle(self, session_name: str, inlay_hint: InlayHint, phantom_uuid: str,
- label_part: Optional[InlayHintLabelPart] = None) -> None:
+ label_part: InlayHintLabelPart | None = None) -> None:
self.handle_inlay_hint_text_edits(session_name, inlay_hint, phantom_uuid)
self.handle_label_part_command(session_name, label_part)
@@ -73,7 +72,7 @@ def handle_inlay_hint_text_edits(self, session_name: str, inlay_hint: InlayHint,
sb.remove_inlay_hint_phantom(phantom_uuid)
apply_text_edits(self.view, text_edits)
- def handle_label_part_command(self, session_name: str, label_part: Optional[InlayHintLabelPart] = None) -> None:
+ def handle_label_part_command(self, session_name: str, label_part: InlayHintLabelPart | None = None) -> None:
if not label_part:
return
command = label_part.get('command')
@@ -100,27 +99,23 @@ def inlay_hint_to_phantom(view: sublime.View, inlay_hint: InlayHint, session: Se
def get_inlay_hint_html(view: sublime.View, inlay_hint: InlayHint, session: Session, phantom_uuid: str) -> str:
label = format_inlay_hint_label(inlay_hint, session, phantom_uuid)
font = view.settings().get('font_face') or "monospace"
- html = """
+ html = f"""
{label}
- """.format(
- font=font,
- css=css().inlay_hints,
- label=label
- )
+ """
return html
-def format_inlay_hint_tooltip(tooltip: Optional[Union[str, MarkupContent]]) -> str:
+def format_inlay_hint_tooltip(tooltip: str | MarkupContent | None) -> str:
if isinstance(tooltip, str):
return html.escape(tooltip)
if isinstance(tooltip, dict): # MarkupContent
@@ -145,12 +140,9 @@ def format_inlay_hint_label(inlay_hint: InlayHint, session: Session, phantom_uui
'phantom_uuid': phantom_uuid
}
})
- result += '
'.format(command=inlay_hint_click_command)
+ result += f''
instruction_text = '\nDouble-click to insert' if has_text_edits else ""
- result += '{value}'.format(
- tooltip=(tooltip + instruction_text).strip(),
- value=html.escape(label)
- )
+ result += f'{html.escape(label)}'
if is_clickable:
result += ""
return result
@@ -169,14 +161,11 @@ def format_inlay_hint_label(inlay_hint: InlayHint, session: Session, phantom_uui
'label_part': cast(dict, label_part)
}
})
- value += '
'.format(command=inlay_hint_click_command)
+ value += f''
value += html.escape(label_part['value'])
if has_command:
value += ""
# InlayHintLabelPart.location is not supported
instruction_text = '\nDouble-click to execute' if has_command else ""
- result += "
{value}".format(
- tooltip=(tooltip + instruction_text).strip(),
- value=value
- )
+ result += f"
{value}"
return result
diff --git a/plugin/locationpicker.py b/plugin/locationpicker.py
index 7fff94d4c..80bcf865f 100644
--- a/plugin/locationpicker.py
+++ b/plugin/locationpicker.py
@@ -9,7 +9,6 @@
from .core.views import get_uri_and_position_from_location
from .core.views import location_to_human_readable
from .core.views import to_encoded_filename
-from typing import List, Optional, Tuple, Union
from urllib.request import url2pathname
import functools
import sublime
@@ -18,7 +17,7 @@
def open_location_async(
session: Session,
- location: Union[Location, LocationLink],
+ location: Location | LocationLink,
side_by_side: bool,
force_group: bool,
group: int = -1
@@ -29,7 +28,7 @@ def open_location_async(
if side_by_side:
flags |= sublime.ADD_TO_SELECTION | sublime.SEMI_TRANSIENT
- def check_success_async(view: Optional[sublime.View]) -> None:
+ def check_success_async(view: sublime.View | None) -> None:
if not view:
sublime.error_message("Unable to open URI")
@@ -41,8 +40,8 @@ def open_basic_file(
uri: str,
position: Position,
flags: int = 0,
- group: Optional[int] = None
-) -> Optional[sublime.View]:
+ group: int | None = None
+) -> sublime.View | None:
if group is None:
group = session.window.active_group()
if uri.startswith("file:"):
@@ -63,7 +62,7 @@ def __init__(
self,
view: sublime.View,
session: Session,
- locations: Union[List[Location], List[LocationLink]],
+ locations: list[Location] | list[LocationLink],
side_by_side: bool,
force_group: bool = True,
group: int = -1,
@@ -82,7 +81,7 @@ def __init__(
self._force_group = force_group
self._group = group
self._items = locations
- self._highlighted_view: Optional[sublime.View] = None
+ self._highlighted_view: sublime.View | None = None
manager = session.manager()
base_dir = manager.get_project_path(view.file_name() or "") if manager else None
self._window.focus_group(group)
@@ -100,7 +99,7 @@ def __init__(
placeholder=placeholder
)
- def _unpack(self, index: int) -> Tuple[Optional[Session], Union[Location, LocationLink], DocumentUri, Position]:
+ def _unpack(self, index: int) -> tuple[Session | None, Location | LocationLink, DocumentUri, Position]:
location = self._items[index]
uri, position = get_uri_and_position_from_location(location)
return self._weaksession(), location, uri, position
@@ -120,7 +119,7 @@ def _select_entry(self, index: int) -> None:
if not self._side_by_side:
view = open_basic_file(session, uri, position, flags)
if not view:
- self._window.status_message("Unable to open {}".format(uri))
+ self._window.status_message(f"Unable to open {uri}")
else:
sublime.set_timeout_async(
functools.partial(
diff --git a/plugin/panels.py b/plugin/panels.py
index 834f862fc..370ca9d07 100644
--- a/plugin/panels.py
+++ b/plugin/panels.py
@@ -4,7 +4,7 @@
from .core.registry import windows
from contextlib import contextmanager
from sublime_plugin import WindowCommand
-from typing import Generator, Optional
+from typing import Generator
import sublime
import sublime_plugin
@@ -50,12 +50,12 @@ def run(self) -> None:
class LspToggleLogPanelLinesLimitCommand(sublime_plugin.TextCommand):
@classmethod
- def is_limit_enabled(cls, window: Optional[sublime.Window]) -> bool:
+ def is_limit_enabled(cls, window: sublime.Window | None) -> bool:
wm = windows.lookup(window)
return bool(wm and wm.is_log_lines_limit_enabled())
@classmethod
- def get_lines_limit(cls, window: Optional[sublime.Window]) -> int:
+ def get_lines_limit(cls, window: sublime.Window | None) -> int:
wm = windows.lookup(window)
return wm.get_log_lines_limit() if wm else 0
@@ -86,7 +86,7 @@ class LspUpdatePanelCommand(sublime_plugin.TextCommand):
A update_panel command to update the error panel with new text.
"""
- def run(self, edit: sublime.Edit, characters: Optional[str] = "") -> None:
+ def run(self, edit: sublime.Edit, characters: str | None = "") -> None:
# Clear folds
self.view.unfold(sublime.Region(0, self.view.size()))
@@ -109,7 +109,7 @@ def run(self, edit: sublime.Edit) -> None:
new_lines = []
for prefix, message in wm.get_and_clear_server_log():
message = message.replace("\r\n", "\n") # normalize Windows eol
- new_lines.append("{}: {}\n".format(prefix, message))
+ new_lines.append(f"{prefix}: {message}\n")
if new_lines:
self.view.insert(edit, self.view.size(), ''.join(new_lines))
last_region_end = 0 # Starting from point 0 in the panel ...
diff --git a/plugin/references.py b/plugin/references.py
index 6590b9114..ff94a6753 100644
--- a/plugin/references.py
+++ b/plugin/references.py
@@ -14,7 +14,7 @@
from .core.views import position_to_offset
from .core.views import text_document_position_params
from .locationpicker import LocationPicker
-from typing import Dict, List, Literal, Optional, Tuple
+from typing import Literal
import functools
import linecache
import os
@@ -30,27 +30,27 @@ class LspSymbolReferencesCommand(LspTextCommand):
def is_enabled(
self,
- event: Optional[dict] = None,
- point: Optional[int] = None,
+ event: dict | None = None,
+ point: int | None = None,
side_by_side: bool = False,
force_group: bool = True,
fallback: bool = False,
group: int = -1,
include_declaration: bool = False,
- output_mode: Optional[OutputMode] = None,
+ output_mode: OutputMode | None = None,
) -> bool:
return fallback or super().is_enabled(event, point)
def is_visible(
self,
- event: Optional[dict] = None,
- point: Optional[int] = None,
+ event: dict | None = None,
+ point: int | None = None,
side_by_side: bool = False,
force_group: bool = True,
fallback: bool = False,
group: int = -1,
include_declaration: bool = False,
- output_mode: Optional[OutputMode] = None,
+ output_mode: OutputMode | None = None,
) -> bool:
# We include "output panel" and "quick panel" variants of `LSP: Find References` in the Command Palette
# but we only show the one that is not the same as the default one (per the `show_references_in_quick_panel`
@@ -66,14 +66,14 @@ def is_visible(
def run(
self,
_: sublime.Edit,
- event: Optional[dict] = None,
- point: Optional[int] = None,
+ event: dict | None = None,
+ point: int | None = None,
side_by_side: bool = False,
force_group: bool = True,
fallback: bool = False,
group: int = -1,
include_declaration: bool = False,
- output_mode: Optional[OutputMode] = None,
+ output_mode: OutputMode | None = None,
) -> None:
session = self.best_session(self.capability)
file_path = self.view.file_name()
@@ -115,10 +115,10 @@ def _handle_response_async(
force_group: bool,
fallback: bool,
group: int,
- output_mode: Optional[OutputMode],
- event: Optional[dict],
+ output_mode: OutputMode | None,
+ event: dict | None,
position: int,
- response: Optional[List[Location]]
+ response: list[Location] | None
) -> None:
sublime.set_timeout(lambda: self._handle_response(
word, session, side_by_side, force_group, fallback, group, output_mode, event, position, response))
@@ -131,10 +131,10 @@ def _handle_response(
force_group: bool,
fallback: bool,
group: int,
- output_mode: Optional[OutputMode],
- event: Optional[dict],
+ output_mode: OutputMode | None,
+ event: dict | None,
position: int,
- response: Optional[List[Location]]
+ response: list[Location] | None
) -> None:
if not response:
self._handle_no_results(fallback, side_by_side)
@@ -166,7 +166,7 @@ def _show_references_in_quick_panel(
self,
word: str,
session: Session,
- locations: List[Location],
+ locations: list[Location],
side_by_side: bool,
force_group: bool,
group: int,
@@ -189,7 +189,7 @@ def _show_references_in_quick_panel(
break
LocationPicker(self.view, session, locations, side_by_side, force_group, group, placeholder, kind, index)
- def _show_references_in_output_panel(self, word: str, session: Session, locations: List[Location]) -> None:
+ def _show_references_in_output_panel(self, word: str, session: Session, locations: list[Location]) -> None:
wm = windows.lookup(session.window)
if not wm:
return
@@ -197,31 +197,31 @@ def _show_references_in_output_panel(self, word: str, session: Session, location
if not panel:
return
base_dir = wm.get_project_path(self.view.file_name() or "")
- to_render: List[str] = []
+ to_render: list[str] = []
references_count = 0
references_by_file = _group_locations_by_uri(wm.window, session.config, locations)
for file, references in references_by_file.items():
- to_render.append('{}:'.format(_get_relative_path(base_dir, file)))
+ to_render.append(f'{_get_relative_path(base_dir, file)}:')
for reference in references:
references_count += 1
point, line = reference
- to_render.append(" {:>4}:{:<4} {}".format(point.row + 1, point.col + 1, line))
+ to_render.append(f" {point.row + 1:>4}:{point.col + 1:<4} {line}")
to_render.append("") # add spacing between filenames
characters = "\n".join(to_render)
panel.settings().set("result_base_dir", base_dir)
panel.run_command("lsp_clear_panel")
wm.window.run_command("show_panel", {"panel": "output.references"})
panel.run_command('append', {
- 'characters': "{} references for '{}'\n\n{}".format(references_count, word, characters),
+ 'characters': f"{references_count} references for '{word}'\n\n{characters}",
'force': True,
'scroll_to_end': False
})
# highlight all word occurrences
- regions = panel.find_all(r"\b{}\b".format(word))
+ regions = panel.find_all(rf"\b{word}\b")
panel.add_regions('ReferenceHighlight', regions, 'comment', flags=sublime.DRAW_NO_FILL | sublime.NO_UNDO)
-def _get_relative_path(base_dir: Optional[str], file_path: str) -> str:
+def _get_relative_path(base_dir: str | None, file_path: str) -> str:
if base_dir:
try:
return os.path.relpath(file_path, base_dir)
@@ -234,10 +234,10 @@ def _get_relative_path(base_dir: Optional[str], file_path: str) -> str:
def _group_locations_by_uri(
window: sublime.Window,
config: ClientConfig,
- locations: List[Location]
-) -> Dict[str, List[Tuple[Point, str]]]:
+ locations: list[Location]
+) -> dict[str, list[tuple[Point, str]]]:
"""Return a dictionary that groups locations by the URI it belongs."""
- grouped_locations: Dict[str, List[Tuple[Point, str]]] = {}
+ grouped_locations: dict[str, list[tuple[Point, str]]] = {}
for location in locations:
uri, position = get_uri_and_position_from_location(location)
file_path = config.map_server_uri_to_client_path(uri)
diff --git a/plugin/rename.py b/plugin/rename.py
index 1ab50322b..73a8d08d9 100644
--- a/plugin/rename.py
+++ b/plugin/rename.py
@@ -18,7 +18,7 @@
from .core.views import range_to_region
from .core.views import text_document_position_params
from functools import partial
-from typing import Any, List, Optional
+from typing import Any
from typing import cast
from typing_extensions import TypeGuard
import os
@@ -122,14 +122,14 @@ def is_visible(
self,
new_name: str = "",
placeholder: str = "",
- event: Optional[dict] = None,
- point: Optional[int] = None
+ event: dict | None = None,
+ point: int | None = None
) -> bool:
if self.applies_to_context_menu(event):
return self.is_enabled(event, point)
return True
- def input(self, args: dict) -> Optional[sublime_plugin.TextInputHandler]:
+ def input(self, args: dict) -> sublime_plugin.TextInputHandler | None:
if "new_name" in args:
# Defer to "run" and trigger rename.
return None
@@ -154,8 +154,8 @@ def run(
edit: sublime.Edit,
new_name: str = "",
placeholder: str = "",
- event: Optional[dict] = None,
- point: Optional[int] = None
+ event: dict | None = None,
+ point: int | None = None
) -> None:
listener = self.get_listener()
if listener:
@@ -188,7 +188,7 @@ def _do_rename(self, position: int, new_name: str) -> None:
request = Request.rename(params, self.view, progress=True)
session.send_request(request, partial(self._on_rename_result_async, session))
- def _on_rename_result_async(self, session: Session, response: Optional[WorkspaceEdit]) -> None:
+ def _on_rename_result_async(self, session: Session, response: WorkspaceEdit | None) -> None:
if not response:
return session.window.status_message('Nothing to rename')
changes = parse_workspace_edit(response)
@@ -197,14 +197,14 @@ def _on_rename_result_async(self, session: Session, response: Optional[Workspace
session.apply_parsed_workspace_edits(changes)
return
total_changes = sum(map(len, changes.values()))
- message = "Replace {} occurrences across {} files?".format(total_changes, file_count)
+ message = f"Replace {total_changes} occurrences across {file_count} files?"
choice = sublime.yes_no_cancel_dialog(message, "Replace", "Preview", title="Rename")
if choice == sublime.DIALOG_YES:
session.apply_parsed_workspace_edits(changes)
elif choice == sublime.DIALOG_NO:
self._render_rename_panel(response, changes, total_changes, file_count, session.config.name)
- def _on_prepare_result(self, pos: int, response: Optional[PrepareRenameResult]) -> None:
+ def _on_prepare_result(self, pos: int, response: PrepareRenameResult | None) -> None:
if response is None:
sublime.error_message("The current selection cannot be renamed")
return
@@ -247,9 +247,9 @@ def _render_rename_panel(
panel = pm.ensure_rename_panel()
if not panel:
return
- to_render: List[str] = []
- reference_document: List[str] = []
- header_lines = "{} changes across {} files.\n".format(total_changes, file_count)
+ to_render: list[str] = []
+ reference_document: list[str] = []
+ header_lines = f"{total_changes} changes across {file_count} files.\n"
to_render.append(header_lines)
reference_document.append(header_lines)
ROWCOL_PREFIX = " {:>4}:{:<4} {}"
diff --git a/plugin/save_command.py b/plugin/save_command.py
index 7833f0f7a..1fa95b93e 100644
--- a/plugin/save_command.py
+++ b/plugin/save_command.py
@@ -3,7 +3,7 @@
from .core.settings import userprefs
from abc import ABCMeta, abstractmethod
from functools import partial
-from typing import Any, Callable, Dict, List, Optional, Type
+from typing import Any, Callable
import sublime
import sublime_plugin
@@ -33,7 +33,7 @@ def run_async(self) -> None:
def _on_timeout(self) -> None:
if not self._completed and not self._cancelled:
- self._set_view_status('LSP: Timeout processing {}'.format(self.__class__.__name__))
+ self._set_view_status(f'LSP: Timeout processing {self.__class__.__name__}')
self._cancelled = True
self._on_done()
@@ -64,12 +64,12 @@ def _purge_changes_async(self) -> None:
class SaveTasksRunner:
def __init__(
- self, text_command: LspTextCommand, tasks: List[Type[SaveTask]], on_complete: Callable[[], None]
+ self, text_command: LspTextCommand, tasks: list[type[SaveTask]], on_complete: Callable[[], None]
) -> None:
self._text_command = text_command
self._tasks = tasks
self._on_tasks_completed = on_complete
- self._pending_tasks: List[SaveTask] = []
+ self._pending_tasks: list[SaveTask] = []
self._canceled = False
def run(self) -> None:
@@ -108,18 +108,18 @@ class LspSaveCommand(LspTextCommand):
A command used as a substitute for native save command. Runs code actions and document
formatting before triggering the native save command.
"""
- _tasks: List[Type[SaveTask]] = []
+ _tasks: list[type[SaveTask]] = []
@classmethod
- def register_task(cls, task: Type[SaveTask]) -> None:
+ def register_task(cls, task: type[SaveTask]) -> None:
assert task not in cls._tasks
cls._tasks.append(task)
def __init__(self, view: sublime.View) -> None:
super().__init__(view)
- self._save_tasks_runner: Optional[SaveTasksRunner] = None
+ self._save_tasks_runner: SaveTasksRunner | None = None
- def run(self, edit: sublime.Edit, **kwargs: Dict[str, Any]) -> None:
+ def run(self, edit: sublime.Edit, **kwargs: dict[str, Any]) -> None:
if self._save_tasks_runner:
self._save_tasks_runner.cancel()
sublime.set_timeout_async(self._trigger_on_pre_save_async)
@@ -134,7 +134,7 @@ def _trigger_on_pre_save_async(self) -> None:
listener.trigger_on_pre_save_async() # type: ignore
break
- def _on_tasks_completed(self, kwargs: Dict[str, Any]) -> None:
+ def _on_tasks_completed(self, kwargs: dict[str, Any]) -> None:
self._save_tasks_runner = None
# Triggered from set_timeout to preserve original semantics of on_pre_save handling
sublime.set_timeout(lambda: self.view.run_command('save', kwargs))
diff --git a/plugin/selection_range.py b/plugin/selection_range.py
index 9d00171b3..911f08a04 100644
--- a/plugin/selection_range.py
+++ b/plugin/selection_range.py
@@ -5,7 +5,7 @@
from .core.registry import LspTextCommand
from .core.views import range_to_region
from .core.views import selection_range_params
-from typing import Any, List, Optional, Tuple
+from typing import Any
import sublime
@@ -15,18 +15,18 @@ class LspExpandSelectionCommand(LspTextCommand):
def __init__(self, view: sublime.View) -> None:
super().__init__(view)
- self._regions: List[sublime.Region] = []
+ self._regions: list[sublime.Region] = []
self._change_count = 0
- def is_enabled(self, event: Optional[dict] = None, point: Optional[int] = None, fallback: bool = False) -> bool:
+ def is_enabled(self, event: dict | None = None, point: int | None = None, fallback: bool = False) -> bool:
return fallback or super().is_enabled(event, point)
- def is_visible(self, event: Optional[dict] = None, point: Optional[int] = None, fallback: bool = False) -> bool:
+ def is_visible(self, event: dict | None = None, point: int | None = None, fallback: bool = False) -> bool:
if self.applies_to_context_menu(event):
return self.is_enabled(event, point, fallback)
return True
- def run(self, edit: sublime.Edit, event: Optional[dict] = None, fallback: bool = False) -> None:
+ def run(self, edit: sublime.Edit, event: dict | None = None, fallback: bool = False) -> None:
position = get_position(self.view, event)
if position is None:
return
@@ -37,9 +37,9 @@ def run(self, edit: sublime.Edit, event: Optional[dict] = None, fallback: bool =
self._change_count = self.view.change_count()
session.send_request(Request.selectionRange(params), self.on_result, self.on_error)
elif fallback:
- self._run_builtin_expand_selection("No {} found".format(self.capability))
+ self._run_builtin_expand_selection(f"No {self.capability} found")
- def on_result(self, params: Optional[List[SelectionRange]]) -> None:
+ def on_result(self, params: list[SelectionRange] | None) -> None:
if self._change_count != self.view.change_count():
return
if params:
@@ -59,10 +59,10 @@ def _status_message(self, msg: str) -> None:
window.status_message(msg)
def _run_builtin_expand_selection(self, fallback_reason: str) -> None:
- self._status_message("{}, reverting to built-in Expand Selection".format(fallback_reason))
+ self._status_message(f"{fallback_reason}, reverting to built-in Expand Selection")
self.view.run_command("expand_selection", {"to": "smart"})
- def _smallest_containing(self, region: sublime.Region, param: SelectionRange) -> Tuple[int, int]:
+ def _smallest_containing(self, region: sublime.Region, param: SelectionRange) -> tuple[int, int]:
r = range_to_region(param["range"], self.view)
# Test for *strict* containment
if r.contains(region) and (r.a < region.a or r.b > region.b):
diff --git a/plugin/semantic_highlighting.py b/plugin/semantic_highlighting.py
index 6aa0a31b8..c5cdcbbfb 100644
--- a/plugin/semantic_highlighting.py
+++ b/plugin/semantic_highlighting.py
@@ -1,6 +1,6 @@
from __future__ import annotations
from .core.registry import LspTextCommand
-from typing import Any, List, Tuple
+from typing import Any, List
from typing import cast
import sublime
import os
@@ -10,7 +10,7 @@ class SemanticToken:
__slots__ = ("region", "type", "modifiers")
- def __init__(self, region: sublime.Region, type: str, modifiers: List[str]):
+ def __init__(self, region: sublime.Region, type: str, modifiers: list[str]):
self.region = region
self.type = type
self.modifiers = modifiers
@@ -53,7 +53,7 @@ def run(self, _: sublime.Edit) -> None:
token_modifiers
)
- def _get_semantic_info(self, point: int) -> Tuple[str, str]:
+ def _get_semantic_info(self, point: int) -> tuple[str, str]:
session = self.best_session('semanticTokensProvider')
session_buffer = None
if session:
@@ -76,7 +76,7 @@ def _render_with_plain_string_stackframes(
self,
scope: str,
scope_list: str,
- stack: List[str],
+ stack: list[str],
token_type: str,
token_modifiers: str
) -> None:
@@ -93,7 +93,7 @@ def _render_with_plain_string_stackframes(
if backtrace:
backtrace += '\n'
- backtrace += '
%s%s
' % (nums, ctx)
+ backtrace += f'
{nums}{ctx}
'
html = """
@@ -139,7 +139,7 @@ def _render_with_fancy_stackframes(
self,
scope: str,
scope_list: str,
- stack: List[Any],
+ stack: list[Any],
token_type: str,
token_modifiers: str
) -> None:
@@ -168,11 +168,11 @@ def _render_with_fancy_stackframes(
else:
href = resource_path
location = display_path
- link = '
%s' % (href, location)
+ link = f'
{location}'
if backtrace:
backtrace += '\n'
- backtrace += '
%s%s%s
' % (nums, ctx, link)
+ backtrace += f'
{nums}{ctx}{link}
'
html = """
diff --git a/plugin/session_buffer.py b/plugin/session_buffer.py
index aab9c46ed..d8eb80df7 100644
--- a/plugin/session_buffer.py
+++ b/plugin/session_buffer.py
@@ -46,7 +46,7 @@
from .inlay_hint import LspToggleInlayHintsCommand
from .semantic_highlighting import SemanticToken
from functools import partial
-from typing import Any, Callable, Dict, Iterable, List, Optional, Protocol, Set, Tuple, Union
+from typing import Any, Callable, Iterable, List, Protocol
from typing import cast
from typing_extensions import TypeGuard
from weakref import WeakSet
@@ -87,13 +87,13 @@ class SemanticTokensData:
'data', 'result_id', 'active_region_keys', 'tokens', 'view_change_count', 'needs_refresh', 'pending_response')
def __init__(self) -> None:
- self.data: List[int] = []
- self.result_id: Optional[str] = None
- self.active_region_keys: Set[int] = set()
- self.tokens: List[SemanticToken] = []
+ self.data: list[int] = []
+ self.result_id: str | None = None
+ self.active_region_keys: set[int] = set()
+ self.tokens: list[SemanticToken] = []
self.view_change_count = 0
self.needs_refresh = False
- self.pending_response: Optional[int] = None
+ self.pending_response: int | None = None
class SessionBuffer:
@@ -115,21 +115,21 @@ def __init__(self, session_view: SessionViewProtocol, buffer_id: int, uri: Docum
self._session_views.add(session_view)
self._last_known_uri = uri
self._id = buffer_id
- self._pending_changes: Optional[PendingChanges] = None
- self.diagnostics: List[Tuple[Diagnostic, sublime.Region]] = []
+ self._pending_changes: PendingChanges | None = None
+ self.diagnostics: list[tuple[Diagnostic, sublime.Region]] = []
self.diagnostics_version = -1
self.diagnostics_flags = 0
self._diagnostics_are_visible = False
self.document_diagnostic_needs_refresh = False
- self._document_diagnostic_pending_response: Optional[int] = None
+ self._document_diagnostic_pending_response: int | None = None
self._last_synced_version = 0
self._last_text_change_time = 0.0
self._diagnostics_debouncer_async = DebouncerNonThreadSafe(async_thread=True)
self._workspace_diagnostics_debouncer_async = DebouncerNonThreadSafe(async_thread=True)
self._color_phantoms = sublime.PhantomSet(view, "lsp_color")
- self._document_links: List[DocumentLink] = []
+ self._document_links: list[DocumentLink] = []
self.semantic_tokens = SemanticTokensData()
- self._semantic_region_keys: Dict[str, int] = {}
+ self._semantic_region_keys: dict[str, int] = {}
self._last_semantic_region_key = 0
self._inlay_hints_phantom_set = sublime.PhantomSet(view, "lsp_inlay_hints")
self.inlay_hints_needs_refresh = False
@@ -146,7 +146,7 @@ def session_views(self) -> WeakSet[SessionViewProtocol]:
return self._session_views
@property
- def version(self) -> Optional[int]:
+ def version(self) -> int | None:
view = self.some_view()
return view.change_count() if view else None
@@ -174,12 +174,12 @@ def _check_did_close(self, view: sublime.View) -> None:
self.session.send_notification(did_close(uri=self._last_known_uri))
self.opened = False
- def get_uri(self) -> Optional[DocumentUri]:
+ def get_uri(self) -> DocumentUri | None:
for sv in self.session_views:
return sv.get_uri()
return None
- def get_language_id(self) -> Optional[str]:
+ def get_language_id(self) -> str | None:
for sv in self.session_views:
return sv.get_language_id()
return None
@@ -227,10 +227,10 @@ def register_capability_async(
registration_id: str,
capability_path: str,
registration_path: str,
- options: Dict[str, Any]
+ options: dict[str, Any]
) -> None:
self.capabilities.register(registration_id, capability_path, registration_path, options)
- view: Optional[sublime.View] = None
+ view: sublime.View | None = None
for sv in self.session_views:
sv.on_capability_added_async(registration_id, capability_path, options)
if view is None:
@@ -253,7 +253,7 @@ def unregister_capability_async(
for sv in self.session_views:
sv.on_capability_removed_async(registration_id, discarded)
- def get_capability(self, capability_path: str) -> Optional[Any]:
+ def get_capability(self, capability_path: str) -> Any | None:
if self.session.config.is_disabled_capability(capability_path):
return None
value = self.capabilities.get(capability_path)
@@ -273,7 +273,7 @@ def should_notify_did_open(self) -> bool:
def should_notify_will_save(self) -> bool:
return self.capabilities.should_notify_will_save() or self.session.should_notify_will_save()
- def should_notify_did_save(self) -> Tuple[bool, bool]:
+ def should_notify_did_save(self) -> tuple[bool, bool]:
do_it, include_text = self.capabilities.should_notify_did_save()
return (do_it, include_text) if do_it else self.session.should_notify_did_save()
@@ -377,7 +377,7 @@ def on_post_save_async(self, view: sublime.View, new_uri: DocumentUri) -> None:
self._has_changed_during_save = False
self._on_after_change_async(view, view.change_count())
- def some_view(self) -> Optional[sublime.View]:
+ def some_view(self) -> sublime.View | None:
if not self.session_views:
return None
# Prefer active view if possible
@@ -408,7 +408,7 @@ def _do_color_boxes_async(self, view: sublime.View, version: int) -> None:
self._if_view_unchanged(self._on_color_boxes_async, version)
)
- def _on_color_boxes_async(self, view: sublime.View, response: List[ColorInformation]) -> None:
+ def _on_color_boxes_async(self, view: sublime.View, response: list[ColorInformation]) -> None:
if response is None: # Guard against spec violation from certain language servers
self._color_phantoms.update([])
return
@@ -424,7 +424,7 @@ def _do_document_link_async(self, view: sublime.View, version: int) -> None:
self._if_view_unchanged(self._on_document_link_async, version)
)
- def _on_document_link_async(self, view: sublime.View, response: Optional[List[DocumentLink]]) -> None:
+ def _on_document_link_async(self, view: sublime.View, response: list[DocumentLink] | None) -> None:
self._document_links = response or []
if self._document_links and userprefs().link_highlight_style == "underline":
view.add_regions(
@@ -435,7 +435,7 @@ def _on_document_link_async(self, view: sublime.View, response: Optional[List[Do
else:
view.erase_regions("lsp_document_link")
- def get_document_link_at_point(self, view: sublime.View, point: int) -> Optional[DocumentLink]:
+ def get_document_link_at_point(self, view: sublime.View, point: int) -> DocumentLink | None:
for link in self._document_links:
if range_to_region(link["range"], view).contains(point):
return link
@@ -452,7 +452,7 @@ def update_document_link(self, new_link: DocumentLink) -> None:
# --- textDocument/diagnostic --------------------------------------------------------------------------------------
- def do_document_diagnostic_async(self, view: sublime.View, version: Optional[int] = None) -> None:
+ def do_document_diagnostic_async(self, view: sublime.View, version: int | None = None) -> None:
mgr = self.session.manager()
if not mgr:
return
@@ -481,7 +481,7 @@ def _on_document_diagnostic_async(self, version: int, response: DocumentDiagnost
self._if_view_unchanged(self._apply_document_diagnostic_async, version)(response)
def _apply_document_diagnostic_async(
- self, view: Optional[sublime.View], response: DocumentDiagnosticReport
+ self, view: sublime.View | None, response: DocumentDiagnosticReport
) -> None:
self.session.diagnostics_result_ids[self._last_known_uri] = response.get('resultId')
if is_full_document_diagnostic_report(response):
@@ -509,7 +509,7 @@ def set_document_diagnostic_pending_refresh(self, needs_refresh: bool = True) ->
# --- textDocument/publishDiagnostics ------------------------------------------------------------------------------
def on_diagnostics_async(
- self, raw_diagnostics: List[Diagnostic], version: Optional[int], visible_session_views: Set[SessionViewProtocol]
+ self, raw_diagnostics: list[Diagnostic], version: int | None, visible_session_views: set[SessionViewProtocol]
) -> None:
view = self.some_view()
if view is None:
@@ -520,8 +520,8 @@ def on_diagnostics_async(
if version != change_count:
return
diagnostics_version = version
- diagnostics: List[Tuple[Diagnostic, sublime.Region]] = []
- data_per_severity: Dict[Tuple[int, bool], DiagnosticSeverityData] = {}
+ diagnostics: list[tuple[Diagnostic, sublime.Region]] = []
+ data_per_severity: dict[tuple[int, bool], DiagnosticSeverityData] = {}
for diagnostic in raw_diagnostics:
region = range_to_region(diagnostic["range"], view)
severity = diagnostic_severity(diagnostic)
@@ -576,7 +576,7 @@ def do_semantic_tokens_async(self, view: sublime.View, only_viewport: bool = Fal
if self.semantic_tokens.pending_response:
self.session.cancel_request(self.semantic_tokens.pending_response)
self.semantic_tokens.view_change_count = view.change_count()
- params: Dict[str, Any] = {"textDocument": text_document_identifier(view)}
+ params: dict[str, Any] = {"textDocument": text_document_identifier(view)}
if only_viewport and self.has_capability("semanticTokensProvider.range"):
params["range"] = region_to_range(view, view.visible_region())
request = Request.semanticTokensRange(cast(SemanticTokensRangeParams, params), view)
@@ -597,18 +597,18 @@ def do_semantic_tokens_async(self, view: sublime.View, only_viewport: bool = Fal
self.semantic_tokens.pending_response = self.session.send_request_async(
request, self._on_semantic_tokens_async, self._on_semantic_tokens_error_async)
- def _on_semantic_tokens_async(self, response: Optional[Dict]) -> None:
+ def _on_semantic_tokens_async(self, response: dict | None) -> None:
self.semantic_tokens.pending_response = None
if response:
self.semantic_tokens.result_id = response.get("resultId")
self.semantic_tokens.data = response["data"]
self._draw_semantic_tokens_async()
- def _on_semantic_tokens_viewport_async(self, view: sublime.View, response: Optional[Dict]) -> None:
+ def _on_semantic_tokens_viewport_async(self, view: sublime.View, response: dict | None) -> None:
self._on_semantic_tokens_async(response)
self.do_semantic_tokens_async(view) # now request semantic tokens for the full file
- def _on_semantic_tokens_delta_async(self, response: Optional[Dict]) -> None:
+ def _on_semantic_tokens_delta_async(self, response: dict | None) -> None:
self.semantic_tokens.pending_response = None
if response:
self.semantic_tokens.result_id = response.get("resultId")
@@ -635,7 +635,7 @@ def _draw_semantic_tokens_async(self) -> None:
if view is None:
return
self.semantic_tokens.tokens.clear()
- scope_regions: Dict[int, Tuple[str, List[sublime.Region]]] = dict()
+ scope_regions: dict[int, tuple[str, list[sublime.Region]]] = dict()
prev_line = 0
prev_col_utf16 = 0
types_legend = tuple(cast(List[str], self.get_capability('semanticTokensProvider.legend.tokenTypes')))
@@ -662,13 +662,13 @@ def _draw_semantic_tokens_async(self) -> None:
# customizations in the color scheme for the scopes of custom token types would require a restart of
# Sublime Text to take effect.
token_general_style = view.style_for_scope("meta.semantic-token")
- token_type_style = view.style_for_scope("meta.semantic-token.{}".format(token_type.lower()))
+ token_type_style = view.style_for_scope(f"meta.semantic-token.{token_type.lower()}")
if token_general_style["source_line"] != token_type_style["source_line"] or \
token_general_style["source_column"] != token_type_style["source_column"]:
if token_modifiers:
- scope = "meta.semantic-token.{}.{}.lsp".format(token_type.lower(), token_modifiers[0].lower())
+ scope = f"meta.semantic-token.{token_type.lower()}.{token_modifiers[0].lower()}.lsp"
else:
- scope = "meta.semantic-token.{}.lsp".format(token_type.lower())
+ scope = f"meta.semantic-token.{token_type.lower()}.lsp"
self.semantic_tokens.tokens.append(SemanticToken(r, token_type, token_modifiers))
if scope:
scope_regions.setdefault(self._get_semantic_region_key_for_scope(scope), (scope, []))[1].append(r)
@@ -679,12 +679,12 @@ def _draw_semantic_tokens_async(self) -> None:
if region_key not in scope_regions.keys():
self.semantic_tokens.active_region_keys.remove(region_key)
for sv in self.session_views:
- sv.view.erase_regions("lsp_semantic_{}".format(region_key))
+ sv.view.erase_regions(f"lsp_semantic_{region_key}")
for region_key, (scope, regions) in scope_regions.items():
if region_key not in self.semantic_tokens.active_region_keys:
self.semantic_tokens.active_region_keys.add(region_key)
for sv in self.session_views:
- sv.view.add_regions("lsp_semantic_{}".format(region_key), regions, scope, flags=SEMANTIC_TOKEN_FLAGS)
+ sv.view.add_regions(f"lsp_semantic_{region_key}", regions, scope, flags=SEMANTIC_TOKEN_FLAGS)
def _get_semantic_region_key_for_scope(self, scope: str) -> int:
if scope not in self._semantic_region_keys:
@@ -694,12 +694,12 @@ def _get_semantic_region_key_for_scope(self, scope: str) -> int:
def _clear_semantic_token_regions(self, view: sublime.View) -> None:
for region_key in self.semantic_tokens.active_region_keys:
- view.erase_regions("lsp_semantic_{}".format(region_key))
+ view.erase_regions(f"lsp_semantic_{region_key}")
def set_semantic_tokens_pending_refresh(self, needs_refresh: bool = True) -> None:
self.semantic_tokens.needs_refresh = needs_refresh
- def get_semantic_tokens(self) -> List[SemanticToken]:
+ def get_semantic_tokens(self) -> list[SemanticToken]:
return self.semantic_tokens.tokens
# --- textDocument/inlayHint ----------------------------------------------------------------------------------
@@ -716,7 +716,7 @@ def do_inlay_hints_async(self, view: sublime.View) -> None:
}
self.session.send_request_async(Request.inlayHint(params, view), self._on_inlay_hints_async)
- def _on_inlay_hints_async(self, response: Union[List[InlayHint], None]) -> None:
+ def _on_inlay_hints_async(self, response: list[InlayHint] | None) -> None:
if response:
view = self.some_view()
if not view:
@@ -726,7 +726,7 @@ def _on_inlay_hints_async(self, response: Union[List[InlayHint], None]) -> None:
else:
sublime.set_timeout(lambda: self.remove_all_inlay_hints())
- def present_inlay_hints(self, phantoms: List[sublime.Phantom]) -> None:
+ def present_inlay_hints(self, phantoms: list[sublime.Phantom]) -> None:
self._inlay_hints_phantom_set.update(phantoms)
def set_inlay_hints_pending_refresh(self, needs_refresh: bool = True) -> None:
@@ -745,4 +745,4 @@ def remove_all_inlay_hints(self) -> None:
# ------------------------------------------------------------------------------------------------------------------
def __str__(self) -> str:
- return '{}:{}:{}'.format(self.session.config.name, self._id, self.get_uri())
+ return f'{self.session.config.name}:{self._id}:{self.get_uri()}'
diff --git a/plugin/session_view.py b/plugin/session_view.py
index 45c7bf75b..6d4d0c706 100644
--- a/plugin/session_view.py
+++ b/plugin/session_view.py
@@ -22,19 +22,19 @@
from .core.views import text_document_identifier
from .diagnostics import DiagnosticsAnnotationsView
from .session_buffer import SessionBuffer
-from typing import Any, Dict, Generator, Iterable, List, Optional, Tuple
+from typing import Any, Generator, Iterable
from weakref import ref
from weakref import WeakValueDictionary
import functools
import sublime
-DIAGNOSTIC_TAG_VALUES: List[int] = [v for (k, v) in DiagnosticTag.__dict__.items() if not k.startswith('_')]
+DIAGNOSTIC_TAG_VALUES: list[int] = [v for (k, v) in DiagnosticTag.__dict__.items() if not k.startswith('_')]
class TagData:
__slots__ = ('key', 'regions', 'scope')
- def __init__(self, key: str, regions: List[sublime.Region] = [], scope: str = '') -> None:
+ def __init__(self, key: str, regions: list[sublime.Region] = [], scope: str = '') -> None:
self.key = key
self.regions = regions
self.scope = scope
@@ -51,14 +51,14 @@ class SessionView:
TRIGGER_CHARACTERS_KEY = "completionProvider.triggerCharacters"
CODE_ACTIONS_KEY = "lsp_code_action"
- _session_buffers: WeakValueDictionary[Tuple[int, int], SessionBuffer] = WeakValueDictionary()
+ _session_buffers: WeakValueDictionary[tuple[int, int], SessionBuffer] = WeakValueDictionary()
def __init__(self, listener: AbstractViewListener, session: Session, uri: DocumentUri) -> None:
self._view = listener.view
self._session = session
self._diagnostic_annotations = DiagnosticsAnnotationsView(self._view, session.config.name)
self._initialize_region_keys()
- self._active_requests: Dict[int, ActiveRequest] = {}
+ self._active_requests: dict[int, ActiveRequest] = {}
self._listener = ref(listener)
self._code_lenses = CodeLensView(self._view)
self.code_lenses_needs_refresh = False
@@ -96,10 +96,10 @@ def on_before_remove(self) -> None:
self.session.unregister_session_view_async(self)
self.session.config.erase_view_status(self.view)
for severity in reversed(range(1, len(DIAGNOSTIC_SEVERITY) + 1)):
- self.view.erase_regions("{}_icon".format(self.diagnostics_key(severity, False)))
- self.view.erase_regions("{}_underline".format(self.diagnostics_key(severity, False)))
- self.view.erase_regions("{}_icon".format(self.diagnostics_key(severity, True)))
- self.view.erase_regions("{}_underline".format(self.diagnostics_key(severity, True)))
+ self.view.erase_regions(f"{self.diagnostics_key(severity, False)}_icon")
+ self.view.erase_regions(f"{self.diagnostics_key(severity, False)}_underline")
+ self.view.erase_regions(f"{self.diagnostics_key(severity, True)}_icon")
+ self.view.erase_regions(f"{self.diagnostics_key(severity, True)}_underline")
self.view.erase_regions("lsp_document_link")
self.session_buffer.remove_session_view(self)
listener = self.listener()
@@ -134,35 +134,35 @@ def _initialize_region_keys(self) -> None:
- gutter icons from region keys which were initialized _first_ are drawn
For more context, see https://github.com/sublimelsp/LSP/issues/1593.
"""
- keys: List[str] = []
+ keys: list[str] = []
r = [sublime.Region(0, 0)]
document_highlight_style = userprefs().document_highlight_style
hover_highlight_style = userprefs().hover_highlight_style
line_modes = ["m", "s"]
self.view.add_regions(self.CODE_ACTIONS_KEY, r) # code actions lightbulb icon should always be on top
for key in range(1, 100):
- keys.append("lsp_semantic_{}".format(key))
+ keys.append(f"lsp_semantic_{key}")
if document_highlight_style in ("background", "fill"):
for kind in DOCUMENT_HIGHLIGHT_KIND_NAMES.values():
for mode in line_modes:
- keys.append("lsp_highlight_{}{}".format(kind, mode))
+ keys.append(f"lsp_highlight_{kind}{mode}")
if hover_highlight_style in ("background", "fill"):
keys.append(HOVER_HIGHLIGHT_KEY)
for severity in range(1, 5):
for mode in line_modes:
for tag in range(1, 3):
- keys.append("lsp{}d{}{}_tags_{}".format(self.session.config.name, mode, severity, tag))
+ keys.append(f"lsp{self.session.config.name}d{mode}{severity}_tags_{tag}")
keys.append("lsp_document_link")
for severity in range(1, 5):
for mode in line_modes:
- keys.append("lsp{}d{}{}_icon".format(self.session.config.name, mode, severity))
+ keys.append(f"lsp{self.session.config.name}d{mode}{severity}_icon")
for severity in range(4, 0, -1):
for mode in line_modes:
- keys.append("lsp{}d{}{}_underline".format(self.session.config.name, mode, severity))
+ keys.append(f"lsp{self.session.config.name}d{mode}{severity}_underline")
if document_highlight_style in ("underline", "stippled"):
for kind in DOCUMENT_HIGHLIGHT_KIND_NAMES.values():
for mode in line_modes:
- keys.append("lsp_highlight_{}{}".format(kind, mode))
+ keys.append(f"lsp_highlight_{kind}{mode}")
if hover_highlight_style in ("underline", "stippled"):
keys.append(HOVER_HIGHLIGHT_KEY)
for key in keys:
@@ -182,7 +182,7 @@ def _setup_auto_complete_triggers(self, settings: sublime.Settings) -> None:
if isinstance(trigger_chars, list) or self.session.config.auto_complete_selector:
self._apply_auto_complete_triggers(settings, trigger_chars or [])
- def _register_auto_complete_triggers(self, registration_id: str, trigger_chars: List[str]) -> None:
+ def _register_auto_complete_triggers(self, registration_id: str, trigger_chars: list[str]) -> None:
"""Register trigger characters from a dynamic server registration."""
self._apply_auto_complete_triggers(self.view.settings(), trigger_chars, registration_id)
@@ -191,7 +191,7 @@ def _unregister_auto_complete_triggers(self, registration_id: str) -> None:
settings = self.view.settings()
triggers = settings.get(self.AC_TRIGGERS_KEY)
if isinstance(triggers, list):
- new_triggers: List[Dict[str, str]] = []
+ new_triggers: list[dict[str, str]] = []
name = self.session.config.name
for trigger in triggers:
if not isinstance(trigger, dict):
@@ -204,8 +204,8 @@ def _unregister_auto_complete_triggers(self, registration_id: str) -> None:
def _apply_auto_complete_triggers(
self,
settings: sublime.Settings,
- trigger_chars: List[str],
- registration_id: Optional[str] = None
+ trigger_chars: list[str],
+ registration_id: str | None = None
) -> None:
"""This method actually modifies the auto_complete_triggers entries for the view."""
selector = self.session.config.auto_complete_selector
@@ -224,7 +224,7 @@ def _apply_auto_complete_triggers(
if isinstance(registration_id, str):
# This key is not used by Sublime, but is used as a "breadcrumb" as well, for dynamic registrations.
trigger["registration_id"] = registration_id
- triggers: List[Dict[str, str]] = settings.get(self.AC_TRIGGERS_KEY) or []
+ triggers: list[dict[str, str]] = settings.get(self.AC_TRIGGERS_KEY) or []
triggers.append(trigger)
settings.set(self.AC_TRIGGERS_KEY, triggers)
@@ -248,22 +248,22 @@ def _decrement_hover_count(self) -> None:
def reset_show_definitions(self) -> None:
self.view.settings().erase(SHOW_DEFINITIONS_KEY)
- def get_uri(self) -> Optional[DocumentUri]:
+ def get_uri(self) -> DocumentUri | None:
listener = self.listener()
return listener.get_uri() if listener else None
- def get_language_id(self) -> Optional[str]:
+ def get_language_id(self) -> str | None:
listener = self.listener()
return listener.get_language_id() if listener else None
- def get_view_for_group(self, group: int) -> Optional[sublime.View]:
+ def get_view_for_group(self, group: int) -> sublime.View | None:
sheet = self.view.sheet()
return self.view if sheet and sheet.group() == group else None
- def get_capability_async(self, capability_path: str) -> Optional[Any]:
+ def get_capability_async(self, capability_path: str) -> Any | None:
return self.session_buffer.get_capability(capability_path)
- def on_capability_added_async(self, registration_id: str, capability_path: str, options: Dict[str, Any]) -> None:
+ def on_capability_added_async(self, registration_id: str, capability_path: str, options: dict[str, Any]) -> None:
if capability_path == self.HOVER_PROVIDER_KEY:
self._increment_hover_count()
elif capability_path.startswith(self.COMPLETION_PROVIDER_KEY):
@@ -275,7 +275,7 @@ def on_capability_added_async(self, registration_id: str, capability_path: str,
if listener:
listener.on_code_lens_capability_registered_async()
- def on_capability_removed_async(self, registration_id: str, discarded_capabilities: Dict[str, Any]) -> None:
+ def on_capability_removed_async(self, registration_id: str, discarded_capabilities: dict[str, Any]) -> None:
if self.HOVER_PROVIDER_KEY in discarded_capabilities:
self._decrement_hover_count()
elif self.COMPLETION_PROVIDER_KEY in discarded_capabilities:
@@ -292,14 +292,14 @@ def shutdown_async(self) -> None:
def diagnostics_key(self, severity: int, multiline: bool) -> str:
return "lsp{}d{}{}".format(self.session.config.name, "m" if multiline else "s", severity)
- def diagnostics_tag_scope(self, tag: int) -> Optional[str]:
+ def diagnostics_tag_scope(self, tag: int) -> str | None:
for k, v in DiagnosticTag.__dict__.items():
if v == tag:
- return 'markup.{}.lsp'.format(k.lower())
+ return f'markup.{k.lower()}.lsp'
return None
def present_diagnostics_async(
- self, is_view_visible: bool, data_per_severity: Dict[Tuple[int, bool], DiagnosticSeverityData]
+ self, is_view_visible: bool, data_per_severity: dict[tuple[int, bool], DiagnosticSeverityData]
) -> None:
flags = userprefs().diagnostics_highlight_style_flags() # for single lines
multiline_flags = None if userprefs().show_multiline_diagnostics_highlights else sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.NO_UNDO # noqa: E501
@@ -316,7 +316,7 @@ def present_diagnostics_async(
def _draw_diagnostics(
self,
- data_per_severity: Dict[Tuple[int, bool], DiagnosticSeverityData],
+ data_per_severity: dict[tuple[int, bool], DiagnosticSeverityData],
severity: int,
max_severity_level: int,
flags: int,
@@ -324,7 +324,7 @@ def _draw_diagnostics(
) -> None:
ICON_FLAGS = sublime.HIDE_ON_MINIMAP | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.NO_UNDO
key = self.diagnostics_key(severity, multiline)
- tags = {tag: TagData('{}_tags_{}'.format(key, tag)) for tag in DIAGNOSTIC_TAG_VALUES}
+ tags = {tag: TagData(f'{key}_tags_{tag}') for tag in DIAGNOSTIC_TAG_VALUES}
data = data_per_severity.get((severity, multiline))
if data and severity <= max_severity_level:
non_tag_regions = data.regions
@@ -336,11 +336,11 @@ def _draw_diagnostics(
tags[tag].scope = tag_scope
else:
non_tag_regions.extend(regions)
- self.view.add_regions("{}_icon".format(key), non_tag_regions, data.scope, data.icon, ICON_FLAGS)
- self.view.add_regions("{}_underline".format(key), non_tag_regions, data.scope, "", flags)
+ self.view.add_regions(f"{key}_icon", non_tag_regions, data.scope, data.icon, ICON_FLAGS)
+ self.view.add_regions(f"{key}_underline", non_tag_regions, data.scope, "", flags)
else:
- self.view.erase_regions("{}_icon".format(key))
- self.view.erase_regions("{}_underline".format(key))
+ self.view.erase_regions(f"{key}_icon")
+ self.view.erase_regions(f"{key}_underline")
for data in tags.values():
if data.regions:
self.view.add_regions(
@@ -354,7 +354,7 @@ def on_request_started_async(self, request_id: int, request: Request) -> None:
def on_request_finished_async(self, request_id: int) -> None:
self._active_requests.pop(request_id, None)
- def on_request_progress(self, request_id: int, params: Dict[str, Any]) -> None:
+ def on_request_progress(self, request_id: int, params: dict[str, Any]) -> None:
request = self._active_requests.get(request_id, None)
if request:
request.update_progress_async(params)
@@ -391,7 +391,7 @@ def start_code_lenses_async(self) -> None:
def clear_code_lenses_async(self) -> None:
self._code_lenses.clear_view()
- def _on_code_lenses_async(self, response: Optional[List[CodeLens]]) -> None:
+ def _on_code_lenses_async(self, response: list[CodeLens] | None) -> None:
if not self._is_listener_alive() or not isinstance(response, list):
return
self._code_lenses.handle_response(self.session.config.name, response)
@@ -405,7 +405,7 @@ def resolve_visible_code_lenses_async(self) -> None:
return
if self._code_lenses.is_empty():
return
- promises: List[Promise[None]] = [Promise.resolve(None)]
+ promises: list[Promise[None]] = [Promise.resolve(None)]
if self.get_capability_async('codeLensProvider.resolveProvider'):
for code_lens in self._code_lenses.unresolved_visible_code_lenses(self.view.visible_region()):
request = Request("codeLens/resolve", code_lens.data, self.view)
@@ -426,4 +426,4 @@ def get_resolved_code_lenses_for_region(self, region: sublime.Region) -> Generat
yield from self._code_lenses.get_resolved_code_lenses_for_region(region)
def __str__(self) -> str:
- return '{}:{}'.format(self.session.config.name, self.view.id())
+ return f'{self.session.config.name}:{self.view.id()}'
diff --git a/plugin/symbols.py b/plugin/symbols.py
index 6948e9b37..cb7b99452 100644
--- a/plugin/symbols.py
+++ b/plugin/symbols.py
@@ -19,7 +19,7 @@
from .core.views import offset_to_point
from .core.views import range_to_region
from .core.views import text_document_identifier
-from typing import Any, Dict, List, Optional, Tuple, TypedDict, Union
+from typing import Any, List, TypedDict
from typing import cast
from typing_extensions import NotRequired, TypeGuard
import functools
@@ -30,7 +30,7 @@
SUPPRESS_INPUT_SETTING_KEY = 'lsp_suppress_input'
-SYMBOL_KIND_NAMES: Dict[SymbolKind, str] = {
+SYMBOL_KIND_NAMES: dict[SymbolKind, str] = {
SymbolKind.File: "File",
SymbolKind.Module: "Module",
SymbolKind.Namespace: "Namespace",
@@ -80,14 +80,14 @@ def is_document_symbol_value(val: Any) -> TypeGuard[DocumentSymbolValue]:
def symbol_to_list_input_item(
- item: Union[DocumentSymbol, WorkspaceSymbol, SymbolInformation],
+ item: DocumentSymbol | WorkspaceSymbol | SymbolInformation,
hierarchy: str = '',
- session_name: Optional[str] = None
+ session_name: str | None = None
) -> sublime.ListInputItem:
name = item['name']
kind = item['kind']
st_kind = SYMBOL_KINDS.get(kind, sublime.KIND_AMBIGUOUS)
- details: List[str] = []
+ details: list[str] = []
deprecated = SymbolTag.Deprecated in (item.get('tags') or []) or item.get('deprecated', False)
value = {'kind': kind, 'deprecated': deprecated}
details_separator = " • "
@@ -142,14 +142,14 @@ def run(self, _: sublime.Edit) -> None:
class LspSelectionAddCommand(sublime_plugin.TextCommand):
- def run(self, _: sublime.Edit, regions: List[Tuple[int, int]]) -> None:
+ def run(self, _: sublime.Edit, regions: list[tuple[int, int]]) -> None:
for region in regions:
self.view.sel().add(sublime.Region(*region))
class LspSelectionSetCommand(sublime_plugin.TextCommand):
- def run(self, _: sublime.Edit, regions: List[Tuple[int, int]]) -> None:
+ def run(self, _: sublime.Edit, regions: list[tuple[int, int]]) -> None:
self.view.sel().clear()
for region in regions:
self.view.sel().add(sublime.Region(*region))
@@ -161,7 +161,7 @@ class LspDocumentSymbolsCommand(LspTextCommand):
def __init__(self, view: sublime.View) -> None:
super().__init__(view)
- self.items: List[sublime.ListInputItem] = []
+ self.items: list[sublime.ListInputItem] = []
self.kind = 0
self.cached = False
self.has_matching_symbols = True
@@ -169,9 +169,9 @@ def __init__(self, view: sublime.View) -> None:
def run(
self,
edit: sublime.Edit,
- event: Optional[Dict[str, Any]] = None,
+ event: dict[str, Any] | None = None,
kind: int = 0,
- index: Optional[int] = None
+ index: int | None = None
) -> None:
if index is None:
if not self.has_matching_symbols:
@@ -179,7 +179,7 @@ def run(
window = self.view.window()
if window:
kind_name = SYMBOL_KIND_NAMES.get(cast(SymbolKind, self.kind))
- window.status_message('No symbols of kind "{}" in this file'.format(kind_name))
+ window.status_message(f'No symbols of kind "{kind_name}" in this file')
return
self.kind = kind
session = self.best_session(self.capability)
@@ -189,7 +189,7 @@ def run(
session.send_request(
Request.documentSymbols(params, self.view), self.handle_response_async, self.handle_response_error)
- def input(self, args: dict) -> Optional[sublime_plugin.CommandInputHandler]:
+ def input(self, args: dict) -> sublime_plugin.CommandInputHandler | None:
if self.cached:
self.cached = False
if self.kind and not any(item.value['kind'] == self.kind for item in self.items):
@@ -208,7 +208,7 @@ def input(self, args: dict) -> Optional[sublime_plugin.CommandInputHandler]:
return DocumentSymbolsKindInputHandler(window, initial_value, self.view, self.items)
return None
- def handle_response_async(self, response: Union[List[DocumentSymbol], List[SymbolInformation], None]) -> None:
+ def handle_response_async(self, response: list[DocumentSymbol] | list[SymbolInformation] | None) -> None:
self.items.clear()
if response and self.view.is_valid():
if 'selectionRange' in response[0]:
@@ -234,7 +234,7 @@ def _reset_suppress_input(self) -> None:
def process_document_symbol_recursive(
self, item: DocumentSymbol, hierarchy: str = ''
- ) -> List[sublime.ListInputItem]:
+ ) -> list[sublime.ListInputItem]:
name = item['name']
name_hierarchy = hierarchy + " > " + name if hierarchy else name
items = [symbol_to_list_input_item(item, hierarchy)]
@@ -250,7 +250,7 @@ def __init__(
window: sublime.Window,
initial_value: sublime.ListInputItem,
view: sublime.View,
- items: List[sublime.ListInputItem],
+ items: list[sublime.ListInputItem],
) -> None:
super().__init__(window, initial_value)
self.view = view
@@ -264,7 +264,7 @@ def name(self) -> str:
def placeholder(self) -> str:
return "Symbol Kind"
- def get_list_items(self) -> Tuple[List[sublime.ListInputItem], int]:
+ def get_list_items(self) -> tuple[list[sublime.ListInputItem], int]:
items = [sublime.ListInputItem('All Kinds', 0, kind=sublime.KIND_AMBIGUOUS)]
items.extend([
sublime.ListInputItem(SYMBOL_KIND_NAMES[lsp_kind], lsp_kind, kind=st_kind)
@@ -281,7 +281,7 @@ def get_list_items(self) -> Tuple[List[sublime.ListInputItem], int]:
def confirm(self, text: int) -> None:
self.last_selected = text
- def next_input(self, args: dict) -> Optional[sublime_plugin.CommandInputHandler]:
+ def next_input(self, args: dict) -> sublime_plugin.CommandInputHandler | None:
kind = args.get('kind')
if kind is not None:
return DocumentSymbolsInputHandler(self.view, kind, self.items, self.old_selection)
@@ -290,7 +290,7 @@ def next_input(self, args: dict) -> Optional[sublime_plugin.CommandInputHandler]
class DocumentSymbolsInputHandler(sublime_plugin.ListInputHandler):
def __init__(
- self, view: sublime.View, kind: int, items: List[sublime.ListInputItem], old_selection: List[sublime.Region]
+ self, view: sublime.View, kind: int, items: list[sublime.ListInputItem], old_selection: list[sublime.Region]
) -> None:
super().__init__()
self.view = view
@@ -301,7 +301,7 @@ def __init__(
def name(self) -> str:
return 'index'
- def list_items(self) -> Tuple[List[sublime.ListInputItem], int]:
+ def list_items(self) -> tuple[list[sublime.ListInputItem], int]:
items = [item for item in self.items if not self.kind or item.value['kind'] == self.kind]
selected_index = 0
if self.old_selection:
@@ -315,7 +315,7 @@ def list_items(self) -> Tuple[List[sublime.ListInputItem], int]:
break
return items, selected_index
- def preview(self, text: Optional[DocumentSymbolValue]) -> Union[str, sublime.Html, None]:
+ def preview(self, text: DocumentSymbolValue | None) -> str | sublime.Html | None:
if is_document_symbol_value(text):
region = range_to_region(text['range'], self.view)
self.view.run_command('lsp_selection_set', {'regions': [(region.a, region.b)]})
@@ -346,7 +346,7 @@ def run(self, symbol: WorkspaceSymbolValue) -> None:
Request.resolveWorkspaceSymbol(symbol['workspaceSymbol']), # type: ignore
functools.partial(self._on_resolved_symbol_async, session_name))
- def input(self, args: Dict[str, Any]) -> Optional[sublime_plugin.ListInputHandler]:
+ def input(self, args: dict[str, Any]) -> sublime_plugin.ListInputHandler | None:
if 'symbol' not in args:
return WorkspaceSymbolsInputHandler(self, args)
return None
@@ -366,7 +366,7 @@ def name(self) -> str:
def placeholder(self) -> str:
return "Start typing to search"
- def preview(self, text: Optional[WorkspaceSymbolValue]) -> Union[str, sublime.Html, None]:
+ def preview(self, text: WorkspaceSymbolValue | None) -> str | sublime.Html | None:
if isinstance(text, dict) and text.get('deprecated'):
return "⚠ Deprecated"
return ""
@@ -376,7 +376,7 @@ def on_modified(self, text: str) -> None:
return
change_count = self.input_view.change_count()
self.command = cast(LspWindowCommand, self.command)
- promises: List[Promise[List[sublime.ListInputItem]]] = []
+ promises: list[Promise[list[sublime.ListInputItem]]] = []
for session in self.command.sessions():
promises.append(
session.send_request_task(Request.workspaceSymbol({"query": text}))
@@ -384,13 +384,13 @@ def on_modified(self, text: str) -> None:
Promise.all(promises).then(functools.partial(self._on_all_responses, change_count))
def _handle_response_async(
- self, session_name: str, response: Union[List[SymbolInformation], List[WorkspaceSymbol], None]
- ) -> List[sublime.ListInputItem]:
+ self, session_name: str, response: list[SymbolInformation] | list[WorkspaceSymbol] | None
+ ) -> list[sublime.ListInputItem]:
return [symbol_to_list_input_item(item, session_name=session_name) for item in response] if response else []
- def _on_all_responses(self, change_count: int, item_lists: List[List[sublime.ListInputItem]]) -> None:
+ def _on_all_responses(self, change_count: int, item_lists: list[list[sublime.ListInputItem]]) -> None:
if self.input_view and self.input_view.change_count() == change_count:
- items: List[sublime.ListInputItem] = []
+ items: list[sublime.ListInputItem] = []
for item_list in item_lists:
items.extend(item_list)
self.update(items)
diff --git a/plugin/tooling.py b/plugin/tooling.py
index f03d680a0..acfb42c0b 100644
--- a/plugin/tooling.py
+++ b/plugin/tooling.py
@@ -17,7 +17,7 @@
from base64 import b64decode
from base64 import b64encode
from subprocess import list2cmdline
-from typing import Any, Callable, Dict, List, Optional, Tuple
+from typing import Any, Callable
from typing import cast
import json
import mdpopups
@@ -29,7 +29,7 @@
import urllib.request
-def _translate_description(translations: Optional[Dict[str, str]], descr: str) -> Tuple[str, bool]:
+def _translate_description(translations: dict[str, str] | None, descr: str) -> tuple[str, bool]:
"""
Translate a placeholder description like "%foo.bar.baz" into an English translation. The translation map is
the first argument.
@@ -41,7 +41,7 @@ def _translate_description(translations: Optional[Dict[str, str]], descr: str) -
return descr, False
-def _preprocess_properties(translations: Optional[Dict[str, str]], properties: Dict[str, Any]) -> None:
+def _preprocess_properties(translations: dict[str, str] | None, properties: dict[str, Any]) -> None:
"""
Preprocess the server settings from a package.json file:
@@ -69,7 +69,7 @@ def _preprocess_properties(translations: Optional[Dict[str, str]], properties: D
if not isinstance(enums, list):
enums = v.get("markdownEnumDescriptions")
if isinstance(enums, list):
- new_enums: List[str] = []
+ new_enums: list[str] = []
for descr in enums:
descr, _ = _translate_description(translations, descr)
new_enums.append(descr)
@@ -94,7 +94,7 @@ def _preprocess_properties(translations: Optional[Dict[str, str]], properties: D
def _enum_to_str(value: Any) -> str:
if isinstance(value, str):
- return '"{}"'.format(value)
+ return f'"{value}"'
return str(value)
@@ -104,13 +104,13 @@ def initial_text(self) -> str:
return "foobar"
def preview(self, text: str) -> str:
- return "Suggested resource location: Packages/LSP-{0}/LSP-{0}.sublime-settings".format(text)
+ return f"Suggested resource location: Packages/LSP-{text}/LSP-{text}.sublime-settings"
class LspParseVscodePackageJson(sublime_plugin.ApplicationCommand):
def __init__(self) -> None:
- self.view: Optional[sublime.View] = None
+ self.view: sublime.View | None = None
def writeline(self, contents: str, indent: int = 0) -> None:
if self.view is not None:
@@ -119,7 +119,7 @@ def writeline(self, contents: str, indent: int = 0) -> None:
def writeline4(self, contents: str) -> None:
self.writeline(contents, indent=4)
- def input(self, args: Dict[str, Any]) -> Optional[sublime_plugin.CommandInputHandler]:
+ def input(self, args: dict[str, Any]) -> sublime_plugin.CommandInputHandler | None:
if "base_package_name" not in args:
return BasePackageNameInputHandler()
return None
@@ -138,7 +138,7 @@ def run(self, base_package_name: str) -> None:
try:
package = json.loads(urllib.request.urlopen(base_url).read().decode("utf-8"))
except Exception as ex:
- sublime.error_message('Unable to load "{}": {}'.format(base_url, ex))
+ sublime.error_message(f'Unable to load "{base_url}": {ex}')
return
# There might be a translations file as well.
@@ -186,7 +186,7 @@ def run(self, base_package_name: str) -> None:
if isinstance(description, str):
for line in description.splitlines():
for wrapped_line in textwrap.wrap(line, width=100 - 8 - 3):
- self.writeline4('// {}'.format(wrapped_line))
+ self.writeline4(f'// {wrapped_line}')
else:
self.writeline4('// unknown setting')
enum = v.get("enum")
@@ -210,16 +210,16 @@ def run(self, base_package_name: str) -> None:
elif typ == "number":
value = 0
else:
- self.writeline4('// UNKNOWN TYPE: {} <-- NEEDS ATTENTION'.format(typ))
+ self.writeline4(f'// UNKNOWN TYPE: {typ} <-- NEEDS ATTENTION')
value = ""
value_lines = json.dumps(value, ensure_ascii=False, indent=4).splitlines()
for index, line in enumerate(value_lines, 1):
is_last_line = index == len(value_lines)
terminator = ',' if is_last_line else ''
if index == 1:
- self.writeline4('"{}": {}{}'.format(k, line, terminator))
+ self.writeline4(f'"{k}": {line}{terminator}')
else:
- self.writeline4('{}{}'.format(line, terminator))
+ self.writeline4(f'{line}{terminator}')
self.writeline("}")
self.view.set_read_only(True)
self.view = None
@@ -235,10 +235,10 @@ def run(self, base_package_name: str) -> None:
"settings": [
{
"file_patterns": [
- "/LSP-{}.sublime-settings".format(base_package_name)
+ f"/LSP-{base_package_name}.sublime-settings"
],
"schema": {
- "$id": "sublime://settings/LSP-{}".format(base_package_name),
+ "$id": f"sublime://settings/LSP-{base_package_name}",
"definitions": {
"PluginConfig": {
"properties": {
@@ -254,7 +254,7 @@ def run(self, base_package_name: str) -> None:
"$ref": "sublime://settings/LSP-plugin-base"
},
{
- "$ref": "sublime://settings/LSP-{}#/definitions/PluginConfig".format(base_package_name) # noqa: E501
+ "$ref": f"sublime://settings/LSP-{base_package_name}#/definitions/PluginConfig" # noqa: E501
}
]
}
@@ -269,8 +269,8 @@ def run(self, base_package_name: str) -> None:
"properties": {
"LSP": {
"properties": {
- "LSP-{}".format(base_package_name): {
- "$ref": "sublime://settings/LSP-{}#/definitions/PluginConfig".format(base_package_name) # noqa: E501
+ f"LSP-{base_package_name}": {
+ "$ref": f"sublime://settings/LSP-{base_package_name}#/definitions/PluginConfig" # noqa: E501
}
}
}
@@ -312,12 +312,12 @@ def run(self) -> None:
wm.window.show_quick_panel(config_names, lambda index: self.on_selected(index, configs, active_view),
placeholder='Select server to troubleshoot')
- def on_selected(self, selected_index: int, configs: List[ClientConfig], active_view: sublime.View) -> None:
+ def on_selected(self, selected_index: int, configs: list[ClientConfig], active_view: sublime.View) -> None:
if selected_index == -1:
return
config = configs[selected_index]
output_sheet = mdpopups.new_html_sheet(
- self.window, 'Server: {}'.format(config.name), '# Running server test...',
+ self.window, f'Server: {config.name}', '# Running server test...',
css=css().sheets, wrapper_class=css().sheets_classname)
sublime.set_timeout_async(lambda: self.test_run_server_async(config, self.window, active_view, output_sheet))
@@ -328,40 +328,40 @@ def test_run_server_async(self, config: ClientConfig, window: sublime.Window,
lambda resolved_command, output, exit_code: self.update_sheet(
config, active_view, output_sheet, resolved_command, output, exit_code))
# Store the instance so that it's not GC'ed before it's finished.
- self.test_runner: Optional[ServerTestRunner] = server
+ self.test_runner: ServerTestRunner | None = server
- def update_sheet(self, config: ClientConfig, active_view: Optional[sublime.View], output_sheet: sublime.HtmlSheet,
- resolved_command: List[str], server_output: str, exit_code: int) -> None:
+ def update_sheet(self, config: ClientConfig, active_view: sublime.View | None, output_sheet: sublime.HtmlSheet,
+ resolved_command: list[str], server_output: str, exit_code: int) -> None:
self.test_runner = None
frontmatter = mdpopups.format_frontmatter({'allow_code_wrap': True})
contents = self.get_contents(config, active_view, resolved_command, server_output, exit_code)
# The href needs to be encoded to avoid having markdown parser ruin it.
copy_link = make_command_link('lsp_copy_to_clipboard_from_base64', '
Copy to clipboard',
{'contents': b64encode(contents.encode()).decode()})
- formatted = '{}{}\n{}'.format(frontmatter, copy_link, contents)
+ formatted = f'{frontmatter}{copy_link}\n{contents}'
mdpopups.update_html_sheet(output_sheet, formatted, css=css().sheets, wrapper_class=css().sheets_classname)
- def get_contents(self, config: ClientConfig, active_view: Optional[sublime.View], resolved_command: List[str],
+ def get_contents(self, config: ClientConfig, active_view: sublime.View | None, resolved_command: list[str],
server_output: str, exit_code: int) -> str:
lines = []
def line(s: str) -> None:
lines.append(s)
- line('# Troubleshooting: {}'.format(config.name))
+ line(f'# Troubleshooting: {config.name}')
line('## Version')
line(' - LSP: {}'.format('.'.join([str(n) for n in __version__])))
- line(' - Sublime Text: {}'.format(sublime.version()))
+ line(f' - Sublime Text: {sublime.version()}')
line('## Server Test Run')
- line(' - exit code: {}\n - output\n{}'.format(exit_code, self.code_block(server_output)))
+ line(f' - exit code: {exit_code}\n - output\n{self.code_block(server_output)}')
line('## Server Configuration')
- line(' - command\n{}'.format(self.json_dump(config.command)))
+ line(f' - command\n{self.json_dump(config.command)}')
line(' - shell command\n{}'.format(self.code_block(list2cmdline(resolved_command), 'sh')))
- line(' - selector\n{}'.format(self.code_block(config.selector)))
- line(' - priority_selector\n{}'.format(self.code_block(config.priority_selector)))
+ line(f' - selector\n{self.code_block(config.selector)}')
+ line(f' - priority_selector\n{self.code_block(config.priority_selector)}')
line(' - init_options')
line(self.json_dump(config.init_options.get()))
line(' - settings')
@@ -382,7 +382,7 @@ def line(s: str) -> None:
if isinstance(settings['syntax'], str):
syntax = sublime.syntax_from_path(settings['syntax'])
if syntax:
- line(' - base scope\n{}'.format(self.code_block(syntax.scope)))
+ line(f' - base scope\n{self.code_block(syntax.scope)}')
else:
line('no active view found!')
@@ -391,9 +391,9 @@ def line(s: str) -> None:
line(' - folders')
line(self.json_dump(window.folders()))
is_project = bool(window.project_file_name())
- line(' - is project: {}'.format(is_project))
+ line(f' - is project: {is_project}')
if is_project:
- line(' - project data:\n{}'.format(self.json_dump(window.project_data())))
+ line(f' - project data:\n{self.json_dump(window.project_data())}')
line('\n## LSP configuration\n')
lsp_settings_contents = self.read_resource('Packages/User/LSP.sublime-settings')
@@ -403,7 +403,7 @@ def line(s: str) -> None:
line('
')
line('## System PATH')
- lines += [' - {}'.format(p) for p in os.environ['PATH'].split(os.pathsep)]
+ lines += [f' - {p}' for p in os.environ['PATH'].split(os.pathsep)]
return '\n'.join(lines)
@@ -411,9 +411,9 @@ def json_dump(self, contents: Any) -> str:
return self.code_block(json.dumps(contents, indent=2, sort_keys=True, ensure_ascii=False), 'json')
def code_block(self, contents: str, lang: str = '') -> str:
- return '```{}\n{}\n```'.format(lang, contents)
+ return f'```{lang}\n{contents}\n```'
- def read_resource(self, path: str) -> Optional[str]:
+ def read_resource(self, path: str) -> str | None:
try:
return sublime.load_resource(path)
except Exception:
@@ -436,7 +436,7 @@ def run(self) -> None:
return
view = self.window.new_file()
view.set_scratch(True)
- view.set_name("Window {} configs".format(self.window.id()))
+ view.set_name(f"Window {self.window.id()} configs")
view.settings().set("word_wrap", False)
view.set_syntax_file("Packages/Python/Python.sublime-syntax")
for config in wm.get_config_manager().get_configs():
@@ -462,16 +462,16 @@ def run(self, edit: sublime.Edit) -> None:
v = wm.window.new_file()
v.set_scratch(True)
v.assign_syntax("Packages/Markdown/Markdown.sublime-settings")
- v.set_name("{} (capabilities)".format(os.path.basename(file_name)))
+ v.set_name(f"{os.path.basename(file_name)} (capabilities)")
def p(s: str) -> None:
v.run_command("append", {"characters": s + "\n"})
def print_capabilities(capabilities: Capabilities) -> str:
- return "```json\n{}\n```".format(json.dumps(capabilities.get(), indent=4, sort_keys=True))
+ return f"```json\n{json.dumps(capabilities.get(), indent=4, sort_keys=True)}\n```"
for sv in listener.session_views_async():
- p("# {}\n".format(sv.session.config.name))
+ p(f"# {sv.session.config.name}\n")
p("## Global capabilities\n")
p(print_capabilities(sv.session.capabilities) + "\n")
p("## View-specific capabilities\n")
@@ -492,12 +492,12 @@ def __init__(
config: ClientConfig,
window: sublime.Window,
initiating_view: sublime.View,
- on_close: Callable[[List[str], str, int], None]
+ on_close: Callable[[list[str], str, int], None]
) -> None:
self._on_close = on_close
- self._transport: Optional[Transport] = None
- self._resolved_command: List[str] = []
- self._stderr_lines: List[str] = []
+ self._transport: Transport | None = None
+ self._resolved_command: list[str] = []
+ self._stderr_lines: list[str] = []
try:
variables = extract_variables(window)
plugin_class = get_plugin(config.name)
@@ -512,7 +512,7 @@ def __init__(
variables.update(additional_variables)
cannot_start_reason = plugin_class.can_start(window, initiating_view, workspace_folders, config)
if cannot_start_reason:
- raise Exception('Plugin.can_start() prevented the start due to: {}'.format(cannot_start_reason))
+ raise Exception(f'Plugin.can_start() prevented the start due to: {cannot_start_reason}')
cwd = plugin_class.on_pre_start(window, initiating_view, workspace_folders, config)
if not cwd and workspace_folders:
cwd = workspace_folders[0].path
@@ -527,13 +527,13 @@ def force_close_transport(self) -> None:
if self._transport:
self._transport.close()
- def on_payload(self, payload: Dict[str, Any]) -> None:
+ def on_payload(self, payload: dict[str, Any]) -> None:
pass
def on_stderr_message(self, message: str) -> None:
self._stderr_lines.append(message)
- def on_transport_close(self, exit_code: int, exception: Optional[Exception]) -> None:
+ def on_transport_close(self, exit_code: int, exception: Exception | None) -> None:
self._transport = None
output = str(exception) if exception else '\n'.join(self._stderr_lines).rstrip()
sublime.set_timeout(lambda: self._on_close(self._resolved_command, output, exit_code))
@@ -541,10 +541,10 @@ def on_transport_close(self, exit_code: int, exception: Optional[Exception]) ->
class LspOnDoubleClickCommand(sublime_plugin.TextCommand):
click_count = 0
- prev_command: Optional[str] = None
- prev_args: Optional[Dict[Any, Any]] = None
+ prev_command: str | None = None
+ prev_args: dict[Any, Any] | None = None
- def run(self, edit: sublime.Edit, command: str, args: Dict[Any, Any]) -> None:
+ def run(self, edit: sublime.Edit, command: str, args: dict[Any, Any]) -> None:
if self.prev_command != command or self.prev_args != args:
self.click_count = 0
self.prev_command = command
diff --git a/scripts/release.py b/scripts/release.py
index 0c59872ed..765428781 100755
--- a/scripts/release.py
+++ b/scripts/release.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
from typing import Generator, List, Optional, Tuple
import argparse
@@ -14,7 +13,7 @@
MESSAGE_DIR = 'messages'
MESSAGE_PATH = os.path.join(PACKAGE_PATH, MESSAGE_DIR)
-with open(os.path.join(PACKAGE_PATH, '.release.json'), 'r') as f:
+with open(os.path.join(PACKAGE_PATH, '.release.json')) as f:
CONFIGURATION = json.load(f)
# Project configuration
@@ -25,12 +24,12 @@
# The prefix to use for release version number. For example with prefix "4000" the version will be "4000-x.y.z".
RELEASE_VERSION_PREFIX = CONFIGURATION['publish_version_prefix'] or ''
# The name of the settings file to get the release token from ("github_token" setting)
-SETTINGS = '{}.sublime-settings'.format(__package__)
+SETTINGS = f'{__package__}.sublime-settings'
PYTHON_VERSION_PATH = CONFIGURATION.get('python_version_path', None)
def get_message(fname: str) -> str:
- with open(fname, 'r', encoding='utf-8') as file:
+ with open(fname, encoding='utf-8') as file:
message = file.read()
return message
@@ -66,14 +65,15 @@ def parse_version(version: str) -> Tuple[int, int, int]:
match = re.match(
r'(?:(?P[^.-]+)\-)?(?P\d+)\.(?P\d+)\.(?P\d+)(?:-.+)?', version)
if match:
- prefix, major, minor, patch = match.groups()
+ _prefix, major, minor, patch = match.groups()
return int(major), int(minor), int(patch)
else:
return 0, 0, 0
+
def get_version_with_prefix(version: str) -> str:
if RELEASE_VERSION_PREFIX:
- return '{}-{}'.format(RELEASE_VERSION_PREFIX, version)
+ return f'{RELEASE_VERSION_PREFIX}-{version}'
return version
@@ -106,7 +106,7 @@ def build_release(args: argparse.Namespace) -> None:
put_message(os.path.join(PACKAGE_PATH, 'VERSION'), version)
if PYTHON_VERSION_PATH:
version_tuple = parse_version(version)
- put_message(PYTHON_VERSION_PATH, '__version__ = {}\n'.format(version_tuple))
+ put_message(PYTHON_VERSION_PATH, f'__version__ = {version_tuple}\n')
build_messages_json(history)
commit_release(version)
print("Release %s created!" % version)
@@ -121,16 +121,16 @@ def publish_release(args: argparse.Namespace) -> None:
version = get_message(os.path.join(PACKAGE_PATH, 'VERSION'))
version_with_prefix = get_version_with_prefix(version)
- repo_url = 'git@github.com:{}'.format(GITHUB_REPO)
+ repo_url = f'git@github.com:{GITHUB_REPO}'
# push release branch to server
git('push', repo_url, RELEASE_BRANCH)
# push tags to server
git('push', repo_url, 'tag', version_with_prefix)
# publish the release
- post_url = '/repos/{}/releases'.format(GITHUB_REPO)
+ post_url = f'/repos/{GITHUB_REPO}/releases'
headers = {
- 'Authorization': 'token {}'.format(args.token),
+ 'Authorization': f'token {args.token}',
'User-Agent': 'Sublime Text',
'Content-type': 'application/json',
}
@@ -166,7 +166,7 @@ def publish_release(args: argparse.Namespace) -> None:
"""
if __name__ == '__main__':
parser = argparse.ArgumentParser(
- description='Buils and Publishes {} Releases'.format(__package__))
+ description=f'Buils and Publishes {__package__} Releases')
subparsers = parser.add_subparsers(help='Available commands')
build_parser = subparsers.add_parser('build', help='Build a release')
build_parser.set_defaults(func=build_release)
diff --git a/tests/server.py b/tests/server.py
index 123f651bc..38c5960d3 100644
--- a/tests/server.py
+++ b/tests/server.py
@@ -23,7 +23,7 @@
from __future__ import annotations
from argparse import ArgumentParser
from enum import IntEnum
-from typing import Any, Callable, Dict, List, Optional, Tuple, Union, Iterable, Awaitable
+from typing import Any, Callable, Dict, List, Union, Iterable, Awaitable
import asyncio
import json
import os
@@ -111,14 +111,14 @@ def dump(payload: PayloadLike) -> bytes:
separators=(",", ":")).encode(ENCODING)
-def content_length(line: bytes) -> Optional[int]:
+def content_length(line: bytes) -> int | None:
if line.startswith(b'Content-Length: '):
_, value = line.split(b'Content-Length: ')
value = value.strip()
try:
return int(value)
except ValueError:
- raise ValueError("Invalid Content-Length header: {}".format(value))
+ raise ValueError(f"Invalid Content-Length header: {value}")
return None
@@ -147,7 +147,7 @@ class SimpleRequest(Request):
def __init__(self) -> None:
self.cv = asyncio.Condition()
self.result: PayloadLike = None
- self.error: Optional[Error] = None
+ self.error: Error | None = None
async def on_result(self, params: PayloadLike) -> None:
self.result = params
@@ -166,16 +166,16 @@ def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -
self._reader = reader
self._writer = writer
- self._response_handlers: Dict[Any, Request] = {}
- self._request_handlers: Dict[str, Callable[[PayloadLike], Awaitable[PayloadLike]]] = {}
- self._notification_handlers: Dict[str, Callable[[PayloadLike], Awaitable[None]]] = {}
+ self._response_handlers: dict[Any, Request] = {}
+ self._request_handlers: dict[str, Callable[[PayloadLike], Awaitable[PayloadLike]]] = {}
+ self._notification_handlers: dict[str, Callable[[PayloadLike], Awaitable[None]]] = {}
# initialize/shutdown/exit dance
self._received_shutdown = False
# properties used for testing purposes
- self._responses: List[Tuple[str, PayloadLike]] = []
- self._received: Dict[str, PayloadLike] = {}
+ self._responses: list[tuple[str, PayloadLike]] = []
+ self._received: dict[str, PayloadLike] = {}
self._received_cv = asyncio.Condition()
self._install_handlers()
@@ -245,8 +245,8 @@ def _on_request(self, request_method: str, handler: Callable[[PayloadLike], Awai
def _on_notification(self, notification_method: str, handler: Callable[[PayloadLike], Awaitable[None]]) -> None:
self._notification_handlers[notification_method] = handler
- async def _handle(self, typestr: str, message: Dict[str, Any], handlers: Dict[str, Callable],
- request_id: Optional[int]) -> None:
+ async def _handle(self, typestr: str, message: dict[str, Any], handlers: dict[str, Callable],
+ request_id: int | None) -> None:
method = message.get("method", "")
params = message.get("params")
unhandled = True
@@ -263,7 +263,7 @@ async def _handle(self, typestr: str, message: Dict[str, Any], handlers: Dict[st
self._reply(request_id, mocked_response)
elif request_id is not None:
self._error(request_id, Error(
- ErrorCode.MethodNotFound, "method '{}' not found".format(method)))
+ ErrorCode.MethodNotFound, f"method '{method}' not found"))
else:
if unhandled:
self._log(f"unhandled {typestr} {method}")
@@ -285,7 +285,7 @@ async def _handle(self, typestr: str, message: Dict[str, Any], handlers: Dict[st
if not self._received_shutdown:
self._notify("window/logMessage", {"type": MessageType.error, "message": str(ex)})
- def _get_mocked_response(self, method: str) -> Union[PayloadLike, bool]:
+ def _get_mocked_response(self, method: str) -> PayloadLike | bool:
for response in self._responses:
resp_method, resp_payload = response
if resp_method == method:
@@ -296,7 +296,7 @@ def _get_mocked_response(self, method: str) -> Union[PayloadLike, bool]:
async def _handle_body(self, body: bytes) -> None:
try:
await self._receive_payload(json.loads(body))
- except IOError as ex:
+ except OSError as ex:
self._log(f"malformed {ENCODING}: {ex}")
except UnicodeDecodeError as ex:
self._log(f"malformed {ENCODING}: {ex}")
@@ -357,7 +357,7 @@ async def _send_notification(self, params: PayloadLike) -> PayloadLike:
return None
async def _get_received(self, params: PayloadLike) -> PayloadLike:
- method, payload = self._validate_request_params(params)
+ method, _payload = self._validate_request_params(params)
async with self._received_cv:
while True:
try:
@@ -370,7 +370,7 @@ async def _fake_request(self, params: PayloadLike) -> PayloadLike:
method, payload = self._validate_request_params(params)
return await self.request(method, payload)
- def _validate_request_params(self, params: PayloadLike) -> Tuple[str, Optional[Union[Dict, List]]]:
+ def _validate_request_params(self, params: PayloadLike) -> tuple[str, dict | list | None]:
if not isinstance(params, dict):
raise Error(ErrorCode.InvalidParams, "expected params to be a dictionary")
if "method" not in params:
@@ -402,7 +402,7 @@ async def _on_exit(self, params: PayloadLike) -> None:
# START: https://stackoverflow.com/a/52702646/990142
-async def stdio() -> Tuple[asyncio.StreamReader, asyncio.StreamWriter]:
+async def stdio() -> tuple[asyncio.StreamReader, asyncio.StreamWriter]:
loop = asyncio.get_event_loop()
if sys.platform == 'win32':
return _win32_stdio(loop)
@@ -410,7 +410,7 @@ async def stdio() -> Tuple[asyncio.StreamReader, asyncio.StreamWriter]:
return await _unix_stdio(loop)
-async def _unix_stdio(loop: asyncio.AbstractEventLoop) -> Tuple[asyncio.StreamReader, asyncio.StreamWriter]:
+async def _unix_stdio(loop: asyncio.AbstractEventLoop) -> tuple[asyncio.StreamReader, asyncio.StreamWriter]:
reader = asyncio.StreamReader(loop=loop)
def reader_factory() -> asyncio.StreamReaderProtocol:
@@ -426,7 +426,7 @@ def writer_factory() -> asyncio.streams.FlowControlMixin:
return reader, writer
-def _win32_stdio(loop: asyncio.AbstractEventLoop) -> Tuple[asyncio.StreamReader, asyncio.StreamWriter]:
+def _win32_stdio(loop: asyncio.AbstractEventLoop) -> tuple[asyncio.StreamReader, asyncio.StreamWriter]:
# no support for asyncio stdio yet on Windows, see https://bugs.python.org/issue26832
# use an executor to read from stdin and write to stdout
@@ -436,7 +436,7 @@ class Reader:
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
self.loop = loop
self.stdin = sys.stdin.buffer
- self.__exception: Optional[Exception] = None
+ self.__exception: Exception | None = None
def at_eof(self) -> bool:
return self.__exception is not None
@@ -461,7 +461,7 @@ class Writer:
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
self.loop = loop
- self.buffer: List[bytes] = []
+ self.buffer: list[bytes] = []
self.stdout = sys.stdout.buffer
def write(self, data: bytes) -> None:
@@ -483,7 +483,7 @@ def do_blocking_drain() -> None:
# END: https://stackoverflow.com/a/52702646/990142
-async def main(tcp_port: Optional[int] = None) -> bool:
+async def main(tcp_port: int | None = None) -> bool:
if tcp_port is not None:
class ClientConnectedCallback:
diff --git a/tests/setup.py b/tests/setup.py
index 95c382b30..6d3a17b62 100644
--- a/tests/setup.py
+++ b/tests/setup.py
@@ -10,7 +10,7 @@
from os.path import join
from sublime_plugin import view_event_listeners
from test_mocks import basic_responses
-from typing import Any, Dict, Generator, List, Optional, Tuple, Union
+from typing import Any, Generator
from unittesting import DeferrableTestCase
import sublime
@@ -18,16 +18,11 @@
CI = any(key in environ for key in ("TRAVIS", "CI", "GITHUB_ACTIONS"))
TIMEOUT_TIME = 10000 if CI else 2000
-text_config = ClientConfig(
- name="textls",
- selector="text.plain",
- command=[],
- tcp_port=None)
+text_config = ClientConfig(name="textls", selector="text.plain", command=[], tcp_port=None)
class YieldPromise:
-
- __slots__ = ('__done', '__result')
+ __slots__ = ("__done", "__result")
def __init__(self) -> None:
self.__done = False
@@ -49,7 +44,8 @@ def make_stdio_test_config() -> ClientConfig:
name="TEST",
command=["python3", join("$packages", "LSP", "tests", "server.py")],
selector="text.plain",
- enabled=True)
+ enabled=True,
+ )
def make_tcp_test_config() -> ClientConfig:
@@ -58,7 +54,8 @@ def make_tcp_test_config() -> ClientConfig:
command=["python3", join("$packages", "LSP", "tests", "server.py"), "--tcp-port", "$port"],
selector="text.plain",
tcp_port=0, # select a free one for me
- enabled=True)
+ enabled=True,
+ )
def add_config(config):
@@ -69,7 +66,7 @@ def remove_config(config):
client_configs.remove_for_testing(config)
-def close_test_view(view: Optional[sublime.View]) -> Generator:
+def close_test_view(view: sublime.View | None) -> Generator:
if view:
view.set_scratch(True)
yield {"condition": lambda: not view.is_loading(), "timeout": TIMEOUT_TIME}
@@ -81,7 +78,6 @@ def expand(s: str, w: sublime.Window) -> str:
class TextDocumentTestCase(DeferrableTestCase):
-
@classmethod
def get_stdio_test_config(cls) -> ClientConfig:
return make_stdio_test_config()
@@ -92,7 +88,7 @@ def setUpClass(cls) -> Generator:
test_name = cls.get_test_name()
server_capabilities = cls.get_test_server_capabilities()
window = sublime.active_window()
- filename = expand(join("$packages", "LSP", "tests", "{}.txt".format(test_name)), window)
+ filename = expand(join("$packages", "LSP", "tests", f"{test_name}.txt"), window)
open_view = window.find_open_file(filename)
yield from close_test_view(open_view)
cls.config = cls.get_stdio_test_config()
@@ -102,9 +98,7 @@ def setUpClass(cls) -> Generator:
cls.view = window.open_file(filename)
yield {"condition": lambda: not cls.view.is_loading(), "timeout": TIMEOUT_TIME}
yield cls.ensure_document_listener_created
- yield {
- "condition": lambda: cls.wm.get_session(cls.config.name, filename) is not None,
- "timeout": TIMEOUT_TIME}
+ yield {"condition": lambda: cls.wm.get_session(cls.config.name, filename) is not None, "timeout": TIMEOUT_TIME}
cls.session = cls.wm.get_session(cls.config.name, filename)
yield {"condition": lambda: cls.session.state == ClientStates.READY, "timeout": TIMEOUT_TIME}
cls.initialize_params = yield from cls.await_message("initialize")
@@ -113,7 +107,7 @@ def setUpClass(cls) -> Generator:
def setUp(self) -> Generator:
window = sublime.active_window()
- filename = expand(join("$packages", "LSP", "tests", "{}.txt".format(self.get_test_name())), window)
+ filename = expand(join("$packages", "LSP", "tests", f"{self.get_test_name()}.txt"), window)
open_view = window.find_open_file(filename)
if not open_view:
self.__class__.view = window.open_file(filename)
@@ -122,7 +116,7 @@ def setUp(self) -> Generator:
self.init_view_settings()
yield self.ensure_document_listener_created
params = yield from self.await_message("textDocument/didOpen")
- self.assertEquals(params['textDocument']['version'], 0)
+ self.assertEqual(params["textDocument"]["version"], 0)
@classmethod
def get_test_name(cls) -> str:
@@ -157,7 +151,7 @@ def ensure_document_listener_created(cls) -> bool:
return False
@classmethod
- def await_message(cls, method: str, promise: Optional[YieldPromise] = None) -> Generator:
+ def await_message(cls, method: str, promise: YieldPromise | None = None) -> Generator:
"""
Awaits until server receives a request with a specified method.
@@ -199,7 +193,7 @@ def on_error(params: Any) -> None:
return promise
@classmethod
- def await_promise(cls, promise: Union[YieldPromise, Promise]) -> Generator:
+ def await_promise(cls, promise: YieldPromise | Promise) -> Generator:
if isinstance(promise, YieldPromise):
yielder = promise
else:
@@ -208,11 +202,13 @@ def await_promise(cls, promise: Union[YieldPromise, Promise]) -> Generator:
yield {"condition": yielder, "timeout": TIMEOUT_TIME}
return yielder.result()
- def await_run_code_action(self, code_action: Dict[str, Any]) -> Generator:
+ def await_run_code_action(self, code_action: dict[str, Any]) -> Generator:
promise = YieldPromise()
sublime.set_timeout_async(
- lambda: self.session.run_code_action_async(code_action, progress=False, view=self.view)
- .then(promise.fulfill))
+ lambda: self.session.run_code_action_async(code_action, progress=False, view=self.view).then(
+ promise.fulfill
+ )
+ )
yield from self.await_promise(promise)
def set_response(self, method: str, response: Any) -> None:
@@ -220,7 +216,7 @@ def set_response(self, method: str, response: Any) -> None:
assert self.session # mypy
self.session.send_notification(Notification("$test/setResponse", {"method": method, "response": response}))
- def set_responses(self, responses: List[Tuple[str, Any]]) -> Generator:
+ def set_responses(self, responses: list[tuple[str, Any]]) -> Generator:
self.assertIsNotNone(self.session)
assert self.session # mypy
promise = YieldPromise()
@@ -251,7 +247,7 @@ def error_handler(params: Any) -> None:
yield from self.await_promise(promise)
def await_clear_view_and_save(self) -> Generator:
- assert self.view # type: Optional[sublime.View]
+ assert isinstance(self.view, sublime.View)
self.view.run_command("select_all")
self.view.run_command("left_delete")
self.view.run_command("save")
@@ -259,7 +255,7 @@ def await_clear_view_and_save(self) -> Generator:
yield from self.await_message("textDocument/didSave")
def await_view_change(self, expected_change_count: int) -> Generator:
- assert self.view # type: Optional[sublime.View]
+ assert isinstance(self.view, sublime.View)
def condition() -> bool:
nonlocal self
@@ -271,7 +267,7 @@ def condition() -> bool:
yield {"condition": condition, "timeout": TIMEOUT_TIME}
def insert_characters(self, characters: str) -> int:
- assert self.view # type: Optional[sublime.View]
+ assert isinstance(self.view, sublime.View)
self.view.run_command("insert", {"characters": characters})
return self.view.change_count()
diff --git a/tests/test_code_actions.py b/tests/test_code_actions.py
index 6ca704895..7932d6004 100644
--- a/tests/test_code_actions.py
+++ b/tests/test_code_actions.py
@@ -9,14 +9,14 @@
from LSP.plugin.core.views import versioned_text_document_identifier
from setup import TextDocumentTestCase
from test_single_document import TEST_FILE_PATH
-from typing import Any, Dict, Generator, List, Optional, Tuple
+from typing import Any, Generator
import unittest
import sublime
TEST_FILE_URI = filename_to_uri(TEST_FILE_PATH)
-def edit_to_lsp(edit: Tuple[str, Range]) -> Dict[str, Any]:
+def edit_to_lsp(edit: tuple[str, Range]) -> dict[str, Any]:
return {"newText": edit[0], "range": edit[1]}
@@ -27,7 +27,7 @@ def range_from_points(start: Point, end: Point) -> Range:
}
-def create_code_action_edit(view: sublime.View, version: int, edits: List[Tuple[str, Range]]) -> Dict[str, Any]:
+def create_code_action_edit(view: sublime.View, version: int, edits: list[tuple[str, Range]]) -> dict[str, Any]:
return {
"documentChanges": [
{
@@ -38,15 +38,15 @@ def create_code_action_edit(view: sublime.View, version: int, edits: List[Tuple[
}
-def create_command(command_name: str, command_args: Optional[List[Any]] = None) -> Dict[str, Any]:
- result: Dict[str, Any] = {"command": command_name}
+def create_command(command_name: str, command_args: list[Any] | None = None) -> dict[str, Any]:
+ result: dict[str, Any] = {"command": command_name}
if command_args is not None:
result["arguments"] = command_args
return result
-def create_test_code_action(view: sublime.View, version: int, edits: List[Tuple[str, Range]],
- kind: Optional[str] = None) -> Dict[str, Any]:
+def create_test_code_action(view: sublime.View, version: int, edits: list[tuple[str, Range]],
+ kind: str | None = None) -> dict[str, Any]:
action = {
"title": "Fix errors",
"edit": create_code_action_edit(view, version, edits)
@@ -56,8 +56,8 @@ def create_test_code_action(view: sublime.View, version: int, edits: List[Tuple[
return action
-def create_test_code_action2(command_name: str, command_args: Optional[List[Any]] = None,
- kind: Optional[str] = None) -> Dict[str, Any]:
+def create_test_code_action2(command_name: str, command_args: list[Any] | None = None,
+ kind: str | None = None) -> dict[str, Any]:
action = {
"title": "Fix errors",
"command": create_command(command_name, command_args)
@@ -67,7 +67,7 @@ def create_test_code_action2(command_name: str, command_args: Optional[List[Any]
return action
-def create_disabled_code_action(view: sublime.View, version: int, edits: List[Tuple[str, Range]]) -> Dict[str, Any]:
+def create_disabled_code_action(view: sublime.View, version: int, edits: list[tuple[str, Range]]) -> dict[str, Any]:
action = {
"title": "Fix errors",
"edit": create_code_action_edit(view, version, edits),
@@ -78,8 +78,8 @@ def create_disabled_code_action(view: sublime.View, version: int, edits: List[Tu
return action
-def create_test_diagnostics(diagnostics: List[Tuple[str, Range]]) -> Dict:
- def diagnostic_to_lsp(diagnostic: Tuple[str, Range]) -> Dict:
+def create_test_diagnostics(diagnostics: list[tuple[str, Range]]) -> dict:
+ def diagnostic_to_lsp(diagnostic: tuple[str, Range]) -> dict:
message, range = diagnostic
return {
"message": message,
@@ -122,8 +122,8 @@ def test_applies_matching_kind(self) -> Generator:
self.view.run_command('lsp_save', {'async': True})
yield from self.await_message('textDocument/codeAction')
yield from self.await_message('textDocument/didSave')
- self.assertEquals(entire_content(self.view), 'const x = 1;')
- self.assertEquals(self.view.is_dirty(), False)
+ self.assertEqual(entire_content(self.view), 'const x = 1;')
+ self.assertEqual(self.view.is_dirty(), False)
def test_requests_with_diagnostics(self) -> Generator:
yield from self._setup_document_with_missing_semicolon()
@@ -137,11 +137,11 @@ def test_requests_with_diagnostics(self) -> Generator:
self.set_response('textDocument/codeAction', [code_action])
self.view.run_command('lsp_save', {'async': True})
code_action_request = yield from self.await_message('textDocument/codeAction')
- self.assertEquals(len(code_action_request['context']['diagnostics']), 1)
- self.assertEquals(code_action_request['context']['diagnostics'][0]['message'], 'Missing semicolon')
+ self.assertEqual(len(code_action_request['context']['diagnostics']), 1)
+ self.assertEqual(code_action_request['context']['diagnostics'][0]['message'], 'Missing semicolon')
yield from self.await_message('textDocument/didSave')
- self.assertEquals(entire_content(self.view), 'const x = 1;')
- self.assertEquals(self.view.is_dirty(), False)
+ self.assertEqual(entire_content(self.view), 'const x = 1;')
+ self.assertEqual(self.view.is_dirty(), False)
def test_applies_only_one_pass(self) -> Generator:
self.insert_characters('const x = 1')
@@ -180,7 +180,7 @@ def test_applies_only_one_pass(self) -> Generator:
self.view.run_command('lsp_save', {'async': True})
# Wait for the view to be saved
yield lambda: not self.view.is_dirty()
- self.assertEquals(entire_content(self.view), 'const x = 1;')
+ self.assertEqual(entire_content(self.view), 'const x = 1;')
def test_applies_immediately_after_text_change(self) -> Generator:
self.insert_characters('const x = 1')
@@ -195,16 +195,16 @@ def test_applies_immediately_after_text_change(self) -> Generator:
self.view.run_command('lsp_save', {'async': True})
yield from self.await_message('textDocument/codeAction')
yield from self.await_message('textDocument/didSave')
- self.assertEquals(entire_content(self.view), 'const x = 1;')
- self.assertEquals(self.view.is_dirty(), False)
+ self.assertEqual(entire_content(self.view), 'const x = 1;')
+ self.assertEqual(self.view.is_dirty(), False)
def test_no_fix_on_non_matching_kind(self) -> Generator:
yield from self._setup_document_with_missing_semicolon()
initial_content = 'const x = 1'
self.view.run_command('lsp_save', {'async': True})
yield from self.await_message('textDocument/didSave')
- self.assertEquals(entire_content(self.view), initial_content)
- self.assertEquals(self.view.is_dirty(), False)
+ self.assertEqual(entire_content(self.view), initial_content)
+ self.assertEqual(self.view.is_dirty(), False)
def test_does_not_apply_unsupported_kind(self) -> Generator:
yield from self._setup_document_with_missing_semicolon()
@@ -218,7 +218,7 @@ def test_does_not_apply_unsupported_kind(self) -> Generator:
self.set_response('textDocument/codeAction', [code_action])
self.view.run_command('lsp_save', {'async': True})
yield from self.await_message('textDocument/didSave')
- self.assertEquals(entire_content(self.view), 'const x = 1')
+ self.assertEqual(entire_content(self.view), 'const x = 1')
def _setup_document_with_missing_semicolon(self) -> Generator:
self.insert_characters('const x = 1')
@@ -234,23 +234,23 @@ def _setup_document_with_missing_semicolon(self) -> Generator:
class CodeActionMatchingTestCase(unittest.TestCase):
def test_does_not_match(self) -> None:
actual = get_matching_on_save_kinds({'a.x': True}, ['a.b'])
- expected: List[str] = []
- self.assertEquals(actual, expected)
+ expected: list[str] = []
+ self.assertEqual(actual, expected)
def test_matches_exact_action(self) -> None:
actual = get_matching_on_save_kinds({'a.b': True}, ['a.b'])
expected = ['a.b']
- self.assertEquals(actual, expected)
+ self.assertEqual(actual, expected)
def test_matches_more_specific_action(self) -> None:
actual = get_matching_on_save_kinds({'a.b': True}, ['a.b.c'])
expected = ['a.b.c']
- self.assertEquals(actual, expected)
+ self.assertEqual(actual, expected)
def test_does_not_match_disabled_action(self) -> None:
actual = get_matching_on_save_kinds({'a.b': True, 'a.b.c': False}, ['a.b.c'])
- expected: List[str] = []
- self.assertEquals(actual, expected)
+ expected: list[str] = []
+ self.assertEqual(actual, expected)
def test_kind_matching(self) -> None:
# Positive
@@ -299,15 +299,15 @@ def test_requests_with_diagnostics(self) -> Generator:
self.view.run_command('lsp_selection_set', {"regions": [(0, 3)]}) # Select a and b.
yield 100
params = yield from self.await_message('textDocument/codeAction')
- self.assertEquals(params['range']['start']['line'], 0)
- self.assertEquals(params['range']['start']['character'], 0)
- self.assertEquals(params['range']['end']['line'], 1)
- self.assertEquals(params['range']['end']['character'], 1)
- self.assertEquals(len(params['context']['diagnostics']), 2)
+ self.assertEqual(params['range']['start']['line'], 0)
+ self.assertEqual(params['range']['start']['character'], 0)
+ self.assertEqual(params['range']['end']['line'], 1)
+ self.assertEqual(params['range']['end']['character'], 1)
+ self.assertEqual(len(params['context']['diagnostics']), 2)
annotations_range = self.view.get_regions(SessionView.CODE_ACTIONS_KEY)
- self.assertEquals(len(annotations_range), 1)
- self.assertEquals(annotations_range[0].a, 3)
- self.assertEquals(annotations_range[0].b, 0)
+ self.assertEqual(len(annotations_range), 1)
+ self.assertEqual(annotations_range[0].a, 3)
+ self.assertEqual(annotations_range[0].b, 0)
def test_requests_with_no_diagnostics(self) -> Generator:
initial_content = 'a\nb\nc'
@@ -321,15 +321,15 @@ def test_requests_with_no_diagnostics(self) -> Generator:
self.view.run_command('lsp_selection_set', {"regions": [(0, 3)]}) # Select a and b.
yield 100
params = yield from self.await_message('textDocument/codeAction')
- self.assertEquals(params['range']['start']['line'], 0)
- self.assertEquals(params['range']['start']['character'], 0)
- self.assertEquals(params['range']['end']['line'], 1)
- self.assertEquals(params['range']['end']['character'], 1)
- self.assertEquals(len(params['context']['diagnostics']), 0)
+ self.assertEqual(params['range']['start']['line'], 0)
+ self.assertEqual(params['range']['start']['character'], 0)
+ self.assertEqual(params['range']['end']['line'], 1)
+ self.assertEqual(params['range']['end']['character'], 1)
+ self.assertEqual(len(params['context']['diagnostics']), 0)
annotations_range = self.view.get_regions(SessionView.CODE_ACTIONS_KEY)
- self.assertEquals(len(annotations_range), 1)
- self.assertEquals(annotations_range[0].a, 3)
- self.assertEquals(annotations_range[0].b, 0)
+ self.assertEqual(len(annotations_range), 1)
+ self.assertEqual(annotations_range[0].a, 3)
+ self.assertEqual(annotations_range[0].b, 0)
def test_excludes_disabled_code_actions(self) -> Generator:
initial_content = 'a\n'
@@ -345,7 +345,7 @@ def test_excludes_disabled_code_actions(self) -> Generator:
yield 100
yield from self.await_message('textDocument/codeAction')
code_action_ranges = self.view.get_regions(SessionView.CODE_ACTIONS_KEY)
- self.assertEquals(len(code_action_ranges), 0)
+ self.assertEqual(len(code_action_ranges), 0)
def test_extends_range_to_include_diagnostics(self) -> Generator:
self.insert_characters('x diagnostic')
@@ -361,11 +361,11 @@ def test_extends_range_to_include_diagnostics(self) -> Generator:
yield 100
params = yield from self.await_message('textDocument/codeAction')
# Range should be extended to include range of all intersecting diagnostics
- self.assertEquals(params['range']['start']['line'], 0)
- self.assertEquals(params['range']['start']['character'], 0)
- self.assertEquals(params['range']['end']['line'], 0)
- self.assertEquals(params['range']['end']['character'], 12)
- self.assertEquals(len(params['context']['diagnostics']), 2)
+ self.assertEqual(params['range']['start']['line'], 0)
+ self.assertEqual(params['range']['start']['character'], 0)
+ self.assertEqual(params['range']['end']['line'], 0)
+ self.assertEqual(params['range']['end']['character'], 12)
+ self.assertEqual(len(params['context']['diagnostics']), 2)
class CodeActionsTestCase(TextDocumentTestCase):
@@ -387,11 +387,11 @@ def test_requests_code_actions_on_newly_published_diagnostics(self) -> Generator
])
)
params = yield from self.await_message('textDocument/codeAction')
- self.assertEquals(params['range']['start']['line'], 1)
- self.assertEquals(params['range']['start']['character'], 0)
- self.assertEquals(params['range']['end']['line'], 1)
- self.assertEquals(params['range']['end']['character'], 1)
- self.assertEquals(len(params['context']['diagnostics']), 1)
+ self.assertEqual(params['range']['start']['line'], 1)
+ self.assertEqual(params['range']['start']['character'], 0)
+ self.assertEqual(params['range']['end']['line'], 1)
+ self.assertEqual(params['range']['end']['character'], 1)
+ self.assertEqual(len(params['context']['diagnostics']), 1)
def test_applies_code_action_with_matching_document_version(self) -> Generator:
code_action = create_test_code_action(self.view, 3, [
@@ -403,7 +403,7 @@ def test_applies_code_action_with_matching_document_version(self) -> Generator:
self.assertEqual(self.view.change_count(), 3)
yield from self.await_run_code_action(code_action)
# yield from self.await_message('codeAction/resolve')
- self.assertEquals(entire_content(self.view), 'c\nd')
+ self.assertEqual(entire_content(self.view), 'c\nd')
def test_does_not_apply_with_nonmatching_document_version(self) -> Generator:
initial_content = 'a\nb'
@@ -414,7 +414,7 @@ def test_does_not_apply_with_nonmatching_document_version(self) -> Generator:
self.insert_characters(initial_content)
yield from self.await_message("textDocument/didChange")
yield from self.await_run_code_action(code_action)
- self.assertEquals(entire_content(self.view), initial_content)
+ self.assertEqual(entire_content(self.view), initial_content)
def test_runs_command_in_resolved_code_action(self) -> Generator:
code_action = create_test_code_action2("dosomethinguseful", ["1", 0, {"hello": "there"}])
@@ -432,7 +432,7 @@ def test_runs_command_in_resolved_code_action(self) -> Generator:
yield from self.await_message('codeAction/resolve')
params = yield from self.await_message('workspace/executeCommand')
self.assertEqual(params, {"command": "dosomethinguseful", "arguments": ["1", 0, {"hello": "there"}]})
- self.assertEquals(entire_content(self.view), 'c\nd')
+ self.assertEqual(entire_content(self.view), 'c\nd')
# Keep this test last as it breaks pyls!
def test_applies_correctly_after_emoji(self) -> Generator:
@@ -442,4 +442,4 @@ def test_applies_correctly_after_emoji(self) -> Generator:
("bye", range_from_points(Point(0, 3), Point(0, 5))),
])
yield from self.await_run_code_action(code_action)
- self.assertEquals(entire_content(self.view), '🕵️bye')
+ self.assertEqual(entire_content(self.view), '🕵️bye')
diff --git a/tests/test_completion.py b/tests/test_completion.py
index 5eae358b0..0476cabb6 100644
--- a/tests/test_completion.py
+++ b/tests/test_completion.py
@@ -9,7 +9,7 @@
from LSP.plugin.core.protocol import CompletionItemTag
from LSP.plugin.core.protocol import InsertTextFormat
from setup import TextDocumentTestCase
-from typing import Any, Callable, Dict, Generator, List, Optional
+from typing import Any, Callable, Generator
from unittest import TestCase
import sublime
@@ -79,7 +79,7 @@ def shift_select_completion(self) -> Generator:
def read_file(self) -> str:
return self.view.substr(sublime.Region(0, self.view.size()))
- def verify(self, *, completion_items: List[Dict[str, Any]], insert_text: str, expected_text: str) -> Generator:
+ def verify(self, *, completion_items: list[dict[str, Any]], insert_text: str, expected_text: str) -> Generator:
if insert_text:
self.type(insert_text)
self.set_response("textDocument/completion", completion_items)
@@ -421,7 +421,7 @@ def test_prefix_should_include_the_dollar_sign(self) -> Generator:
yield from self.select_completion()
yield from self.await_message('textDocument/completion')
- self.assertEquals(self.read_file(), '\n')
+ self.assertEqual(self.read_file(), '\n')
def test_fuzzy_match_plaintext_insert_text(self) -> Generator:
yield from self.verify(
@@ -467,7 +467,7 @@ def test_fuzzy_match_snippet_text_edit(self) -> Generator:
insert_text='aab',
expected_text='aaca')
- def verify_multi_cursor(self, completion: Dict[str, Any]) -> Generator:
+ def verify_multi_cursor(self, completion: dict[str, Any]) -> Generator:
"""
This checks whether `fd` gets replaced by `fmod` when the cursor is at `fd|`.
Turning the `d` into an `m` is an important part of the test.
@@ -687,7 +687,7 @@ def check(
resolve_support: bool,
expected_regex: str,
label: str,
- label_details: Optional[CompletionItemLabelDetails]
+ label_details: CompletionItemLabelDetails | None
) -> None:
lsp: CompletionItem = {"label": label, "filterText": "force_label_to_go_into_st_detail_field"}
if label_details is not None:
@@ -738,7 +738,7 @@ def check(
resolve_support: bool,
expected_regex: str,
label: str,
- label_details: Optional[CompletionItemLabelDetails]
+ label_details: CompletionItemLabelDetails | None
) -> None:
lsp: CompletionItem = {"label": label}
if label_details is not None:
@@ -913,10 +913,10 @@ def _verify_completion(
) -> None:
item = format_completion(
payload, index=0, can_resolve_completion_items=False, session_name='abc', item_defaults={}, view_id=0)
- self.assertEquals(item.trigger, trigger)
- self.assertEquals(item.annotation, annotation)
- self.assertEquals(item.details, details)
- self.assertEquals(item.flags, flags)
+ self.assertEqual(item.trigger, trigger)
+ self.assertEqual(item.annotation, annotation)
+ self.assertEqual(item.details, details)
+ self.assertEqual(item.flags, flags)
def test_label(self) -> None:
self._verify_completion(
diff --git a/tests/test_configs.py b/tests/test_configs.py
index 3cdade0b2..ef1e2ea94 100644
--- a/tests/test_configs.py
+++ b/tests/test_configs.py
@@ -81,7 +81,7 @@ def test_transport_config_extends_env_path(self):
transport_config = config.resolve_transport_config({})
original_path = environ.copy()['PATH']
resolved_path = transport_config.env['PATH']
- self.assertEqual(resolved_path, '/a/b/{}{}'.format(pathsep, original_path))
+ self.assertEqual(resolved_path, f'/a/b/{pathsep}{original_path}')
def test_list_in_environment(self):
settings = {
diff --git a/tests/test_edit.py b/tests/test_edit.py
index 9607ecdfe..7b2e99dee 100644
--- a/tests/test_edit.py
+++ b/tests/test_edit.py
@@ -9,7 +9,6 @@
from LSP.plugin.edit import temporary_setting
from setup import TextDocumentTestCase
from test_protocol import LSP_RANGE
-from typing import List
import sublime
import unittest
@@ -231,7 +230,7 @@ class ApplyDocumentEditTestCase(TextDocumentTestCase):
def test_applies_text_edit(self) -> None:
self.insert_characters('abc')
- edits: List[TextEdit] = [{
+ edits: list[TextEdit] = [{
'newText': 'x$0y',
'range': {
'start': {
@@ -245,11 +244,11 @@ def test_applies_text_edit(self) -> None:
}
}]
apply_text_edits(self.view, edits)
- self.assertEquals(entire_content(self.view), 'ax$0yc')
+ self.assertEqual(entire_content(self.view), 'ax$0yc')
def test_applies_text_edit_with_placeholder(self) -> None:
self.insert_characters('abc')
- edits: List[TextEdit] = [{
+ edits: list[TextEdit] = [{
'newText': 'x$0y',
'range': {
'start': {
@@ -263,7 +262,7 @@ def test_applies_text_edit_with_placeholder(self) -> None:
}
}]
apply_text_edits(self.view, edits, process_placeholders=True)
- self.assertEquals(entire_content(self.view), 'axyc')
+ self.assertEqual(entire_content(self.view), 'axyc')
self.assertEqual(len(self.view.sel()), 1)
self.assertEqual(self.view.sel()[0], sublime.Region(2, 2))
@@ -282,9 +281,9 @@ def test_applies_multiple_text_edits_with_placeholders(self) -> None:
}
}
}
- edits: List[TextEdit] = [newline_edit, newline_edit]
+ edits: list[TextEdit] = [newline_edit, newline_edit]
apply_text_edits(self.view, edits, process_placeholders=True)
- self.assertEquals(entire_content(self.view), 'a\n\nb')
+ self.assertEqual(entire_content(self.view), 'a\n\nb')
self.assertEqual(len(self.view.sel()), 2)
self.assertEqual(self.view.sel()[0], sublime.Region(2, 2))
self.assertEqual(self.view.sel()[1], sublime.Region(3, 3))
diff --git a/tests/test_file_watcher.py b/tests/test_file_watcher.py
index b9cf0c289..990163d3d 100644
--- a/tests/test_file_watcher.py
+++ b/tests/test_file_watcher.py
@@ -11,7 +11,7 @@
from os.path import join
from setup import expand
from setup import TextDocumentTestCase
-from typing import Generator, List, Optional
+from typing import Generator
import sublime
import unittest
@@ -33,15 +33,15 @@ def setup_workspace_folder() -> str:
class TestFileWatcher(FileWatcher):
# The list of watchers created by active sessions.
- _active_watchers: List[TestFileWatcher] = []
+ _active_watchers: list[TestFileWatcher] = []
@classmethod
def create(
cls,
root_path: str,
- patterns: List[str],
- events: List[FileWatcherEventType],
- ignores: List[str],
+ patterns: list[str],
+ events: list[FileWatcherEventType],
+ ignores: list[str],
handler: FileWatcherProtocol
) -> TestFileWatcher:
watcher = TestFileWatcher(root_path, patterns, events, ignores, handler)
@@ -51,9 +51,9 @@ def create(
def __init__(
self,
root_path: str,
- patterns: List[str],
- events: List[FileWatcherEventType],
- ignores: List[str],
+ patterns: list[str],
+ events: list[FileWatcherEventType],
+ ignores: list[str],
handler: FileWatcherProtocol
) -> None:
self.root_path = root_path
@@ -66,7 +66,7 @@ def destroy(self) -> None:
self.handler = None
self._active_watchers.remove(self)
- def trigger_event(self, events: List[FileWatcherEvent]) -> None:
+ def trigger_event(self, events: list[FileWatcherEvent]) -> None:
def trigger_async():
if self.handler:
@@ -250,10 +250,10 @@ def test_project_relative_patterns(self):
def _verify_patterns(
self,
- patterns: List[str],
- expected: List[str],
+ patterns: list[str],
+ expected: list[str],
is_directory_pattern: bool,
- root_path: Optional[str] = None
+ root_path: str | None = None
) -> None:
glob_patterns = [
sublime_pattern_to_glob(pattern, is_directory_pattern=is_directory_pattern, root_path=root_path)
diff --git a/tests/test_mocks.py b/tests/test_mocks.py
index f155d5315..b833a6026 100644
--- a/tests/test_mocks.py
+++ b/tests/test_mocks.py
@@ -4,7 +4,7 @@
from LSP.plugin.core.protocol import Request
from LSP.plugin.core.protocol import Response
from LSP.plugin.core.types import ClientConfig
-from typing import Any, Callable, List
+from typing import Any, Callable
TEST_CONFIG = ClientConfig(name="test", command=[], selector="text.plain", tcp_port=None)
@@ -41,10 +41,10 @@
}
-class MockSession(object):
+class MockSession:
def __init__(self, async_response=None) -> None:
self.responses = basic_responses
- self._notifications: List[Notification] = []
+ self._notifications: list[Notification] = []
self._async_response_callback = async_response
def send_request(self, request: Request, on_success: Callable, on_error: Callable = None) -> None:
diff --git a/tests/test_server_requests.py b/tests/test_server_requests.py
index 3e24d555e..7bef59bf0 100644
--- a/tests/test_server_requests.py
+++ b/tests/test_server_requests.py
@@ -5,13 +5,13 @@
from LSP.plugin.core.types import ClientConfig
from LSP.plugin.core.url import filename_to_uri
from setup import TextDocumentTestCase
-from typing import Any, Dict, Generator, List, Optional
+from typing import Any, Generator
import os
import sublime
import tempfile
-def get_auto_complete_trigger(sb: SessionBufferProtocol) -> Optional[List[Dict[str, str]]]:
+def get_auto_complete_trigger(sb: SessionBufferProtocol) -> list[dict[str, str]] | None:
for sv in sb.session_views:
triggers = sv.view.settings().get("auto_complete_triggers")
for trigger in triggers:
@@ -47,7 +47,7 @@ def test_m_workspace_configuration(self) -> Generator:
class TempPlugin:
@classmethod
- def additional_variables(cls) -> Optional[Dict[str, str]]:
+ def additional_variables(cls) -> dict[str, str] | None:
return {"hello": "X", "world": "Y"}
self.session._plugin_class = TempPlugin # type: ignore
@@ -72,7 +72,7 @@ def test_m_workspace_applyEdit_with_nontrivial_promises(self) -> Generator:
initial_text = ["a b", "c d"]
file_paths = []
for i in range(0, 2):
- file_paths.append(os.path.join(dirpath, "file{}.txt".format(i)))
+ file_paths.append(os.path.join(dirpath, f"file{i}.txt"))
with open(file_paths[-1], "w") as fp:
fp.write(initial_text[i])
yield from verify(
diff --git a/tests/test_session.py b/tests/test_session.py
index 86c42155d..ffb0cdd09 100644
--- a/tests/test_session.py
+++ b/tests/test_session.py
@@ -11,7 +11,7 @@
from LSP.plugin.core.types import ClientConfig
from LSP.plugin.core.workspace import WorkspaceFolder
from test_mocks import TEST_CONFIG
-from typing import Any, Dict, Generator, List, Optional
+from typing import Any, Generator
import sublime
import unittest
import unittest.mock
@@ -26,19 +26,19 @@ def __init__(self, window: sublime.Window) -> None:
def window(self) -> sublime.Window:
return self._window
- def sessions(self, view: sublime.View, capability: Optional[str] = None) -> Generator[Session, None, None]:
+ def sessions(self, view: sublime.View, capability: str | None = None) -> Generator[Session, None, None]:
pass
- def get_project_path(self, file_name: str) -> Optional[str]:
+ def get_project_path(self, file_name: str) -> str | None:
return None
- def should_ignore_diagnostics(self, uri: DocumentUri, configuration: ClientConfig) -> Optional[str]:
+ def should_ignore_diagnostics(self, uri: DocumentUri, configuration: ClientConfig) -> str | None:
return None
def start_async(self, configuration: ClientConfig, initiating_view: sublime.View) -> None:
pass
- def on_post_exit_async(self, session: Session, exit_code: int, exception: Optional[Exception]) -> None:
+ def on_post_exit_async(self, session: Session, exit_code: int, exception: Exception | None) -> None:
pass
def on_diagnostics_updated(self) -> None:
@@ -62,7 +62,7 @@ def outgoing_request(self, request_id: int, method: str, params: Any, blocking:
def outgoing_notification(self, method: str, params: Any) -> None:
pass
- def incoming_response(self, request_id: Optional[int], params: Any, is_error: bool, blocking: bool) -> None:
+ def incoming_response(self, request_id: int | None, params: Any, is_error: bool, blocking: bool) -> None:
pass
def incoming_request(self, request_id: Any, method: str, params: Any) -> None:
@@ -80,10 +80,10 @@ def __init__(self, session: Session, mock_uri: str, mock_language_id: str) -> No
self.mock_uri = mock_uri
self.mock_language_id = mock_language_id
- def get_uri(self) -> Optional[DocumentUri]:
+ def get_uri(self) -> DocumentUri | None:
return self.mock_uri
- def get_language_id(self) -> Optional[str]:
+ def get_language_id(self) -> str | None:
return self.mock_language_id
def register_capability_async(
@@ -91,7 +91,7 @@ def register_capability_async(
registration_id: str,
capability_path: str,
registration_path: str,
- options: Dict[str, Any]
+ options: dict[str, Any]
) -> None:
pass
@@ -103,7 +103,7 @@ def unregister_capability_async(
) -> None:
pass
- def on_diagnostics_async(self, raw_diagnostics: List[Diagnostic], version: Optional[int]) -> None:
+ def on_diagnostics_async(self, raw_diagnostics: list[Diagnostic], version: int | None) -> None:
pass
diff --git a/tests/test_single_document.py b/tests/test_single_document.py
index 186bfb993..7ae66f027 100644
--- a/tests/test_single_document.py
+++ b/tests/test_single_document.py
@@ -111,7 +111,7 @@ def test_formats_on_save(self) -> Generator:
yield from self.await_message("textDocument/didChange")
yield from self.await_message("textDocument/didSave")
text = self.view.substr(sublime.Region(0, self.view.size()))
- self.assertEquals("BBB", text)
+ self.assertEqual("BBB", text)
yield from self.await_clear_view_and_save()
def test_hover_info(self) -> Generator:
@@ -201,9 +201,9 @@ def test_tabs_are_respected_even_when_translate_tabs_to_spaces_is_set_to_true(se
def __run_formatting_test(
self,
- original: 'Iterable[str]',
- expected: 'Iterable[str]',
- file_changes: 'List[Tuple[Tuple[int, int], Tuple[int, int], str]]'
+ original: Iterable[str],
+ expected: Iterable[str],
+ file_changes: list[tuple[tuple[int, int], tuple[int, int], str]]
) -> Generator:
assert self.view
original_change_count = self.insert_characters(''.join(original))
@@ -217,7 +217,7 @@ def __run_formatting_test(
yield from self.await_message('textDocument/formatting')
yield from self.await_view_change(original_change_count + len(file_changes))
edited_content = self.view.substr(sublime.Region(0, self.view.size()))
- self.assertEquals(edited_content, ''.join(expected))
+ self.assertEqual(edited_content, ''.join(expected))
def __run_goto_test(self, response: list, text_document_request: str, subl_command_suffix: str) -> Generator:
assert self.view
@@ -225,9 +225,9 @@ def __run_goto_test(self, response: list, text_document_request: str, subl_comma
# Put the cursor back at the start of the buffer, otherwise is_at_word fails in goto.py.
self.view.sel().clear()
self.view.sel().add(sublime.Region(0, 0))
- method = 'textDocument/{}'.format(text_document_request)
+ method = f'textDocument/{text_document_request}'
self.set_response(method, response)
- self.view.run_command('lsp_symbol_{}'.format(subl_command_suffix))
+ self.view.run_command(f'lsp_symbol_{subl_command_suffix}')
yield from self.await_message(method)
def condition() -> bool:
@@ -420,5 +420,5 @@ def test_will_save_wait_until(self) -> Generator:
yield from self.await_message("textDocument/didChange")
yield from self.await_message("textDocument/didSave")
text = self.view.substr(sublime.Region(0, self.view.size()))
- self.assertEquals("BBB", text)
+ self.assertEqual("BBB", text)
yield from self.await_clear_view_and_save()
diff --git a/tests/test_types.py b/tests/test_types.py
index 35dc30fd0..5b81e1da5 100644
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -2,7 +2,6 @@
from LSP.plugin.core.types import diff
from LSP.plugin.core.types import basescope2languageid
from LSP.plugin.core.types import DocumentSelector
-from typing import List
from unittest.mock import MagicMock
import sublime
import unittest
@@ -45,7 +44,7 @@ def test_completely_new(self) -> None:
class TestDocumentSelector(unittest.TestCase):
def setUp(self) -> None:
- self._opened_views: List[sublime.View] = []
+ self._opened_views: list[sublime.View] = []
def tearDown(self) -> None:
for view in self._opened_views: