From 1c7ad5a4bcef318db1bcee63810e97cef1b32ebc Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:04:54 -0700 Subject: [PATCH 1/4] Correctly type DirtySprite.source_rect as Optional --- 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 148c54dea2..66a10ffb3d 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -68,7 +68,7 @@ class Sprite(_HasImageAndRect): class DirtySprite(Sprite): dirty: int blendmode: int - source_rect: Union[FRect, Rect] + source_rect: Optional[Union[FRect, Rect]] visible: int _layer: int From 4607af4341825baccd98250d608be1559c75624a Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:12:47 -0700 Subject: [PATCH 2/4] Remove default None initialization and property accessors of sprite rect and surface --- buildconfig/stubs/pygame/sprite.pyi | 12 ++++++------ src_py/sprite.py | 26 ++++++-------------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 66a10ffb3d..ab755cb54f 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -30,12 +30,12 @@ from pygame.typing import Point, RectLike # Some sprite functions only need objects with certain attributes, not always a sprite class _HasRect(Protocol): @property - def rect(self) -> Optional[Union[FRect, Rect]]: ... + def rect(self) -> Union[FRect, Rect]: ... # image in addition to rect class _HasImageAndRect(_HasRect, Protocol): @property - def image(self) -> Optional[Surface]: ... + def image(self) -> Surface: ... # mask in addition to rect class _HasMaskAndRect(_HasRect, Protocol): @@ -44,13 +44,13 @@ class _HasMaskAndRect(_HasRect, Protocol): class Sprite(_HasImageAndRect): @property - def image(self) -> Optional[Surface]: ... + def image(self) -> Surface: ... @image.setter - def image(self, value: Optional[Surface]) -> None: ... + def image(self, value: Surface) -> None: ... @property - def rect(self) -> Optional[Union[FRect, Rect]]: ... + def rect(self) -> Union[FRect, Rect]: ... @rect.setter - def rect(self, value: Optional[Union[FRect, Rect]]) -> None: ... + def rect(self, value: Union[FRect, Rect]) -> None: ... @property def layer(self) -> int: ... @layer.setter diff --git a/src_py/sprite.py b/src_py/sprite.py index 9e72c3f2e1..ec4386750b 100644 --- a/src_py/sprite.py +++ b/src_py/sprite.py @@ -85,12 +85,13 @@ # specialized cases. import types -from typing import Optional +from typing import Union from warnings import warn import pygame from pygame.mask import from_surface -from pygame.rect import Rect +from pygame.rect import FRect, Rect +from pygame.surface import Surface from pygame.time import get_ticks @@ -109,29 +110,14 @@ class Sprite: """ + image: Surface + rect: Union[Rect, FRect] + def __init__(self, *groups): self.__g = {} # The groups the sprite is in - self.__image: Optional[pygame.surface.Surface] = None - self.__rect: Optional[pygame.rect.Rect] = None if groups: self.add(*groups) - @property - def image(self): - return self.__image - - @image.setter - def image(self, value: Optional[pygame.surface.Surface]): - self.__image = value - - @property - def rect(self): - return self.__rect - - @rect.setter - def rect(self, value: Optional[pygame.rect.Rect]): - self.__rect = value - def add(self, *groups): """add the sprite to groups From d1c7a6304a79b75ccdb2c13df9705959638d6aa7 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:40:10 -0700 Subject: [PATCH 3/4] Fix stubtest tests for sprite rect and image attributes --- buildconfig/stubs/pygame/sprite.pyi | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index ab755cb54f..7ac483f160 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -43,14 +43,8 @@ class _HasMaskAndRect(_HasRect, Protocol): def mask(self) -> Mask: ... class Sprite(_HasImageAndRect): - @property - def image(self) -> Surface: ... - @image.setter - def image(self, value: Surface) -> None: ... - @property - def rect(self) -> Union[FRect, Rect]: ... - @rect.setter - def rect(self, value: Union[FRect, Rect]) -> None: ... + image: Surface # Uses attribute annotation instead of property to satisfy stubtest + rect: Union[FRect, Rect] # Same as image, see above @property def layer(self) -> int: ... @layer.setter From 0a8311ee843f9663683ab6b2ea8b1b54bfe152be Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:43:44 -0700 Subject: [PATCH 4/4] Fix LayeredDirty.get_clip() return type annotation --- buildconfig/stubs/pygame/sprite.pyi | 2 +- src_py/sprite.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildconfig/stubs/pygame/sprite.pyi b/buildconfig/stubs/pygame/sprite.pyi index 7ac483f160..b3245324ef 100644 --- a/buildconfig/stubs/pygame/sprite.pyi +++ b/buildconfig/stubs/pygame/sprite.pyi @@ -144,7 +144,7 @@ class LayeredDirty(LayeredUpdates[_DirtySpriteT]): def clear(self, surface: Surface, bgd: Surface) -> None: ... # type: ignore[override] def repaint_rect(self, screen_rect: RectLike) -> None: ... def set_clip(self, screen_rect: Optional[RectLike] = None) -> None: ... - def get_clip(self) -> Union[FRect, Rect]: ... + def get_clip(self) -> Optional[Union[FRect, Rect]]: ... def set_timing_threshold(self, time_ms: SupportsFloat) -> None: ... @deprecated( "since 2.1.1. Use `pygame.sprite.LayeredDirty.set_timing_threshold` instead" diff --git a/src_py/sprite.py b/src_py/sprite.py index ec4386750b..f4a90a7530 100644 --- a/src_py/sprite.py +++ b/src_py/sprite.py @@ -1323,7 +1323,7 @@ def set_clip(self, screen_rect=None): def get_clip(self): """get the area where drawing will occur - LayeredDirty.get_clip(): return Rect + LayeredDirty.get_clip(): return Rect or None """ return self._clip