From fe99a2331c2a787c83b8929aed3571e0853d4749 Mon Sep 17 00:00:00 2001 From: FriendlyGecko <68018798+FriendlyGecko@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:17:45 +0200 Subject: [PATCH 01/14] FriendlyGecko's initial Color RGB PR * Updated the color setter so that it does not change the current alpha * Updated it to check for use arcade.Color * Added an isintance check to the len3 check and moved those before the len4 check. So now if the user does a tuple of 3 (ie (255,255,255)) or uses the arcade.Color type (i.e. arcade.Color.BLACK) it will just reuse the old alpha. * Demo 1 * Added deeper RGB class * cleaned up RGB --- arcade/sprite/base.py | 25 +++++++++- arcade/types.py | 106 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 118 insertions(+), 13 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 4d3272a43d..aab7766807 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Iterable, List, TypeVar, Any import arcade -from arcade.types import Point, Color, RGBA255, RGBOrA255, PointList +from arcade.types import Point, Color, RGBA255, RGBOrA255, PointList, RGB from arcade.color import BLACK, WHITE from arcade.hitbox import HitBox from arcade.texture import Texture @@ -61,6 +61,7 @@ def __init__( self._scale = scale, scale self._visible = bool(visible) self._color: Color = WHITE + self._rgb: RGB = RGB(255, 255, 255) self.sprite_lists: List["SpriteList"] = [] # Core properties we don't use, but spritelist expects it @@ -337,6 +338,25 @@ def visible(self, value: bool): for sprite_list in self.sprite_lists: sprite_list._update_color(self) + @property + def rgb(self) -> RGB: + """ Gets the sprites RGB. """ + return self._rgb + + @rgb.setter + def rgb(self, color: RGB): + if ( + self._rgb[0] == color[0] + and self._rgb[1] == color[1] + and self._rgb[2] == color[2] + ): + return + self._rgb = RGB(color[0], color[1], color[2]) + self._color = Color(self._rgb[0], self._rgb[1], self._rgb[2], self.alpha) + + for sprite_list in self.sprite_lists: + sprite_list._update_color(self) + @property def color(self) -> Color: """ @@ -360,7 +380,7 @@ def color(self) -> Color: >>> sprite.color = 255, 0, 0, 128 """ - return self._color + return Color(self.rgb[0], self.rgb[1], self.rgb[2], self.alpha) @color.setter def color(self, color: RGBOrA255): @@ -373,6 +393,7 @@ def color(self, color: RGBOrA255): if len(_a) > 1: raise ValueError(f"iterable must unpack to 3 or 4 values not {len(color)}") a = _a[0] + else: a = self._color.a diff --git a/arcade/types.py b/arcade/types.py index 36f2dc8db0..9d14d23df7 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -3,7 +3,6 @@ """ from __future__ import annotations -import sys from array import array import ctypes import random @@ -18,8 +17,7 @@ Sequence, Tuple, Union, - TYPE_CHECKING, - TypeVar + TYPE_CHECKING, TypeVar ) from typing_extensions import Self @@ -87,6 +85,92 @@ ] +class RGB(Tuple): + """ + A :py:class:`tuple` subclass representing an RGB color. + + All channels are byte values from 0 to 255, inclusive. If any are + outside this range, a :py:class:`~arcade.utils.ByteRangeError` will + be raised, which can be handled as a :py:class:`ValueError`. + + :param r: the red channel of the color, between 0 and 255 + :param g: the green channel of the color, between 0 and 255 + :param b: the blue channel of the color, between 0 and 255 + """ + + def __new__(cls, r: int, g: int, b: int): + + if not 0 <= r <= 255: + raise ByteRangeError("r", r) + + if not 0 <= g <= 255: + raise ByteRangeError("g", g) + + if not 0 <= g <= 255: + raise ByteRangeError("b", b) + + # Typechecking is ignored because of a mypy bug involving + # tuples & super: + # https://github.com/python/mypy/issues/8541 + return super().__new__(cls, (r, g, b)) # type: ignore + + def __deepcopy__(self, _) -> Self: + """Allow :py:func:`~copy.deepcopy` to be used with Color""" + return self.__class__(r=self.r, g=self.g, b=self.b) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(r={self.r}, g={self.g}, b={self.b})" + + @property + def r(self) -> int: + return self[0] + + @property + def g(self) -> int: + return self[1] + + @property + def b(self) -> int: + return self[2] + + @classmethod + def random( + cls, + r: Optional[int] = None, + g: Optional[int] = None, + b: Optional[int] = None, + ) -> Self: + """ + Return a random color. + + The parameters are optional and can be used to fix the value of + a particular channel. If a channel is not fixed, it will be + randomly generated. + + Examples:: + + # Randomize all channels + >>> Color.random() + Color(r=35, g=145, b=4, a=200) + + # Random color with fixed alpha + >>> Color.random(a=255) + Color(r=25, g=99, b=234, a=255) + + :param r: Fixed value for red channel + :param g: Fixed value for green channel + :param b: Fixed value for blue channel + """ + if r is None: + r = random.randint(0, 255) + if g is None: + g = random.randint(0, 255) + if b is None: + b = random.randint(0, 255) + + return cls(r, g, b) + + class Color(RGBA255): """ A :py:class:`tuple` subclass representing an RGBA Color. @@ -501,11 +585,11 @@ class TiledObject(NamedTuple): type: Optional[str] = None -if sys.version_info >= (3, 12): - from collections.abc import Buffer as BufferProtocol -else: - # This is used instead of the typing_extensions version since they - # use an ABC which registers virtual subclasses. This will not work - # with ctypes.Array since virtual subclasses must be concrete. - # See: https://peps.python.org/pep-0688/ - BufferProtocol = Union[ByteString, memoryview, array, ctypes.Array] +# This is a temporary workaround for the lack of a way to type annotate +# objects implementing the buffer protocol. Although there is a PEP to +# add typing, it is scheduled for 3.12. Since that is years away from +# being our minimum Python version, we have to use a workaround. See +# the PEP and Python doc for more information: +# https://peps.python.org/pep-0688/ +# https://docs.python.org/3/c-api/buffer.html +BufferProtocol = Union[ByteString, memoryview, array, ctypes.Array] From fa329c145d8f7a55d51763c8209e48d7ae5c7172 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:50:03 -0400 Subject: [PATCH 02/14] Imports + clean up .rgb property --- arcade/sprite/base.py | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index aab7766807..b4689b01a3 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -1,9 +1,9 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Iterable, List, TypeVar, Any +from typing import TYPE_CHECKING, Iterable, List, TypeVar, Any, Tuple import arcade -from arcade.types import Point, Color, RGBA255, RGBOrA255, PointList, RGB +from arcade.types import Point, Color, RGBA255, RGBOrA255, PointList from arcade.color import BLACK, WHITE from arcade.hitbox import HitBox from arcade.texture import Texture @@ -61,7 +61,6 @@ def __init__( self._scale = scale, scale self._visible = bool(visible) self._color: Color = WHITE - self._rgb: RGB = RGB(255, 255, 255) self.sprite_lists: List["SpriteList"] = [] # Core properties we don't use, but spritelist expects it @@ -339,21 +338,33 @@ def visible(self, value: bool): sprite_list._update_color(self) @property - def rgb(self) -> RGB: - """ Gets the sprites RGB. """ - return self._rgb + def rgb(self) -> Tuple[int, int, int]: + """Get or set only the RGB components of a color. + + If a 4-color RGBA tuple is passed, the alpha value will be + ignored. + """ + return self._color[:3] @rgb.setter - def rgb(self, color: RGB): - if ( - self._rgb[0] == color[0] - and self._rgb[1] == color[1] - and self._rgb[2] == color[2] - ): + def rgb(self, color: RGBOrA255): + + # Fast validation by unpacking into channel values + unused + try: + r, g, b, *_ = color + except ValueError as _: + raise ValueError( + f"{self.__class__.__name__},rgb takes 3 or 4 channels") + + # Unpack to avoid index / . overhead & prep for repack + current_r, current_g, current_g, a = self._color + + # Early exit if equivalent + if current_r == r and current_g == g and current_b == b: return - self._rgb = RGB(color[0], color[1], color[2]) - self._color = Color(self._rgb[0], self._rgb[1], self._rgb[2], self.alpha) - + + # Preserve the current alpha value & update sprite lists + self._color = Color(r, g, b, a) for sprite_list in self.sprite_lists: sprite_list._update_color(self) From a203d43d5449d9e03f9dfc082b121da37b77c7ff Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:51:27 -0400 Subject: [PATCH 03/14] Revert BasicSprite.color changes --- arcade/sprite/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index b4689b01a3..381b273ad0 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -391,7 +391,7 @@ def color(self) -> Color: >>> sprite.color = 255, 0, 0, 128 """ - return Color(self.rgb[0], self.rgb[1], self.rgb[2], self.alpha) + return self._color @color.setter def color(self, color: RGBOrA255): From 870885ade04ef8f51e9d7878509079466a93bcbe Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:52:40 -0400 Subject: [PATCH 04/14] Revert RGB type since 0 tests + conflicts w/ existing type alias --- arcade/types.py | 86 ------------------------------------------------- 1 file changed, 86 deletions(-) diff --git a/arcade/types.py b/arcade/types.py index 9d14d23df7..0395ed8869 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -85,92 +85,6 @@ ] -class RGB(Tuple): - """ - A :py:class:`tuple` subclass representing an RGB color. - - All channels are byte values from 0 to 255, inclusive. If any are - outside this range, a :py:class:`~arcade.utils.ByteRangeError` will - be raised, which can be handled as a :py:class:`ValueError`. - - :param r: the red channel of the color, between 0 and 255 - :param g: the green channel of the color, between 0 and 255 - :param b: the blue channel of the color, between 0 and 255 - """ - - def __new__(cls, r: int, g: int, b: int): - - if not 0 <= r <= 255: - raise ByteRangeError("r", r) - - if not 0 <= g <= 255: - raise ByteRangeError("g", g) - - if not 0 <= g <= 255: - raise ByteRangeError("b", b) - - # Typechecking is ignored because of a mypy bug involving - # tuples & super: - # https://github.com/python/mypy/issues/8541 - return super().__new__(cls, (r, g, b)) # type: ignore - - def __deepcopy__(self, _) -> Self: - """Allow :py:func:`~copy.deepcopy` to be used with Color""" - return self.__class__(r=self.r, g=self.g, b=self.b) - - def __repr__(self) -> str: - return f"{self.__class__.__name__}(r={self.r}, g={self.g}, b={self.b})" - - @property - def r(self) -> int: - return self[0] - - @property - def g(self) -> int: - return self[1] - - @property - def b(self) -> int: - return self[2] - - @classmethod - def random( - cls, - r: Optional[int] = None, - g: Optional[int] = None, - b: Optional[int] = None, - ) -> Self: - """ - Return a random color. - - The parameters are optional and can be used to fix the value of - a particular channel. If a channel is not fixed, it will be - randomly generated. - - Examples:: - - # Randomize all channels - >>> Color.random() - Color(r=35, g=145, b=4, a=200) - - # Random color with fixed alpha - >>> Color.random(a=255) - Color(r=25, g=99, b=234, a=255) - - :param r: Fixed value for red channel - :param g: Fixed value for green channel - :param b: Fixed value for blue channel - """ - if r is None: - r = random.randint(0, 255) - if g is None: - g = random.randint(0, 255) - if b is None: - b = random.randint(0, 255) - - return cls(r, g, b) - - class Color(RGBA255): """ A :py:class:`tuple` subclass representing an RGBA Color. From ff2aefc8c5bdd0386dc3e83fa56c298cde84b802 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:54:18 -0400 Subject: [PATCH 05/14] Revert whitespace change --- arcade/sprite/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 381b273ad0..833b931ee9 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -404,7 +404,6 @@ def color(self, color: RGBOrA255): if len(_a) > 1: raise ValueError(f"iterable must unpack to 3 or 4 values not {len(color)}") a = _a[0] - else: a = self._color.a From c7b161ef0f8e36611c5de50bfb0c15ebdb51d894 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:56:25 -0400 Subject: [PATCH 06/14] Rephrase BasicSprite.rgb docstring --- arcade/sprite/base.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 833b931ee9..9f2ad79ba1 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -339,10 +339,13 @@ def visible(self, value: bool): @property def rgb(self) -> Tuple[int, int, int]: - """Get or set only the RGB components of a color. + """Get or set only the sprite's RGB color components. + + If a 4-color RGBA tuple is passed: + + * The new color's alpha value will be ignored + * The old alpha value will be preserved - If a 4-color RGBA tuple is passed, the alpha value will be - ignored. """ return self._color[:3] From 02eec1363459f851d66bc4cf1f71827698c738a0 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:57:24 -0400 Subject: [PATCH 07/14] Revert sys removal --- arcade/types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/arcade/types.py b/arcade/types.py index 0395ed8869..8bf30d108e 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import sys from array import array import ctypes import random From 25d9b5d8fe704c3762820e4bbea28c50c3ee73bc Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:57:54 -0400 Subject: [PATCH 08/14] Revert typing import noise --- arcade/types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arcade/types.py b/arcade/types.py index 8bf30d108e..eebaacd78c 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -18,7 +18,8 @@ Sequence, Tuple, Union, - TYPE_CHECKING, TypeVar + TYPE_CHECKING, + TypeVar ) from typing_extensions import Self From c40333cc1ed5036518216b24cd5bb7042643445a Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 01:58:53 -0400 Subject: [PATCH 09/14] Revert BufferProtocol change --- arcade/types.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arcade/types.py b/arcade/types.py index eebaacd78c..36f2dc8db0 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -501,11 +501,11 @@ class TiledObject(NamedTuple): type: Optional[str] = None -# This is a temporary workaround for the lack of a way to type annotate -# objects implementing the buffer protocol. Although there is a PEP to -# add typing, it is scheduled for 3.12. Since that is years away from -# being our minimum Python version, we have to use a workaround. See -# the PEP and Python doc for more information: -# https://peps.python.org/pep-0688/ -# https://docs.python.org/3/c-api/buffer.html -BufferProtocol = Union[ByteString, memoryview, array, ctypes.Array] +if sys.version_info >= (3, 12): + from collections.abc import Buffer as BufferProtocol +else: + # This is used instead of the typing_extensions version since they + # use an ABC which registers virtual subclasses. This will not work + # with ctypes.Array since virtual subclasses must be concrete. + # See: https://peps.python.org/pep-0688/ + BufferProtocol = Union[ByteString, memoryview, array, ctypes.Array] From c5cad01a7cc63474ffa39a8d75565cb0c8826223 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 02:07:55 -0400 Subject: [PATCH 10/14] Add Color.rgb property --- arcade/types.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arcade/types.py b/arcade/types.py index 36f2dc8db0..b8e328fa47 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -159,6 +159,26 @@ def b(self) -> int: def a(self) -> int: return self[3] + @property + def rgb(self) -> Tuple[int, int, int]: + """Return only a color's RGB components. + + This is syntactic sugar for slice indexing as below: + + .. code-block:: python + + >>> from arcade.color import WHITE + >>> WHITE[:3] + (255, 255, 255) + # Equivalent but slower than the above + >>> (WHITE.r, WHITE.g, WHITE.b) + (255, 255, 255) + + To reorder the channels as you retrieve them, see + :meth:`.swizzle`. + """ + return self[:3] + @classmethod def from_iterable(cls, iterable: Iterable[int]) -> Self: """ From 3ca48dc6a543e9d940a916b8a47b09a98df08d5f Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 02:11:13 -0400 Subject: [PATCH 11/14] Add quick tests for Color.rgb property --- tests/unit/color/test_color_type.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/unit/color/test_color_type.py b/tests/unit/color/test_color_type.py index cdf063930a..30bdc16081 100644 --- a/tests/unit/color/test_color_type.py +++ b/tests/unit/color/test_color_type.py @@ -190,6 +190,16 @@ def test_color_normalized_property(): assert colors.GRAY.normalized == (128 / 255, 128 / 255, 128 / 255, 1.0) +def test_color_rgb_property(): + # Try some bounds + assert colors.WHITE.rgb == (255, 255, 255) + assert colors.BLACK.rgb == (0, 0, 0) + + # Spot check unique colors + assert colors.COBALT.rgb == (0, 71, 171) + assert Color(1,3,5,7) == (1, 3, 5) + + def test_deepcopy_color_values(): expected_color = Color(255, 255, 255, 255) assert deepcopy(expected_color) == expected_color From e87221d80e0782a5f5833452961c44cd186ee91c Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 02:29:19 -0400 Subject: [PATCH 12/14] Add tests for BasicSprite / Sprite .rgb property --- tests/unit/sprite/test_sprite.py | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/unit/sprite/test_sprite.py b/tests/unit/sprite/test_sprite.py index 1e88f6221a..ff5d9391f5 100644 --- a/tests/unit/sprite/test_sprite.py +++ b/tests/unit/sprite/test_sprite.py @@ -336,6 +336,44 @@ def test_visible(): assert sprite.alpha == 100 +def test_sprite_rgb_property(): + sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png") + + # Initial multiply tint is white + assert sprite.rgb == (255, 255, 255) + + # Test color setting + .rgb report when .visible == True + sprite.rgb = (1, 3, 5, 7) + assert sprite.color.r == 1 + assert sprite.color.g == 3 + assert sprite.color.b == 5 + assert sprite.rgb[0] == 1 + assert sprite.rgb[1] == 3 + assert sprite.rgb[2] == 5 + + # Test alpha preservation + assert sprite.color.a == 255 + assert sprite.alpha == 255 + + # Test .rgb sets rgb chanels when visible == False as with .color, + # but also still preserves original alpha values. + sprite.visible = False + sprite.color = (9, 11, 13, 15) + sprite.rgb = (17, 21, 23, 25) + + # Check the color channels + assert sprite.color.r == 17 + assert sprite.color.g == 21 + assert sprite.color.b == 23 + assert sprite.rgb[0] == 17 + assert sprite.rgb[1] == 21 + assert sprite.rgb[2] == 23 + + # Alpha preserved? + assert sprite.color.a == 15 + assert sprite.alpha == 15 + + def test_sprite_scale_xy(window): sprite = arcade.SpriteSolidColor(20, 20, color=arcade.color.WHITE) From 00dfe555404663799a0c8174f5976b66346526df Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 02:52:19 -0400 Subject: [PATCH 13/14] Bug/typo fix + test tweaks --- arcade/sprite/base.py | 18 +++++++++++------- tests/unit/sprite/test_sprite.py | 12 +++++++++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 9f2ad79ba1..41d2c2f338 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -352,17 +352,21 @@ def rgb(self) -> Tuple[int, int, int]: @rgb.setter def rgb(self, color: RGBOrA255): - # Fast validation by unpacking into channel values + unused + # Fast validation of size by unpacking channel values try: - r, g, b, *_ = color - except ValueError as _: - raise ValueError( - f"{self.__class__.__name__},rgb takes 3 or 4 channels") + r, g, b, *_a = color + if len(_a) > 1: # Alpha's only used to validate here + raise ValueError() + + except ValueError as _: # It's always a length issue + raise ValueError(( + f"{self.__class__.__name__},rgb takes 3 or 4 channel" + f" colors, but got {len(color)} channels")) # Unpack to avoid index / . overhead & prep for repack - current_r, current_g, current_g, a = self._color + current_r, current_b, current_g, a = self._color - # Early exit if equivalent + # Do nothing if equivalent to current color if current_r == r and current_g == g and current_b == b: return diff --git a/tests/unit/sprite/test_sprite.py b/tests/unit/sprite/test_sprite.py index ff5d9391f5..9e33b27c4a 100644 --- a/tests/unit/sprite/test_sprite.py +++ b/tests/unit/sprite/test_sprite.py @@ -336,12 +336,22 @@ def test_visible(): assert sprite.alpha == 100 -def test_sprite_rgb_property(): +def test_sprite_rgb_property_basics(): sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png") # Initial multiply tint is white assert sprite.rgb == (255, 255, 255) + # Values which are too short are not allowed + with pytest.raises(ValueError): + sprite.rgb = (1,2) + with pytest.raises(ValueError): + sprite.rgb = (0,) + + # Nor are values which are too long + with pytest.raises(ValueError): + sprite.rgb = (100,100,100,100,100) + # Test color setting + .rgb report when .visible == True sprite.rgb = (1, 3, 5, 7) assert sprite.color.r == 1 From bf84bf1a9e0a77985d93002f0743244f2d06c6c8 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Wed, 10 Apr 2024 02:58:48 -0400 Subject: [PATCH 14/14] Fix typo in color type tests --- tests/unit/color/test_color_type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/color/test_color_type.py b/tests/unit/color/test_color_type.py index 30bdc16081..7bf5dc11f7 100644 --- a/tests/unit/color/test_color_type.py +++ b/tests/unit/color/test_color_type.py @@ -197,7 +197,7 @@ def test_color_rgb_property(): # Spot check unique colors assert colors.COBALT.rgb == (0, 71, 171) - assert Color(1,3,5,7) == (1, 3, 5) + assert Color(1,3,5,7).rgb == (1, 3, 5) def test_deepcopy_color_values():