diff --git a/disagreement/color.py b/disagreement/color.py index 59d5e8b..5682a66 100644 --- a/disagreement/color.py +++ b/disagreement/color.py @@ -48,3 +48,29 @@ class Color: def to_rgb(self) -> tuple[int, int, int]: return ((self.value >> 16) & 0xFF, (self.value >> 8) & 0xFF, self.value & 0xFF) + + @classmethod + def parse(cls, value: "Color | int | str | None") -> "Color | None": + """Convert ``value`` to a :class:`Color` instance. + + Parameters + ---------- + value: + The value to convert. May be ``None``, an existing ``Color``, an + integer in the ``0xRRGGBB`` format, or a hex string like ``"#RRGGBB"``. + + Returns + ------- + Optional[Color] + A ``Color`` object if ``value`` is not ``None``. + """ + + if value is None: + return None + if isinstance(value, cls): + return value + if isinstance(value, int): + return cls(value) + if isinstance(value, str): + return cls.from_hex(value) + raise TypeError("Color value must be Color, int, str, or None") diff --git a/disagreement/interactions.py b/disagreement/interactions.py index 4dc7337..c314d96 100644 --- a/disagreement/interactions.py +++ b/disagreement/interactions.py @@ -503,9 +503,7 @@ class InteractionCallbackData: self.tts: Optional[bool] = data.get("tts") self.content: Optional[str] = data.get("content") self.embeds: Optional[List[Embed]] = ( - [Embed(e) for e in data.get("embeds", [])] - if data.get("embeds") - else None + [Embed(e) for e in data.get("embeds", [])] if data.get("embeds") else None ) self.allowed_mentions: Optional[AllowedMentions] = ( AllowedMentions(data["allowed_mentions"]) @@ -572,3 +570,6 @@ class InteractionResponsePayload: def __repr__(self) -> str: return f"" + + def __getitem__(self, item: str) -> Any: + return self.to_dict()[item] diff --git a/disagreement/models.py b/disagreement/models.py index 6bc5d39..c492569 100644 --- a/disagreement/models.py +++ b/disagreement/models.py @@ -25,6 +25,7 @@ from .enums import ( # These enums will need to be defined in disagreement/enum # SelectMenuType will be part of ComponentType or a new enum if needed ) from .permissions import Permissions +from .color import Color if TYPE_CHECKING: @@ -312,7 +313,7 @@ class Embed: self.description: Optional[str] = data.get("description") self.url: Optional[str] = data.get("url") self.timestamp: Optional[str] = data.get("timestamp") # ISO8601 timestamp - self.color: Optional[int] = data.get("color") + self.color = Color.parse(data.get("color")) self.footer: Optional[EmbedFooter] = ( EmbedFooter(data["footer"]) if data.get("footer") else None @@ -342,7 +343,7 @@ class Embed: if self.timestamp: payload["timestamp"] = self.timestamp if self.color is not None: - payload["color"] = self.color + payload["color"] = self.color.value if self.footer: payload["footer"] = self.footer.to_dict() if self.image: @@ -1708,13 +1709,13 @@ class Container(Component): def __init__( self, components: List[Component], - accent_color: Optional[int] = None, + accent_color: Color | int | str | None = None, spoiler: bool = False, id: Optional[int] = None, ): super().__init__(ComponentType.CONTAINER) self.components = components - self.accent_color = accent_color + self.accent_color = Color.parse(accent_color) self.spoiler = spoiler self.id = id @@ -1722,7 +1723,7 @@ class Container(Component): payload = super().to_dict() payload["components"] = [c.to_dict() for c in self.components] if self.accent_color: - payload["accent_color"] = self.accent_color + payload["accent_color"] = self.accent_color.value if self.spoiler: payload["spoiler"] = self.spoiler if self.id is not None: diff --git a/docs/using_components.md b/docs/using_components.md index 9ebd65a..ac508b0 100644 --- a/docs/using_components.md +++ b/docs/using_components.md @@ -152,7 +152,7 @@ from disagreement.models import Container, TextDisplay container = Container( components=[TextDisplay(content="Inside a container")], - accent_color=0xFF0000, + accent_color="#FF0000", # int or Color() also work spoiler=False, ) ``` diff --git a/tests/test_color_acceptance.py b/tests/test_color_acceptance.py new file mode 100644 index 0000000..c6248e7 --- /dev/null +++ b/tests/test_color_acceptance.py @@ -0,0 +1,28 @@ +from disagreement.color import Color +from disagreement.models import Embed, Container, Component + + +def test_color_parse(): + assert Color.parse(0x123456).value == 0x123456 + assert Color.parse("#123456").value == 0x123456 + c = Color(0xABCDEF) + assert Color.parse(c) is c + assert Color.parse(None) is None + + +def test_embed_color_parsing(): + e = Embed({"color": "#FF0000"}) + assert e.color.value == 0xFF0000 + e = Embed({"color": Color(0x00FF00)}) + assert e.color.value == 0x00FF00 + e = Embed({"color": 0x0000FF}) + assert e.color.value == 0x0000FF + + +def test_container_accent_color_parsing(): + container = Container(components=[], accent_color="#010203") + assert container.accent_color.value == 0x010203 + container = Container(components=[], accent_color=Color(0x111111)) + assert container.accent_color.value == 0x111111 + container = Container(components=[], accent_color=0x222222) + assert container.accent_color.value == 0x222222