diff --git a/stubs/greenlet/@tests/stubtest_allowlist.txt b/stubs/greenlet/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000..38d2d0569 --- /dev/null +++ b/stubs/greenlet/@tests/stubtest_allowlist.txt @@ -0,0 +1,7 @@ +# Error: is not present in stub +# ============================= +# this module only contains C code and exports no Python code, so it's better +# if we pretend it doesn't exist +greenlet.platform +# the tests should not be part of the modules +greenlet.tests diff --git a/stubs/greenlet/@tests/test_cases/check_greenlet.py b/stubs/greenlet/@tests/test_cases/check_greenlet.py new file mode 100644 index 000000000..976772d17 --- /dev/null +++ b/stubs/greenlet/@tests/test_cases/check_greenlet.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +from typing import Optional +from typing_extensions import assert_type + +import greenlet + +g = greenlet.greenlet() +h = greenlet.greenlet() +assert_type(g.parent, Optional[greenlet.greenlet]) +g.parent = h + +# Although "parent" sometimes can be None at runtime, +# it's always illegal for it to be set to None +g.parent = None # type: ignore diff --git a/stubs/greenlet/METADATA.toml b/stubs/greenlet/METADATA.toml new file mode 100644 index 000000000..3e0cb4f94 --- /dev/null +++ b/stubs/greenlet/METADATA.toml @@ -0,0 +1,2 @@ +version = "2.0.*" +upstream_repository = "https://github.com/python-greenlet/greenlet" diff --git a/stubs/greenlet/greenlet/__init__.pyi b/stubs/greenlet/greenlet/__init__.pyi new file mode 100644 index 000000000..8fe0be636 --- /dev/null +++ b/stubs/greenlet/greenlet/__init__.pyi @@ -0,0 +1,9 @@ +from ._greenlet import ( + _C_API as _C_API, + GreenletExit as GreenletExit, + error as error, + getcurrent as getcurrent, + gettrace as gettrace, + greenlet as greenlet, + settrace as settrace, +) diff --git a/stubs/greenlet/greenlet/_greenlet.pyi b/stubs/greenlet/greenlet/_greenlet.pyi new file mode 100644 index 000000000..e3ec8a53c --- /dev/null +++ b/stubs/greenlet/greenlet/_greenlet.pyi @@ -0,0 +1,74 @@ +from collections.abc import Callable +from contextvars import Context +from types import FrameType, TracebackType +from typing import Any, Protocol, overload +from typing_extensions import Literal, TypeAlias + +_TraceEvent: TypeAlias = Literal["switch", "throw"] +_TraceCallback: TypeAlias = Callable[[_TraceEvent, tuple[greenlet, greenlet]], object] + +CLOCKS_PER_SEC: int +GREENLET_USE_CONTEXT_VARS: bool +GREENLET_USE_GC: bool +GREENLET_USE_STANDARD_THREADING: bool +GREENLET_USE_TRACING: bool +# this is a PyCapsule, it may be used to pass the gevent C-API to another C-extension +# there isn't a runtime type for this, since it's only an opaque wrapper around void* +# but it's probably still better than pretending it doesn't exist, so people that need +# to pass this around, can still pass it around without having to ignore type errors... +_C_API: object + +class _ParentDescriptor(Protocol): + def __get__(self, obj: greenlet, owner: type[greenlet] | None = None) -> greenlet | None: ... + def __set__(self, obj: greenlet, value: greenlet) -> None: ... + +class GreenletExit(BaseException): ... +class error(Exception): ... + +class greenlet: + @property + def dead(self) -> bool: ... + @property + def gr_context(self) -> Context | None: ... + @gr_context.setter + def gr_context(self, value: Context | None) -> None: ... + @property + def gr_frame(self) -> FrameType | None: ... + # the parent attribute is a bit special, since it can't be set to `None` manually, but + # it can be `None` for the master greenlet which will always be around, regardless of + # how many greenlets have been spawned explicitly. Since there can only be one such + # greenlet per thread, there is no way to create another one manually. + parent: _ParentDescriptor + @property + def run(self) -> Callable[..., Any]: ... + @run.setter + def run(self, value: Callable[..., Any]) -> None: ... + def __init__(self, run: Callable[..., Any] | None = None, parent: greenlet | None = None) -> None: ... + def switch(self, *args: Any, **kwargs: Any) -> Any: ... + @overload + def throw( + self, __typ: type[BaseException] = ..., __val: BaseException | object = None, __tb: TracebackType | None = None + ) -> Any: ... + @overload + def throw(self, __typ: BaseException = ..., __val: None = None, __tb: TracebackType | None = None) -> Any: ... + def __bool__(self) -> bool: ... + + # aliases for some module attributes/methods + GreenletExit: type[GreenletExit] + error: type[error] + @staticmethod + def getcurrent() -> greenlet: ... + @staticmethod + def gettrace() -> _TraceCallback | None: ... + @staticmethod + def settrace(__callback: _TraceCallback | None) -> _TraceCallback | None: ... + +def enable_optional_cleanup(__enabled: bool) -> None: ... +def get_clocks_used_doing_optional_cleanup() -> int: ... +def get_pending_cleanup_count() -> int: ... +def get_total_main_greenlets() -> int: ... +def get_tstate_trash_delete_nesting() -> int: ... +def getcurrent() -> greenlet: ... +def gettrace() -> _TraceCallback | None: ... +def set_thread_local(__key: object, __value: object) -> None: ... +def settrace(__callback: _TraceCallback | None) -> _TraceCallback | None: ...