Skip to content

Commit d20f900

Browse files
committed
Introduce custom 'Sequence' to fix issues
1 parent 1f48a95 commit d20f900

File tree

17 files changed

+155
-83
lines changed

17 files changed

+155
-83
lines changed
Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,104 @@
11
from os import PathLike
2-
from typing import IO, Callable, Sequence, Tuple, Union
2+
from typing import IO, Callable, Tuple, Union, TypeVar
33

4-
from typing_extensions import Literal as Literal
4+
from typing_extensions import Literal as Literal, SupportsIndex as SupportsIndex
55
from typing_extensions import Protocol
66

7-
from pygame.color import Color
8-
from pygame.math import Vector2
9-
from pygame.rect import Rect, FRect
10-
117
# For functions that take a file name
128
AnyPath = Union[str, bytes, PathLike[str], PathLike[bytes]]
139

1410
# Most pygame functions that take a file argument should be able to handle
1511
# a FileArg type
1612
FileArg = Union[AnyPath, IO[bytes], IO[str]]
1713

18-
Coordinate = Union[Tuple[float, float], Sequence[float], Vector2]
14+
_T = TypeVar("_T", covariant=True)
15+
16+
class Sequence(Protocol[_T]):
17+
"""
18+
This is different from the standard python 'Sequence' abc. This is used in places
19+
where only __getitem__ and __len__ is actually needed (basically almost all places
20+
where a sequence is used). The standard 'Sequence' abc has some extra methods.
21+
"""
22+
def __getitem__(self, __i: SupportsIndex) -> _T: ...
23+
def __len__(self) -> int: ...
24+
25+
# Right now, it isn't possible to annotate sizes (popular tools don't support it) but
26+
# when it is, the below types should be appropriately annotated
27+
28+
# Yes, float. The reason being, pygame handles float without erroring in a lot of places
29+
# where a coordinate is expected (usually by rounding to int).
30+
# Also, 'Union[int, float] == float'
31+
Coordinate = Sequence[float]
32+
33+
# This is used in places where ints are strictly required
34+
IntCoordinate = Sequence[int]
1935

20-
# This typehint is used when a function would return an RGBA tuble
36+
# This typehint is used when a function would return an RGBA tuple
2137
RGBAOutput = Tuple[int, int, int, int]
22-
ColorValue = Union[Color, int, str, Tuple[int, int, int], RGBAOutput, Sequence[int]]
23-
24-
_CanBeRect = Union[
25-
Rect,
26-
FRect,
27-
Tuple[int, int, int, int],
28-
Tuple[float, float, float, float],
29-
Tuple[Coordinate, Coordinate],
30-
Sequence[int],
31-
Sequence[float],
32-
Sequence[Coordinate],
33-
]
38+
ColorValue = Union[int, str, Sequence[int]]
39+
40+
_CanBeRect = Sequence[Union[float, Coordinate]]
3441

3542
class _HasRectAttribute(Protocol):
3643
# An object that has a rect attribute that is either a rect, or a function
3744
# that returns a rect confirms to the rect protocol
3845
rect: Union[RectValue, Callable[[], RectValue]]
3946

4047
RectValue = Union[_CanBeRect, _HasRectAttribute]
48+
49+
"""
50+
# testing code
51+
def a(b: Coordinate):
52+
b[0]
53+
b[1]
54+
len(b)
55+
e1, e2 = b
56+
for i in b:
57+
i -= 1
58+
59+
60+
import numpy
61+
from pygame import Vector2
62+
63+
class MyAmoger:
64+
def __init__(self):
65+
pass
66+
67+
def __getitem__(self, index):
68+
if index not in (0, 1):
69+
raise IndexError()
70+
71+
return 42 if index else 69
72+
73+
def __len__(self):
74+
return 2
75+
76+
77+
# should pass
78+
a([1, 2])
79+
a([4.2, 5.2])
80+
a((1, 2))
81+
a((1.4, 2.8))
82+
a(MyAmoger())
83+
a(range(2, 4)) # yes, range object is a 'Sequence'
84+
a(numpy.array([1.3, 2.1]))
85+
a(b"ab") # weird but this actually works in code (this represents (97, 98) btw)
86+
a(bytearray([1, 2]))
87+
a(Vector2())
88+
89+
print("Done testing the passes!")
90+
91+
# should technically error, but right now we can't annotate sizes so they pass on
92+
# type testing
93+
a([1, 2, 3])
94+
a([4.2, 5.2, 2, 4])
95+
a((1,))
96+
a(numpy.array([1.3, 2.1, 4.2]))
97+
98+
# all of the below should always error
99+
a({})
100+
a({1: 2})
101+
a("abc")
102+
a({1, 2})
103+
104+
"""

