Skip to content

Commit 4e4c110

Browse files
authored
Improve SpriteList typing (#1977)
* Add missing SpriteType annotations * Add broader Iterable[Texture] annotation for preload_textures * Remove extra whitespace after preload_textures * Add None return annotation to enable_spatial_hashing * Add None return annotation to SpriteList.sort * Add None return annotation to SpriteList.shuffle * Add None return annotation to SpriteList.reverse * Add None return annotation to SpriteList.insert * Add None return annotation to SpriteList.extend * Add None return annotation to SpriteList.remove * Add None return annotation to SpriteList.swap * Add None return annotation to SpriteList.append * Add None return annotation to SpriteList.clear * Add SpriteType return annotation to SpriteList.__getitem__ * Add None return type to internal _update and _*_buffermethods on SpriteList * Add None return type to on_update and update_animation * Add None return annotation to _recalculate_spatial_hashes * Revert __getitem__ return annotation for the moment * Add None return type for SpriteList.__setitem__ * Add None return annotation to SpriteList._init_deferred * Use @overload typing for SpriteList.__getitem__ * Annotate SpriteList's program attribute * Import Program type and use it to annotate * Annotate protected buffer props * Ugly handling for buffer initialization on Optional[Buffer] protected attrs * Revert "Use @overload typing for SpriteList.__getitem__" This reverts commit 64c5ae9.
1 parent ad690e6 commit 4e4c110

File tree

1 file changed

+49
-46
lines changed

1 file changed

+49
-46
lines changed

arcade/sprite_list/sprite_list.py

+49-46
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
get_window,
3434
gl,
3535
)
36-
from arcade.gl import Texture2D
36+
from arcade.gl import Texture2D, Program
3737
from arcade.types import Color, RGBA255
3838
from arcade.gl.types import OpenGlFilter, BlendFunction, PyGLenum
3939
from arcade.gl.buffer import Buffer
@@ -104,7 +104,7 @@ def __init__(
104104
lazy: bool = False,
105105
visible: bool = True,
106106
):
107-
self.program = None
107+
self.program: Optional[Program] = None
108108
self._atlas: Optional[TextureAtlas] = atlas
109109
self._initialized = False
110110
self._lazy = lazy
@@ -137,22 +137,25 @@ def __init__(
137137
# Index buffer
138138
self._sprite_index_data = array("i", [0] * self._idx_capacity)
139139

140-
self._sprite_pos_buf = None
141-
self._sprite_size_buf = None
142-
self._sprite_angle_buf = None
143-
self._sprite_color_buf = None
144-
self._sprite_texture_buf = None
140+
# Define and annotate storage space for buffers
141+
self._sprite_pos_buf: Optional[Buffer] = None
142+
self._sprite_size_buf: Optional[Buffer] = None
143+
self._sprite_angle_buf: Optional[Buffer] = None
144+
self._sprite_color_buf: Optional[Buffer] = None
145+
self._sprite_texture_buf: Optional[Buffer] = None
146+
145147
# Index buffer
146-
self._sprite_index_buf = None
148+
self._sprite_index_buf: Optional[Buffer] = None
149+
150+
self._geometry: Optional[Geometry] = None
147151

148-
self._geometry = None
149152
# Flags for signaling if a buffer needs to be written to the opengl buffer
150-
self._sprite_pos_changed = False
151-
self._sprite_size_changed = False
152-
self._sprite_angle_changed = False
153-
self._sprite_color_changed = False
154-
self._sprite_texture_changed = False
155-
self._sprite_index_changed = False
153+
self._sprite_pos_changed: bool = False
154+
self._sprite_size_changed: bool = False
155+
self._sprite_angle_changed: bool = False
156+
self._sprite_color_changed: bool = False
157+
self._sprite_texture_changed: bool = False
158+
self._sprite_index_changed: bool = False
156159

157160
# Used in collision detection optimization
158161
from .spatial_hash import SpatialHash
@@ -179,7 +182,7 @@ def __init__(
179182
except RuntimeError:
180183
pass
181184

182-
def _init_deferred(self):
185+
def _init_deferred(self) -> None:
183186
"""
184187
Since spritelist can be created before the window we need to defer initialization.
185188
It also makes us able to support lazy loading.
@@ -252,7 +255,7 @@ def __iter__(self) -> Iterator[SpriteType]:
252255
def __getitem__(self, i):
253256
return self.sprite_list[i]
254257

255-
def __setitem__(self, index: int, sprite: SpriteType):
258+
def __setitem__(self, index: int, sprite: SpriteType) -> None:
256259
"""Replace a sprite at a specific index"""
257260
# print(f"{id(self)} : {id(sprite)} __setitem__({index})")
258261

@@ -525,7 +528,7 @@ def index(self, sprite: SpriteType) -> int:
525528
"""
526529
return self.sprite_list.index(sprite)
527530

528-
def clear(self, deep: bool = True):
531+
def clear(self, deep: bool = True) -> None:
529532
"""
530533
Remove all the sprites resetting the spritelist
531534
to it's initial state.
@@ -588,7 +591,7 @@ def pop(self, index: int = -1) -> SpriteType:
588591
self.remove(sprite)
589592
return sprite
590593

591-
def append(self, sprite: SpriteType):
594+
def append(self, sprite: SpriteType) -> None:
592595
"""
593596
Add a new sprite to the list.
594597
@@ -624,7 +627,7 @@ def append(self, sprite: SpriteType):
624627
raise ValueError("Sprite must have a texture when added to a SpriteList")
625628
self._atlas.add(sprite.texture) # type: ignore
626629

627-
def swap(self, index_1: int, index_2: int):
630+
def swap(self, index_1: int, index_2: int) -> None:
628631
"""
629632
Swap two sprites by index
630633
:param index_1: Item index to swap
@@ -644,7 +647,7 @@ def swap(self, index_1: int, index_2: int):
644647
self._sprite_index_data[i1] = slot_2
645648
self._sprite_index_data[i2] = slot_1
646649

647-
def remove(self, sprite: SpriteType):
650+
def remove(self, sprite: SpriteType) -> None:
648651
"""
649652
Remove a specific sprite from the list.
650653
:param sprite: Item to remove from the list
@@ -676,7 +679,7 @@ def remove(self, sprite: SpriteType):
676679
if self.spatial_hash is not None:
677680
self.spatial_hash.remove(sprite)
678681

679-
def extend(self, sprites: Union[Iterable[SpriteType], "SpriteList"]):
682+
def extend(self, sprites: Union[Iterable[SpriteType], SpriteList[SpriteType]]) -> None:
680683
"""
681684
Extends the current list with the given iterable
682685
@@ -685,7 +688,7 @@ def extend(self, sprites: Union[Iterable[SpriteType], "SpriteList"]):
685688
for sprite in sprites:
686689
self.append(sprite)
687690

688-
def insert(self, index: int, sprite: SpriteType):
691+
def insert(self, index: int, sprite: SpriteType) -> None:
689692
"""
690693
Inserts a sprite at a given index.
691694
@@ -716,7 +719,7 @@ def insert(self, index: int, sprite: SpriteType):
716719
if self.spatial_hash is not None:
717720
self.spatial_hash.add(sprite)
718721

719-
def reverse(self):
722+
def reverse(self) -> None:
720723
"""
721724
Reverses the current list in-place
722725
"""
@@ -732,7 +735,7 @@ def reverse(self):
732735

733736
self._sprite_index_changed = True
734737

735-
def shuffle(self):
738+
def shuffle(self) -> None:
736739
"""
737740
Shuffles the current list in-place
738741
"""
@@ -759,7 +762,7 @@ def shuffle(self):
759762

760763
self._sprite_index_changed = True
761764

762-
def sort(self, *, key: Callable, reverse: bool = False):
765+
def sort(self, *, key: Callable, reverse: bool = False) -> None:
763766
"""
764767
Sort the spritelist in place using ``<`` comparison between sprites.
765768
This function is similar to python's :py:meth:`list.sort`.
@@ -799,7 +802,7 @@ def disable_spatial_hashing(self) -> None:
799802
"""
800803
self.spatial_hash = None
801804

802-
def enable_spatial_hashing(self, spatial_hash_cell_size: int = 128):
805+
def enable_spatial_hashing(self, spatial_hash_cell_size: int = 128) -> None:
803806
"""Turn on spatial hashing."""
804807
if self.spatial_hash is None or self.spatial_hash.cell_size != spatial_hash_cell_size:
805808
LOG.debug("Enabled spatial hashing with cell size %s", spatial_hash_cell_size)
@@ -809,7 +812,7 @@ def enable_spatial_hashing(self, spatial_hash_cell_size: int = 128):
809812
else:
810813
LOG.debug("Spatial hashing is already enabled with size %s", spatial_hash_cell_size)
811814

812-
def _recalculate_spatial_hashes(self):
815+
def _recalculate_spatial_hashes(self) -> None:
813816
if self.spatial_hash is None:
814817
from .spatial_hash import SpatialHash
815818
self.spatial_hash = SpatialHash(cell_size=self._spatial_hash_cell_size)
@@ -825,14 +828,14 @@ def update(self) -> None:
825828
for sprite in self.sprite_list:
826829
sprite.update()
827830

828-
def on_update(self, delta_time: float = 1 / 60):
831+
def on_update(self, delta_time: float = 1 / 60) -> None:
829832
"""
830833
Update the sprite. Similar to update, but also takes a delta-time.
831834
"""
832835
for sprite in self.sprite_list:
833836
sprite.on_update(delta_time)
834837

835-
def update_animation(self, delta_time: float = 1 / 60):
838+
def update_animation(self, delta_time: float = 1 / 60) -> None:
836839
"""
837840
Call the update_animation in every sprite in the sprite list.
838841
"""
@@ -870,7 +873,7 @@ def move(self, change_x: float, change_y: float) -> None:
870873
sprite.center_x += change_x
871874
sprite.center_y += change_y
872875

873-
def preload_textures(self, texture_list: List["Texture"]) -> None:
876+
def preload_textures(self, texture_list: Iterable["Texture"]) -> None:
874877
"""
875878
Preload a set of textures that will be used for sprites in this
876879
sprite list.
@@ -885,7 +888,6 @@ def preload_textures(self, texture_list: List["Texture"]) -> None:
885888
self._atlas.add( # type: ignore
886889
texture)
887890

888-
889891
def write_sprite_buffers_to_gpu(self) -> None:
890892
"""
891893
Ensure buffers are resized and fresh sprite data
@@ -903,7 +905,7 @@ def write_sprite_buffers_to_gpu(self) -> None:
903905
"""
904906
self._write_sprite_buffers_to_gpu()
905907

906-
def _write_sprite_buffers_to_gpu(self):
908+
def _write_sprite_buffers_to_gpu(self) -> None:
907909
LOG.debug(
908910
"[%s] SpriteList._write_sprite_buffers_to_gpu: pos=%s, size=%s, angle=%s, color=%s tex=%s idx=%s",
909911
id(self),
@@ -1043,7 +1045,7 @@ def draw_hit_boxes(self, color: RGBA255 = (0, 0, 0, 255), line_thickness: float
10431045
for sprite in self.sprite_list:
10441046
sprite.draw_hit_box(color, line_thickness)
10451047

1046-
def _normalize_index_buffer(self):
1048+
def _normalize_index_buffer(self) -> None:
10471049
"""
10481050
Removes unused slots in the index buffer.
10491051
The other buffers don't need this because they re-use slots.
@@ -1062,7 +1064,7 @@ def _normalize_index_buffer(self):
10621064
# NOTE: Right now the index buffer is always normalized
10631065
pass
10641066

1065-
def _grow_sprite_buffers(self):
1067+
def _grow_sprite_buffers(self) -> None:
10661068
"""Double the internal buffer sizes"""
10671069
# Resize sprite buffers if needed
10681070
if self._sprite_buffer_slots <= self._buf_capacity:
@@ -1087,19 +1089,20 @@ def _grow_sprite_buffers(self):
10871089
self._sprite_texture_data.extend([0] * extend_by)
10881090

10891091
if self._initialized:
1090-
self._sprite_pos_buf.orphan(double=True)
1091-
self._sprite_size_buf.orphan(double=True)
1092-
self._sprite_angle_buf.orphan(double=True)
1093-
self._sprite_color_buf.orphan(double=True)
1094-
self._sprite_texture_buf.orphan(double=True)
1092+
# Proper initialization implies these buffers are allocated
1093+
self._sprite_pos_buf.orphan(double=True) # type: ignore
1094+
self._sprite_size_buf.orphan(double=True) # type: ignore
1095+
self._sprite_angle_buf.orphan(double=True) # type: ignore
1096+
self._sprite_color_buf.orphan(double=True) # type: ignore
1097+
self._sprite_texture_buf.orphan(double=True) # type: ignore
10951098

10961099
self._sprite_pos_changed = True
10971100
self._sprite_size_changed = True
10981101
self._sprite_angle_changed = True
10991102
self._sprite_color_changed = True
11001103
self._sprite_texture_changed = True
11011104

1102-
def _grow_index_buffer(self):
1105+
def _grow_index_buffer(self) -> None:
11031106
# Extend the index buffer capacity if needed
11041107
if self._sprite_index_slots <= self._idx_capacity:
11051108
return
@@ -1127,7 +1130,7 @@ def _grow_index_buffer(self):
11271130

11281131
self._sprite_index_changed = True
11291132

1130-
def _update_all(self, sprite: SpriteType):
1133+
def _update_all(self, sprite: SpriteType) -> None:
11311134
"""
11321135
Update all sprite data. This is faster when adding and moving sprites.
11331136
This duplicate code, but reduces call overhead, dict lookups etc.
@@ -1168,7 +1171,7 @@ def _update_all(self, sprite: SpriteType):
11681171
self._sprite_texture_data[slot] = tex_slot
11691172
self._sprite_texture_changed = True
11701173

1171-
def _update_texture(self, sprite) -> None:
1174+
def _update_texture(self, sprite: SpriteType) -> None:
11721175
"""Make sure we update the texture for this sprite for the next batch
11731176
drawing"""
11741177
# We cannot interact with texture atlases unless the context
@@ -1274,7 +1277,7 @@ def _update_size(self, sprite: SpriteType) -> None:
12741277
self._sprite_size_data[slot * 2 + 1] = sprite._height
12751278
self._sprite_size_changed = True
12761279

1277-
def _update_width(self, sprite: SpriteType):
1280+
def _update_width(self, sprite: SpriteType) -> None:
12781281
"""
12791282
Called by the Sprite class to update the size/scale in this sprite.
12801283
Necessary for batch drawing of items.
@@ -1285,7 +1288,7 @@ def _update_width(self, sprite: SpriteType):
12851288
self._sprite_size_data[slot * 2] = sprite._width
12861289
self._sprite_size_changed = True
12871290

1288-
def _update_height(self, sprite: SpriteType):
1291+
def _update_height(self, sprite: SpriteType) -> None:
12891292
"""
12901293
Called by the Sprite class to update the size/scale in this sprite.
12911294
Necessary for batch drawing of items.
@@ -1296,7 +1299,7 @@ def _update_height(self, sprite: SpriteType):
12961299
self._sprite_size_data[slot * 2 + 1] = sprite._height
12971300
self._sprite_size_changed = True
12981301

1299-
def _update_angle(self, sprite: SpriteType):
1302+
def _update_angle(self, sprite: SpriteType) -> None:
13001303
"""
13011304
Called by the Sprite class to update the angle in this sprite.
13021305
Necessary for batch drawing of items.

0 commit comments

Comments
 (0)