Skip to content

Commit c3d5fdc

Browse files
authored
Merge pull request #3080 from aatle/fix-typing
Fix and improve `pygame.typing` module
2 parents c507028 + d2c254f commit c3d5fdc

File tree

3 files changed

+73
-34
lines changed

3 files changed

+73
-34
lines changed

buildconfig/stubs/pygame/typing.pyi

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,29 @@
33
# NOTE: `src_py/typing.py` and `buildconfig/stubs/pygame/typing.pyi` must be duplicates.
44
# Use the command `python buildconfig/stubs/gen_stubs.py` to copy typing.py to typing.pyi
55

6+
__all__ = [
7+
"RectLike",
8+
"SequenceLike",
9+
"FileLike",
10+
"PathLike",
11+
"ColorLike",
12+
"RGBATuple",
13+
"Coordinate",
14+
"IntCoordinate",
15+
]
16+
617
import sys
7-
from typing import IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex
18+
from abc import abstractmethod
19+
from typing import IO, Callable, Tuple, Union, TypeVar, Protocol
820

921
if sys.version_info >= (3, 9):
1022
from os import PathLike as _PathProtocol
1123
else:
12-
_T = TypeVar("_T", bound=Union[str, bytes])
24+
_AnyStr_co = TypeVar("_AnyStr_co", str, bytes, covariant=True)
1325

14-
class _PathProtocol(Protocol[_T]):
15-
def __fspath__(self) -> _T: ...
26+
class _PathProtocol(Protocol[_AnyStr_co]):
27+
@abstractmethod
28+
def __fspath__(self) -> _AnyStr_co: ...
1629

1730

