From f752f3056410ca86057b1e7f786afe792eb579d4 Mon Sep 17 00:00:00 2001 From: Paul Craven Date: Wed, 15 Jul 2026 16:03:42 -0500 Subject: [PATCH 1/2] Fix SpriteList.insert() not marking index buffer as changed SpriteList.insert() updated the CPU-side index data but never set self._sprite_index_changed = True, unlike append() and every other mutating method. As a result, a sprite added via insert() was present in the list but never uploaded to the GPU index buffer, so it was not rendered until an unrelated flag-setting operation forced a sync. Set the flag at the end of insert() to mirror append(). Fixes #2863 --- arcade/sprite_list/sprite_list.py | 1 + tests/unit/spritelist/test_spritelist.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arcade/sprite_list/sprite_list.py b/arcade/sprite_list/sprite_list.py index d24641dea6..0fd48c6f2f 100644 --- a/arcade/sprite_list/sprite_list.py +++ b/arcade/sprite_list/sprite_list.py @@ -751,6 +751,7 @@ def insert(self, index: int, sprite: SpriteType) -> None: self._grow_index_buffer() self._sprite_index_data.insert(index, slot) self._sprite_index_data.pop() + self._sprite_index_changed = True if self.spatial_hash is not None: self.spatial_hash.add(sprite) diff --git a/tests/unit/spritelist/test_spritelist.py b/tests/unit/spritelist/test_spritelist.py index b0f371eced..5e4214e827 100644 --- a/tests/unit/spritelist/test_spritelist.py +++ b/tests/unit/spritelist/test_spritelist.py @@ -116,6 +116,9 @@ def test_it_can_insert_in_a_spritelist(): assert [spritelist.sprite_slot[s] for s in spritelist] == [0, 2, 1] # Index buffer should refer to the slots in the same order assert list(spritelist._sprite_index_data[:3]) == [0, 2, 1] + # insert() must flag the index buffer as changed so the sprite is + # actually uploaded to the GPU and rendered on the next draw (#2863) + assert spritelist._sprite_index_changed is True def test_it_can_reverse_a_spritelist(): From 5b15505bb86c17ccf02cc443a70e42c060fc3001 Mon Sep 17 00:00:00 2001 From: Paul Craven Date: Wed, 15 Jul 2026 16:09:13 -0500 Subject: [PATCH 2/2] Validate texture in SpriteList.insert() to match append() append() raises ValueError when a textureless sprite is added to an initialized SpriteList. insert() silently accepted it. Mirror the same guard in insert() for consistency between the two entry points. Note: this is a validation-only change; the atlas registration itself is already handled by _update_all() for both append() and insert(). --- arcade/sprite_list/sprite_list.py | 4 ++++ tests/unit/spritelist/test_spritelist.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/arcade/sprite_list/sprite_list.py b/arcade/sprite_list/sprite_list.py index 0fd48c6f2f..613e59702c 100644 --- a/arcade/sprite_list/sprite_list.py +++ b/arcade/sprite_list/sprite_list.py @@ -756,6 +756,10 @@ def insert(self, index: int, sprite: SpriteType) -> None: if self.spatial_hash is not None: self.spatial_hash.add(sprite) + if self._initialized: + if sprite.texture is None: + raise ValueError("Sprite must have a texture when added to a SpriteList") + def reverse(self) -> None: """Reverses the current list in-place""" # Reverse the sprites and index buffer diff --git a/tests/unit/spritelist/test_spritelist.py b/tests/unit/spritelist/test_spritelist.py index 5e4214e827..07277b4700 100644 --- a/tests/unit/spritelist/test_spritelist.py +++ b/tests/unit/spritelist/test_spritelist.py @@ -121,6 +121,20 @@ def test_it_can_insert_in_a_spritelist(): assert spritelist._sprite_index_changed is True +def test_insert_requires_texture_when_initialized(ctx): + """insert() into an initialized list should validate the texture, like append()""" + spritelist = make_named_sprites(1) + # Force initialization (as a draw would do) + spritelist.draw() + + sprite = arcade.SpriteSolidColor(16, 16, color=arcade.color.RED) + # Bypass the texture setter to simulate a textureless sprite + sprite._texture = None + + with pytest.raises(ValueError): + spritelist.insert(0, sprite) + + def test_it_can_reverse_a_spritelist(): spritelist = make_named_sprites(3) spritelist.reverse()