From a35a40bf356d4537e0f490d5a23bd5bda1856388 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sun, 28 Apr 2024 16:11:52 +0100 Subject: [PATCH] Fix or suppress all Python type errors (#2307) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Depends on https://github.com/cursorless-dev/cursorless/pull/2306 - Supercedes https://github.com/cursorless-dev/cursorless/pull/2267 This does add a lot of noise, and it can't be enforced in CI because Talon doesn't publish type stubs (that I know of), so I wonder whether it's worth it 🤔 ## Checklist - [x] I have run Talon spoken form tests - [-] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [-] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [x] I have not broken the cheatsheet --- src/actions/actions.py | 15 +++++++++------ src/actions/bring_move.py | 2 +- src/actions/call.py | 2 +- src/actions/get_text.py | 4 ++-- src/actions/homophones.py | 7 +++++-- src/actions/paste.py | 4 +++- src/actions/reformat.py | 10 ++++++++-- src/actions/swap.py | 4 +++- src/actions/wrap.py | 8 ++++++-- src/apps/vscode_settings.py | 5 +++-- src/cheatsheet/cheat_sheet.py | 2 +- src/cheatsheet/get_list.py | 3 ++- src/command.py | 8 ++++---- src/csv_overrides.py | 5 ++++- src/cursorless_command_server.py | 12 +++++++++--- src/modifiers/surrounding_pair.py | 4 +++- src/number_small.py | 4 +++- src/private_api/private_api.py | 10 ++++++---- src/scope_visualizer.py | 3 ++- src/snippets.py | 31 ++++++++++++++++++------------- src/targets/target_types.py | 5 +++++ src/terms.py | 4 +++- 22 files changed, 101 insertions(+), 51 deletions(-) diff --git a/src/actions/actions.py b/src/actions/actions.py index 2b44f084..c9e75cf7 100644 --- a/src/actions/actions.py +++ b/src/actions/actions.py @@ -4,6 +4,7 @@ from ..targets.target_types import ( CursorlessDestination, + CursorlessExplicitTarget, CursorlessTarget, ImplicitDestination, ) @@ -48,7 +49,7 @@ "custom_action", ] -callback_actions: dict[str, Callable[[CursorlessTarget], None]] = { +callback_actions: dict[str, Callable[[CursorlessExplicitTarget], None]] = { "nextHomophone": cursorless_homophones_action, } @@ -88,7 +89,7 @@ def cursorless_action_or_ide_command(m) -> dict[str, str]: @mod.action_class class Actions: - def cursorless_command(action_name: str, target: CursorlessTarget): + def cursorless_command(action_name: str, target: CursorlessExplicitTarget): # pyright: ignore [reportGeneralTypeIssues] """Perform cursorless command on target""" if action_name in callback_actions: callback_actions[action_name](target) @@ -107,7 +108,7 @@ def cursorless_command(action_name: str, target: CursorlessTarget): action = {"name": action_name, "target": target} actions.user.private_cursorless_command_and_wait(action) - def cursorless_vscode_command(command_id: str, target: CursorlessTarget): + def cursorless_vscode_command(command_id: str, target: CursorlessTarget): # pyright: ignore [reportGeneralTypeIssues] """ Perform vscode command on cursorless target @@ -115,12 +116,13 @@ def cursorless_vscode_command(command_id: str, target: CursorlessTarget): """ return actions.user.cursorless_ide_command(command_id, target) - def cursorless_ide_command(command_id: str, target: CursorlessTarget): + def cursorless_ide_command(command_id: str, target: CursorlessTarget): # pyright: ignore [reportGeneralTypeIssues] """Perform ide command on cursorless target""" return cursorless_execute_command_action(command_id, target) def cursorless_insert( - destination: CursorlessDestination, text: Union[str, list[str]] + destination: CursorlessDestination, # pyright: ignore [reportGeneralTypeIssues] + text: Union[str, list[str]], ): """Perform text insertion on Cursorless destination""" if isinstance(text, str): @@ -128,7 +130,8 @@ def cursorless_insert( cursorless_replace_action(destination, text) def private_cursorless_action_or_ide_command( - instruction: dict[str, str], target: CursorlessTarget + instruction: dict[str, str], # pyright: ignore [reportGeneralTypeIssues] + target: CursorlessTarget, ): """Perform cursorless action or ide command on target (internal use only)""" type = instruction["type"] diff --git a/src/actions/bring_move.py b/src/actions/bring_move.py index 7861f76f..bb13497a 100644 --- a/src/actions/bring_move.py +++ b/src/actions/bring_move.py @@ -35,7 +35,7 @@ def cursorless_bring_move_targets(m) -> BringMoveTargets: @mod.action_class class Actions: - def private_cursorless_bring_move(action_name: str, targets: BringMoveTargets): + def private_cursorless_bring_move(action_name: str, targets: BringMoveTargets): # pyright: ignore [reportGeneralTypeIssues] """Execute Cursorless move/bring action""" actions.user.private_cursorless_command_and_wait( { diff --git a/src/actions/call.py b/src/actions/call.py index 6601d7ba..7bfe75cb 100644 --- a/src/actions/call.py +++ b/src/actions/call.py @@ -9,7 +9,7 @@ @mod.action_class class Actions: def private_cursorless_call( - callee: CursorlessTarget, + callee: CursorlessTarget, # pyright: ignore [reportGeneralTypeIssues] argument: CursorlessTarget = ImplicitTarget(), ): """Execute Cursorless call action""" diff --git a/src/actions/get_text.py b/src/actions/get_text.py index e95f35de..6f1770ad 100644 --- a/src/actions/get_text.py +++ b/src/actions/get_text.py @@ -10,7 +10,7 @@ @mod.action_class class Actions: def cursorless_get_text( - target: CursorlessTarget, + target: CursorlessTarget, # pyright: ignore [reportGeneralTypeIssues] hide_decorations: bool = False, ) -> str: """Get target text. If hide_decorations is True, don't show decorations""" @@ -21,7 +21,7 @@ def cursorless_get_text( )[0] def cursorless_get_text_list( - target: CursorlessTarget, + target: CursorlessTarget, # pyright: ignore [reportGeneralTypeIssues] hide_decorations: bool = False, ) -> list[str]: """Get texts for multiple targets. If hide_decorations is True, don't show decorations""" diff --git a/src/actions/homophones.py b/src/actions/homophones.py index df571f94..4b3b7f32 100644 --- a/src/actions/homophones.py +++ b/src/actions/homophones.py @@ -2,12 +2,15 @@ from talon import actions, app -from ..targets.target_types import CursorlessTarget, PrimitiveDestination +from ..targets.target_types import ( + CursorlessExplicitTarget, + PrimitiveDestination, +) from .get_text import cursorless_get_text_action from .replace import cursorless_replace_action -def cursorless_homophones_action(target: CursorlessTarget): +def cursorless_homophones_action(target: CursorlessExplicitTarget): """Replaced target with next homophone""" texts = cursorless_get_text_action(target, show_decorations=False) try: diff --git a/src/actions/paste.py b/src/actions/paste.py index bcef75d9..5ee32b97 100644 --- a/src/actions/paste.py +++ b/src/actions/paste.py @@ -9,7 +9,9 @@ @mod.action_class class Actions: - def private_cursorless_paste(destination: CursorlessDestination): + def private_cursorless_paste( + destination: CursorlessDestination, # pyright: ignore [reportGeneralTypeIssues] + ): """Execute Cursorless paste action""" actions.user.private_cursorless_command_and_wait( { diff --git a/src/actions/reformat.py b/src/actions/reformat.py index ce2b89d4..1b60bee8 100644 --- a/src/actions/reformat.py +++ b/src/actions/reformat.py @@ -1,6 +1,9 @@ from talon import Module, actions -from ..targets.target_types import CursorlessTarget, PrimitiveDestination +from ..targets.target_types import ( + CursorlessExplicitTarget, + PrimitiveDestination, +) from .get_text import cursorless_get_text_action from .replace import cursorless_replace_action @@ -11,7 +14,10 @@ @mod.action_class class Actions: - def private_cursorless_reformat(target: CursorlessTarget, formatters: str): + def private_cursorless_reformat( + target: CursorlessExplicitTarget, # pyright: ignore [reportGeneralTypeIssues] + formatters: str, + ): """Execute Cursorless reformat action. Reformat target with formatter""" texts = cursorless_get_text_action(target, show_decorations=False) updated_texts = [actions.user.reformat_text(text, formatters) for text in texts] diff --git a/src/actions/swap.py b/src/actions/swap.py index cb3eb8d9..862f7dca 100644 --- a/src/actions/swap.py +++ b/src/actions/swap.py @@ -36,7 +36,9 @@ def cursorless_swap_targets(m) -> SwapTargets: @mod.action_class class Actions: - def private_cursorless_swap(targets: SwapTargets): + def private_cursorless_swap( + targets: SwapTargets, # pyright: ignore [reportGeneralTypeIssues] + ): """Execute Cursorless swap action""" actions.user.private_cursorless_command_and_wait( { diff --git a/src/actions/wrap.py b/src/actions/wrap.py index df0fe182..f9e846fc 100644 --- a/src/actions/wrap.py +++ b/src/actions/wrap.py @@ -10,7 +10,9 @@ @mod.action_class class Actions: def private_cursorless_wrap_with_paired_delimiter( - action_name: str, target: CursorlessTarget, paired_delimiter: list[str] + action_name: str, # pyright: ignore [reportGeneralTypeIssues] + target: CursorlessTarget, + paired_delimiter: list[str], ): """Execute Cursorless wrap/rewrap with paired delimiter action""" if action_name == "rewrap": @@ -26,7 +28,9 @@ def private_cursorless_wrap_with_paired_delimiter( ) def private_cursorless_wrap_with_snippet( - action_name: str, target: CursorlessTarget, snippet_location: str + action_name: str, # pyright: ignore [reportGeneralTypeIssues] + target: CursorlessTarget, + snippet_location: str, ): """Execute Cursorless wrap with snippet action""" if action_name == "wrapWithPairedDelimiter": diff --git a/src/apps/vscode_settings.py b/src/apps/vscode_settings.py index 42d05af1..f1ec80a6 100644 --- a/src/apps/vscode_settings.py +++ b/src/apps/vscode_settings.py @@ -28,8 +28,9 @@ class Actions: def vscode_settings_path() -> Path: """Get path of vscode settings json file""" + ... - def vscode_get_setting(key: str, default_value: Any = None): + def vscode_get_setting(key: str, default_value: Any = None): # pyright: ignore [reportGeneralTypeIssues] """Get the value of vscode setting at the given key""" path: Path = actions.user.vscode_settings_path() settings: dict = loads(path.read_text()) @@ -40,7 +41,7 @@ def vscode_get_setting(key: str, default_value: Any = None): return settings[key] def vscode_get_setting_with_fallback( - key: str, + key: str, # pyright: ignore [reportGeneralTypeIssues] default_value: Any, fallback_value: Any, fallback_message: str, diff --git a/src/cheatsheet/cheat_sheet.py b/src/cheatsheet/cheat_sheet.py index 673feb62..5d4b9385 100644 --- a/src/cheatsheet/cheat_sheet.py +++ b/src/cheatsheet/cheat_sheet.py @@ -76,7 +76,7 @@ def cheatsheet_dir_linux() -> Path: """Get cheatsheet directory for Linux""" try: # 1. Get users actual document directory - import platformdirs + import platformdirs # pyright: ignore [reportMissingImports] return Path(platformdirs.user_documents_dir()) except Exception: diff --git a/src/cheatsheet/get_list.py b/src/cheatsheet/get_list.py index c74f3643..341873fd 100644 --- a/src/cheatsheet/get_list.py +++ b/src/cheatsheet/get_list.py @@ -1,4 +1,5 @@ import re +import typing from collections.abc import Mapping, Sequence from typing import Optional, TypedDict @@ -37,7 +38,7 @@ def get_lists( def get_raw_list(name: str) -> Mapping[str, str]: cursorless_list_name = get_cursorless_list_name(name) - return registry.lists[cursorless_list_name][0].copy() + return typing.cast(dict[str, str], registry.lists[cursorless_list_name][0]).copy() def get_spoken_form_from_list(list_name: str, value: str) -> str: diff --git a/src/command.py b/src/command.py index 32967864..5d7c9459 100644 --- a/src/command.py +++ b/src/command.py @@ -16,7 +16,7 @@ class CursorlessCommand: CURSORLESS_COMMAND_ID = "cursorless.command" -last_phrase = None +last_phrase: dict = {} mod = Module() @@ -31,7 +31,7 @@ def on_phrase(d): @mod.action_class class Actions: - def private_cursorless_command_and_wait(action: dict): + def private_cursorless_command_and_wait(action: dict): # pyright: ignore [reportGeneralTypeIssues] """Execute cursorless command and wait for it to finish""" response = actions.user.private_cursorless_run_rpc_command_get( CURSORLESS_COMMAND_ID, @@ -40,14 +40,14 @@ def private_cursorless_command_and_wait(action: dict): if "fallback" in response: perform_fallback(response["fallback"]) - def private_cursorless_command_no_wait(action: dict): + def private_cursorless_command_no_wait(action: dict): # pyright: ignore [reportGeneralTypeIssues] """Execute cursorless command without waiting""" actions.user.private_cursorless_run_rpc_command_no_wait( CURSORLESS_COMMAND_ID, construct_cursorless_command(action), ) - def private_cursorless_command_get(action: dict): + def private_cursorless_command_get(action: dict): # pyright: ignore [reportGeneralTypeIssues] """Execute cursorless command and return result""" response = actions.user.private_cursorless_run_rpc_command_get( CURSORLESS_COMMAND_ID, diff --git a/src/csv_overrides.py b/src/csv_overrides.py index f9891139..f71b0d90 100644 --- a/src/csv_overrides.py +++ b/src/csv_overrides.py @@ -1,4 +1,5 @@ import csv +import typing from collections import defaultdict from collections.abc import Container from dataclasses import dataclass @@ -453,7 +454,9 @@ def get_full_path(filename: str): filename = f"{filename}.csv" user_dir: Path = actions.path.talon_user() - settings_directory = Path(settings.get("user.cursorless_settings_directory")) + settings_directory = Path( + typing.cast(str, settings.get("user.cursorless_settings_directory")) + ) if not settings_directory.is_absolute(): settings_directory = user_dir / settings_directory diff --git a/src/cursorless_command_server.py b/src/cursorless_command_server.py index c6177d30..78d30ad7 100644 --- a/src/cursorless_command_server.py +++ b/src/cursorless_command_server.py @@ -8,7 +8,9 @@ @mod.action_class class Actions: def private_cursorless_run_rpc_command_and_wait( - command_id: str, arg1: Any = None, arg2: Any = None + command_id: str, # pyright: ignore [reportGeneralTypeIssues] + arg1: Any = None, + arg2: Any = None, ): """Execute command via rpc and wait for command to finish.""" try: @@ -17,7 +19,9 @@ def private_cursorless_run_rpc_command_and_wait( actions.user.vscode_with_plugin_and_wait(command_id, arg1, arg2) def private_cursorless_run_rpc_command_no_wait( - command_id: str, arg1: Any = None, arg2: Any = None + command_id: str, # pyright: ignore [reportGeneralTypeIssues] + arg1: Any = None, + arg2: Any = None, ): """Execute command via rpc and DON'T wait.""" try: @@ -26,7 +30,9 @@ def private_cursorless_run_rpc_command_no_wait( actions.user.vscode_with_plugin(command_id, arg1, arg2) def private_cursorless_run_rpc_command_get( - command_id: str, arg1: Any = None, arg2: Any = None + command_id: str, # pyright: ignore [reportGeneralTypeIssues] + arg1: Any = None, + arg2: Any = None, ) -> Any: """Execute command via rpc and return command output.""" try: diff --git a/src/modifiers/surrounding_pair.py b/src/modifiers/surrounding_pair.py index a6df5b2b..72e1cbdd 100644 --- a/src/modifiers/surrounding_pair.py +++ b/src/modifiers/surrounding_pair.py @@ -11,7 +11,9 @@ "cursorless_delimiter_force_direction", desc="Can be used to force an ambiguous delimiter to extend in one direction", ) -ctx.lists["user.cursorless_delimiter_force_direction"] = [ +# FIXME: Remove type ignore once Talon supports list types +# See https://github.com/talonvoice/talon/issues/654 +ctx.lists["user.cursorless_delimiter_force_direction"] = [ # pyright: ignore [reportArgumentType] "left", "right", ] diff --git a/src/number_small.py b/src/number_small.py index 28ce298f..fd800ae2 100644 --- a/src/number_small.py +++ b/src/number_small.py @@ -33,7 +33,9 @@ def private_cursorless_number_small(m) -> int: number_small_map = {n: i for i, n in enumerate(number_small_list)} mod.list("private_cursorless_number_small", desc="List of small numbers") -ctx.lists["self.private_cursorless_number_small"] = number_small_map.keys() +# FIXME: Remove type ignore once Talon supports list types +# See https://github.com/talonvoice/talon/issues/654 +ctx.lists["self.private_cursorless_number_small"] = number_small_map.keys() # pyright: ignore [reportArgumentType] @ctx.capture( diff --git a/src/private_api/private_api.py b/src/private_api/private_api.py index dd047e21..16665942 100644 --- a/src/private_api/private_api.py +++ b/src/private_api/private_api.py @@ -25,14 +25,15 @@ class TargetBuilderActions: """Cursorless private api low-level target builder actions""" def cursorless_private_build_primitive_target( - modifiers: list[dict], mark: Optional[dict] + modifiers: list[dict], # pyright: ignore [reportGeneralTypeIssues] + mark: Optional[dict], ) -> PrimitiveTarget: """Cursorless private api low-level target builder: Create a primitive target""" return PrimitiveTarget(mark, modifiers) def cursorless_private_build_list_target( - elements: list[Union[PrimitiveTarget, RangeTarget]], - ) -> Union[PrimitiveTarget, ListTarget]: + elements: list[Union[PrimitiveTarget, RangeTarget]], # pyright: ignore [reportGeneralTypeIssues] + ) -> Union[PrimitiveTarget, RangeTarget, ListTarget]: """Cursorless private api low-level target builder: Create a list target""" if len(elements) == 1: return elements[0] @@ -50,7 +51,8 @@ def cursorless_private_target_nothing() -> PrimitiveTarget: @mod.action_class class ActionActions: def cursorless_private_action_highlight( - target: CursorlessTarget, highlightId: Optional[str] = None + target: CursorlessTarget, # pyright: ignore [reportGeneralTypeIssues] + highlightId: Optional[str] = None, ) -> None: """Cursorless private api: Highlights a target""" payload = { diff --git a/src/scope_visualizer.py b/src/scope_visualizer.py index 96180b8b..423796ba 100644 --- a/src/scope_visualizer.py +++ b/src/scope_visualizer.py @@ -12,7 +12,8 @@ @mod.action_class class Actions: def private_cursorless_show_scope_visualizer( - scope_type: dict, visualization_type: str + scope_type: dict, # pyright: ignore [reportGeneralTypeIssues] + visualization_type: str, ): """Shows scope visualizer""" actions.user.private_cursorless_run_rpc_command_no_wait( diff --git a/src/snippets.py b/src/snippets.py index ae4b766b..1a28fb1d 100644 --- a/src/snippets.py +++ b/src/snippets.py @@ -19,14 +19,14 @@ class InsertionSnippet: @dataclass class CommunityInsertionSnippet: body: str - scopes: list[str] = None + scopes: list[str] | None = None @dataclass class CommunityWrapperSnippet: body: str variable_name: str - scope: str = None + scope: str | None = None mod = Module() @@ -99,7 +99,7 @@ def insert_named_snippet( destination: CursorlessDestination, substitutions: Optional[dict] = None, ): - snippet = { + snippet: dict = { "type": "named", "name": name, } @@ -113,7 +113,7 @@ def insert_custom_snippet( destination: CursorlessDestination, scope_types: Optional[list[dict]] = None, ): - snippet = { + snippet: dict = { "type": "custom", "body": body, } @@ -126,7 +126,7 @@ def insert_custom_snippet( @mod.action_class class Actions: - def private_cursorless_insert_snippet(insertion_snippet: InsertionSnippet): + def private_cursorless_insert_snippet(insertion_snippet: InsertionSnippet): # pyright: ignore [reportGeneralTypeIssues] """Execute Cursorless insert snippet action""" insert_named_snippet( insertion_snippet.name, @@ -134,7 +134,8 @@ def private_cursorless_insert_snippet(insertion_snippet: InsertionSnippet): ) def private_cursorless_insert_snippet_with_phrase( - snippet_description: str, text: str + snippet_description: str, # pyright: ignore [reportGeneralTypeIssues] + text: str, ): """Cursorless: Insert snippet with phrase """ snippet_name, snippet_variable = snippet_description.split(".") @@ -144,7 +145,7 @@ def private_cursorless_insert_snippet_with_phrase( {snippet_variable: text}, ) - def cursorless_insert_snippet_by_name(name: str): + def cursorless_insert_snippet_by_name(name: str): # pyright: ignore [reportGeneralTypeIssues] """Cursorless: Insert named snippet """ insert_named_snippet( name, @@ -152,8 +153,8 @@ def cursorless_insert_snippet_by_name(name: str): ) def cursorless_insert_snippet( - body: str, - destination: Optional[CursorlessDestination] = ImplicitDestination(), + body: str, # pyright: ignore [reportGeneralTypeIssues] + destination: CursorlessDestination = ImplicitDestination(), scope_type: Optional[Union[str, list[str]]] = None, ): """Cursorless: Insert custom snippet """ @@ -168,7 +169,9 @@ def cursorless_insert_snippet( insert_custom_snippet(body, destination, scope_types) def cursorless_wrap_with_snippet_by_name( - name: str, variable_name: str, target: CursorlessTarget + name: str, # pyright: ignore [reportGeneralTypeIssues] + variable_name: str, + target: CursorlessTarget, ): """Cursorless: Wrap target with a named snippet """ wrap_with_snippet( @@ -181,7 +184,7 @@ def cursorless_wrap_with_snippet_by_name( ) def cursorless_wrap_with_snippet( - body: str, + body: str, # pyright: ignore [reportGeneralTypeIssues] target: CursorlessTarget, variable_name: Optional[str] = None, scope: Optional[str] = None, @@ -201,7 +204,8 @@ def cursorless_wrap_with_snippet( ) def private_cursorless_insert_community_snippet( - name: str, destination: CursorlessDestination + name: str, # pyright: ignore [reportGeneralTypeIssues] + destination: CursorlessDestination, ): """Cursorless: Insert community snippet """ snippet: CommunityInsertionSnippet = actions.user.get_insertion_snippet(name) @@ -210,7 +214,8 @@ def private_cursorless_insert_community_snippet( ) def private_cursorless_wrap_with_community_snippet( - name: str, target: CursorlessTarget + name: str, # pyright: ignore [reportGeneralTypeIssues] + target: CursorlessTarget, ): """Cursorless: Wrap target with community snippet """ snippet: CommunityWrapperSnippet = actions.user.get_wrapper_snippet(name) diff --git a/src/targets/target_types.py b/src/targets/target_types.py index 49e02832..05800e52 100644 --- a/src/targets/target_types.py +++ b/src/targets/target_types.py @@ -40,6 +40,11 @@ class ListTarget: PrimitiveTarget, ImplicitTarget, ] +CursorlessExplicitTarget = Union[ + ListTarget, + RangeTarget, + PrimitiveTarget, +] @dataclass diff --git a/src/terms.py b/src/terms.py index f8ef66c6..d41727af 100644 --- a/src/terms.py +++ b/src/terms.py @@ -12,7 +12,9 @@ "Various alternative pronunciations of 'cursorless' to improve accuracy", ) -ctx.lists["user.cursorless_homophone"] = [ +# FIXME: Remove type ignore once Talon supports list types +# See https://github.com/talonvoice/talon/issues/654 +ctx.lists["user.cursorless_homophone"] = [ # pyright: ignore [reportArgumentType] "cursorless", "cursor less", "cursor list",