-
-
Notifications
You must be signed in to change notification settings - Fork 195
Improve sprite stubs #3525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Improve sprite stubs #3525
Changes from all commits
763aa7e
fa42eb9
ecbf7bd
0aded36
66885ce
db62783
131b5dc
dd12ade
c31a63c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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]]: ... | ||
|
@@ -41,51 +39,10 @@ class _HasImageAndRect(_HasRect, Protocol): | |
|
||
# mask in addition to rect | ||
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] | ||
|
||
# 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: _Group) -> None: ... | ||
def remove(self, *groups: _Group) -> 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: ... | ||
def mask(self) -> Mask: ... | ||
|
||
# concrete sprite implementation class | ||
class Sprite(_SupportsSprite): | ||
class Sprite(_HasImageAndRect): | ||
@property | ||
def image(self) -> Optional[Surface]: ... | ||
@image.setter | ||
|
@@ -98,52 +55,47 @@ class Sprite(_SupportsSprite): | |
def layer(self) -> int: ... | ||
@layer.setter | ||
def layer(self, value: int) -> None: ... | ||
def __init__(self, *groups: _Group) -> None: ... | ||
def add_internal(self, group: _Group) -> None: ... | ||
def remove_internal(self, group: _Group) -> None: ... | ||
def __init__(self, *groups: _GroupOrGroups[Any]) -> 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: _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]]: ... | ||
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] | ||
visible: int | ||
_layer: int | ||
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) | ||
_SpriteT = TypeVar("_SpriteT", bound=Sprite) | ||
_SpriteT2 = TypeVar("_SpriteT2", bound=Sprite) | ||
_DirtySpriteT = TypeVar("_DirtySpriteT", bound=DirtySprite) | ||
|
||
# typevar for sprite or iterable of sprites, used in Group init, add and remove | ||
_SpriteOrIterable = Union[_TSprite, Iterable[_SpriteOrIterable[_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: _SpriteOrIterable[_TSprite]) -> None: ... | ||
def remove(self, *sprites: _SpriteOrIterable[_TSprite]) -> None: ... | ||
def has(self, *sprites: _SpriteOrIterable[_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 | ||
|
@@ -155,41 +107,39 @@ class AbstractGroup(Generic[_TSprite]): | |
) -> None: ... | ||
def empty(self) -> None: ... | ||
|
||
class Group(AbstractGroup[_TSprite]): | ||
def __init__(self, *sprites: _SpriteOrIterable[_TSprite]) -> None: ... | ||
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[_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: _SpriteOrIterable[_TSprite], **kwargs: Any | ||
) -> None: ... | ||
def add(self, *sprites: _SpriteOrIterable[_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, | ||
|
@@ -207,20 +157,19 @@ class LayeredDirty(LayeredUpdates[_TDirtySprite]): | |
) | ||
def set_timing_treshold(self, time_ms: SupportsFloat) -> None: ... | ||
|
||
class GroupSingle(AbstractGroup[_TSprite]): | ||
sprite: _TSprite | ||
def __init__(self, sprite: Optional[_TSprite] = None) -> None: ... | ||
class GroupSingle(AbstractGroup[_SpriteT]): | ||
sprite: Optional[_SpriteT] | ||
def __init__(self, sprite: Optional[_SpriteT] = None) -> None: ... | ||
|
||
# argument to collide_rect must have rect attribute | ||
def collide_rect(left: _HasRect, right: _HasRect) -> bool: ... | ||
|
||
class collide_rect_ratio: | ||
ratio: float | ||
def __init__(self, ratio: float) -> None: ... | ||
def __call__(self, left: _HasRect, right: _HasRect) -> bool: ... | ||
|
||
# must have rect attribute, may optionally have radius attribute | ||
_SupportsCollideCircle = Union[_HasRect, _HasRadiusAndRect] | ||
# Must have rect attribute, may optionally have radius attribute | ||
_SupportsCollideCircle = _HasRect | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that this is a simplification and while its not incorrect to do this, I think keeping this as it is can convey more information to the user? Or is the extra information useless? Im not sure either way There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although it is more information, the redundancy of it made me feel like removing it. (Also, sometimes only |
||
|
||
def collide_circle( | ||
left: _SupportsCollideCircle, right: _SupportsCollideCircle | ||
|
@@ -233,32 +182,31 @@ 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] | ||
|
||
def collide_mask( | ||
left: _SupportsCollideMask, right: _SupportsCollideMask | ||
) -> Optional[tuple[int, int]]: ... | ||
|
||
# _HasRect typevar for sprite collide functions | ||
_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]: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This renaming made the diff slightly more complicated to review than it should have been. Is this a standard convention or just preference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it is a standard convention: the
T
in a typevar name is always a suffix rather than a prefix.Typing users may see the name of the typevars.
See:
Unfortunately, I did not come up with a shorter name for the typevars.
(Note: I did not change other nonconforming module typevar names.)