From cb7f3443582651b25c28cbdda6a1e05db70589c2 Mon Sep 17 00:00:00 2001 From: Jacky Date: Thu, 22 Jan 2026 22:55:06 +0100 Subject: [PATCH 1/2] allow for message in bits used event to be None --- docs/getting-started/changelog.rst | 1 + twitchio/models/eventsub_.py | 12 ++++++------ twitchio/types_/eventsub.py | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/getting-started/changelog.rst b/docs/getting-started/changelog.rst index 74db26ba..700198f3 100644 --- a/docs/getting-started/changelog.rst +++ b/docs/getting-started/changelog.rst @@ -27,6 +27,7 @@ Changelog - Bug fixes - Fix :func:`~twitchio.utils.setup_logging` breaking coloured formatting on `CRITICAL` logging level - Fix :class:`~models.eventsub_.ChannelPointsAutoRedeemAdd` now accounts for attribute message in payload to be None + - Fix :class:`~models.eventsub_.ChannelBitsUse` now accounts for attribute message in payload to be None 3.1.0 diff --git a/twitchio/models/eventsub_.py b/twitchio/models/eventsub_.py index 90c67335..356e42c2 100644 --- a/twitchio/models/eventsub_.py +++ b/twitchio/models/eventsub_.py @@ -874,7 +874,7 @@ class ChannelBitsUse(_ResponderEvent): The redeeming user. bits: int The number of Bits used. - type: typing.Literal["cheer", "power_up"] + type: typing.Literal["cheer", "power_up", "combo"] What the Bits were used for. text: str | None The chat message in plain text. Is `None` if no chat message was used. @@ -894,13 +894,13 @@ def __init__(self, payload: ChannelBitsUseEvent, *, http: HTTPClient) -> None: ) self.user = PartialUser(payload["user_id"], payload["user_login"], payload["user_name"], http=http) self.bits: int = int(payload["bits"]) - self.type: Literal["cheer", "power_up"] = payload["type"] - self.text: str | None = payload.get("message").get("text") + self.type: Literal["cheer", "power_up", "combo"] = payload["type"] + message = payload.get("message") or {} + self.text: str = message.get("text", "") power_up = payload.get("power_up") self.power_up: PowerUp | None = PowerUp(power_up) if power_up is not None else None - self.fragments: list[ChatMessageFragment] = [ - ChatMessageFragment(fragment, http=http) for fragment in payload["message"]["fragments"] - ] + fragments = message.get("fragments", []) + self.fragments: list[ChatMessageFragment] = [ChatMessageFragment(f, http=http) for f in fragments] def __repr__(self) -> str: return f"" diff --git a/twitchio/types_/eventsub.py b/twitchio/types_/eventsub.py index abaaadb4..aeddea4d 100644 --- a/twitchio/types_/eventsub.py +++ b/twitchio/types_/eventsub.py @@ -376,8 +376,8 @@ class PowerUpData(TypedDict): class ChannelBitsUseEvent(BroadcasterUserEvent): bits: int - type: Literal["cheer", "power_up"] - message: ChatMessageData + type: Literal["cheer", "power_up", "combo"] + message: ChatMessageData | None power_up: PowerUpData | None From 738ce3491493f7f73cbc619d8fb61f8d1d3560c4 Mon Sep 17 00:00:00 2001 From: Jacky Date: Fri, 23 Jan 2026 21:15:10 +0100 Subject: [PATCH 2/2] text is None if message is None --- twitchio/models/eventsub_.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/twitchio/models/eventsub_.py b/twitchio/models/eventsub_.py index 356e42c2..f53f1fd4 100644 --- a/twitchio/models/eventsub_.py +++ b/twitchio/models/eventsub_.py @@ -879,7 +879,7 @@ class ChannelBitsUse(_ResponderEvent): text: str | None The chat message in plain text. Is `None` if no chat message was used. fragments: list[ChatMessageFragment] - The ordered list of chat message fragments. Is `None` if no chat message was used. + The ordered list of chat message fragments. This is only populated for Bits uses that contain a message. power_up: PowerUp | None Data about Power-up. Is `None` if a Power-up is not used. """ @@ -896,7 +896,7 @@ def __init__(self, payload: ChannelBitsUseEvent, *, http: HTTPClient) -> None: self.bits: int = int(payload["bits"]) self.type: Literal["cheer", "power_up", "combo"] = payload["type"] message = payload.get("message") or {} - self.text: str = message.get("text", "") + self.text: str | None = message.get("text") power_up = payload.get("power_up") self.power_up: PowerUp | None = PowerUp(power_up) if power_up is not None else None fragments = message.get("fragments", [])