diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 798b9e9c9de4..4ec042db84e6 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -87,6 +87,7 @@ "stubs/SQLAlchemy", "stubs/stripe", "stubs/tqdm", + "stubs/tree-sitter", "stubs/tzlocal/tzlocal/utils.pyi", "stubs/ttkthemes", "stubs/urllib3", diff --git a/stubs/tree-sitter/@tests/stubtest_allowlist.txt b/stubs/tree-sitter/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000000..0b012eb99055 --- /dev/null +++ b/stubs/tree-sitter/@tests/stubtest_allowlist.txt @@ -0,0 +1,31 @@ +# "self" argument is missing when stubtest inspects these methods +tree_sitter.Node.child_by_field_id +tree_sitter.Node.child_by_field_name +tree_sitter.Node.sexp +tree_sitter.Node.walk +tree_sitter.Parser.parse +tree_sitter.Parser.set_language +tree_sitter.Tree.edit +tree_sitter.Tree.walk +tree_sitter.TreeCursor.current_field_name +tree_sitter.TreeCursor.goto_first_child +tree_sitter.TreeCursor.goto_next_sibling +tree_sitter.TreeCursor.goto_parent +tree_sitter.binding.Node.child_by_field_id +tree_sitter.binding.Node.child_by_field_name +tree_sitter.binding.Node.sexp +tree_sitter.binding.Node.walk +tree_sitter.binding.Parser.parse +tree_sitter.binding.Parser.set_language +tree_sitter.binding.Query.captures +tree_sitter.binding.Query.matches +tree_sitter.binding.Tree.edit +tree_sitter.binding.Tree.walk +tree_sitter.binding.TreeCursor.current_field_name +tree_sitter.binding.TreeCursor.goto_first_child +tree_sitter.binding.TreeCursor.goto_next_sibling +tree_sitter.binding.TreeCursor.goto_parent + +# Runtime takes *args and **kwargs and ignores them. Passing arguments is most likely a mistake. +tree_sitter.Parser.__init__ +tree_sitter.binding.Parser.__init__ diff --git a/stubs/tree-sitter/METADATA.toml b/stubs/tree-sitter/METADATA.toml new file mode 100644 index 000000000000..997ea098d4ca --- /dev/null +++ b/stubs/tree-sitter/METADATA.toml @@ -0,0 +1,4 @@ +version = "0.20.*" + +[tool.stubtest] +ignore_missing_stub = false diff --git a/stubs/tree-sitter/tree_sitter/__init__.pyi b/stubs/tree-sitter/tree_sitter/__init__.pyi new file mode 100644 index 000000000000..2450e0a9540f --- /dev/null +++ b/stubs/tree-sitter/tree_sitter/__init__.pyi @@ -0,0 +1,17 @@ +import ctypes +from _typeshed import StrPath +from collections.abc import Sequence + +# Query is missing at runtime for some reason +from tree_sitter.binding import Node as Node, Parser as Parser, Tree as Tree, TreeCursor as TreeCursor + +class Language: + @staticmethod + def build_library(output_path: str, repo_paths: Sequence[StrPath]) -> bool: ... + name: str + lib: ctypes.CDLL + language_id: int + # library_path is passed into ctypes LoadLibrary + def __init__(self, library_path: str, name: str) -> None: ... + def field_id_for_name(self, name): ... + def query(self, source): ... diff --git a/stubs/tree-sitter/tree_sitter/binding.pyi b/stubs/tree-sitter/tree_sitter/binding.pyi new file mode 100644 index 000000000000..8e175394426a --- /dev/null +++ b/stubs/tree-sitter/tree_sitter/binding.pyi @@ -0,0 +1,94 @@ +from typing import Any, ClassVar +from typing_extensions import final + +from tree_sitter import Language + +@final +class Node: + @property + def start_byte(self) -> int: ... + @property + def start_point(self) -> tuple[int, int]: ... + @property + def end_byte(self) -> int: ... + @property + def end_point(self) -> tuple[int, int]: ... + @property + def has_changes(self) -> bool: ... + @property + def has_error(self) -> bool: ... + @property + def is_missing(self) -> bool: ... + @property + def is_named(self) -> bool: ... + @property + def child_count(self) -> int: ... + @property + def named_child_count(self) -> bool: ... + @property + def children(self) -> list[Node]: ... + @property + def next_named_sibling(self) -> Node | None: ... + @property + def next_sibling(self) -> Node | None: ... + @property + def parent(self) -> Node | None: ... + @property + def prev_named_sibling(self) -> Node | None: ... + @property + def prev_sibling(self) -> Node | None: ... + @property + def text(self) -> bytes | Any: ... # can be None, but annoying to check + @property + def type(self) -> str: ... + __hash__: ClassVar[None] # type: ignore[assignment] + def child_by_field_id(self, __id: int) -> Node | None: ... + def child_by_field_name(self, __name: str) -> Node | None: ... + def sexp(self) -> str: ... + def walk(self) -> TreeCursor: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + # There are __ge__, __gt__, __le__, __lt__ methods but they always return False + # + # >>> n + # + # >>> n >= "", n <= "", n >= 0, n <= 0, n >= (0,0), n <= (0,0) + # (False, False, False, False, False, False) + +@final +class Parser: + # At runtime, Parser(1, 2, 3) ignores the arguments, but that's most likely buggy code + def __init__(self) -> None: ... + def parse(self, source: bytes, old_tree: Tree | None = ..., keep_text: bool = ...) -> Tree: ... + def set_language(self, __language: Language) -> None: ... + +@final +class Query: + # start_point and end_point arguments don't seem to do anything + def captures(self) -> list[tuple[Node, str]]: ... + +@final +class Tree: + @property + def root_node(self) -> Node: ... + @property + def text(self) -> bytes | Any: ... # technically ReadableBuffer | Any + def edit( + self, + start_byte: int, + old_end_byte: int, + new_end_byte: int, + start_point: tuple[int, int], + old_end_point: tuple[int, int], + new_end_point: tuple[int, int], + ) -> None: ... + def walk(self) -> TreeCursor: ... + +@final +class TreeCursor: + @property + def node(self) -> Node: ... + def current_field_name(self) -> str | None: ... + def goto_first_child(self) -> bool: ... + def goto_next_sibling(self) -> bool: ... + def goto_parent(self) -> bool: ...