diff --git a/buildconfig/stubs/pygame/typing.pyi b/buildconfig/stubs/pygame/typing.pyi index 883fe2def1..f3f7aad434 100644 --- a/buildconfig/stubs/pygame/typing.pyi +++ b/buildconfig/stubs/pygame/typing.pyi @@ -3,16 +3,29 @@ # NOTE: `src_py/typing.py` and `buildconfig/stubs/pygame/typing.pyi` must be duplicates. # Use the command `python buildconfig/stubs/gen_stubs.py` to copy typing.py to typing.pyi +__all__ = [ + "RectLike", + "SequenceLike", + "FileLike", + "PathLike", + "ColorLike", + "RGBATuple", + "Coordinate", + "IntCoordinate", +] + import sys -from typing import IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex +from abc import abstractmethod +from typing import IO, Callable, Tuple, Union, TypeVar, Protocol if sys.version_info >= (3, 9): from os import PathLike as _PathProtocol else: - _T = TypeVar("_T", bound=Union[str, bytes]) + _AnyStr_co = TypeVar("_AnyStr_co", str, bytes, covariant=True) - class _PathProtocol(Protocol[_T]): - def __fspath__(self) -> _T: ... + class _PathProtocol(Protocol[_AnyStr_co]): + @abstractmethod + def __fspath__(self) -> _AnyStr_co: ... # For functions that take a file name @@ -28,7 +41,9 @@ class SequenceLike(Protocol[_T_co]): Variant of the standard `Sequence` ABC that only requires `__getitem__` and `__len__`. """ - def __getitem__(self, __i: SupportsIndex) -> _T_co: ... + @abstractmethod + def __getitem__(self, index: int, /) -> _T_co: ... + @abstractmethod def __len__(self) -> int: ... @@ -44,16 +59,16 @@ IntCoordinate = SequenceLike[int] RGBATuple = Tuple[int, int, int, int] ColorLike = Union[int, str, SequenceLike[int]] -_CanBeRect = SequenceLike[Union[float, Coordinate]] - class _HasRectAttribute(Protocol): # An object that has a rect attribute that is either a rect, or a function # that returns a rect conforms to the rect protocol - rect: Union["RectLike", Callable[[], "RectLike"]] + @property + def rect(self) -> Union["RectLike", Callable[[], "RectLike"]]: ... + +RectLike = Union[SequenceLike[float], SequenceLike[Coordinate], _HasRectAttribute] -RectLike = Union[_CanBeRect, _HasRectAttribute] # cleanup namespace -del sys, IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex +del sys, abstractmethod, IO, Callable, Tuple, Union, TypeVar, Protocol diff --git a/buildconfig/stubs/typing_sample_app.py b/buildconfig/stubs/typing_sample_app.py index dae94bd0ac..33b3bac0a8 100644 --- a/buildconfig/stubs/typing_sample_app.py +++ b/buildconfig/stubs/typing_sample_app.py @@ -1,22 +1,22 @@ -""" -Sample app run by mypy to ensure typing.py aliases work as expected -""" +"""Sample app run by mypy to ensure typing.py aliases work as expected""" + from pygame import typing import pygame import pathlib + # validate SequenceLike class MySequence: - def __getitem__(self, index): + def __getitem__(self, index: int) -> str: if index > 20: raise IndexError() if index % 2 == 0: - return 1 - return 0 - - def __len__(self): + return "a" + return "bc" + + def __len__(self) -> int: return 20 - + def validator_SequenceLike(sequence: typing.SequenceLike) -> int: return 0 @@ -40,14 +40,15 @@ def validator_SequenceLikeTypes( (-1.5, -0.5, 0, 0.5, 2.5, 10), (-2, -1, 0, 1, 2, 3), "abcdefghijklmnopqrstuvwxyz", - [(0.5, 1.5), (-1, 1), "123", [(), (), ()]] + [(0.5, 1.5), (-1, 1), "123", [(), (), ()]], ) + # validate PathLike class MyPath: def __fspath__(self) -> str: return "file.py" - + def validator_PathLike(path: typing.PathLike) -> int: return 0 @@ -57,8 +58,8 @@ def validator_PathLike(path: typing.PathLike) -> int: validator_PathLike(pathlib.Path("file.py")) validator_PathLike(MyPath()) -# validate Coordinate, IntCoordinate +# validate Coordinate, IntCoordinate def validator_Coordinate(coordinate: typing.Coordinate) -> int: return 0 @@ -75,6 +76,7 @@ def validator_IntCoordinate(coordinate: typing.IntCoordinate) -> int: validator_IntCoordinate((3, 4)) validator_IntCoordinate([-4, -3]) + # validate RGBATuple, ColorLike def validator_RGBATuple(rgba: typing.RGBATuple) -> int: return 0 @@ -89,21 +91,28 @@ def validator_ColorLike(color: typing.ColorLike) -> int: validator_ColorLike((255, 255, 255, 30)) validator_ColorLike(pygame.Color(100, 100, 100, 100)) + # validate RectLike class MyObject1: def __init__(self): self.rect = pygame.Rect(10, 10, 20, 20) - + class MyObject2: def __init__(self): self.rect = lambda: pygame.Rect(5, 5, 10, 10) - + +class MyObject3: + def rect(self) -> pygame.Rect: + return pygame.Rect(15, 15, 30, 30) + def validator_RectLike(rect: typing.RectLike) -> int: return 0 # must pass validator_RectLike((10, 10, 10, 10)) validator_RectLike(((5, 5), (30, 30))) +validator_RectLike(([3, 3.2], pygame.Vector2())) validator_RectLike(pygame.Rect(1, 2, 3, 4)) validator_RectLike(MyObject1()) validator_RectLike(MyObject2()) +validator_RectLike(MyObject3()) diff --git a/src_py/typing.py b/src_py/typing.py index 883fe2def1..f3f7aad434 100644 --- a/src_py/typing.py +++ b/src_py/typing.py @@ -3,16 +3,29 @@ # NOTE: `src_py/typing.py` and `buildconfig/stubs/pygame/typing.pyi` must be duplicates. # Use the command `python buildconfig/stubs/gen_stubs.py` to copy typing.py to typing.pyi +__all__ = [ + "RectLike", + "SequenceLike", + "FileLike", + "PathLike", + "ColorLike", + "RGBATuple", + "Coordinate", + "IntCoordinate", +] + import sys -from typing import IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex +from abc import abstractmethod +from typing import IO, Callable, Tuple, Union, TypeVar, Protocol if sys.version_info >= (3, 9): from os import PathLike as _PathProtocol else: - _T = TypeVar("_T", bound=Union[str, bytes]) + _AnyStr_co = TypeVar("_AnyStr_co", str, bytes, covariant=True) - class _PathProtocol(Protocol[_T]): - def __fspath__(self) -> _T: ... + class _PathProtocol(Protocol[_AnyStr_co]): + @abstractmethod + def __fspath__(self) -> _AnyStr_co: ... # For functions that take a file name @@ -28,7 +41,9 @@ class SequenceLike(Protocol[_T_co]): Variant of the standard `Sequence` ABC that only requires `__getitem__` and `__len__`. """ - def __getitem__(self, __i: SupportsIndex) -> _T_co: ... + @abstractmethod + def __getitem__(self, index: int, /) -> _T_co: ... + @abstractmethod def __len__(self) -> int: ... @@ -44,16 +59,16 @@ def __len__(self) -> int: ... RGBATuple = Tuple[int, int, int, int] ColorLike = Union[int, str, SequenceLike[int]] -_CanBeRect = SequenceLike[Union[float, Coordinate]] - class _HasRectAttribute(Protocol): # An object that has a rect attribute that is either a rect, or a function # that returns a rect conforms to the rect protocol - rect: Union["RectLike", Callable[[], "RectLike"]] + @property + def rect(self) -> Union["RectLike", Callable[[], "RectLike"]]: ... + +RectLike = Union[SequenceLike[float], SequenceLike[Coordinate], _HasRectAttribute] -RectLike = Union[_CanBeRect, _HasRectAttribute] # cleanup namespace -del sys, IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex +del sys, abstractmethod, IO, Callable, Tuple, Union, TypeVar, Protocol