From ede6d034f509ac8f9b81d8d71b20e5e1fca3a881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= Date: Mon, 6 Jan 2020 08:48:32 +0900 Subject: [PATCH] server: more specific types for decorators Use a TypeVar so that type checkers understand that the signature is same as the decorated functions, so that these functions can be typechecked. fixes #88 --- CHANGELOG.md | 6 ++++++ pygls/server.py | 10 ++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 224c0185..d741bbf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning][semver]. ## [Unreleased] +### Changed + +- Fixed `@command`, `@feature` and `@thread` decorators to retain type of wrapped functions ([#89]) + +[#89]: https://github.com/openlawlibrary/pygls/pull/89 + ### Added - Add comparisons and repr support to Range and Location types ([#90]) diff --git a/pygls/server.py b/pygls/server.py index 66e4bca0..38e6a7fd 100644 --- a/pygls/server.py +++ b/pygls/server.py @@ -21,7 +21,7 @@ from concurrent.futures import Future, ThreadPoolExecutor from multiprocessing.pool import ThreadPool from threading import Event -from typing import Callable, Dict, List +from typing import Callable, Dict, List, TypeVar from pygls.types import (ApplyWorkspaceEditResponse, ConfigCallbackType, Diagnostic, MessageType, RegistrationParams, TextDocumentSyncKind, UnregistrationParams, @@ -34,6 +34,8 @@ logger = logging.getLogger(__name__) +F = TypeVar('F', bound=Callable) + async def aio_readline(loop, executor, stop_event, rfile, proxy): """Reads data from stdin in separate thread (asynchronously).""" @@ -234,7 +236,7 @@ def apply_edit(self, edit: WorkspaceEdit, label: str = None) -> ApplyWorkspaceEd """Sends apply edit request to the client.""" return self.lsp.apply_edit(edit, label) - def command(self, command_name: str) -> Callable: + def command(self, command_name: str) -> Callable[[F], F]: """Decorator used to register custom commands. Example: @@ -244,7 +246,7 @@ def my_cmd(ls, a, b, c): """ return self.lsp.fm.command(command_name) - def feature(self, feature_name: str, **options: Dict) -> Callable: + def feature(self, feature_name: str, **options: Dict) -> Callable[[F], F]: """Decorator used to register LSP features. Example: @@ -287,7 +289,7 @@ def show_message_log(self, message, msg_type=MessageType.Log) -> None: """Sends message to the client's output channel.""" self.lsp.show_message_log(message, msg_type) - def thread(self) -> Callable: + def thread(self) -> Callable[[F], F]: """Decorator that mark function to execute it in a thread.""" return self.lsp.thread()