buildconfig/stubs/pygame/camera.pyi

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from abc import ABC, abstractmethod
2-
from typing import List, Optional, Sequence, Tuple, Union
2+
from typing import List, Optional, Tuple, Union
3+
4+
from ._common import IntCoordinate
35

46
from pygame.surface import Surface
57

@@ -31,7 +33,7 @@ class Camera(AbstractCamera):
3133
def __init__(
3234
self,
3335
device: Union[str, int] = 0,
34-
size: Union[Tuple[int, int], Sequence[int]] = (640, 480),
36+
size: IntCoordinate = (640, 480),
3537
format: str = "RGB",
3638
) -> None: ...
3739
def start(self) -> None: ...

buildconfig/stubs/pygame/color.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import sys
22
from typing import Any, Dict, Iterator, Tuple, Union, overload
33

4-
from ._common import ColorValue
4+
from ._common import ColorValue, SupportsIndex
55

66
if sys.version_info >= (3, 9):
77
from collections.abc import Collection
@@ -28,7 +28,7 @@ class Color(Collection[int]):
2828
@overload
2929
def __init__(self, rgbvalue: ColorValue) -> None: ...
3030
@overload
31-
def __getitem__(self, i: int) -> int: ...
31+
def __getitem__(self, i: SupportsIndex) -> int: ...
3232
@overload
3333
def __getitem__(self, s: slice) -> Tuple[int]: ...
3434
def __setitem__(self, key: int, value: int) -> None: ...

buildconfig/stubs/pygame/cursors.pyi

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from typing import Any, Iterator, Sequence, Tuple, Union, overload
1+
from typing import Any, Iterator, Tuple, Union, overload
22

33
from pygame.surface import Surface
44

5-
from ._common import FileArg, Literal
5+
from ._common import FileArg, Literal, IntCoordinate, Sequence
66

77
_Small_string = Tuple[
88
str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str
@@ -64,15 +64,15 @@ class Cursor:
6464
@overload
6565
def __init__(
6666
self,
67-
size: Union[Tuple[int, int], Sequence[int]],
68-
hotspot: Union[Tuple[int, int], Sequence[int]],
67+
size: IntCoordinate,
68+
hotspot: IntCoordinate,
6969
xormasks: Sequence[int],
7070
andmasks: Sequence[int],
7171
) -> None: ...
7272
@overload
7373
def __init__(
7474
self,
75-
hotspot: Union[Tuple[int, int], Sequence[int]],
75+
hotspot: IntCoordinate,
7676
surface: Surface,
7777
) -> None: ...
7878
def __iter__(self) -> Iterator[Any]: ...
@@ -81,11 +81,11 @@ class Cursor:
8181
def __hash__(self) -> int: ...
8282
def __getitem__(
8383
self, index: int
84-
) -> Union[int, Tuple[int, int], Sequence[int], Surface]: ...
84+
) -> Union[int, IntCoordinate, Surface]: ...
8585
copy = __copy__
8686
type: Literal["system", "color", "bitmap"]
8787
data: Union[
8888
Tuple[int],
8989
Tuple[Tuple[int, int], Tuple[int, int], Tuple[int, ...], Tuple[int, ...]],
90-
Tuple[Union[Tuple[int, int], Sequence[int]], Surface],
90+
Tuple[IntCoordinate, Surface],
9191
]

buildconfig/stubs/pygame/display.pyi

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
from typing import Union, Tuple, List, Optional, Dict, Sequence, overload
1+
from typing import Dict, List, Optional, Tuple, Union, overload
22

3-
from pygame.surface import Surface
43
from pygame.constants import FULLSCREEN
5-
from ._common import Coordinate, RectValue, ColorValue, RGBAOutput
4+
from pygame.surface import Surface
5+
6+
from ._common import (
7+
ColorValue,
8+
Coordinate,
9+
IntCoordinate,
10+
RectValue,
11+
RGBAOutput,
12+
Sequence,
13+
)
614