1831
# For functions that take a file name
@@ -28,7 +41,9 @@ class SequenceLike(Protocol[_T_co]):
2841
Variant of the standard `Sequence` ABC that only requires `__getitem__` and `__len__`.
2942
"""
3043

31-
def __getitem__(self, __i: SupportsIndex) -> _T_co: ...
44+
@abstractmethod
45+
def __getitem__(self, index: int, /) -> _T_co: ...
46+
@abstractmethod
3247
def __len__(self) -> int: ...
3348

3449

@@ -44,16 +59,16 @@ IntCoordinate = SequenceLike[int]
4459
RGBATuple = Tuple[int, int, int, int]
4560
ColorLike = Union[int, str, SequenceLike[int]]
4661

47-
_CanBeRect = SequenceLike[Union[float, Coordinate]]
48-
4962

5063
class _HasRectAttribute(Protocol):
5164
# An object that has a rect attribute that is either a rect, or a function
5265
# that returns a rect conforms to the rect protocol
53-
rect: Union["RectLike", Callable[[], "RectLike"]]
66+
@property
67+
def rect(self) -> Union["RectLike", Callable[[], "RectLike"]]: ...
68+
5469

70+
RectLike = Union[SequenceLike[float], SequenceLike[Coordinate], _HasRectAttribute]
5571

56-
RectLike = Union[_CanBeRect, _HasRectAttribute]
5772

5873
# cleanup namespace
59-
del sys, IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex
74+
del sys, abstractmethod, IO, Callable, Tuple, Union, TypeVar, Protocol

buildconfig/stubs/typing_sample_app.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
"""
2-
Sample app run by mypy to ensure typing.py aliases work as expected
3-
"""
1+
"""Sample app run by mypy to ensure typing.py aliases work as expected"""
2+
43
from pygame import typing
54
import pygame
65
import pathlib
76

7+
88
# validate SequenceLike
99
class MySequence:
10-
def __getitem__(self, index):
10+
def __getitem__(self, index: int) -> str:
1111
if index > 20:
1212
raise IndexError()
1313
if index % 2 == 0:
14-
return 1
15-
return 0
16-
17-
def __len__(self):
14+
return "a"
15+
return "bc"
16+
17+
def __len__(self) -> int:
1818
return 20
19-
19+
2020
def validator_SequenceLike(sequence: typing.SequenceLike) -> int:
2121
return 0
2222

@@ -40,14 +40,15 @@ def validator_SequenceLikeTypes(
4040
(-1.5, -0.5, 0, 0.5, 2.5, 10),
4141
(-2, -1, 0, 1, 2, 3),
4242
"abcdefghijklmnopqrstuvwxyz",
43-
[(0.5, 1.5), (-1, 1), "123", [(), (), ()]]
43+
[(0.5, 1.5), (-1, 1), "123", [(), (), ()]],
4444
)
4545

46+
4647
# validate PathLike
4748
class MyPath:
4849
def __fspath__(self) -> str:
4950
return "file.py"
50-
51+
5152
def validator_PathLike(path: typing.PathLike) -> int:
5253
return 0
5354

@@ -57,8 +58,8 @@ def validator_PathLike(path: typing.PathLike) -> int:
5758
validator_PathLike(pathlib.Path("file.py"))
5859
validator_PathLike(MyPath())
5960

60-
# validate Coordinate, IntCoordinate
6161

62+
# validate Coordinate, IntCoordinate
6263
def validator_Coordinate(coordinate: typing.Coordinate) -> int:
6364
return 0
6465

@@ -75,6 +76,7 @@ def validator_IntCoordinate(coordinate: typing.IntCoordinate) -> int:
7576
validator_IntCoordinate((3, 4))
7677
validator_IntCoordinate([-4, -3])
7778

79+
7880
# validate RGBATuple, ColorLike
7981
def validator_RGBATuple(rgba: typing.RGBATuple) -> int:
8082
return 0
@@ -89,21 +91,28 @@ def validator_ColorLike(color: typing.ColorLike) -> int:
8991
validator_ColorLike((255, 255, 255, 30))
9092
validator_ColorLike(pygame.Color(100, 100, 100, 100))
9193

94+
9295
# validate RectLike
9396
class MyObject1:
9497
def __init__(self):
9598
self.rect = pygame.Rect(10, 10, 20, 20)
96-
99+
97100
class MyObject2:
98101
def __init__(self):
99102
self.rect = lambda: pygame.Rect(5, 5, 10, 10)
100-
103+
104+
class MyObject3:
105+
def rect(self) -> pygame.Rect:
106+
return pygame.Rect(15, 15, 30, 30)
107+
101108
def validator_RectLike(rect: typing.RectLike) -> int:
102109
return 0
103110

104111
# must pass
105112
validator_RectLike((10, 10, 10, 10))
106113
validator_RectLike(((5, 5), (30, 30)))
114+
validator_RectLike(([3, 3.2], pygame.Vector2()))
107115
validator_RectLike(pygame.Rect(1, 2, 3, 4))
108116
validator_RectLike(MyObject1())
109117
validator_RectLike(MyObject2())
118+
validator_RectLike(MyObject3())

src_py/typing.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,29 @@
33
# NOTE: `src_py/typing.py` and `buildconfig/stubs/pygame/typing.pyi` must be duplicates.
44
# Use the command `python buildconfig/stubs/gen_stubs.py` to copy typing.py to typing.pyi
55

6+
__all__ = [
7+
"RectLike",
8+
"SequenceLike",
9+
"FileLike",
10+
"PathLike",
11+
"ColorLike",
12+
"RGBATuple",
13+
"Coordinate",
14+
"IntCoordinate",
15+
]
16+
617
import sys
7-
from typing import IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex
18+
from abc import abstractmethod
19+
from typing import IO, Callable, Tuple, Union, TypeVar, Protocol
820

921
if sys.version_info >= (3, 9):
1022
from os import PathLike as _PathProtocol
1123
else:
12-
_T = TypeVar("_T", bound=Union[str, bytes])
24+
_AnyStr_co = TypeVar("_AnyStr_co", str, bytes, covariant=True)
1325

14-
class _PathProtocol(Protocol[_T]):
15-
def __fspath__(self) -> _T: ...
26+
class _PathProtocol(Protocol[_AnyStr_co]):
27+
@abstractmethod
28+
def __fspath__(self) -> _AnyStr_co: ...
1629

1730

1831
# For functions that take a file name
@@ -28,7 +41,9 @@ class SequenceLike(Protocol[_T_co]):
2841
Variant of the standard `Sequence` ABC that only requires `__getitem__` and `__len__`.
2942
"""
3043

31-
def __getitem__(self, __i: SupportsIndex) -> _T_co: ...
44+
@abstractmethod
45+
def __getitem__(self, index: int, /) -> _T_co: ...
46+
@abstractmethod
3247
def __len__(self) -> int: ...
3348

3449

@@ -44,16 +59,16 @@ def __len__(self) -> int: ...
4459
RGBATuple = Tuple[int, int, int, int]
4560
ColorLike = Union[int, str, SequenceLike[int]]
4661

47-
_CanBeRect = SequenceLike[Union[float, Coordinate]]
48-
4962

5063
class _HasRectAttribute(Protocol):
5164
# An object that has a rect attribute that is either a rect, or a function
5265
# that returns a rect conforms to the rect protocol
53-
rect: Union["RectLike", Callable[[], "RectLike"]]
66+
@property
67+
def rect(self) -> Union["RectLike", Callable[[], "RectLike"]]: ...
68+
5469

70+
RectLike = Union[SequenceLike[float], SequenceLike[Coordinate], _HasRectAttribute]
5571

56-
RectLike = Union[_CanBeRect, _HasRectAttribute]
5772

5873
# cleanup namespace
59-
del sys, IO, Callable, Tuple, Union, TypeVar, Protocol, SupportsIndex
74+
del sys, abstractmethod, IO, Callable, Tuple, Union, TypeVar, Protocol

0 commit comments

Comments
 (0)