diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 86227ac6a..668861ee5 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -69,7 +69,6 @@ "stubs/pep8-naming", "stubs/psutil", "stubs/psycopg2", - "stubs/PyAutoGUI", "stubs/pyflakes", "stubs/Pygments", "stubs/PyMySQL", diff --git a/stubs/PyAutoGUI/METADATA.toml b/stubs/PyAutoGUI/METADATA.toml index c0c77d1f6..94211917e 100644 --- a/stubs/PyAutoGUI/METADATA.toml +++ b/stubs/PyAutoGUI/METADATA.toml @@ -1,4 +1,5 @@ version = "0.9.*" +requires = ["types-Pillow"] [tool.stubtest] # pyautogui requires a display, resulting in the following error on the CI: diff --git a/stubs/PyAutoGUI/pyautogui/__init__.pyi b/stubs/PyAutoGUI/pyautogui/__init__.pyi index f5ca56afc..7f64c470a 100644 --- a/stubs/PyAutoGUI/pyautogui/__init__.pyi +++ b/stubs/PyAutoGUI/pyautogui/__init__.pyi @@ -1,10 +1,11 @@ import contextlib +from _typeshed import Incomplete from collections.abc import Callable, Generator, Iterable, Sequence from datetime import datetime -from typing import NamedTuple, TypeVar, overload -from typing_extensions import ParamSpec +from typing import NamedTuple, SupportsFloat, SupportsInt, TypeVar, overload +from typing_extensions import ParamSpec, SupportsIndex, TypeAlias -# from pyscreeze import Box +from PIL import Image class PyAutoGUIException(Exception): ... class FailSafeException(PyAutoGUIException): ... @@ -12,12 +13,14 @@ class ImageNotFoundException(PyAutoGUIException): ... _P = ParamSpec("_P") _R = TypeVar("_R") +_NormalizeableXArg: TypeAlias = str | SupportsInt | Sequence[SupportsInt] +_Unused: TypeAlias = object -# TODO: Complete types with pyscreeze once we can import it as a type dependency -# Actually `pyscreeze.Box`, but typeshed doesn't currently have stubs for pyscreeze -# (and the library doesn't have type annotations either) +# TODO: cv2.Mat is not available as a type yet: https://github.com/microsoft/python-type-stubs/issues/211 +# cv2.Mat is just an alias for a numpy NDArray, but can't import that either. +_Mat: TypeAlias = Incomplete -class _Box(NamedTuple): +class _Box(NamedTuple): # Same as pyscreeze.Box left: int top: int width: int @@ -25,13 +28,150 @@ class _Box(NamedTuple): def raisePyAutoGUIImageNotFoundException(wrappedFunction: Callable[_P, _R]) -> Callable[_P, _R]: ... -# These functions reuse pyscreeze functions directly. See above TODO. -def locate(*args, **kwargs) -> _Box | None: ... -def locateAll(*args, **kwargs) -> Generator[_Box, None, None]: ... -def locateAllOnScreen(*args, **kwargs) -> Generator[_Box, None, None]: ... -def locateCenterOnScreen(*args, **kwargs) -> Point | None: ... -def locateOnScreen(*args, **kwargs) -> _Box | None: ... -def locateOnWindow(*args, **kwargs) -> _Box | None: ... +# These functions reuse pyscreeze functions directly. +# TODO: Once pyscreeze is typed, we can alias them to simplify this stub + +# _locateAll_opencv +@overload +def locate( + needleImage: str | Image.Image | _Mat, + haystackImage: str | Image.Image | _Mat, + grayscale: bool | None = ..., + limit: _Unused = ..., + region: _Box | None = ..., + step: int = ..., + confidence: SupportsFloat = ..., +) -> _Box | None: ... + +# _locateAll_python / _locateAll_pillow +@overload +def locate( + needleImage: str | Image.Image, + haystackImage: str | Image.Image, + grayscale: bool | None = ..., + limit: _Unused = ..., + region: _Box | None = ..., + step: int = ..., + confidence: None = ..., +) -> _Box | None: ... + +# _locateAll_opencv +@overload +def locateAll( + needleImage: str | Image.Image | _Mat, + haystackImage: str | Image.Image | _Mat, + grayscale: bool | None = ..., + limit: int = ..., + region: _Box | None = ..., + step: int = ..., + confidence: SupportsFloat = ..., +) -> Generator[_Box, None, None]: ... + +# _locateAll_python / _locateAll_pillow +@overload +def locateAll( + needleImage: str | Image.Image, + haystackImage: str | Image.Image, + grayscale: bool | None = ..., + limit: int | None = ..., + region: _Box | None = ..., + step: int = ..., + confidence: None = ..., +) -> Generator[_Box, None, None]: ... + +# _locateAll_opencv +@overload +def locateAllOnScreen( + image: str | Image.Image | _Mat, + grayscale: bool | None = ..., + limit: int = ..., + region: _Box | None = ..., + step: int = ..., + confidence: SupportsFloat = ..., +) -> Generator[_Box, None, None]: ... + +# _locateAll_python / _locateAll_pillow +@overload +def locateAllOnScreen( + image: str | Image.Image, + grayscale: bool | None = ..., + limit: int | None = ..., + region: _Box | None = ..., + step: int = ..., + confidence: None = ..., +) -> Generator[_Box, None, None]: ... + +# _locateAll_opencv +@overload +def locateCenterOnScreen( + image: str | Image.Image | _Mat, + minSearchTime: float, + grayscale: bool | None = ..., + limit: _Unused = ..., + region: _Box | None = ..., + step: int = ..., + confidence: SupportsFloat = ..., +) -> Point | None: ... + +# _locateAll_python / _locateAll_pillow +@overload +def locateCenterOnScreen( + image: str | Image.Image, + minSearchTime: float, + grayscale: bool | None = ..., + limit: _Unused = ..., + region: _Box | None = ..., + step: int = ..., + confidence: None = ..., +) -> Point | None: ... + +# _locateAll_opencv +@overload +def locateOnScreen( + image: str | Image.Image | _Mat, + minSearchTime: float, + grayscale: bool | None = ..., + limit: _Unused = ..., + region: _Box | None = ..., + step: int = ..., + confidence: SupportsFloat = ..., +) -> _Box | None: ... + +# _locateAll_python / _locateAll_pillow +@overload +def locateOnScreen( + image: str | Image.Image, + minSearchTime: float, + grayscale: bool | None = ..., + limit: _Unused = ..., + region: _Box | None = ..., + step: int = ..., + confidence: None = ..., +) -> _Box | None: ... + +# _locateAll_opencv +@overload +def locateOnWindow( + image: str | Image.Image | _Mat, + title: str, + grayscale: bool | None = ..., + limit: _Unused = ..., + step: int = ..., + confidence: SupportsFloat = ..., +) -> _Box | None: ... + +# _locateAll_python / _locateAll_pillow +@overload +def locateOnWindow( + image: str | Image.Image, + title: str, + grayscale: bool | None = ..., + limit: _Unused = ..., + step: int = ..., + confidence: None = ..., +) -> _Box | None: ... + +# end of reused pyscreeze functions def mouseInfo() -> None: ... def useImageNotFoundException(value: bool | None = ...) -> None: ... @@ -69,13 +209,10 @@ def getPointOnLine(x1: float, y1: float, x2: float, y2: float, n: float) -> tupl def linear(n: float) -> float: ... def position(x: int | None = ..., y: int | None = ...) -> Point: ... def size() -> Size: ... -@overload -def onScreen(x: tuple[float, float], y: None = ...) -> bool: ... -@overload -def onScreen(x: float, y: float) -> bool: ... +def onScreen(x: _NormalizeableXArg | None, y: SupportsInt | None = ...) -> bool: ... def mouseDown( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., # Docstring says `button` can also be `int`, but `.lower()` is called unconditionally in `_normalizeButton()` button: str = ..., duration: float = ..., @@ -84,8 +221,8 @@ def mouseDown( _pause: bool = ..., ) -> None: ... def mouseUp( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., # Docstring says `button` can also be `int`, but `.lower()` is called unconditionally in `_normalizeButton()` button: str = ..., duration: float = ..., @@ -94,9 +231,9 @@ def mouseUp( _pause: bool = ..., ) -> None: ... def click( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., - clicks: int = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., + clicks: SupportsIndex = ..., interval: float = ..., # Docstring says `button` can also be `int`, but `.lower()` is called unconditionally in `_normalizeButton()` button: str = ..., @@ -106,8 +243,8 @@ def click( _pause: bool = ..., ) -> None: ... def leftClick( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., interval: float = ..., duration: float = ..., tween: Callable[[float], float] = ..., @@ -115,8 +252,8 @@ def leftClick( _pause: bool = ..., ) -> None: ... def rightClick( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., interval: float = ..., duration: float = ..., tween: Callable[[float], float] = ..., @@ -124,8 +261,8 @@ def rightClick( _pause: bool = ..., ) -> None: ... def middleClick( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., interval: float = ..., duration: float = ..., tween: Callable[[float], float] = ..., @@ -133,8 +270,8 @@ def middleClick( _pause: bool = ..., ) -> None: ... def doubleClick( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., interval: float = ..., # Docstring says `button` can also be `int`, but `.lower()` is called unconditionally in `_normalizeButton()` button: str = ..., @@ -144,8 +281,8 @@ def doubleClick( _pause: bool = ..., ) -> None: ... def tripleClick( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., interval: float = ..., # Docstring says `button` can also be `int`, but `.lower()` is called unconditionally in `_normalizeButton()` button: str = ..., @@ -156,36 +293,36 @@ def tripleClick( ) -> None: ... def scroll( clicks: float, - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., logScreenshot: bool | None = ..., _pause: bool = ..., ) -> None: ... def hscroll( clicks: float, - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., logScreenshot: bool | None = ..., _pause: bool = ..., ) -> None: ... def vscroll( clicks: float, - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., logScreenshot: bool | None = ..., _pause: bool = ..., ) -> None: ... def moveTo( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., duration: float = ..., tween: Callable[[float], float] = ..., logScreenshot: bool = ..., _pause: bool = ..., ) -> None: ... def moveRel( - xOffset: float | Sequence[float] | str | None = ..., - yOffset: float | None = ..., + xOffset: _NormalizeableXArg | None = ..., + yOffset: SupportsInt | None = ..., duration: float = ..., tween: Callable[[float], float] = ..., logScreenshot: bool = ..., @@ -195,8 +332,8 @@ def moveRel( move = moveRel def dragTo( - x: float | Sequence[float] | str | None = ..., - y: float | None = ..., + x: _NormalizeableXArg | None = ..., + y: SupportsInt | None = ..., duration: float = ..., tween: Callable[[float], float] = ..., # Docstring says `button` can also be `int`, but `.lower()` is called unconditionally in `_normalizeButton()` @@ -206,8 +343,8 @@ def dragTo( mouseDownUp: bool = ..., ) -> None: ... def dragRel( - xOffset: float | Sequence[float] | str = ..., - yOffset: float = ..., + xOffset: _NormalizeableXArg | None = ..., + yOffset: SupportsInt | None = ..., duration: float = ..., tween: Callable[[float], float] = ..., # Docstring says `button` can also be `int`, but `.lower()` is called unconditionally in `_normalizeButton()` @@ -223,7 +360,11 @@ def isValidKey(key: str) -> bool: ... def keyDown(key: str, logScreenshot: bool | None = ..., _pause: bool = ...) -> None: ... def keyUp(key: str, logScreenshot: bool | None = ..., _pause: bool = ...) -> None: ... def press( - keys: str | Iterable[str], presses: int = ..., interval: float = ..., logScreenshot: bool | None = ..., _pause: bool = ... + keys: str | Iterable[str], + presses: SupportsIndex = ..., + interval: float = ..., + logScreenshot: bool | None = ..., + _pause: bool = ..., ) -> None: ... def hold( keys: str | Iterable[str], logScreenshot: bool | None = ..., _pause: bool = ... @@ -238,7 +379,7 @@ def hotkey(*args: str, logScreenshot: bool | None = ..., interval: float = ...) def failSafeCheck() -> None: ... def displayMousePosition(xOffset: float = ..., yOffset: float = ...) -> None: ... def sleep(seconds: float) -> None: ... -def countdown(seconds: int) -> None: ... +def countdown(seconds: SupportsIndex) -> None: ... def run(commandStr: str, _ssCount: Sequence[int] | None = ...) -> None: ... def printInfo(dontPrint: bool = ...) -> str: ... def getInfo() -> tuple[str, str, str, str, Size, datetime]: ...