Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(types): Mark properties with NotRequired #2062

Merged
merged 10 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ jobs:
python-version: '3.8'
- run: sudo apt update
- run: sudo apt install --no-install-recommends -y x11-xserver-utils
- run: pip3 install mypy==0.910 flake8==3.9.2 yapf==0.31.0 --user
- run: pip3 install mypy==0.971 flake8==5.0.4 pyright==1.1.271 yapf==0.31.0 --user
- run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- run: mypy -p plugin
# - run: mypy -p plugin
predragnikolic marked this conversation as resolved.
Show resolved Hide resolved
- run: flake8 plugin tests
- run: pyright plugin
2 changes: 1 addition & 1 deletion plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from .core.protocol import Notification
from .core.protocol import Request
from .core.protocol import Response
from .core.protocol import WorkspaceFolder
from .core.registry import LspTextCommand
from .core.registry import LspWindowCommand
from .core.sessions import AbstractPlugin
Expand All @@ -23,6 +22,7 @@
from .core.url import uri_to_filename # deprecated
from .core.version import __version__
from .core.views import MarkdownLangMap
from .core.workspace import WorkspaceFolder

# This is the public API for LSP-* packages
__all__ = [
Expand Down
13 changes: 7 additions & 6 deletions plugin/code_actions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .core.promise import Promise
from .core.protocol import CodeAction
from .core.protocol import CodeActionKind
from .core.protocol import Command
from .core.protocol import Diagnostic
from .core.protocol import Error
Expand All @@ -8,7 +9,7 @@
from .core.registry import windows
from .core.sessions import SessionBufferProtocol
from .core.settings import userprefs
from .core.typing import Any, List, Dict, Callable, Optional, Tuple, Union
from .core.typing import Any, List, Dict, Callable, Optional, Tuple, Union, cast
from .core.views import entire_content_region
from .core.views import first_selection_region
from .core.views import format_code_actions_for_quick_panel
Expand Down Expand Up @@ -143,7 +144,7 @@ def _request_async(
diagnostics = diags
break
if on_save_actions:
supported_kinds = session.get_capability('codeActionProvider.codeActionKinds')
supported_kinds = session.get_capability('codeActionProvider.codeActionKinds') # type: Optional[List[CodeActionKind]] # noqa
matching_kinds = get_matching_kinds(on_save_actions, supported_kinds or [])
if matching_kinds:
params = text_document_code_action_params(view, region, diagnostics, matching_kinds, manual)
Expand All @@ -162,7 +163,7 @@ def _request_async(

def filtering_collector(
config_name: str,
kinds: List[str],
kinds: List[CodeActionKind],
actions_collector: CodeActionsCollector
) -> Tuple[Callable[[CodeActionsResponse], None], Callable[[Any], None]]:
"""
Expand All @@ -173,7 +174,7 @@ def filtering_collector(
"""

def actions_filter(actions: CodeActionsResponse) -> List[CodeActionOrCommand]:
return [a for a in (actions or []) if a.get('kind') in kinds] # type: ignore
return [a for a in (actions or []) if a.get('kind') in kinds]

collector = actions_collector.create_collector(config_name)
return (
Expand All @@ -185,7 +186,7 @@ def actions_filter(actions: CodeActionsResponse) -> List[CodeActionOrCommand]:
actions_manager = CodeActionsManager()


def get_matching_kinds(user_actions: Dict[str, bool], session_actions: List[str]) -> List[str]:
def get_matching_kinds(user_actions: Dict[str, bool], session_actions: List[CodeActionKind]) -> List[CodeActionKind]:
"""
Filters user-enabled or disabled actions so that only ones matching the session actions
are returned. Returned actions are those that are enabled and are not overridden by more
Expand All @@ -199,7 +200,7 @@ def get_matching_kinds(user_actions: Dict[str, bool], session_actions: List[str]
matching_kinds = []
for session_action in session_actions:
enabled = False
action_parts = session_action.split('.')
action_parts = cast(str, session_action).split('.')
for i in range(len(action_parts)):
current_part = '.'.join(action_parts[0:i + 1])
user_value = user_actions.get(current_part, None)
Expand Down
26 changes: 15 additions & 11 deletions plugin/code_lens.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .core.protocol import CodeLens, Error
from .core.typing import List, Tuple, Dict, Iterable, Generator, Union
from .core.protocol import CodeLens, CodeLensExtended, Error
from .core.typing import List, Tuple, Dict, Iterable, Generator, Union, cast
from .core.registry import LspTextCommand
from .core.registry import windows
from .core.views import make_command_link
Expand Down Expand Up @@ -33,8 +33,8 @@ def is_resolved(self) -> bool:
"""A code lens is considered resolved if the inner data contains the 'command' key."""
return 'command' in self.data or self.is_resolve_error

def to_lsp(self) -> CodeLens:
copy = self.data.copy()
def to_lsp(self) -> CodeLensExtended:
copy = cast(CodeLensExtended, self.data.copy())
copy['session_name'] = self.session_name
return copy

Expand Down Expand Up @@ -165,7 +165,7 @@ def render(self, mode: str) -> None:
for index, lens in enumerate(self._flat_iteration()):
self.view.add_regions(self._region_key(index), [lens.region], "", "", 0, [lens.small_html], accent)

def get_resolved_code_lenses_for_region(self, region: sublime.Region) -> Generator[CodeLens, None, None]:
def get_resolved_code_lenses_for_region(self, region: sublime.Region) -> Generator[CodeLensExtended, None, None]:
region = self.view.line(region)
for lens in self._flat_iteration():
if lens.is_resolved() and lens.region.intersects(region):
Expand All @@ -178,19 +178,21 @@ def run(self, edit: sublime.Edit) -> None:
listener = windows.listener_for_view(self.view)
if not listener:
return
code_lenses = [] # type: List[CodeLens]
code_lenses = [] # type: List[CodeLensExtended]
for region in self.view.sel():
for sv in listener.session_views_async():
code_lenses.extend(sv.get_resolved_code_lenses_for_region(region))
if not code_lenses:
return
elif len(code_lenses) == 1:
command = code_lenses[0]["command"]
command = code_lenses[0].get("command")
assert command
if not command:
return
args = {
"session_name": code_lenses[0]["session_name"],
"command_name": command["command"],
"command_args": command["arguments"]
"command_args": command.get("arguments")
}
self.view.run_command("lsp_execute", args)
else:
Expand All @@ -199,16 +201,18 @@ def run(self, edit: sublime.Edit) -> None:
lambda i: self.on_select(code_lenses, i)
)

def on_select(self, code_lenses: List[CodeLens], index: int) -> None:
def on_select(self, code_lenses: List[CodeLensExtended], index: int) -> None:
try:
code_lens = code_lenses[index]
except IndexError:
return
command = code_lens["command"]
command = code_lens.get("command")
assert command
if not command:
return
args = {
"session_name": code_lens["session_name"],
"command_name": command["command"],
"command_args": command["arguments"]
"command_args": command.get("arguments")
}
self.view.run_command("lsp_execute", args)
5 changes: 3 additions & 2 deletions plugin/completion.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from .core.edit import parse_text_edit
from .core.logging import debug
from .core.protocol import InsertReplaceEdit, TextEdit, Range, Request, InsertTextFormat, CompletionItem
from .core.protocol import MarkupContent, MarkedString, MarkupKind
from .core.registry import LspTextCommand
from .core.settings import userprefs
from .core.typing import List, Dict, Optional, Generator, Union, cast
Expand Down Expand Up @@ -49,7 +50,7 @@ def run_async() -> None:

def _format_documentation(
self,
content: Union[str, Dict[str, str]],
content: Union[MarkedString, MarkupContent, List[MarkedString]],
language_map: Optional[MarkdownLangMap]
) -> str:
return minihtml(self.view, content, FORMAT_STRING | FORMAT_MARKUP_CONTENT, language_map)
Expand All @@ -61,7 +62,7 @@ def _handle_resolve_response_async(self, language_map: Optional[MarkdownLangMap]
detail = self._format_documentation(item.get('detail') or "", language_map)
documentation = self._format_documentation(item.get("documentation") or "", language_map)
if not documentation:
markdown = {"kind": "markdown", "value": "*No documentation available.*"}
markdown = {"kind": MarkupKind.Markdown, "value": "*No documentation available.*"} # type: MarkupContent
# No need for a language map here
documentation = self._format_documentation(markdown, None)
minihtml_content = ""
Expand Down
8 changes: 4 additions & 4 deletions plugin/core/edit.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from .logging import debug
from .open import open_file
from .promise import Promise
from .protocol import UINT_MAX, TextEdit as LspTextEdit, Position
from .typing import List, Dict, Any, Optional, Tuple
from .protocol import UINT_MAX, TextEdit as LspTextEdit, Position, WorkspaceEdit
from .typing import List, Dict, Optional, Tuple
from functools import partial
import sublime

Expand All @@ -11,7 +11,7 @@
TextEditTuple = Tuple[Tuple[int, int], Tuple[int, int], str, Optional[int]]


def parse_workspace_edit(workspace_edit: Dict[str, Any]) -> Dict[str, List[TextEditTuple]]:
def parse_workspace_edit(workspace_edit: WorkspaceEdit) -> Dict[str, List[TextEditTuple]]:
changes = {} # type: Dict[str, List[TextEditTuple]]
document_changes = workspace_edit.get('documentChanges')
if isinstance(document_changes, list):
Expand All @@ -37,7 +37,7 @@ def parse_range(range: Position) -> Tuple[int, int]:
return range['line'], min(UINT_MAX, range['character'])


def parse_text_edit(text_edit: LspTextEdit, version: int = None) -> TextEditTuple:
def parse_text_edit(text_edit: LspTextEdit, version: Optional[int] = None) -> TextEditTuple:
return (
parse_range(text_edit['range']['start']),
parse_range(text_edit['range']['end']),
Expand Down
18 changes: 9 additions & 9 deletions plugin/core/file_watcher.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from .protocol import FileChangeType, FileChangeTypeCreated, FileChangeTypeChanged, FileChangeTypeDeleted
from .protocol import WatchKind, WatchKindCreate, WatchKindChange, WatchKindDelete
from .protocol import FileChangeType
from .protocol import WatchKind
from .typing import List, Literal, Optional, Protocol, Tuple, Type, Union
from abc import ABCMeta
from abc import abstractmethod

DEFAULT_KIND = WatchKindCreate | WatchKindChange | WatchKindDelete
DEFAULT_KIND = WatchKind.Create | WatchKind.Change | WatchKind.Delete

FileWatcherEventType = Union[Literal['create'], Literal['change'], Literal['delete']]
FilePath = str
Expand All @@ -13,20 +13,20 @@

def lsp_watch_kind_to_file_watcher_event_types(kind: WatchKind) -> List[FileWatcherEventType]:
event_types = [] # type: List[FileWatcherEventType]
if kind & WatchKindCreate:
if kind & WatchKind.Create:
event_types.append('create')
if kind & WatchKindChange:
if kind & WatchKind.Change:
event_types.append('change')
if kind & WatchKindDelete:
if kind & WatchKind.Delete:
event_types.append('delete')
return event_types


def file_watcher_event_type_to_lsp_file_change_type(kind: FileWatcherEventType) -> FileChangeType:
return {
'create': FileChangeTypeCreated,
'change': FileChangeTypeChanged,
'delete': FileChangeTypeDeleted,
'create': FileChangeType.Created,
'change': FileChangeType.Changed,
'delete': FileChangeType.Deleted,
}[kind]


Expand Down
2 changes: 1 addition & 1 deletion plugin/core/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def trace() -> None:
debug("TRACE (unknown frame)")
return
previous_frame = current_frame.f_back
file_name, line_number, function_name, _, __ = inspect.getframeinfo(previous_frame) # type: ignore
file_name, line_number, function_name, _, _ = inspect.getframeinfo(previous_frame) # type: ignore
file_name = file_name[len(sublime.packages_path()) + len("/LSP/"):]
debug("TRACE {0:<32} {1}:{2}".format(function_name, file_name, line_number))

Expand Down
42 changes: 16 additions & 26 deletions plugin/core/promise.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from .typing import Callable, Generic, List, Optional, Protocol, Tuple, TypeVar, Union
import functools
import sublime
import threading

T = TypeVar('T')
S = TypeVar('S')
TExecutor = TypeVar('TExecutor')
T_contra = TypeVar('T_contra', contravariant=True)
TResult = TypeVar('TResult')


class ResolveFunc(Protocol[T_contra]):
def __call__(self, value: Union[T_contra, 'Promise[T_contra]']) -> None:
def __call__(self, resolve_value: T_contra) -> None:
...


Expand Down Expand Up @@ -64,8 +64,8 @@ def process_value(value):
Promise(do_work_async_1).then(do_more_work_async).then(process_value)
"""

@classmethod
def resolve(cls, resolve_value: T) -> 'Promise[T]':
@staticmethod
def resolve(resolve_value: S) -> 'Promise[S]':
"""Immediately resolves a Promise.

Convenience function for creating a Promise that gets immediately
Expand All @@ -74,23 +74,13 @@ def resolve(cls, resolve_value: T) -> 'Promise[T]':
Arguments:
resolve_value: The value to resolve the promise with.
"""
def executor_func(resolve_fn: ResolveFunc[T]) -> None:
def executor_func(resolve_fn: ResolveFunc[S]) -> None:
resolve_fn(resolve_value)

return cls(executor_func)
return Promise(executor_func)

@classmethod
def on_main_thread(cls, value: T) -> 'Promise[T]':
"""Return a promise that resolves on the main thread."""
return Promise(lambda resolve: sublime.set_timeout(lambda: resolve(value)))

@classmethod
def on_async_thread(cls, value: T) -> 'Promise[T]':
"""Return a promise that resolves on the worker thread."""
return Promise(lambda resolve: sublime.set_timeout_async(lambda: resolve(value)))

@classmethod
def packaged_task(cls) -> PackagedTask[T]:
@staticmethod
def packaged_task() -> PackagedTask[S]:

class Executor(Generic[TExecutor]):

Expand All @@ -102,14 +92,14 @@ def __init__(self) -> None:
def __call__(self, resolver: ResolveFunc[TExecutor]) -> None:
self.resolver = resolver

executor = Executor() # type: Executor[T]
promise = cls(executor)
executor = Executor() # type: Executor[S]
promise = Promise(executor)
assert callable(executor.resolver)
return promise, executor.resolver

# Could also support passing plain T.
@classmethod
def all(cls, promises: List['Promise[T]']) -> 'Promise[List[T]]':
# Could also support passing plain S.
@staticmethod
def all(promises: List['Promise[S]']) -> 'Promise[List[S]]':
"""
Takes a list of promises and returns a Promise that gets resolved when all promises
gets resolved.
Expand All @@ -119,10 +109,10 @@ def all(cls, promises: List['Promise[T]']) -> 'Promise[List[T]]':
:returns: A promise that gets resolved when all passed promises gets resolved.
Gets passed a list with all resolved values.
"""
def executor(resolve: ResolveFunc[List[T]]) -> None:
def executor(resolve: ResolveFunc[List[S]]) -> None:
was_resolved = False

def recheck_resolve_status(_: T) -> None:
def recheck_resolve_status(_: S) -> None:
nonlocal was_resolved
# We're being called from a Promise that is holding a lock so don't try to use
# any methods that would try to acquire it.
Expand Down Expand Up @@ -150,7 +140,7 @@ def __init__(self, executor_func: ExecutorFunc[T]) -> None:
self.resolved = False
self.mutex = threading.Lock()
self.callbacks = [] # type: List[ResolveFunc[T]]
executor_func(lambda value=None: self._do_resolve(value))
executor_func(lambda resolve_value=None: self._do_resolve(resolve_value))

def __repr__(self) -> str:
if self.resolved:
Expand Down
Loading