715
class _VidInfo:
816
hw: int
@@ -51,7 +59,7 @@ def list_modes(
5159
display: int = 0,
5260
) -> List[Tuple[int, int]]: ...
5361
def mode_ok(
54-
size: Union[Sequence[int], Tuple[int, int]],
62+
size: IntCoordinate,
5563
flags: int = 0,
5664
depth: int = 0,
5765
display: int = 0,

buildconfig/stubs/pygame/draw.pyi

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
from typing import Optional, Sequence
2-
31
from pygame.rect import Rect
42
from pygame.surface import Surface
53

6-
from ._common import ColorValue, Coordinate, RectValue
4+
from ._common import ColorValue, Coordinate, RectValue, Sequence
75

86
def rect(
97
surface: Surface,

buildconfig/stubs/pygame/event.pyi

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ from typing import (
33
Dict,
44
List,
55
Optional,
6-
Sequence,
7-
SupportsInt,
8-
Tuple,
96
Union,
107
final,
11-
overload,
128
)
139

10+
from ._common import Sequence
11+
1412
@final
1513
class Event:
1614
type: int
@@ -25,7 +23,7 @@ class Event:
2523
def __delattr__(self, name: str) -> None: ...
2624
def __bool__(self) -> bool: ...
2725

28-
_EventTypes = Union[SupportsInt, Tuple[SupportsInt, ...], Sequence[SupportsInt]]
26+
_EventTypes = Union[int, Sequence[int]]
2927

3028
def pump() -> None: ...
3129
def get(

buildconfig/stubs/pygame/gfxdraw.pyi

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
from typing import Sequence
2-
31
from pygame.surface import Surface
42

5-
from ._common import ColorValue, Coordinate, RectValue
3+
from ._common import ColorValue, Coordinate, RectValue, Sequence
64

75
def pixel(surface: Surface, x: int, y: int, color: ColorValue) -> None: ...
86
def hline(surface: Surface, x1: int, x2: int, y: int, color: ColorValue) -> None: ...

buildconfig/stubs/pygame/image.pyi

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from typing import Optional, Sequence, Tuple, Union
1+
from typing import Optional, Tuple, Union
22

33
from pygame.bufferproxy import BufferProxy
44
from pygame.surface import Surface
55

6-
from ._common import FileArg, Literal
6+
from ._common import FileArg, Literal, IntCoordinate
77

88
_BufferStyle = Union[BufferProxy, bytes, bytearray, memoryview]
99
_to_string_format = Literal[
@@ -23,7 +23,7 @@ def tostring(
2323
) -> bytes: ...
2424
def fromstring(
2525
bytes: bytes,
26-
size: Union[Sequence[int], Tuple[int, int]],
26+
size: IntCoordinate,
2727
format: _from_string_format,
2828
flipped: bool = False,
2929
pitch: int = -1,
@@ -35,14 +35,14 @@ def tobytes(
3535
) -> bytes: ...
3636
def frombytes(
3737
bytes: bytes,
38-
size: Union[Sequence[int], Tuple[int, int]],
38+
size: IntCoordinate,
3939
format: _from_string_format,
4040
flipped: bool = False,
4141
pitch: int = -1,
4242
) -> Surface: ...
4343
def frombuffer(
4444
bytes: _BufferStyle,
45-
size: Union[Sequence[int], Tuple[int, int]],
45+
size: IntCoordinate,
4646
format: _from_buffer_format,
4747
pitch: int = -1,
4848
) -> Surface: ...

buildconfig/stubs/pygame/mask.pyi

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, List, Optional, Sequence, Tuple, Union
1+
from typing import Any, List, Optional, Tuple, Union
22

33
from pygame.rect import Rect
44
from pygame.surface import Surface
@@ -41,9 +41,7 @@ class Mask:
4141
output: Optional[Mask] = None,
4242
offset: Coordinate = (0, 0),
4343
) -> Mask: ...
44-
def connected_component(
45-
self, pos: Union[Sequence[int], Tuple[int, int]] = ...
46-
) -> Mask: ...
44+
def connected_component(self, pos: Coordinate = ...) -> Mask: ...
4745
def connected_components(self, minimum: int = 0) -> List[Mask]: ...
4846
def get_bounding_rects(self) -> Rect: ...
4947
def to_surface(

0 commit comments

Comments
 (0)