From 763aa7ed497ecedbcc05dc6e6a325a6c75c1525e Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:12:02 -0700 Subject: [PATCH 1/9] Remove redunant _HasRadiusAndRect protocol --- buildconfig/stubs/pygame/sprite.pyi | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 25f5986f07..1b56bc2e19 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -43,10 +43,6 @@ class _HasImageAndRect(_HasRect, Protocol): class _HasMaskAndRect(_HasRect, Protocol): mask: Mask -# radius in addition to rect -class _HasRadiusAndRect(_HasRect, Protocol): - radius: float - # non-generic Group, used in Sprite _Group = AbstractGroup[Any] @@ -220,7 +216,7 @@ class collide_rect_ratio: def __call__(self, left: _HasRect, right: _HasRect) -> bool: ... # must have rect attribute, may optionally have radius attribute -_SupportsCollideCircle = Union[_HasRect, _HasRadiusAndRect] +_SupportsCollideCircle = _HasRect def collide_circle( left: _SupportsCollideCircle, right: _SupportsCollideCircle From fa42eb9b46217bf3400e6e177841338f57eac9d0 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:13:01 -0700 Subject: [PATCH 2/9] Fix GroupSingle.sprite optional type --- buildconfig/stubs/pygame/sprite.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 1b56bc2e19..5a56a382ac 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -204,7 +204,7 @@ class LayeredDirty(LayeredUpdates[_TDirtySprite]): def set_timing_treshold(self, time_ms: SupportsFloat) -> None: ... class GroupSingle(AbstractGroup[_TSprite]): - sprite: _TSprite + sprite: Optional[_TSprite] def __init__(self, sprite: Optional[_TSprite] = None) -> None: ... # argument to collide_rect must have rect attribute From ecbf7bdc21284cd71f1408ec4775f63b2f3a1f6d Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:20:55 -0700 Subject: [PATCH 3/9] Type _GroupOrGroups, rename _SpriteOrIterable --- buildconfig/stubs/pygame/sprite.pyi | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 5a56a382ac..dec265b7a8 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -64,8 +64,8 @@ class _SupportsSprite(_HasImageAndRect, Protocol): def add_internal(self, group: _Group) -> None: ... def remove_internal(self, group: _Group) -> None: ... def update(self, *args: Any, **kwargs: Any) -> None: ... - def add(self, *groups: _Group) -> None: ... - def remove(self, *groups: _Group) -> None: ... + def add(self, *groups: _GroupOrGroups[Any]) -> None: ... + def remove(self, *groups: _GroupOrGroups[Any]) -> None: ... def kill(self) -> None: ... def alive(self) -> bool: ... def groups(self) -> list[_Group]: ... @@ -94,12 +94,12 @@ class Sprite(_SupportsSprite): def layer(self) -> int: ... @layer.setter def layer(self, value: int) -> None: ... - def __init__(self, *groups: _Group) -> None: ... + def __init__(self, *groups: _GroupOrGroups[Any]) -> None: ... def add_internal(self, group: _Group) -> None: ... def remove_internal(self, group: _Group) -> None: ... def update(self, *args: Any, **kwargs: Any) -> None: ... - def add(self, *groups: _Group) -> None: ... - def remove(self, *groups: _Group) -> None: ... + def add(self, *groups: _GroupOrGroups[Any]) -> None: ... + def remove(self, *groups: _GroupOrGroups[Any]) -> None: ... def kill(self) -> None: ... def alive(self) -> bool: ... def groups(self) -> list[AbstractGroup[_SupportsSprite]]: ... @@ -120,8 +120,8 @@ _TSprite = TypeVar("_TSprite", bound=_SupportsSprite) _TSprite2 = TypeVar("_TSprite2", bound=_SupportsSprite) _TDirtySprite = TypeVar("_TDirtySprite", bound=_SupportsDirtySprite) -# typevar for sprite or iterable of sprites, used in Group init, add and remove -_SpriteOrIterable = Union[_TSprite, Iterable[_SpriteOrIterable[_TSprite]]] +_GroupOrGroups = Union[AbstractGroup[_TSprite], Iterable[_GroupOrGroups[_TSprite]]] +_SpriteOrSprites = Union[_TSprite, Iterable[_SpriteOrSprites[_TSprite]]] class AbstractGroup(Generic[_TSprite]): spritedict: dict[_TSprite, Optional[Union[FRect, Rect]]] @@ -137,9 +137,9 @@ class AbstractGroup(Generic[_TSprite]): def has_internal(self, sprite: _TSprite) -> bool: ... def copy(self) -> Self: ... def sprites(self) -> list[_TSprite]: ... - def add(self, *sprites: _SpriteOrIterable[_TSprite]) -> None: ... - def remove(self, *sprites: _SpriteOrIterable[_TSprite]) -> None: ... - def has(self, *sprites: _SpriteOrIterable[_TSprite]) -> bool: ... + def add(self, *sprites: _SpriteOrSprites[_TSprite]) -> None: ... + def remove(self, *sprites: _SpriteOrSprites[_TSprite]) -> None: ... + def has(self, *sprites: _SpriteOrSprites[_TSprite]) -> bool: ... def update(self, *args: Any, **kwargs: Any) -> None: ... def draw( self, surface: Surface, bgd: Optional[Surface] = None, special_flags: int = 0 @@ -152,7 +152,7 @@ class AbstractGroup(Generic[_TSprite]): def empty(self) -> None: ... class Group(AbstractGroup[_TSprite]): - def __init__(self, *sprites: _SpriteOrIterable[_TSprite]) -> None: ... + def __init__(self, *sprites: _SpriteOrSprites[_TSprite]) -> None: ... # these are aliased in the code too @deprecated("Use `pygame.sprite.Group` instead") @@ -167,10 +167,8 @@ class RenderUpdates(Group[_TSprite]): ... class OrderedUpdates(RenderUpdates[_TSprite]): ... class LayeredUpdates(AbstractGroup[_TSprite]): - def __init__( - self, *sprites: _SpriteOrIterable[_TSprite], **kwargs: Any - ) -> None: ... - def add(self, *sprites: _SpriteOrIterable[_TSprite], **kwargs: Any) -> None: ... + def __init__(self, *sprites: _SpriteOrSprites[_TSprite], **kwargs: Any) -> None: ... + def add(self, *sprites: _SpriteOrSprites[_TSprite], **kwargs: Any) -> None: ... def get_sprites_at(self, pos: Point) -> list[_TSprite]: ... def get_sprite(self, idx: int) -> _TSprite: ... def remove_sprites_of_layer(self, layer_nr: int) -> list[_TSprite]: ... From 0aded362a231a24ebe53ccd49efd93d45e081b99 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:25:21 -0700 Subject: [PATCH 4/9] Remove _SupportsSprite and _SupportsDirtySprite protocols --- buildconfig/stubs/pygame/sprite.pyi | 50 ++++------------------------- 1 file changed, 6 insertions(+), 44 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index dec265b7a8..0caca647f8 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -46,42 +46,7 @@ class _HasMaskAndRect(_HasRect, Protocol): # non-generic Group, used in Sprite _Group = AbstractGroup[Any] -# protocol helps with structural subtyping for typevars in sprite group generics -# and allows the use of any class with the required attributes and methods -class _SupportsSprite(_HasImageAndRect, Protocol): - @property - def image(self) -> Optional[Surface]: ... - @image.setter - def image(self, value: Optional[Surface]) -> None: ... - @property - def rect(self) -> Optional[Union[FRect, Rect]]: ... - @rect.setter - def rect(self, value: Optional[Union[FRect, Rect]]) -> None: ... - @property - def layer(self) -> int: ... - @layer.setter - def layer(self, value: int) -> None: ... - def add_internal(self, group: _Group) -> None: ... - def remove_internal(self, group: _Group) -> None: ... - def update(self, *args: Any, **kwargs: Any) -> None: ... - def add(self, *groups: _GroupOrGroups[Any]) -> None: ... - def remove(self, *groups: _GroupOrGroups[Any]) -> None: ... - def kill(self) -> None: ... - def alive(self) -> bool: ... - def groups(self) -> list[_Group]: ... - -# also a protocol -class _SupportsDirtySprite(_SupportsSprite, Protocol): - dirty: int - blendmode: int - source_rect: Union[FRect, Rect] - visible: int - _layer: int - def _set_visible(self, val: int) -> None: ... - def _get_visible(self) -> int: ... - -# concrete sprite implementation class -class Sprite(_SupportsSprite): +class Sprite: @property def image(self) -> Optional[Surface]: ... @image.setter @@ -102,10 +67,9 @@ class Sprite(_SupportsSprite): def remove(self, *groups: _GroupOrGroups[Any]) -> None: ... def kill(self) -> None: ... def alive(self) -> bool: ... - def groups(self) -> list[AbstractGroup[_SupportsSprite]]: ... + def groups(self) -> list[AbstractGroup[Sprite]]: ... -# concrete dirty sprite implementation class -class DirtySprite(Sprite, _SupportsDirtySprite): +class DirtySprite(Sprite): dirty: int blendmode: int source_rect: Union[FRect, Rect] @@ -114,11 +78,9 @@ class DirtySprite(Sprite, _SupportsDirtySprite): def _set_visible(self, val: int) -> None: ... def _get_visible(self) -> int: ... -# typevar bound to Sprite, _SupportsSprite Protocol ensures sprite -# subclass passed to group has image and rect attributes -_TSprite = TypeVar("_TSprite", bound=_SupportsSprite) -_TSprite2 = TypeVar("_TSprite2", bound=_SupportsSprite) -_TDirtySprite = TypeVar("_TDirtySprite", bound=_SupportsDirtySprite) +_TSprite = TypeVar("_TSprite", bound=Sprite) +_TSprite2 = TypeVar("_TSprite2", bound=Sprite) +_TDirtySprite = TypeVar("_TDirtySprite", bound=DirtySprite) _GroupOrGroups = Union[AbstractGroup[_TSprite], Iterable[_GroupOrGroups[_TSprite]]] _SpriteOrSprites = Union[_TSprite, Iterable[_SpriteOrSprites[_TSprite]]] From 66885ce2a477803aa46350287064ae1b5725a844 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:26:45 -0700 Subject: [PATCH 5/9] Undocument private _set_visible and _get_visible accessor methods --- buildconfig/stubs/pygame/sprite.pyi | 2 -- 1 file changed, 2 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 0caca647f8..5f854359c9 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -75,8 +75,6 @@ class DirtySprite(Sprite): source_rect: Union[FRect, Rect] visible: int _layer: int - def _set_visible(self, val: int) -> None: ... - def _get_visible(self) -> int: ... _TSprite = TypeVar("_TSprite", bound=Sprite) _TSprite2 = TypeVar("_TSprite2", bound=Sprite) From db62783b0e7c5471a0edbbe929b4ba8087e0b037 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:42:04 -0700 Subject: [PATCH 6/9] Misc sprite stub improvements --- buildconfig/stubs/pygame/sprite.pyi | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 5f854359c9..f40c80fd66 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -43,9 +43,6 @@ class _HasImageAndRect(_HasRect, Protocol): class _HasMaskAndRect(_HasRect, Protocol): mask: Mask -# non-generic Group, used in Sprite -_Group = AbstractGroup[Any] - class Sprite: @property def image(self) -> Optional[Surface]: ... @@ -60,8 +57,8 @@ class Sprite: @layer.setter def layer(self, value: int) -> None: ... def __init__(self, *groups: _GroupOrGroups[Any]) -> None: ... - def add_internal(self, group: _Group) -> None: ... - def remove_internal(self, group: _Group) -> None: ... + def add_internal(self, group: AbstractGroup[Any]) -> None: ... + def remove_internal(self, group: AbstractGroup[Any]) -> None: ... def update(self, *args: Any, **kwargs: Any) -> None: ... def add(self, *groups: _GroupOrGroups[Any]) -> None: ... def remove(self, *groups: _GroupOrGroups[Any]) -> None: ... @@ -165,7 +162,6 @@ class GroupSingle(AbstractGroup[_TSprite]): sprite: Optional[_TSprite] def __init__(self, sprite: Optional[_TSprite] = None) -> None: ... -# argument to collide_rect must have rect attribute def collide_rect(left: _HasRect, right: _HasRect) -> bool: ... class collide_rect_ratio: @@ -173,7 +169,7 @@ class collide_rect_ratio: def __init__(self, ratio: float) -> None: ... def __call__(self, left: _HasRect, right: _HasRect) -> bool: ... -# must have rect attribute, may optionally have radius attribute +# Must have rect attribute, may optionally have radius attribute _SupportsCollideCircle = _HasRect def collide_circle( @@ -187,7 +183,7 @@ class collide_circle_ratio: self, left: _SupportsCollideCircle, right: _SupportsCollideCircle ) -> bool: ... -# argument to collide_mask must either have mask or have image attribute, in +# Argument to collide_mask must either have mask or have image attribute, in # addition to mandatorily having a rect attribute _SupportsCollideMask = Union[_HasImageAndRect, _HasMaskAndRect] @@ -195,7 +191,6 @@ def collide_mask( left: _SupportsCollideMask, right: _SupportsCollideMask ) -> Optional[tuple[int, int]]: ... -# _HasRect typevar for sprite collide functions _THasRect = TypeVar("_THasRect", bound=_HasRect) def spritecollide( From 131b5dce8a432141bdaf2432bf580f7422b03637 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:44:03 -0700 Subject: [PATCH 7/9] Remove sprite type vars to follow pep 8 --- buildconfig/stubs/pygame/sprite.pyi | 102 ++++++++++++++-------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index f40c80fd66..71c0b41f0d 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -73,30 +73,30 @@ class DirtySprite(Sprite): visible: int _layer: int -_TSprite = TypeVar("_TSprite", bound=Sprite) -_TSprite2 = TypeVar("_TSprite2", bound=Sprite) -_TDirtySprite = TypeVar("_TDirtySprite", bound=DirtySprite) +_SpriteT = TypeVar("_SpriteT", bound=Sprite) +_SpriteT2 = TypeVar("_SpriteT2", bound=Sprite) +_DirtySpriteT = TypeVar("_DirtySpriteT", bound=DirtySprite) -_GroupOrGroups = Union[AbstractGroup[_TSprite], Iterable[_GroupOrGroups[_TSprite]]] -_SpriteOrSprites = Union[_TSprite, Iterable[_SpriteOrSprites[_TSprite]]] +_GroupOrGroups = Union[AbstractGroup[_SpriteT], Iterable[_GroupOrGroups[_SpriteT]]] +_SpriteOrSprites = Union[_SpriteT, Iterable[_SpriteOrSprites[_SpriteT]]] -class AbstractGroup(Generic[_TSprite]): - spritedict: dict[_TSprite, Optional[Union[FRect, Rect]]] +class AbstractGroup(Generic[_SpriteT]): + spritedict: dict[_SpriteT, Optional[Union[FRect, Rect]]] lostsprites: list[Union[FRect, Rect]] def __class_getitem__(cls, item: Any, /) -> types.GenericAlias: ... def __init__(self) -> None: ... def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_TSprite]: ... + def __iter__(self) -> Iterator[_SpriteT]: ... def __bool__(self) -> bool: ... def __contains__(self, item: Any) -> bool: ... - def add_internal(self, sprite: _TSprite, layer: None = None) -> None: ... - def remove_internal(self, sprite: _TSprite) -> None: ... - def has_internal(self, sprite: _TSprite) -> bool: ... + def add_internal(self, sprite: _SpriteT, layer: None = None) -> None: ... + def remove_internal(self, sprite: _SpriteT) -> None: ... + def has_internal(self, sprite: _SpriteT) -> bool: ... def copy(self) -> Self: ... - def sprites(self) -> list[_TSprite]: ... - def add(self, *sprites: _SpriteOrSprites[_TSprite]) -> None: ... - def remove(self, *sprites: _SpriteOrSprites[_TSprite]) -> None: ... - def has(self, *sprites: _SpriteOrSprites[_TSprite]) -> bool: ... + def sprites(self) -> list[_SpriteT]: ... + def add(self, *sprites: _SpriteOrSprites[_SpriteT]) -> None: ... + def remove(self, *sprites: _SpriteOrSprites[_SpriteT]) -> None: ... + def has(self, *sprites: _SpriteOrSprites[_SpriteT]) -> bool: ... def update(self, *args: Any, **kwargs: Any) -> None: ... def draw( self, surface: Surface, bgd: Optional[Surface] = None, special_flags: int = 0 @@ -108,39 +108,39 @@ class AbstractGroup(Generic[_TSprite]): ) -> None: ... def empty(self) -> None: ... -class Group(AbstractGroup[_TSprite]): - def __init__(self, *sprites: _SpriteOrSprites[_TSprite]) -> None: ... +class Group(AbstractGroup[_SpriteT]): + def __init__(self, *sprites: _SpriteOrSprites[_SpriteT]) -> None: ... # these are aliased in the code too @deprecated("Use `pygame.sprite.Group` instead") -class RenderPlain(Group[_TSprite]): ... +class RenderPlain(Group[_SpriteT]): ... @deprecated("Use `pygame.sprite.Group` instead") -class RenderClear(Group[_TSprite]): ... +class RenderClear(Group[_SpriteT]): ... -class RenderUpdates(Group[_TSprite]): ... +class RenderUpdates(Group[_SpriteT]): ... @deprecated("Use `pygame.sprite.RenderUpdates` instead") -class OrderedUpdates(RenderUpdates[_TSprite]): ... - -class LayeredUpdates(AbstractGroup[_TSprite]): - def __init__(self, *sprites: _SpriteOrSprites[_TSprite], **kwargs: Any) -> None: ... - def add(self, *sprites: _SpriteOrSprites[_TSprite], **kwargs: Any) -> None: ... - def get_sprites_at(self, pos: Point) -> list[_TSprite]: ... - def get_sprite(self, idx: int) -> _TSprite: ... - def remove_sprites_of_layer(self, layer_nr: int) -> list[_TSprite]: ... +class OrderedUpdates(RenderUpdates[_SpriteT]): ... + +class LayeredUpdates(AbstractGroup[_SpriteT]): + def __init__(self, *sprites: _SpriteOrSprites[_SpriteT], **kwargs: Any) -> None: ... + def add(self, *sprites: _SpriteOrSprites[_SpriteT], **kwargs: Any) -> None: ... + def get_sprites_at(self, pos: Point) -> list[_SpriteT]: ... + def get_sprite(self, idx: int) -> _SpriteT: ... + def remove_sprites_of_layer(self, layer_nr: int) -> list[_SpriteT]: ... def layers(self) -> list[int]: ... - def change_layer(self, sprite: _TSprite, new_layer: int) -> None: ... - def get_layer_of_sprite(self, sprite: _TSprite) -> int: ... + def change_layer(self, sprite: _SpriteT, new_layer: int) -> None: ... + def get_layer_of_sprite(self, sprite: _SpriteT) -> int: ... def get_top_layer(self) -> int: ... def get_bottom_layer(self) -> int: ... - def move_to_front(self, sprite: _TSprite) -> None: ... - def move_to_back(self, sprite: _TSprite) -> None: ... - def get_top_sprite(self) -> _TSprite: ... - def get_sprites_from_layer(self, layer: int) -> list[_TSprite]: ... + def move_to_front(self, sprite: _SpriteT) -> None: ... + def move_to_back(self, sprite: _SpriteT) -> None: ... + def get_top_sprite(self) -> _SpriteT: ... + def get_sprites_from_layer(self, layer: int) -> list[_SpriteT]: ... def switch_layer(self, layer1_nr: int, layer2_nr: int) -> None: ... -class LayeredDirty(LayeredUpdates[_TDirtySprite]): +class LayeredDirty(LayeredUpdates[_DirtySpriteT]): def draw( self, surface: Surface, @@ -158,9 +158,9 @@ class LayeredDirty(LayeredUpdates[_TDirtySprite]): ) def set_timing_treshold(self, time_ms: SupportsFloat) -> None: ... -class GroupSingle(AbstractGroup[_TSprite]): - sprite: Optional[_TSprite] - def __init__(self, sprite: Optional[_TSprite] = None) -> None: ... +class GroupSingle(AbstractGroup[_SpriteT]): + sprite: Optional[_SpriteT] + def __init__(self, sprite: Optional[_SpriteT] = None) -> None: ... def collide_rect(left: _HasRect, right: _HasRect) -> bool: ... @@ -191,23 +191,23 @@ def collide_mask( left: _SupportsCollideMask, right: _SupportsCollideMask ) -> Optional[tuple[int, int]]: ... -_THasRect = TypeVar("_THasRect", bound=_HasRect) +_HasRectT = TypeVar("_HasRectT", bound=_HasRect) def spritecollide( - sprite: _THasRect, - group: AbstractGroup[_TSprite], + sprite: _HasRectT, + group: AbstractGroup[_SpriteT], dokill: bool, - collided: Optional[Callable[[_THasRect, _TSprite], Any]] = None, -) -> list[_TSprite]: ... + collided: Optional[Callable[[_HasRectT, _SpriteT], Any]] = None, +) -> list[_SpriteT]: ... def groupcollide( - groupa: AbstractGroup[_TSprite], - groupb: AbstractGroup[_TSprite2], + groupa: AbstractGroup[_SpriteT], + groupb: AbstractGroup[_SpriteT2], dokilla: bool, dokillb: bool, - collided: Optional[Callable[[_TSprite, _TSprite2], Any]] = None, -) -> dict[_TSprite, list[_TSprite2]]: ... + collided: Optional[Callable[[_SpriteT, _SpriteT2], Any]] = None, +) -> dict[_SpriteT, list[_SpriteT2]]: ... def spritecollideany( - sprite: _THasRect, - group: AbstractGroup[_TSprite], - collided: Optional[Callable[[_THasRect, _TSprite], Any]] = None, -) -> Optional[_TSprite]: ... + sprite: _HasRectT, + group: AbstractGroup[_SpriteT], + collided: Optional[Callable[[_HasRectT, _SpriteT], Any]] = None, +) -> Optional[_SpriteT]: ... From dd12ade807b0c60c07c014d63ffb1f15c7137e18 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:45:41 -0700 Subject: [PATCH 8/9] Make mask of _HasMaskAndRect protocol read-only --- buildconfig/stubs/pygame/sprite.pyi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 71c0b41f0d..b1e3173f64 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -41,7 +41,8 @@ class _HasImageAndRect(_HasRect, Protocol): # mask in addition to rect class _HasMaskAndRect(_HasRect, Protocol): - mask: Mask + @property + def mask(self) -> Mask: ... class Sprite: @property From c31a63c2f5630ccad78555c1b722e4eba1bbeeb0 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:51:36 -0700 Subject: [PATCH 9/9] Small sprite stub improvements --- buildconfig/stubs/pygame/sprite.pyi | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index b1e3173f64..992536b974 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -27,9 +27,7 @@ from pygame.rect import FRect, Rect from pygame.surface import Surface from pygame.typing import Point, RectLike -# define some useful protocols first, which sprite functions accept -# sprite functions don't need all sprite attributes to be present in the -# arguments passed, they only use a few which are marked in the below protocols +# Some sprite functions only need objects with certain attributes, not always a sprite class _HasRect(Protocol): @property def rect(self) -> Optional[Union[FRect, Rect]]: ... @@ -44,7 +42,7 @@ class _HasMaskAndRect(_HasRect, Protocol): @property def mask(self) -> Mask: ... -class Sprite: +class Sprite(_HasImageAndRect): @property def image(self) -> Optional[Surface]: ... @image.setter @@ -112,7 +110,7 @@ class AbstractGroup(Generic[_SpriteT]): class Group(AbstractGroup[_SpriteT]): def __init__(self, *sprites: _SpriteOrSprites[_SpriteT]) -> None: ... -# these are aliased in the code too +# These deprecated types are just aliases in the code too @deprecated("Use `pygame.sprite.Group` instead") class RenderPlain(Group[_SpriteT]): ... @@ -184,7 +182,7 @@ class collide_circle_ratio: self, left: _SupportsCollideCircle, right: _SupportsCollideCircle ) -> bool: ... -# Argument to collide_mask must either have mask or have image attribute, in +# Arguments to collide_mask must either have mask or have image attribute, in # addition to mandatorily having a rect attribute _SupportsCollideMask = Union[_HasImageAndRect, _HasMaskAndRect]