Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and improve pygame.typing module #3080

Merged
merged 16 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions buildconfig/stubs/pygame/typing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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: ...


Expand All @@ -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
37 changes: 23 additions & 14 deletions buildconfig/stubs/typing_sample_app.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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

Expand All @@ -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

Expand All @@ -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
Expand All @@ -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())
35 changes: 25 additions & 10 deletions src_py/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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: ...


Expand All @@ -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
Loading