Complete pyautogui stubs (#8684)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Samuel T
2022-09-09 07:34:45 -04:00
committed by GitHub
parent 8a8db9c6d4
commit 4f2666ba8e
3 changed files with 193 additions and 52 deletions

View File

@@ -69,7 +69,6 @@
"stubs/pep8-naming",
"stubs/psutil",
"stubs/psycopg2",
"stubs/PyAutoGUI",
"stubs/pyflakes",
"stubs/Pygments",
"stubs/PyMySQL",

View File

@@ -1,4 +1,5 @@
version = "0.9.*"
requires = ["types-Pillow"]
[tool.stubtest]
# pyautogui requires a display, resulting in the following error on the CI:

View File

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