From bbf23b285cf9c0e990eeae1ec238522a60cfcd1d Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Fri, 23 Aug 2019 21:58:08 -0400 Subject: [PATCH 01/25] Renames Rotatable to RotatableMixin --- ppb/sprites.py | 4 ++-- tests/test_sprites.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ppb/sprites.py b/ppb/sprites.py index fe6ff222..86b469ec 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -165,7 +165,7 @@ def _attribute_gate(self, attribute, bad_sides): raise AttributeError(message) -class Rotatable: +class RotatableMixin: """ A simple rotation mixin. Can be included with sprites. """ @@ -205,7 +205,7 @@ def rotate(self, degrees): self.rotation += degrees -class BaseSprite(EventMixin, Rotatable): +class BaseSprite(EventMixin, RotatableMixin): """ The base Sprite class. All sprites should inherit from this (directly or indirectly). diff --git a/tests/test_sprites.py b/tests/test_sprites.py index efdd9b29..ba8961b6 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -2,7 +2,7 @@ from unittest.mock import patch from ppb import BaseSprite, Vector -from ppb.sprites import Rotatable +from ppb.sprites import RotatableMixin class TestBaseSprite(TestCase): @@ -287,30 +287,30 @@ class TestSprite(BaseSprite): def test_rotatable_instatiation(): - rotatable = Rotatable() + rotatable = RotatableMixin() assert rotatable.rotation == 0 def test_rotatable_subclass(): - class TestRotatable(Rotatable): + class TestRotatableMixin(RotatableMixin): _rotation = 180 basis = Vector(0, 1) - rotatable = TestRotatable() + rotatable = TestRotatableMixin() assert rotatable.rotation == 180 assert rotatable.facing == Vector(0, -1) def test_rotatable_rotation_setter(): - rotatable = Rotatable() + rotatable = RotatableMixin() rotatable.rotation = 405 assert rotatable.rotation == 45 def test_rotatable_rotate(): - rotatable = Rotatable() + rotatable = RotatableMixin() assert rotatable.rotation == 0 rotatable.rotate(180) From 60ca123b7c56102c2cb00070e4854c4ec6c68b3f Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 09:23:25 -0400 Subject: [PATCH 02/25] Moves RotatableMixin higher in file. --- ppb/sprites.py | 80 +++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/ppb/sprites.py b/ppb/sprites.py index 86b469ec..b8682430 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -19,6 +19,46 @@ side_attribute_error_message = error_message.format +class RotatableMixin: + """ + A simple rotation mixin. Can be included with sprites. + """ + _rotation = 0 + # This is necessary to make facing do the thing while also being adjustable. + #: The baseline vector, representing the "front" of the sprite + basis = Vector(0, -1) + # Considered making basis private, the only reason to do so is to + # discourage people from relying on it as data. + + @property + def facing(self): + """ + The direction the "front" is facing + """ + return Vector(*self.basis).rotate(self.rotation).normalize() + + @facing.setter + def facing(self, value): + self.rotation = self.basis.angle(value) + + @property + def rotation(self): + """ + The amount the sprite is rotated, in degrees + """ + return self._rotation + + @rotation.setter + def rotation(self, value): + self._rotation = value % 360 + + def rotate(self, degrees): + """ + Rotate the sprite by a given angle (in degrees). + """ + self.rotation += degrees + + class Side(FauxFloat): """ Acts like a float, but also has a variety of accessors. @@ -165,46 +205,6 @@ def _attribute_gate(self, attribute, bad_sides): raise AttributeError(message) -class RotatableMixin: - """ - A simple rotation mixin. Can be included with sprites. - """ - _rotation = 0 - # This is necessary to make facing do the thing while also being adjustable. - #: The baseline vector, representing the "front" of the sprite - basis = Vector(0, -1) - # Considered making basis private, the only reason to do so is to - # discourage people from relying on it as data. - - @property - def facing(self): - """ - The direction the "front" is facing - """ - return Vector(*self.basis).rotate(self.rotation).normalize() - - @facing.setter - def facing(self, value): - self.rotation = self.basis.angle(value) - - @property - def rotation(self): - """ - The amount the sprite is rotated, in degrees - """ - return self._rotation - - @rotation.setter - def rotation(self, value): - self._rotation = value % 360 - - def rotate(self, degrees): - """ - Rotate the sprite by a given angle (in degrees). - """ - self.rotation += degrees - - class BaseSprite(EventMixin, RotatableMixin): """ The base Sprite class. All sprites should inherit from this (directly or From 318af497c4b0a12ccfc44e3fcf6a3b1e14d21c01 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 09:37:58 -0400 Subject: [PATCH 03/25] Adds stubs that throw a deprecation warning and replace BaseSprite. --- ppb/__init__.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ppb/__init__.py b/ppb/__init__.py index f2e2dc1a..e305d27a 100644 --- a/ppb/__init__.py +++ b/ppb/__init__.py @@ -1,11 +1,12 @@ import logging +import warnings from typing import Callable from ppb import events from ppb_vector import Vector from ppb.engine import GameEngine from ppb.scenes import BaseScene -from ppb.sprites import BaseSprite +from ppb.sprites import BaseSprite as OldBaseSprite from ppb.systems import Image from ppb.systems import Sound @@ -17,6 +18,28 @@ ) +class BaseSprite(OldBaseSprite): + """ + A stub that raises a deprecation warning when a user uses + ``ppb.BaseSprite.`` + """ + __warning = """Using ppb.BaseSprite is deprecated. + + You probably want ppb.Sprite. If you're wanting to use BaseSprite and + mixins to change what features your sprites have, import + ppb.sprites.BaseSprite. + """ + + def __init__(self, *args, **kwargs): + warnings.warn(self.__warning, DeprecationWarning) + + +class Sprite(OldBaseSprite): + """ + A stub pointing to current functionality under the new name. + """ + + def _make_kwargs(setup, title, engine_opts): kwargs = { "resolution": (800, 600), From 32bd32d32d835fce5997511457ee85aabc93e5bf Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 09:49:44 -0400 Subject: [PATCH 04/25] Adds Square Shape Mixin to ppb.sprites. --- ppb/sprites.py | 67 +++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/ppb/sprites.py b/ppb/sprites.py index b8682430..1a141647 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -70,7 +70,7 @@ class Side(FauxFloat): BOTTOM: ('y', -1) } - def __init__(self, parent: 'BaseSprite', side: str): + def __init__(self, parent: 'SquareShapeMixin', side: str): self.side = side self.parent = parent @@ -205,37 +205,17 @@ def _attribute_gate(self, attribute, bad_sides): raise AttributeError(message) -class BaseSprite(EventMixin, RotatableMixin): +class SquareShapeMixin: """ - The base Sprite class. All sprites should inherit from this (directly or - indirectly). + A mixin that applies square shapes to sprites. + + You should include SquareShapeMixin after ppb.sprites.BaseSprite in + your parent classes. """ - #: (:py:class:`ppb.Image`): The image asset - image = None - #: (:py:class:`ppb.Vector`): Location of the sprite - position: Vector = Vector(0, 0) #: The width/height of the sprite (sprites are square) size: Union[int, float] = 1 - #: The layer a sprite exists on. - layer: int = 0 - - def __init__(self, **kwargs): - super().__init__() - - self.position = Vector(self.position) - - # Initialize things - for k, v in kwargs.items(): - # Abbreviations - if k == 'pos': - k = 'position' - # Castings - if k == 'position': - v = Vector(v) - setattr(self, k, v) - - # Trigger some calculations - self.size = self.size + #: Just here for typing and linting purposes. Your sprite should already have a position. + position: ppb_vector.Vector @property def center(self) -> Vector: @@ -296,6 +276,37 @@ def bottom(self, value): def _offset_value(self): return self.size / 2 + +class BaseSprite(EventMixin, RotatableMixin): + """ + The base Sprite class. All sprites should inherit from this (directly or + indirectly). + """ + #: (:py:class:`ppb.Image`): The image asset + image = None + #: (:py:class:`ppb.Vector`): Location of the sprite + position: Vector = Vector(0, 0) + #: The layer a sprite exists on. + layer: int = 0 + + def __init__(self, **kwargs): + super().__init__() + + self.position = Vector(self.position) + + # Initialize things + for k, v in kwargs.items(): + # Abbreviations + if k == 'pos': + k = 'position' + # Castings + if k == 'position': + v = Vector(v) + setattr(self, k, v) + + # Trigger some calculations + self.size = self.size + def __image__(self): if self.image is None: klass = type(self) From f99aeffcaa518869ded2caa9370bcb3a0ce44109 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 09:58:22 -0400 Subject: [PATCH 05/25] Pulls out RenderableMixin from BaseSprite. --- ppb/sprites.py | 118 ++++++++++++++++++++++++---------------- ppb/systems/renderer.py | 2 + 2 files changed, 72 insertions(+), 48 deletions(-) diff --git a/ppb/sprites.py b/ppb/sprites.py index 1a141647..c97b47c2 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -19,6 +19,76 @@ side_attribute_error_message = error_message.format +class BaseSprite(EventMixin): + """ + The base Sprite class. All sprites should inherit from this (directly or + indirectly). + + The things that define a BaseSprite: + + * The __event__ protocol (see ppb.eventlib.EventMixin) + * A position vector + * A layer + + BaseSprite provides an __init__ method that sets attributes based on kwargs + to make rapid prototyping easier. + """ + #: (:py:class:`ppb.Vector`): Location of the sprite + position: Vector = Vector(0, 0) + #: The layer a sprite exists on. + layer: int = 0 + + def __init__(self, **kwargs): + super().__init__() + + self.position = Vector(self.position) + + # Initialize things + for k, v in kwargs.items(): + # Abbreviations + if k == 'pos': + k = 'position' + # Castings + if k == 'position': + v = Vector(v) + setattr(self, k, v) + + # Trigger some calculations + self.size = self.size + + +class RenderableMixin: + """ + A class implementing the API expected by ppb.systems.renderer.Renderer. + + You should include RenderableMixin after BaseSprite in your parent class + definitions. + """ + #: (:py:class:`ppb.Image`): The image asset + image = None # TODO: Type hint appropriately + + def __image__(self): + """ + Returns the sprite's image attribute if provided, or sets a default + one. + """ + if self.image is None: + klass = type(self) + prefix = Path(klass.__module__.replace('.', '/')) + try: + klassfile = getfile(klass) + except TypeError: + prefix = Path('.') + else: + if Path(klassfile).name != '__init__.py': + prefix = prefix.parent + if prefix == Path('.'): + self.image = ppb.Image(f"{klass.__name__.lower()}.png") + else: + self.image = ppb.Image(f"{prefix!s}/{klass.__name__.lower()}.png") + return self.image + + class RotatableMixin: """ A simple rotation mixin. Can be included with sprites. @@ -275,51 +345,3 @@ def bottom(self, value): @property def _offset_value(self): return self.size / 2 - - -class BaseSprite(EventMixin, RotatableMixin): - """ - The base Sprite class. All sprites should inherit from this (directly or - indirectly). - """ - #: (:py:class:`ppb.Image`): The image asset - image = None - #: (:py:class:`ppb.Vector`): Location of the sprite - position: Vector = Vector(0, 0) - #: The layer a sprite exists on. - layer: int = 0 - - def __init__(self, **kwargs): - super().__init__() - - self.position = Vector(self.position) - - # Initialize things - for k, v in kwargs.items(): - # Abbreviations - if k == 'pos': - k = 'position' - # Castings - if k == 'position': - v = Vector(v) - setattr(self, k, v) - - # Trigger some calculations - self.size = self.size - - def __image__(self): - if self.image is None: - klass = type(self) - prefix = Path(klass.__module__.replace('.', '/')) - try: - klassfile = getfile(klass) - except TypeError: - prefix = Path('.') - else: - if Path(klassfile).name != '__init__.py': - prefix = prefix.parent - if prefix == Path('.'): - self.image = ppb.Image(f"{klass.__name__.lower()}.png") - else: - self.image = ppb.Image(f"{prefix!s}/{klass.__name__.lower()}.png") - return self.image diff --git a/ppb/systems/renderer.py b/ppb/systems/renderer.py index 7ed2e071..b1dc9951 100644 --- a/ppb/systems/renderer.py +++ b/ppb/systems/renderer.py @@ -15,6 +15,8 @@ DEFAULT_RESOLUTION = 800, 600 +# TODO: Move Image out of the renderer so sprites can type hint +# appropriately. class Image(assets.Asset): def background_parse(self, data): return pygame.image.load(io.BytesIO(data), self.name).convert_alpha() From b3785be4c1645b17903104cfacfb7609d0addb18 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 10:05:17 -0400 Subject: [PATCH 06/25] Reorganizers Sprite. --- ppb/__init__.py | 15 +++++---------- ppb/sprites.py | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/ppb/__init__.py b/ppb/__init__.py index e305d27a..0b482df0 100644 --- a/ppb/__init__.py +++ b/ppb/__init__.py @@ -6,25 +6,26 @@ from ppb_vector import Vector from ppb.engine import GameEngine from ppb.scenes import BaseScene -from ppb.sprites import BaseSprite as OldBaseSprite +from ppb.sprites import Sprite from ppb.systems import Image from ppb.systems import Sound __all__ = ( # Shortcuts - 'Vector', 'BaseScene', 'BaseSprite', 'Image', 'Sound', 'events', + 'Vector', 'BaseScene', 'BaseSprite', 'Image', 'Sprite', 'Sound', + 'events', # Local stuff 'run', 'make_engine', ) -class BaseSprite(OldBaseSprite): +class BaseSprite(Sprite): """ A stub that raises a deprecation warning when a user uses ``ppb.BaseSprite.`` """ __warning = """Using ppb.BaseSprite is deprecated. - + You probably want ppb.Sprite. If you're wanting to use BaseSprite and mixins to change what features your sprites have, import ppb.sprites.BaseSprite. @@ -34,12 +35,6 @@ def __init__(self, *args, **kwargs): warnings.warn(self.__warning, DeprecationWarning) -class Sprite(OldBaseSprite): - """ - A stub pointing to current functionality under the new name. - """ - - def _make_kwargs(setup, title, engine_opts): kwargs = { "resolution": (800, 600), diff --git a/ppb/sprites.py b/ppb/sprites.py index c97b47c2..a46a4772 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -9,6 +9,13 @@ from ppb.eventlib import EventMixin from ppb.utils import FauxFloat +__all__ = ( + "BaseSprite", + "Sprite", + "RotatableMixin", + "SquareShapeMixin", + "RenderableMixin", +) TOP = "top" BOTTOM = "bottom" @@ -345,3 +352,18 @@ def bottom(self, value): @property def _offset_value(self): return self.size / 2 + + +class Sprite(BaseSprite, SquareShapeMixin, RenderableMixin, RotatableMixin): + """ + The default Sprite class. + + Sprite includes: + + * BaseSprite + * SquareShapeMixin + * RenderableMixin + * RotatableMixin + + New in 0.7.0: Use this in place of BaseSprite in your games. + """ From f763c152894d14487b8bd63eeb92f38e222d2fbe Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 10:29:41 -0400 Subject: [PATCH 07/25] BaseSprite stub needs to call super().__init__ to work properly. --- ppb/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ppb/__init__.py b/ppb/__init__.py index 0b482df0..d4502578 100644 --- a/ppb/__init__.py +++ b/ppb/__init__.py @@ -31,8 +31,9 @@ class BaseSprite(Sprite): ppb.sprites.BaseSprite. """ - def __init__(self, *args, **kwargs): + def __init__(self, **kwargs): warnings.warn(self.__warning, DeprecationWarning) + super().__init__(**kwargs) def _make_kwargs(setup, title, engine_opts): From 674f57a9fd68a6ac462e81bb5ecc5f1b7dd613e7 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 10:49:57 -0400 Subject: [PATCH 08/25] Size calculations have to happen in the SquareShapeMixin init. --- ppb/sprites.py | 9 ++++++--- tests/test_sprites.py | 15 ++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ppb/sprites.py b/ppb/sprites.py index a46a4772..adc684ad 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -60,9 +60,6 @@ def __init__(self, **kwargs): v = Vector(v) setattr(self, k, v) - # Trigger some calculations - self.size = self.size - class RenderableMixin: """ @@ -294,6 +291,12 @@ class SquareShapeMixin: #: Just here for typing and linting purposes. Your sprite should already have a position. position: ppb_vector.Vector + def __init__(self, **kwargs): + super().__init__(**kwargs) + + # Trigger some calculations + self.size = self.size + @property def center(self) -> Vector: """ diff --git a/tests/test_sprites.py b/tests/test_sprites.py index ba8961b6..ca21175e 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -1,15 +1,16 @@ from unittest import TestCase from unittest.mock import patch -from ppb import BaseSprite, Vector -from ppb.sprites import RotatableMixin +from ppb import BaseSprite as DeprecatedBaseSprite +from ppb.sprites import * +from ppb_vector import Vector class TestBaseSprite(TestCase): def setUp(self): - self.sprite = BaseSprite() - self.wide_sprite = BaseSprite(size=2, pos=(2, 2)) + self.sprite = Sprite() + self.wide_sprite = Sprite(size=2, pos=(2, 2)) def test_pos(self): self.assertEqual(self.sprite.position, Vector(0, 0)) @@ -280,7 +281,7 @@ class TestSprite(BaseSprite): def test_offset(): - class TestSprite(BaseSprite): + class TestSprite(Sprite): size = 1.1 assert TestSprite().left < -0.5 @@ -322,7 +323,7 @@ def test_rotatable_rotate(): def test_rotatable_base_sprite(): - test_sprite = BaseSprite() + test_sprite = Sprite() test_sprite.rotate(1) assert test_sprite.rotation == 1 @@ -333,7 +334,7 @@ def test_sprite_in_main(): Test that Sprite.__resource_path__ returns a meaningful value inside REPLs where __main__ doesn't have a file. """ - class TestSprite(BaseSprite): + class TestSprite(Sprite): pass s = TestSprite() From 84e445e4c59d7da5a007bd43552e38fa77b8d678 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 10:51:38 -0400 Subject: [PATCH 09/25] Removes unittest test_pos --- tests/test_sprites.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index ca21175e..1f0ddf0b 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -12,10 +12,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_pos(self): - self.assertEqual(self.sprite.position, Vector(0, 0)) - self.assertEqual(self.wide_sprite.position, Vector(2, 2)) - def test_center(self): self.assertEqual(self.sprite.center, self.sprite.position) From 60c8a12042f0612cf77a67b338f59f6ef7d1cfff Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 11:26:23 -0400 Subject: [PATCH 10/25] Removes TestBaseSprite.test_center in favor of hypothesis tests. --- tests/test_sprites.py | 52 ++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index 1f0ddf0b..e52b4249 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -1,6 +1,10 @@ from unittest import TestCase from unittest.mock import patch +from hypothesis import given +from hypothesis.strategies import floats +import pytest + from ppb import BaseSprite as DeprecatedBaseSprite from ppb.sprites import * from ppb_vector import Vector @@ -12,26 +16,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_center(self): - self.assertEqual(self.sprite.center, self.sprite.position) - - self.sprite.center = 1, 1 - self.assertEqual(self.sprite.position.x, 1) - self.assertEqual(self.sprite.position.y, 1) - self.assertEqual(self.sprite.center, self.sprite.position) - - self.sprite.center = Vector(2, 2) - self.assertEqual(self.sprite.position.x, 2) - self.assertEqual(self.sprite.position.y, 2) - - self.sprite.center += -1, -1 - self.assertEqual(self.sprite.position.x, 1) - self.assertEqual(self.sprite.position.y, 1) - - self.sprite.center += 0, 1 - self.assertEqual(self.sprite.position.x, 1) - self.assertEqual(self.sprite.position.y, 2) - def test_left(self): self.assertEqual(self.sprite.left, -0.5) self.assertEqual(self.wide_sprite.left, 1) @@ -325,6 +309,34 @@ def test_rotatable_base_sprite(): assert test_sprite.rotation == 1 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_center_equals_position(x, y): + sprite = Sprite(position=(x, y)) + assert sprite.center == sprite.position + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_center_setting(x, y, vector_type): + sprite = Sprite() + sprite.center = vector_type((x, y)) + assert sprite.center.x == x + assert sprite.center.y == y + assert sprite.position == sprite.center + + +@given(x=floats(allow_nan=False, allow_infinity=False), + y=floats(allow_nan=False, allow_infinity=False), + delta_x=floats(allow_nan=False, allow_infinity=False), + delta_y=floats(allow_nan=False, allow_infinity=False)) +def test_center_plus_equals(x, y, delta_x, delta_y): + sprite = Sprite(position=(x, y)) + sprite.center += delta_x, delta_y + assert sprite.position.x == x + delta_x + assert sprite.position.y == y + delta_y + assert sprite.position == sprite.center + + def test_sprite_in_main(): """ Test that Sprite.__resource_path__ returns a meaningful value inside From 0d7803230a5a6d8a43e34c2e782fc0b06e775193 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 11:36:49 -0400 Subject: [PATCH 11/25] Parametrizes test_sides_center_plus_equals --- tests/test_sprites.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index e52b4249..e5f0deaf 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -325,13 +325,14 @@ def test_sides_center_setting(x, y, vector_type): assert sprite.position == sprite.center +@pytest.mark.parametrize("vector_type", [tuple, Vector]) @given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False), delta_x=floats(allow_nan=False, allow_infinity=False), delta_y=floats(allow_nan=False, allow_infinity=False)) -def test_center_plus_equals(x, y, delta_x, delta_y): +def test_sides_center_plus_equals(x, y, delta_x, delta_y, vector_type): sprite = Sprite(position=(x, y)) - sprite.center += delta_x, delta_y + sprite.center += vector_type((delta_x, delta_y)) assert sprite.position.x == x + delta_x assert sprite.position.y == y + delta_y assert sprite.position == sprite.center From 109a5489b30e959ed39547205fcf1a93bd7ff35c Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 12:18:17 -0400 Subject: [PATCH 12/25] Refacters TestBaseSprite.test_left --- tests/test_sprites.py | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index e5f0deaf..2f38e900 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -1,8 +1,10 @@ +from math import isclose from unittest import TestCase from unittest.mock import patch from hypothesis import given from hypothesis.strategies import floats +from hypothesis.strategies import integers import pytest from ppb import BaseSprite as DeprecatedBaseSprite @@ -16,18 +18,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_left(self): - self.assertEqual(self.sprite.left, -0.5) - self.assertEqual(self.wide_sprite.left, 1) - - self.sprite.left = 0 - self.assertEqual(self.sprite.position.x, 0.5) - self.assertEqual(self.sprite.position.y, 0) - - self.sprite.left += 2 - self.assertEqual(self.sprite.position.x, 2.5) - self.assertEqual(self.sprite.position.y, 0) - def test_right(self): self.assertEqual(self.sprite.right, 0.5) self.assertEqual(self.wide_sprite.right, 3) @@ -338,6 +328,31 @@ def test_sides_center_plus_equals(x, y, delta_x, delta_y, vector_type): assert sprite.position == sprite.center +@given(x=floats(allow_nan=False, allow_infinity=False)) +def test_sides_left(x): + sprite = Sprite(position=(x, 0)) + assert isclose(sprite.left, x - 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@given(x=integers(max_value=1_000_000, min_value=-1_000_000)) +def test_sides_set_left(x): + sprite = Sprite() + sprite.left = x + print(float(sprite.left)) + assert sprite.left == x + assert sprite.position.x == x + 0.5 + + +@given(x=integers()) +def test_sides_plus_equals_left(x): + sprite = Sprite() + sprite.left += x + assert sprite.left == x - 0.5 + assert sprite.position.x == sprite.left + 0.5 + + def test_sprite_in_main(): """ Test that Sprite.__resource_path__ returns a meaningful value inside From 66edcf5b1ae973e75549a81a0c3862cecb28f424 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 12:26:12 -0400 Subject: [PATCH 13/25] Refactors TestBaseSprite.test_right --- tests/test_sprites.py | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index 2f38e900..03578a1b 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -18,18 +18,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_right(self): - self.assertEqual(self.sprite.right, 0.5) - self.assertEqual(self.wide_sprite.right, 3) - - self.sprite.right = 0 - self.assertEqual(self.sprite.position.x, -0.5) - self.assertEqual(self.sprite.position.y, 0) - - self.sprite.right += 2 - self.assertEqual(self.sprite.position.x, 1.5) - self.assertEqual(self.sprite.position.y, 0) - def test_top(self): self.assertEqual(self.sprite.top, 0.5) self.assertEqual(self.wide_sprite.top, 3) @@ -336,7 +324,7 @@ def test_sides_left(x): # ints because the kinds of floats hypothesis generates aren't realistic # to our use case. -@given(x=integers(max_value=1_000_000, min_value=-1_000_000)) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000)) def test_sides_set_left(x): sprite = Sprite() sprite.left = x @@ -345,7 +333,7 @@ def test_sides_set_left(x): assert sprite.position.x == x + 0.5 -@given(x=integers()) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000)) def test_sides_plus_equals_left(x): sprite = Sprite() sprite.left += x @@ -353,6 +341,31 @@ def test_sides_plus_equals_left(x): assert sprite.position.x == sprite.left + 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False)) +def test_sides_right(x): + sprite = Sprite(position=(x, 0)) + assert isclose(sprite.right, x + 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@given(x=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_right_set(x): + sprite = Sprite() + sprite.right = x + print(float(sprite.left)) + assert sprite.right == x + assert sprite.position.x == x - 0.5 + + +@given(x=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_right_plus_equals(x): + sprite = Sprite() + sprite.right += x + assert sprite.right == x + 0.5 + assert sprite.position.x == sprite.right - 0.5 + + def test_sprite_in_main(): """ Test that Sprite.__resource_path__ returns a meaningful value inside From fa1e4a736bb86c7e034316b758bdfe7e344af942 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 12:30:34 -0400 Subject: [PATCH 14/25] Refactors TestBaseSprite.test_top --- tests/test_sprites.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index 03578a1b..2bfc8e0f 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -18,18 +18,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_top(self): - self.assertEqual(self.sprite.top, 0.5) - self.assertEqual(self.wide_sprite.top, 3) - - self.sprite.top = 0 - self.assertEqual(self.sprite.position.x, 0) - self.assertEqual(self.sprite.position.y, -0.5) - - self.sprite.top += 2 - self.assertEqual(self.sprite.position.x, 0) - self.assertEqual(self.sprite.position.y, 1.5) - def test_bottom(self): self.assertEqual(self.sprite.bottom, -0.5) self.assertEqual(self.wide_sprite.bottom, 1) @@ -366,6 +354,30 @@ def test_sides_right_plus_equals(x): assert sprite.position.x == sprite.right - 0.5 +@given(y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_top(y): + sprite = Sprite(position=(0, y)) + assert isclose(sprite.top, y + 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@given(y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_set(y): + sprite = Sprite() + sprite.top = y + assert sprite.top == y + assert sprite.position.y == y - 0.5 + + +@given(y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_plus_equals(y): + sprite = Sprite() + sprite.top += y + assert sprite.top == y + 0.5 + assert sprite.position.y == sprite.top - 0.5 + + def test_sprite_in_main(): """ Test that Sprite.__resource_path__ returns a meaningful value inside From 23bda32883d4e25fe5f1d80752a6baee715ba27c Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 12:33:47 -0400 Subject: [PATCH 15/25] Refactors TestBaseSprite.test_bottom --- tests/test_sprites.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index 2bfc8e0f..c22e50c5 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -18,18 +18,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_bottom(self): - self.assertEqual(self.sprite.bottom, -0.5) - self.assertEqual(self.wide_sprite.bottom, 1) - - self.sprite.bottom = 0 - self.assertEqual(self.sprite.position.x, 0) - self.assertEqual(self.sprite.position.y, 0.5) - - self.sprite.bottom += 2 - self.assertEqual(self.sprite.position.x, 0) - self.assertEqual(self.sprite.position.y, 2.5) - def test_left_top(self): self.assertEqual(self.sprite.left.top, Vector(-0.5, 0.5)) @@ -275,6 +263,30 @@ def test_rotatable_base_sprite(): assert test_sprite.rotation == 1 +@given(y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_bottom(y): + sprite = Sprite(position=(0, y)) + assert isclose(sprite.bottom, y - 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@given(y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_set(y): + sprite = Sprite() + sprite.bottom = y + assert sprite.bottom == y + assert sprite.position.y == y + 0.5 + + +@given(y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_plus_equals(y): + sprite = Sprite() + sprite.bottom += y + assert sprite.bottom == y - 0.5 + assert sprite.position.y == sprite.bottom + 0.5 + + @given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) def test_sides_center_equals_position(x, y): sprite = Sprite(position=(x, y)) From 0905c61945215efc76f82b540134a450b7e604d7 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 12:50:38 -0400 Subject: [PATCH 16/25] Adds test to confirm ppb.BaseSprite warns of deprecation. --- tests/test_sprites.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index c22e50c5..c54b439f 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -1,6 +1,7 @@ from math import isclose from unittest import TestCase from unittest.mock import patch +import warnings from hypothesis import given from hypothesis.strategies import floats @@ -403,3 +404,15 @@ class TestSprite(Sprite): with patch("ppb.sprites.getfile", side_effect=TypeError): # This patch simulates what happens when TestSprite was defined in the REPL assert s.__image__() # We don't care what it is, as long as it's something + + +def test_deprecated_base_sprite_warns(): + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + # Trigger a warning. + sprite = DeprecatedBaseSprite() + # Verify some things + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) + assert "deprecated" in str(w[-1].message) \ No newline at end of file From 77b2aecd81f6dbf332240756150eaf0e296652a3 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 13:18:17 -0400 Subject: [PATCH 17/25] Refactors TestBaseSprite tests related to top_left --- tests/test_sprites.py | 84 ++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index c54b439f..4544e829 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -19,20 +19,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_left_top(self): - self.assertEqual(self.sprite.left.top, Vector(-0.5, 0.5)) - - self.sprite.left.top = (2, 2) - self.assertEqual(self.sprite.left.top, Vector(2, 2)) - - self.sprite.left.top += (2, 2) - self.assertEqual(self.sprite.left.top, Vector(4, 4)) - - result = self.sprite.left.top + (3, 3) - self.assertEqual(result, Vector(7, 7)) - - self.assertEqual(self.sprite.position, Vector(4.5, 3.5)) - def test_left_bottom(self): self.assertEqual(self.sprite.left.bottom, Vector(-0.5, -0.5)) @@ -119,20 +105,6 @@ def test_right_left(self): self.assertRaises(AttributeError, getattr, self.sprite.right, "left") self.assertRaises(AttributeError, setattr, self.sprite.right, "left", Vector(1, 1)) - def test_top_left(self): - self.assertEqual(self.sprite.top.left, Vector(-0.5, 0.5)) - - self.sprite.top.left = (2, 2) - self.assertEqual(self.sprite.top.left, Vector(2, 2)) - - self.sprite.top.left += (2, 2) - self.assertEqual(self.sprite.top.left, Vector(4, 4)) - - result = self.sprite.top.left + (3, 3) - self.assertEqual(result, Vector(7, 7)) - - self.assertEqual(self.sprite.position, Vector(4.5, 3.5)) - def test_top_right(self): self.assertEqual(self.sprite.top.right, Vector(0.5, 0.5)) @@ -391,6 +363,60 @@ def test_sides_top_plus_equals(y): assert sprite.position.y == sprite.top - 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_top_left(x, y): + sprite = Sprite(position=(x, y)) + top_left = sprite.top.left + left_top = sprite.left.top + assert top_left == left_top + assert isclose(top_left.y, y + 0.5) + assert isclose(top_left.x, x - 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_left_set(x, y, vector_type): + sprite = Sprite() + sprite.top.left = vector_type((x, y)) + top_left = sprite.top.left + left_top = sprite.left.top + assert top_left == left_top + assert top_left == Vector(x, y) + assert sprite.position == top_left + Vector(0.5, -0.5) + + # duplicating to prove top.left and left.top are the same. + sprite = Sprite() + sprite.left.top = vector_type((x, y)) + top_left = sprite.top.left + left_top = sprite.left.top + assert left_top == top_left + assert left_top == Vector(x, y) + assert sprite.position == left_top + Vector(0.5, -0.5) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_left_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.top.left += vector_type((x, y)) + top_left = sprite.top.left + left_top = sprite.left.top + assert top_left == left_top + assert top_left == Vector(x - 0.5, y + 0.5) + assert sprite.position == top_left + Vector(0.5, -0.5) + + # duplicating to prove top.left and left.top are the same. + sprite = Sprite() + sprite.top.left += vector_type((x, y)) + top_left = sprite.top.left + left_top = sprite.left.top + assert left_top == top_left + assert left_top == Vector(x - 0.5, y + 0.5) + assert sprite.position == left_top + Vector(0.5, -0.5) + + def test_sprite_in_main(): """ Test that Sprite.__resource_path__ returns a meaningful value inside @@ -415,4 +441,4 @@ def test_deprecated_base_sprite_warns(): # Verify some things assert len(w) == 1 assert issubclass(w[-1].category, DeprecationWarning) - assert "deprecated" in str(w[-1].message) \ No newline at end of file + assert "deprecated" in str(w[-1].message) From 89fede07f0c8d22777063d1435c7da3e11c13093 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 13:29:58 -0400 Subject: [PATCH 18/25] Refactors top_right tests. --- tests/test_sprites.py | 82 ++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index 4544e829..d353f1cf 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -61,20 +61,6 @@ def test_right_bottom(self): self.assertEqual(self.sprite.position, Vector(2.5, 2.5)) - def test_right_top(self): - self.assertEqual(self.sprite.right.top, Vector(0.5, 0.5)) - - self.sprite.right.top = (1, 1) - self.assertEqual(self.sprite.right.top, Vector(1, 1)) - - self.sprite.right.top += (2, 1) - self.assertEqual(self.sprite.right.top, Vector(3, 2)) - - result = self.sprite.right.top + (2, 3) - self.assertEqual(result, Vector(5, 5)) - - self.assertEqual(self.sprite.position, Vector(2.5, 1.5)) - def test_right_center(self): self.assertEqual(self.sprite.right.center, Vector(0.5, 0)) @@ -105,20 +91,6 @@ def test_right_left(self): self.assertRaises(AttributeError, getattr, self.sprite.right, "left") self.assertRaises(AttributeError, setattr, self.sprite.right, "left", Vector(1, 1)) - def test_top_right(self): - self.assertEqual(self.sprite.top.right, Vector(0.5, 0.5)) - - self.sprite.top.right = (1, 1) - self.assertEqual(self.sprite.top.right, Vector(1, 1)) - - self.sprite.top.right += (2, 1) - self.assertEqual(self.sprite.top.right, Vector(3, 2)) - - result = self.sprite.top.right + (2, 3) - self.assertEqual(result, Vector(5, 5)) - - self.assertEqual(self.sprite.position, Vector(2.5, 1.5)) - def test_top_center(self): self.assertEqual(self.sprite.top.center, Vector(0, 0.5)) @@ -417,6 +389,60 @@ def test_sides_top_left_plus_equals(x, y, vector_type): assert sprite.position == left_top + Vector(0.5, -0.5) +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_top_right(x, y): + sprite = Sprite(position=(x, y)) + top_right = sprite.top.right + right_top = sprite.right.top + assert top_right == right_top + assert isclose(top_right.y, y + 0.5) + assert isclose(top_right.x, x + 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_right_set(x, y, vector_type): + sprite = Sprite() + sprite.top.right = vector_type((x, y)) + top_right = sprite.top.right + right_top = sprite.right.top + assert top_right == right_top + assert top_right == Vector(x, y) + assert sprite.position == top_right + Vector(-0.5, -0.5) + + # duplicating to prove top.left and left.top are the same. + sprite = Sprite() + sprite.right.top = vector_type((x, y)) + top_right = sprite.top.right + right_top = sprite.right.top + assert right_top == top_right + assert right_top == Vector(x, y) + assert sprite.position == right_top + Vector(-0.5, -0.5) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_right_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.top.right += vector_type((x, y)) + top_right = sprite.top.right + right_top = sprite.right.top + assert top_right == right_top + assert top_right == Vector(x + 0.5, y + 0.5) + assert sprite.position == top_right + Vector(-0.5, -0.5) + + # duplicating to prove top.left and left.top are the same. + sprite = Sprite() + sprite.top.left += vector_type((x, y)) + top_right = sprite.top.right + right_top = sprite.right.top + assert right_top == top_right + assert right_top == Vector(x + 0.5, y + 0.5) + assert sprite.position == right_top + Vector(-0.5, -0.5) + + def test_sprite_in_main(): """ Test that Sprite.__resource_path__ returns a meaningful value inside From ec30ee6d476b9aad67ba3d0a7bb29a5d1a02dea2 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 13:56:08 -0400 Subject: [PATCH 19/25] Refactors bottom_right tests. --- tests/test_sprites.py | 82 ++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index d353f1cf..1f708c70 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -47,20 +47,6 @@ def test_left_center(self): self.assertEqual(self.sprite.position, Vector(3.5, 2)) - def test_right_bottom(self): - self.assertEqual(self.sprite.right.bottom, Vector(0.5, -0.5)) - - self.sprite.right.bottom = (1, 1) - self.assertEqual(self.sprite.right.bottom, Vector(1, 1)) - - self.sprite.right.bottom += (2, 1) - self.assertEqual(self.sprite.right.bottom, Vector(3, 2)) - - result = self.sprite.right.bottom + (2, 3) - self.assertEqual(result, Vector(5, 5)) - - self.assertEqual(self.sprite.position, Vector(2.5, 2.5)) - def test_right_center(self): self.assertEqual(self.sprite.right.center, Vector(0.5, 0)) @@ -119,20 +105,6 @@ def test_bottom_left(self): self.assertEqual(self.sprite.position, Vector(4.5, 4.5)) - def test_bottom_right(self): - self.assertEqual(self.sprite.bottom.right, Vector(0.5, -0.5)) - - self.sprite.bottom.right = (1, 1) - self.assertEqual(self.sprite.bottom.right, Vector(1, 1)) - - self.sprite.bottom.right += (2, 1) - self.assertEqual(self.sprite.bottom.right, Vector(3, 2)) - - result = self.sprite.bottom.right + (2, 3) - self.assertEqual(result, Vector(5, 5)) - - self.assertEqual(self.sprite.position, Vector(2.5, 2.5)) - def test_bottom_center(self): self.assertEqual(self.sprite.bottom.center, Vector(0, -0.5)) @@ -232,6 +204,60 @@ def test_sides_bottom_plus_equals(y): assert sprite.position.y == sprite.bottom + 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_bottom_right(x, y): + sprite = Sprite(position=(x, y)) + bottom_right = sprite.bottom.right + right_bottom = sprite.right.bottom + assert bottom_right == right_bottom + assert isclose(bottom_right.y, y - 0.5) + assert isclose(bottom_right.x, x + 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_right_set(x, y, vector_type): + sprite = Sprite() + sprite.bottom.right = vector_type((x, y)) + bottom_right = sprite.bottom.right + right_bottom = sprite.right.bottom + assert bottom_right == right_bottom + assert bottom_right == Vector(x, y) + assert sprite.position == bottom_right + Vector(-0.5, 0.5) + + # duplicating to prove top.left and left.top are the same. + sprite = Sprite() + sprite.right.bottom = vector_type((x, y)) + bottom_right = sprite.bottom.right + right_bottom = sprite.right.bottom + assert right_bottom == bottom_right + assert right_bottom == Vector(x, y) + assert sprite.position == right_bottom + Vector(-0.5, 0.5) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_right_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.bottom.right += vector_type((x, y)) + bottom_right = sprite.bottom.right + right_bottom = sprite.right.bottom + assert bottom_right == right_bottom + assert bottom_right == Vector(x + 0.5, y - 0.5) + assert sprite.position == bottom_right + Vector(-0.5, 0.5) + + # duplicating to prove bottom.left and left.bottom are the same. + sprite = Sprite() + sprite.bottom.left += vector_type((x, y)) + bottom_right = sprite.bottom.right + right_bottom = sprite.right.bottom + assert right_bottom == bottom_right + assert right_bottom == Vector(x + 0.5, y - 0.5) + assert sprite.position == right_bottom + Vector(-0.5, 0.5) + + @given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) def test_sides_center_equals_position(x, y): sprite = Sprite(position=(x, y)) From 7321a33d537d4703a8ee5d18338b30c8cddb4408 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 14:02:37 -0400 Subject: [PATCH 20/25] Refactor bottom_left tests. --- tests/test_sprites.py | 82 ++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index 1f708c70..3431b12e 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -19,20 +19,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_left_bottom(self): - self.assertEqual(self.sprite.left.bottom, Vector(-0.5, -0.5)) - - self.sprite.left.bottom = (1, 2) - self.assertEqual(self.sprite.left.bottom, Vector(1, 2)) - - self.sprite.left.bottom += (2, 1) - self.assertEqual(self.sprite.left.bottom, Vector(3, 3)) - - result = self.sprite.left.bottom + (3, 2) - self.assertEqual(result, Vector(6, 5)) - - self.assertEqual(self.sprite.position, Vector(3.5, 3.5)) - def test_left_center(self): self.assertEqual(self.sprite.left.center, Vector(-0.5, 0)) @@ -91,20 +77,6 @@ def test_top_bottom(self): self.assertRaises(AttributeError, getattr, self.sprite.top, "bottom") self.assertRaises(AttributeError, setattr, self.sprite.top, "bottom", Vector(1, 1)) - def test_bottom_left(self): - self.assertEqual(self.sprite.bottom.left, Vector(-0.5, -0.5)) - - self.sprite.bottom.left = (2, 2) - self.assertEqual(self.sprite.bottom.left, Vector(2, 2)) - - self.sprite.bottom.left += (2, 2) - self.assertEqual(self.sprite.bottom.left, Vector(4, 4)) - - result = self.sprite.bottom.left + (3, 3) - self.assertEqual(result, Vector(7, 7)) - - self.assertEqual(self.sprite.position, Vector(4.5, 4.5)) - def test_bottom_center(self): self.assertEqual(self.sprite.bottom.center, Vector(0, -0.5)) @@ -204,6 +176,60 @@ def test_sides_bottom_plus_equals(y): assert sprite.position.y == sprite.bottom + 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_bottom_left(x, y): + sprite = Sprite(position=(x, y)) + bottom_left = sprite.bottom.left + left_bottom = sprite.left.bottom + assert bottom_left == left_bottom + assert isclose(bottom_left.y, y - 0.5) + assert isclose(bottom_left.x, x - 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_left_set(x, y, vector_type): + sprite = Sprite() + sprite.bottom.left = vector_type((x, y)) + bottom_left = sprite.bottom.left + left_bottom = sprite.left.bottom + assert bottom_left == left_bottom + assert bottom_left == Vector(x, y) + assert sprite.position == bottom_left + Vector(0.5, 0.5) + + # duplicating to prove top.left and left.top are the same. + sprite = Sprite() + sprite.left.bottom = vector_type((x, y)) + bottom_left = sprite.bottom.left + left_bottom = sprite.left.bottom + assert left_bottom == bottom_left + assert left_bottom == Vector(x, y) + assert sprite.position == left_bottom + Vector(0.5, 0.5) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_left_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.bottom.left += vector_type((x, y)) + bottom_left = sprite.bottom.left + left_bottom = sprite.left.bottom + assert bottom_left == left_bottom + assert bottom_left == Vector(x - 0.5, y - 0.5) + assert sprite.position == bottom_left + Vector(0.5, 0.5) + + # duplicating to prove bottom.left and left.bottom are the same. + sprite = Sprite() + sprite.bottom.left += vector_type((x, y)) + bottom_left = sprite.bottom.left + left_bottom = sprite.left.bottom + assert left_bottom == bottom_left + assert left_bottom == Vector(x +- 0.5, y - 0.5) + assert sprite.position == left_bottom + Vector(0.5, 0.5) + + @given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) def test_sides_bottom_right(x, y): sprite = Sprite(position=(x, y)) From d1696505814efeaf38e0d3d572d0bd2461bb2244 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 14:48:52 -0400 Subject: [PATCH 21/25] Refactors side.center tests. --- tests/test_sprites.py | 164 +++++++++++++++++++++++++++++++----------- 1 file changed, 122 insertions(+), 42 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index 3431b12e..c470997e 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -19,34 +19,6 @@ def setUp(self): self.sprite = Sprite() self.wide_sprite = Sprite(size=2, pos=(2, 2)) - def test_left_center(self): - self.assertEqual(self.sprite.left.center, Vector(-0.5, 0)) - - self.sprite.left.center = (1, 1) - self.assertEqual(self.sprite.left.center, Vector(1, 1)) - - self.sprite.left.center += (2, 1) - self.assertEqual(self.sprite.left.center, Vector(3, 2)) - - result = self.sprite.left.center + (2, 3) - self.assertEqual(result, Vector(5, 5)) - - self.assertEqual(self.sprite.position, Vector(3.5, 2)) - - def test_right_center(self): - self.assertEqual(self.sprite.right.center, Vector(0.5, 0)) - - self.sprite.right.center = (1, 1) - self.assertEqual(self.sprite.right.center, Vector(1, 1)) - - self.sprite.right.center += (2, 1) - self.assertEqual(self.sprite.right.center, Vector(3, 2)) - - result = self.sprite.right.center + (2, 3) - self.assertEqual(result, Vector(5, 5)) - - self.assertEqual(self.sprite.position, Vector(2.5, 2)) - def test_left_left(self): self.assertRaises(AttributeError, getattr, self.sprite.left, "left") self.assertRaises(AttributeError, setattr, self.sprite.left, "left", Vector(1, 1)) @@ -63,12 +35,6 @@ def test_right_left(self): self.assertRaises(AttributeError, getattr, self.sprite.right, "left") self.assertRaises(AttributeError, setattr, self.sprite.right, "left", Vector(1, 1)) - def test_top_center(self): - self.assertEqual(self.sprite.top.center, Vector(0, 0.5)) - - self.sprite.top.center = (1, 1) - self.assertEqual(self.sprite.top.center, Vector(1, 1)) - def test_top_top(self): self.assertRaises(AttributeError, getattr, self.sprite.top, "top") self.assertRaises(AttributeError, setattr, self.sprite.top, "top", Vector(1, 1)) @@ -77,12 +43,6 @@ def test_top_bottom(self): self.assertRaises(AttributeError, getattr, self.sprite.top, "bottom") self.assertRaises(AttributeError, setattr, self.sprite.top, "bottom", Vector(1, 1)) - def test_bottom_center(self): - self.assertEqual(self.sprite.bottom.center, Vector(0, -0.5)) - - self.sprite.bottom.center = (1, 1) - self.assertEqual(self.sprite.bottom.center, Vector(1, 1)) - def test_bottom_top(self): self.assertRaises(AttributeError, getattr, self.sprite.bottom, "top") self.assertRaises(AttributeError, setattr, self.sprite.bottom, "top", Vector(1, 1)) @@ -176,6 +136,36 @@ def test_sides_bottom_plus_equals(y): assert sprite.position.y == sprite.bottom + 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_bottom_center(x, y): + sprite = Sprite(position=(x, y)) + bottom_center = sprite.bottom.center + assert isclose(bottom_center.y, y - 0.5) + assert isclose(bottom_center.x, x) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_center_set(x, y, vector_type): + sprite = Sprite() + sprite.bottom.center = vector_type((x, y)) + bottom_center = sprite.bottom.center + assert bottom_center == Vector(x, y) + assert sprite.position == bottom_center + Vector(0, 0.5) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_bottom_center_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.bottom.center += vector_type((x, y)) + bottom_center = sprite.bottom.center + assert bottom_center == Vector(x, y - 0.5) + assert sprite.position == bottom_center + Vector(0, 0.5) + + @given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) def test_sides_bottom_left(x, y): sprite = Sprite(position=(x, y)) @@ -322,7 +312,7 @@ def test_sides_left(x): # ints because the kinds of floats hypothesis generates aren't realistic # to our use case. @given(x=integers(max_value=10_000_000, min_value=-10_000_000)) -def test_sides_set_left(x): +def test_sides_left_set(x): sprite = Sprite() sprite.left = x print(float(sprite.left)) @@ -331,13 +321,43 @@ def test_sides_set_left(x): @given(x=integers(max_value=10_000_000, min_value=-10_000_000)) -def test_sides_plus_equals_left(x): +def test_sides_left_plus_equals(x): sprite = Sprite() sprite.left += x assert sprite.left == x - 0.5 assert sprite.position.x == sprite.left + 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_left_center(x, y): + sprite = Sprite(position=(x, y)) + left_center = sprite.left.center + assert isclose(left_center.y, y) + assert isclose(left_center.x, x - 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_left_center_set(x, y, vector_type): + sprite = Sprite() + sprite.left.center = vector_type((x, y)) + left_center = sprite.left.center + assert left_center == Vector(x, y) + assert sprite.position == left_center + Vector(0.5, 0) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_left_center_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.left.center += vector_type((x, y)) + left_center = sprite.left.center + assert left_center == Vector(x - 0.5, y) + assert sprite.position == left_center + Vector(0.5, 0) + + @given(x=floats(allow_nan=False, allow_infinity=False)) def test_sides_right(x): sprite = Sprite(position=(x, 0)) @@ -363,6 +383,36 @@ def test_sides_right_plus_equals(x): assert sprite.position.x == sprite.right - 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_right_center(x, y): + sprite = Sprite(position=(x, y)) + right_center = sprite.right.center + assert isclose(right_center.y, y) + assert isclose(right_center.x, x + 0.5) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_right_center_set(x, y, vector_type): + sprite = Sprite() + sprite.right.center = vector_type((x, y)) + right_center = sprite.right.center + assert right_center == Vector(x, y) + assert sprite.position == right_center + Vector(-0.5, 0) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_right_center_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.right.center += vector_type((x, y)) + right_center = sprite.right.center + assert right_center == Vector(x + 0.5, y) + assert sprite.position == right_center + Vector(-0.5, 0) + + @given(y=floats(allow_nan=False, allow_infinity=False)) def test_sides_top(y): sprite = Sprite(position=(0, y)) @@ -387,6 +437,36 @@ def test_sides_top_plus_equals(y): assert sprite.position.y == sprite.top - 0.5 +@given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) +def test_sides_top_center(x, y): + sprite = Sprite(position=(x, y)) + top_center = sprite.top.center + assert isclose(top_center.y, y + 0.5) + assert isclose(top_center.x, x) + + +# ints because the kinds of floats hypothesis generates aren't realistic +# to our use case. +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_center_set(x, y, vector_type): + sprite = Sprite() + sprite.top.center = vector_type((x, y)) + top_center = sprite.top.center + assert top_center == Vector(x, y) + assert sprite.position == top_center + Vector(0, -0.5) + + +@pytest.mark.parametrize("vector_type", [tuple, Vector]) +@given(x=integers(max_value=10_000_000, min_value=-10_000_000), y=integers(max_value=10_000_000, min_value=-10_000_000)) +def test_sides_top_center_plus_equals(x, y, vector_type): + sprite = Sprite() + sprite.top.center += vector_type((x, y)) + top_center = sprite.top.center + assert top_center == Vector(x, y + 0.5) + assert sprite.position == top_center + Vector(0, -0.5) + + @given(x=floats(allow_nan=False, allow_infinity=False), y=floats(allow_nan=False, allow_infinity=False)) def test_sides_top_left(x, y): sprite = Sprite(position=(x, y)) From 1fba4b7cf67aa54293c77d868b500ccf8ede168c Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 15:06:30 -0400 Subject: [PATCH 22/25] Finishes refactor of sides API: removes unittest! --- tests/test_sprites.py | 77 +++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/tests/test_sprites.py b/tests/test_sprites.py index c470997e..ec11fcae 100644 --- a/tests/test_sprites.py +++ b/tests/test_sprites.py @@ -1,5 +1,4 @@ from math import isclose -from unittest import TestCase from unittest.mock import patch import warnings @@ -13,45 +12,6 @@ from ppb_vector import Vector -class TestBaseSprite(TestCase): - - def setUp(self): - self.sprite = Sprite() - self.wide_sprite = Sprite(size=2, pos=(2, 2)) - - def test_left_left(self): - self.assertRaises(AttributeError, getattr, self.sprite.left, "left") - self.assertRaises(AttributeError, setattr, self.sprite.left, "left", Vector(1, 1)) - - def test_left_right(self): - self.assertRaises(AttributeError, getattr, self.sprite.left, "right") - self.assertRaises(AttributeError, setattr, self.sprite.left, "right", Vector(1, 1)) - - def test_right_right(self): - self.assertRaises(AttributeError, getattr, self.sprite.right, "right") - self.assertRaises(AttributeError, setattr, self.sprite.right, "right", Vector(1, 1)) - - def test_right_left(self): - self.assertRaises(AttributeError, getattr, self.sprite.right, "left") - self.assertRaises(AttributeError, setattr, self.sprite.right, "left", Vector(1, 1)) - - def test_top_top(self): - self.assertRaises(AttributeError, getattr, self.sprite.top, "top") - self.assertRaises(AttributeError, setattr, self.sprite.top, "top", Vector(1, 1)) - - def test_top_bottom(self): - self.assertRaises(AttributeError, getattr, self.sprite.top, "bottom") - self.assertRaises(AttributeError, setattr, self.sprite.top, "bottom", Vector(1, 1)) - - def test_bottom_top(self): - self.assertRaises(AttributeError, getattr, self.sprite.bottom, "top") - self.assertRaises(AttributeError, setattr, self.sprite.bottom, "top", Vector(1, 1)) - - def test_bottom_bottom(self): - self.assertRaises(AttributeError, getattr, self.sprite.bottom, "bottom") - self.assertRaises(AttributeError, setattr, self.sprite.bottom, "bottom", Vector(1, 1)) - - def test_class_attrs(): class TestSprite(BaseSprite): position = Vector(4, 2) @@ -118,6 +78,15 @@ def test_sides_bottom(y): assert isclose(sprite.bottom, y - 0.5) +def test_sides_bottom_invalid_access(): + sprite = Sprite() + with pytest.raises(AttributeError): + unknown = sprite.bottom.bottom + + with pytest.raises(AttributeError): + unknown = sprite.bottom.top + + # ints because the kinds of floats hypothesis generates aren't realistic # to our use case. @given(y=integers(max_value=10_000_000, min_value=-10_000_000)) @@ -309,6 +278,16 @@ def test_sides_left(x): assert isclose(sprite.left, x - 0.5) + +def test_sides_left_invalid_access(): + sprite = Sprite() + with pytest.raises(AttributeError): + unknown = sprite.left.right + + with pytest.raises(AttributeError): + unknown = sprite.left.left + + # ints because the kinds of floats hypothesis generates aren't realistic # to our use case. @given(x=integers(max_value=10_000_000, min_value=-10_000_000)) @@ -364,6 +343,15 @@ def test_sides_right(x): assert isclose(sprite.right, x + 0.5) +def test_sides_right_invalid_access(): + sprite = Sprite() + with pytest.raises(AttributeError): + unknown = sprite.right.right + + with pytest.raises(AttributeError): + unknown = sprite.right.left + + # ints because the kinds of floats hypothesis generates aren't realistic # to our use case. @given(x=integers(max_value=10_000_000, min_value=-10_000_000)) @@ -419,6 +407,15 @@ def test_sides_top(y): assert isclose(sprite.top, y + 0.5) +def test_sides_top_invalid_access(): + sprite = Sprite() + with pytest.raises(AttributeError): + unknown = sprite.top.bottom + + with pytest.raises(AttributeError): + unknown = sprite.top.top + + # ints because the kinds of floats hypothesis generates aren't realistic # to our use case. @given(y=integers(max_value=10_000_000, min_value=-10_000_000)) From ce1fe44be6c0606511bf98ad0552ba86ec409a0c Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 15:28:30 -0400 Subject: [PATCH 23/25] Touch up API documentation for sprites. --- docs/reference/sprites.rst | 47 +++++++++++++++++++++++++++++++++++++- ppb/sprites.py | 10 ++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/docs/reference/sprites.rst b/docs/reference/sprites.rst index 59d06355..4e9f84e5 100644 --- a/docs/reference/sprites.rst +++ b/docs/reference/sprites.rst @@ -4,10 +4,55 @@ All About Sprites ================= -.. autoclass:: ppb.BaseSprite +.. automodule:: ppb.sprites + +------------------ +Default Sprite +------------------ + +This is the class you should instantiate or subclass for your games unless +you are changing the defaults. + +.. autoclass:: ppb.Sprite :members: :inherited-members: +Note that ``ppb.BaseSprite`` is deprecated in favor of ppb.Sprite. Scheduled +for removal in ppb v0.8.0. + +------------------- +Feature Mixins +------------------- + +These mixins are the various features already available in Sprite. Here for +complete documentation. + +.. autoclass:: ppb.sprites.RenderableMixin + :members: + +.. autoclass:: ppb.sprites.RotatableMixin + :members: + +.. autoclass:: ppb.sprites.SquareShapeMixin + :members: + +------------------- +Base Classes +------------------- + +The base class of Sprite, use this if you need to change the low level +expectations. + +.. autoclass:: ppb.sprites.BaseSprite + :members: + :inherited-members: + + +------------------- +Internals +------------------- + +These classes are internals for various APIs included with mixins. .. autoclass:: ppb.sprites.Side :members: diff --git a/ppb/sprites.py b/ppb/sprites.py index adc684ad..220673d7 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -1,3 +1,12 @@ +""" +Sprites are game objects. + +In ppb all sprites are built from composition via mixins or subclassing via +traditional Python inheritance. Sprite is provided as a default expectation +used in ppb. + +If you intend to build your own set of expectation, see BaseSprite. +""" from inspect import getfile from pathlib import Path from typing import Union @@ -70,6 +79,7 @@ class RenderableMixin: """ #: (:py:class:`ppb.Image`): The image asset image = None # TODO: Type hint appropriately + size = 1 def __image__(self): """ From d82a35b267a64828b25bb800ba20d50058bd8ed7 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 15:33:04 -0400 Subject: [PATCH 24/25] Change documentation and change inheritence order on Sprite mixins. --- ppb/sprites.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ppb/sprites.py b/ppb/sprites.py index 220673d7..745cf673 100644 --- a/ppb/sprites.py +++ b/ppb/sprites.py @@ -74,8 +74,8 @@ class RenderableMixin: """ A class implementing the API expected by ppb.systems.renderer.Renderer. - You should include RenderableMixin after BaseSprite in your parent class - definitions. + You should include RenderableMixin before BaseSprite in your parent + class definitions. """ #: (:py:class:`ppb.Image`): The image asset image = None # TODO: Type hint appropriately @@ -293,7 +293,7 @@ class SquareShapeMixin: """ A mixin that applies square shapes to sprites. - You should include SquareShapeMixin after ppb.sprites.BaseSprite in + You should include SquareShapeMixin before ppb.sprites.BaseSprite in your parent classes. """ #: The width/height of the sprite (sprites are square) @@ -367,7 +367,7 @@ def _offset_value(self): return self.size / 2 -class Sprite(BaseSprite, SquareShapeMixin, RenderableMixin, RotatableMixin): +class Sprite(SquareShapeMixin, RenderableMixin, RotatableMixin, BaseSprite): """ The default Sprite class. From 6c7c449ef838cb2e8cf3507adc0de087a4b22553 Mon Sep 17 00:00:00 2001 From: Piper Thunstrom Date: Sat, 24 Aug 2019 15:35:28 -0400 Subject: [PATCH 25/25] Fixes instantiating BaseSprite in test_camera. --- tests/test_camera.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_camera.py b/tests/test_camera.py index 75afcb8f..637de756 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -1,6 +1,6 @@ from math import isclose -from ppb import BaseSprite +from ppb import Sprite from ppb import Vector from ppb.camera import Camera @@ -69,7 +69,7 @@ def test_sprite_in_viewport(): # 80 is the legacy value. cam = Camera(viewport=(0, 0, 800, 600), pixel_ratio=80) - class Thing(BaseSprite): + class Thing(Sprite): def __init__(self, position=Vector(2, 2)): super().__init__() self.size = 2