Fix or suppress all Python type errors (#2307)

- 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
This commit is contained in:
Pokey Rule 2024-04-28 16:11:52 +01:00 committed by GitHub
parent cb042d67b9
commit d7dd8003f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 116 additions and 57 deletions

View File

@ -42,17 +42,23 @@ class UserActions:
return True
def private_cursorless_run_rpc_command_and_wait(
command_id: str, arg1: Any, arg2: Any = None
command_id: str, # pyright: ignore [reportGeneralTypeIssues]
arg1: Any,
arg2: Any = None,
):
commands_run.append(arg1)
def private_cursorless_run_rpc_command_no_wait(
command_id: str, arg1: Any, arg2: Any = None
command_id: str, # pyright: ignore [reportGeneralTypeIssues]
arg1: Any,
arg2: Any = None,
):
commands_run.append(arg1)
def private_cursorless_run_rpc_command_get(
command_id: str, arg1: Any, arg2: Any = None
command_id: str, # pyright: ignore [reportGeneralTypeIssues]
arg1: Any,
arg2: Any = None,
) -> Any:
commands_run.append(arg1)
return mockedGetValue
@ -60,7 +66,7 @@ class UserActions:
@mod.action_class
class Actions:
def private_cursorless_spoken_form_test_mode(enable: bool):
def private_cursorless_spoken_form_test_mode(enable: bool): # pyright: ignore [reportGeneralTypeIssues]
"""Enable/disable Cursorless spoken form test mode"""
global saved_modes, saved_microphone
@ -84,7 +90,7 @@ class Actions:
"Cursorless spoken form tests are done. Talon microphone is re-enabled."
)
def private_cursorless_use_community_snippets(enable: bool):
def private_cursorless_use_community_snippets(enable: bool): # pyright: ignore [reportGeneralTypeIssues]
"""Enable/disable cursorless community snippets in test mode"""
if enable:
tags = set(ctx.tags)
@ -99,7 +105,8 @@ class Actions:
print(f"Set community snippet enablement to {enable}")
def private_cursorless_spoken_form_test(
phrase: str, mockedGetValue_: Optional[str]
phrase: str, # pyright: ignore [reportGeneralTypeIssues]
mockedGetValue_: Optional[str],
):
"""Run Cursorless spoken form test"""
global commands_run, mockedGetValue

View File

@ -4,6 +4,7 @@ from talon import Module, actions
from ..targets.target_types import (
CursorlessDestination,
CursorlessExplicitTarget,
CursorlessTarget,
ImplicitDestination,
)
@ -48,7 +49,7 @@ ACTION_LIST_NAMES = [
"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 @@ class Actions:
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 @@ class Actions:
"""
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 @@ class Actions:
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"]

View File

@ -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(
{

View File

@ -9,7 +9,7 @@ mod.list("cursorless_call_action", desc="Cursorless call action")
@mod.action_class
class Actions:
def private_cursorless_call(
callee: CursorlessTarget,
callee: CursorlessTarget, # pyright: ignore [reportGeneralTypeIssues]
argument: CursorlessTarget = ImplicitTarget(),
):
"""Execute Cursorless call action"""

View File

@ -10,7 +10,7 @@ mod = Module()
@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 @@ class Actions:
)[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"""

View File

@ -2,12 +2,15 @@ from typing import Optional
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:

View File

@ -9,7 +9,9 @@ mod.list("cursorless_paste_action", desc="Cursorless paste action")
@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(
{

View File

@ -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.list("cursorless_reformat_action", desc="Cursorless reformat action")
@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]

View File

@ -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(
{

View File

@ -10,7 +10,9 @@ mod.list("cursorless_wrap_action", desc="Cursorless wrap action")
@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 @@ class Actions:
)
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":

View File

@ -28,8 +28,9 @@ os: linux
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 @@ class Actions:
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,

View File

@ -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:

View File

@ -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:

View File

@ -16,7 +16,7 @@ class CursorlessCommand:
CURSORLESS_COMMAND_ID = "cursorless.command"
last_phrase = None
last_phrase: dict = {}
mod = Module()
@ -31,7 +31,7 @@ speech_system.register("pre:phrase", on_phrase)
@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 @@ class Actions:
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,

View File

@ -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

View File

@ -8,7 +8,9 @@ mod = Module()
@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 @@ class Actions:
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 @@ class Actions:
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:

View File

@ -11,7 +11,9 @@ mod.list(
"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",
]

View File

@ -33,7 +33,9 @@ for ten in tens:
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(

View File

@ -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 @@ class TargetActions:
@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 = {

View File

@ -12,7 +12,8 @@ mod.list(
@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(

View File

@ -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 @@ class Actions:
)
def private_cursorless_insert_snippet_with_phrase(
snippet_description: str, text: str
snippet_description: str, # pyright: ignore [reportGeneralTypeIssues]
text: str,
):
"""Cursorless: Insert snippet <snippet_description> with phrase <text>"""
snippet_name, snippet_variable = snippet_description.split(".")
@ -144,7 +145,7 @@ class Actions:
{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 <name>"""
insert_named_snippet(
name,
@ -152,8 +153,8 @@ class Actions:
)
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 <body>"""
@ -168,7 +169,9 @@ class Actions:
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 <name>"""
wrap_with_snippet(
@ -181,7 +184,7 @@ class Actions:
)
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 @@ class Actions:
)
def private_cursorless_insert_community_snippet(
name: str, destination: CursorlessDestination
name: str, # pyright: ignore [reportGeneralTypeIssues]
destination: CursorlessDestination,
):
"""Cursorless: Insert community snippet <name>"""
snippet: CommunityInsertionSnippet = actions.user.get_insertion_snippet(name)
@ -210,7 +214,8 @@ class Actions:
)
def private_cursorless_wrap_with_community_snippet(
name: str, target: CursorlessTarget
name: str, # pyright: ignore [reportGeneralTypeIssues]
target: CursorlessTarget,
):
"""Cursorless: Wrap target with community snippet <name>"""
snippet: CommunityWrapperSnippet = actions.user.get_wrapper_snippet(name)

View File

@ -40,6 +40,11 @@ CursorlessTarget = Union[
PrimitiveTarget,
ImplicitTarget,
]
CursorlessExplicitTarget = Union[
ListTarget,
RangeTarget,
PrimitiveTarget,
]
@dataclass

View File

@ -12,7 +12,9 @@ mod.list(
"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",

View File

@ -17,3 +17,5 @@ ignore = ["E501", "SIM105", "UP007", "UP035"]
[tool.pyright]
reportSelfClsParameterName = false
reportMissingModuleSource = false
exclude = ["**/node_modules", "**/__pycache__", "**/.*", "**/vendor", "data/playground"]