Skip to content

Fix platforms.deleter + add tests for physics behavior properties #2166

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

Merged
merged 3 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arcade/physics_engines.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def platforms(self, platforms: Optional[Union[SpriteList, Iterable[SpriteList]]]

@platforms.deleter
def platforms(self):
self._platforms = []
self._platforms.clear()

@property
def walls(self):
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/physics_engine/test_physics_engine2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,43 @@
OUT_OF_THE_WAY = (250, 250)


def check_spritelists_prop_clears_instead_of_overwrites(engine, prop_name: str):
"""Some properties are backed by lists which shouldn't be recreated.

Implementing them this way is helpful for cases when a user has lots
of different SpriteLists added to the physics engine's lists. It
helps by avoiding:

* extra allocations from copying lists (see arcade.utils.Chain)
* Avoid GC thrash from creating & deleting items
"""
def _get_current():
return getattr(engine, f'_{prop_name}')

original_list = _get_current()

# Make sure we don't replace it when adding
setattr(engine, prop_name, [arcade.SpriteList()])
assert _get_current() is original_list

# Ensure setting a property to None doesn't kill it
setattr(engine, prop_name, None)
assert _get_current() is original_list

# Ensure empty iterables don't clobber
setattr(engine, prop_name, [])
assert _get_current() is original_list
setattr(engine, prop_name, ())
assert _get_current() is original_list
setattr(engine, prop_name, (arcade.SpriteList() for _ in range(0)))

# We support the del keyword on these properties for some reason,
# but it should only clear the internal list instead of deleting the
# property.
delattr(engine, prop_name)
assert _get_current() is original_list


def basic_tests(moving_sprite, wall_list, physics_engine):
"""Run basic tests that can be done by both engines."""
wall_sprite_1 = wall_list[0]
Expand Down Expand Up @@ -221,6 +258,7 @@ def simple_engine_tests(moving_sprite, wall_list, physics_engine):
else:
assert len(collisions) == 1

check_spritelists_prop_clears_instead_of_overwrites(physics_engine, 'walls')

def platformer_tests(moving_sprite, wall_list, physics_engine):
wall_sprite_1 = wall_list[0]
Expand Down Expand Up @@ -289,6 +327,9 @@ def platformer_tests(moving_sprite, wall_list, physics_engine):
collisions = physics_engine.update()
assert moving_sprite.position == (3, -6)

check_spritelists_prop_clears_instead_of_overwrites(physics_engine, 'platforms')
check_spritelists_prop_clears_instead_of_overwrites(physics_engine, 'ladders')


# Temp fix for https://github.com/pythonarcade/arcade/issues/2074
def nocopy_tests(physics_engine):
Expand Down
Loading