Skip to content

Commit

Permalink
Merge pull request #3080 from aatle/fix-typing
Browse files Browse the repository at this point in the history
Fix and improve `pygame.typing` module
  • Loading branch information
ankith26 authored Aug 27, 2024
2 parents c507028 + d2c254f commit c3d5fdc
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 34 deletions.
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

0 comments on commit c3d5fdc

Please sign in to comment.