Skip to content

Commit c20b6f5

Browse files
Paillat-devclaude
andcommitted
feat(events): migrate parse_x events to Event subclasses
Migrate 18 remaining parse_x methods from ConnectionState to new Event subclasses following the established event migration pattern. Created event files: - audit_log.py: GuildAuditLogEntryCreate - scheduled_event.py: GuildScheduledEvent{Create,Update,Delete,UserAdd,UserRemove} - integration.py: GuildIntegrationsUpdate, Integration{Create,Update,Delete} - stage_instance.py: StageInstance{Create,Update,Delete} - voice.py: VoiceStateUpdate, VoiceServerUpdate, VoiceChannelStatusUpdate - typing.py: TypingStart - webhook.py: WebhooksUpdate Changes to ConnectionState: - Removed 18 parse_x methods - Removed _get_typing_user helper (moved to typing.py) - Cleaned up unused imports (AuditLogEntry, ScheduledEventStatus, _integration_factory, ScheduledEvent, StageInstance) - Kept parse_guild_members_chunk (internal infrastructure) Bug fixes: - Fixed subscriber count decrement in GuildScheduledEventUserRemove 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b1a350f commit c20b6f5

File tree

8 files changed

+799
-322
lines changed

8 files changed

+799
-322
lines changed

discord/app/state.py

Lines changed: 1 addition & 322 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,13 @@
4646

4747
from .. import utils
4848
from ..activity import BaseActivity
49-
from ..audit_logs import AuditLogEntry
5049
from ..automod import AutoModRule
5150
from ..channel import *
5251
from ..channel import _channel_factory
5352
from ..emoji import AppEmoji, GuildEmoji
54-
from ..enums import ChannelType, InteractionType, ScheduledEventStatus, Status, try_enum
53+
from ..enums import ChannelType, InteractionType, Status, try_enum
5554
from ..flags import ApplicationFlags, Intents, MemberCacheFlags
5655
from ..guild import Guild
57-
from ..integrations import _integration_factory
5856
from ..interactions import Interaction
5957
from ..invite import Invite
6058
from ..member import Member
@@ -66,8 +64,6 @@
6664
from ..poll import Poll, PollAnswerCount
6765
from ..raw_models import *
6866
from ..role import Role
69-
from ..scheduled_events import ScheduledEvent
70-
from ..stage_instance import StageInstance
7167
from ..sticker import GuildSticker
7268
from ..threads import Thread, ThreadMember
7369
from ..ui.modal import Modal
@@ -531,23 +527,6 @@ async def _chunk_and_dispatch(self, guild, unavailable):
531527
else:
532528
self.dispatch("guild_join", guild)
533529

534-
def parse_guild_audit_log_entry_create(self, data) -> None:
535-
guild = self._get_guild(int(data["guild_id"]))
536-
if guild is None:
537-
_log.debug(
538-
("GUILD_AUDIT_LOG_ENTRY_CREATE referencing an unknown guild ID: %s. Discarding."),
539-
data["guild_id"],
540-
)
541-
return
542-
payload = RawAuditLogEntryEvent(data)
543-
payload.guild = guild
544-
self.dispatch("raw_audit_log_entry", payload)
545-
user = self.get_user(payload.user_id)
546-
if user is not None:
547-
data.pop("guild_id")
548-
entry = AuditLogEntry(users={data["user_id"]: user}, data=data, guild=guild)
549-
self.dispatch("audit_log_entry", entry)
550-
551530
def parse_guild_members_chunk(self, data) -> None:
552531
guild_id = int(data["guild_id"])
553532
guild = self._get_guild(guild_id)
@@ -569,306 +548,6 @@ def parse_guild_members_chunk(self, data) -> None:
569548
complete = data.get("chunk_index", 0) + 1 == data.get("chunk_count")
570549
self.process_chunk_requests(guild_id, data.get("nonce"), members, complete)
571550

572-
def parse_guild_scheduled_event_create(self, data) -> None:
573-
guild = self._get_guild(int(data["guild_id"]))
574-
if guild is None:
575-
_log.debug(
576-
("GUILD_SCHEDULED_EVENT_CREATE referencing an unknown guild ID: %s. Discarding."),
577-
data["guild_id"],
578-
)
579-
return
580-
581-
creator = None if not data.get("creator", None) else guild.get_member(data.get("creator_id"))
582-
scheduled_event = ScheduledEvent(state=self, guild=guild, creator=creator, data=data)
583-
guild._add_scheduled_event(scheduled_event)
584-
self.dispatch("scheduled_event_create", scheduled_event)
585-
586-
def parse_guild_scheduled_event_update(self, data) -> None:
587-
guild = self._get_guild(int(data["guild_id"]))
588-
if guild is None:
589-
_log.debug(
590-
("GUILD_SCHEDULED_EVENT_UPDATE referencing an unknown guild ID: %s. Discarding."),
591-
data["guild_id"],
592-
)
593-
return
594-
595-
creator = None if not data.get("creator", None) else guild.get_member(data.get("creator_id"))
596-
scheduled_event = ScheduledEvent(state=self, guild=guild, creator=creator, data=data)
597-
old_event = guild.get_scheduled_event(int(data["id"]))
598-
guild._add_scheduled_event(scheduled_event)
599-
self.dispatch("scheduled_event_update", old_event, scheduled_event)
600-
601-
def parse_guild_scheduled_event_delete(self, data) -> None:
602-
guild = self._get_guild(int(data["guild_id"]))
603-
if guild is None:
604-
_log.debug(
605-
("GUILD_SCHEDULED_EVENT_DELETE referencing an unknown guild ID: %s. Discarding."),
606-
data["guild_id"],
607-
)
608-
return
609-
610-
creator = None if not data.get("creator", None) else guild.get_member(data.get("creator_id"))
611-
scheduled_event = ScheduledEvent(state=self, guild=guild, creator=creator, data=data)
612-
scheduled_event.status = ScheduledEventStatus.canceled
613-
guild._remove_scheduled_event(scheduled_event)
614-
self.dispatch("scheduled_event_delete", scheduled_event)
615-
616-
def parse_guild_scheduled_event_user_add(self, data) -> None:
617-
guild = self._get_guild(int(data["guild_id"]))
618-
if guild is None:
619-
_log.debug(
620-
("GUILD_SCHEDULED_EVENT_USER_ADD referencing an unknown guild ID: %s. Discarding."),
621-
data["guild_id"],
622-
)
623-
return
624-
625-
payload = RawScheduledEventSubscription(data, "USER_ADD")
626-
payload.guild = guild
627-
self.dispatch("raw_scheduled_event_user_add", payload)
628-
629-
member = guild.get_member(data["user_id"])
630-
if member is not None:
631-
event = guild.get_scheduled_event(data["guild_scheduled_event_id"])
632-
if event:
633-
event.subscriber_count += 1
634-
guild._add_scheduled_event(event)
635-
self.dispatch("scheduled_event_user_add", event, member)
636-
637-
def parse_guild_scheduled_event_user_remove(self, data) -> None:
638-
guild = self._get_guild(int(data["guild_id"]))
639-
if guild is None:
640-
_log.debug(
641-
("GUILD_SCHEDULED_EVENT_USER_REMOVE referencing an unknown guild ID: %s. Discarding."),
642-
data["guild_id"],
643-
)
644-
return
645-
646-
payload = RawScheduledEventSubscription(data, "USER_REMOVE")
647-
payload.guild = guild
648-
self.dispatch("raw_scheduled_event_user_remove", payload)
649-
650-
member = guild.get_member(data["user_id"])
651-
if member is not None:
652-
event = guild.get_scheduled_event(data["guild_scheduled_event_id"])
653-
if event:
654-
event.subscriber_count += 1
655-
guild._add_scheduled_event(event)
656-
self.dispatch("scheduled_event_user_remove", event, member)
657-
658-
def parse_guild_integrations_update(self, data) -> None:
659-
guild = self._get_guild(int(data["guild_id"]))
660-
if guild is not None:
661-
self.dispatch("guild_integrations_update", guild)
662-
else:
663-
_log.debug(
664-
("GUILD_INTEGRATIONS_UPDATE referencing an unknown guild ID: %s. Discarding."),
665-
data["guild_id"],
666-
)
667-
668-
def parse_integration_create(self, data) -> None:
669-
guild_id = int(data.pop("guild_id"))
670-
guild = self._get_guild(guild_id)
671-
if guild is not None:
672-
cls, _ = _integration_factory(data["type"])
673-
integration = cls(data=data, guild=guild)
674-
self.dispatch("integration_create", integration)
675-
else:
676-
_log.debug(
677-
"INTEGRATION_CREATE referencing an unknown guild ID: %s. Discarding.",
678-
guild_id,
679-
)
680-
681-
def parse_integration_update(self, data) -> None:
682-
guild_id = int(data.pop("guild_id"))
683-
guild = self._get_guild(guild_id)
684-
if guild is not None:
685-
cls, _ = _integration_factory(data["type"])
686-
integration = cls(data=data, guild=guild)
687-
self.dispatch("integration_update", integration)
688-
else:
689-
_log.debug(
690-
"INTEGRATION_UPDATE referencing an unknown guild ID: %s. Discarding.",
691-
guild_id,
692-
)
693-
694-
def parse_integration_delete(self, data) -> None:
695-
guild_id = int(data["guild_id"])
696-
guild = self._get_guild(guild_id)
697-
if guild is not None:
698-
raw = RawIntegrationDeleteEvent(data)
699-
self.dispatch("raw_integration_delete", raw)
700-
else:
701-
_log.debug(
702-
"INTEGRATION_DELETE referencing an unknown guild ID: %s. Discarding.",
703-
guild_id,
704-
)
705-
706-
def parse_webhooks_update(self, data) -> None:
707-
guild = self._get_guild(int(data["guild_id"]))
708-
if guild is None:
709-
_log.debug(
710-
"WEBHOOKS_UPDATE referencing an unknown guild ID: %s. Discarding",
711-
data["guild_id"],
712-
)
713-
return
714-
715-
channel_id = data["channel_id"]
716-
if channel_id is not None:
717-
channel = guild.get_channel(int(channel_id))
718-
if channel is not None:
719-
self.dispatch("webhooks_update", channel)
720-
else:
721-
_log.debug(
722-
"WEBHOOKS_UPDATE referencing an unknown channel ID: %s. Discarding.",
723-
data["channel_id"],
724-
)
725-
else:
726-
_log.debug(
727-
"WEBHOOKS_UPDATE channel ID was null for guild: %s. Discarding.",
728-
data["guild_id"],
729-
)
730-
731-
def parse_stage_instance_create(self, data) -> None:
732-
guild = self._get_guild(int(data["guild_id"]))
733-
if guild is not None:
734-
stage_instance = StageInstance(guild=guild, state=self, data=data)
735-
guild._stage_instances[stage_instance.id] = stage_instance
736-
self.dispatch("stage_instance_create", stage_instance)
737-
else:
738-
_log.debug(
739-
"STAGE_INSTANCE_CREATE referencing unknown guild ID: %s. Discarding.",
740-
data["guild_id"],
741-
)
742-
743-
def parse_stage_instance_update(self, data) -> None:
744-
guild = self._get_guild(int(data["guild_id"]))
745-
if guild is not None:
746-
stage_instance = guild._stage_instances.get(int(data["id"]))
747-
if stage_instance is not None:
748-
old_stage_instance = copy.copy(stage_instance)
749-
stage_instance._update(data)
750-
self.dispatch("stage_instance_update", old_stage_instance, stage_instance)
751-
else:
752-
_log.debug(
753-
("STAGE_INSTANCE_UPDATE referencing unknown stage instance ID: %s. Discarding."),
754-
data["id"],
755-
)
756-
else:
757-
_log.debug(
758-
"STAGE_INSTANCE_UPDATE referencing unknown guild ID: %s. Discarding.",
759-
data["guild_id"],
760-
)
761-
762-
def parse_stage_instance_delete(self, data) -> None:
763-
guild = self._get_guild(int(data["guild_id"]))
764-
if guild is not None:
765-
try:
766-
stage_instance = guild._stage_instances.pop(int(data["id"]))
767-
except KeyError:
768-
pass
769-
else:
770-
self.dispatch("stage_instance_delete", stage_instance)
771-
else:
772-
_log.debug(
773-
"STAGE_INSTANCE_DELETE referencing unknown guild ID: %s. Discarding.",
774-
data["guild_id"],
775-
)
776-
777-
def parse_voice_state_update(self, data) -> None:
778-
guild = self._get_guild(get_as_snowflake(data, "guild_id"))
779-
channel_id = get_as_snowflake(data, "channel_id")
780-
flags = self.member_cache_flags
781-
# self.user is *always* cached when this is called
782-
self_id = self.user.id # type: ignore
783-
if guild is not None:
784-
if int(data["user_id"]) == self_id:
785-
voice = self._get_voice_client(guild.id)
786-
if voice is not None:
787-
coro = voice.on_voice_state_update(data)
788-
asyncio.create_task(logging_coroutine(coro, info="Voice Protocol voice state update handler"))
789-
member, before, after = guild._update_voice_state(data, channel_id) # type: ignore
790-
if member is not None:
791-
if flags.voice:
792-
if channel_id is None and flags._voice_only and member.id != self_id:
793-
# Only remove from cache if we only have the voice flag enabled
794-
# Member doesn't meet the Snowflake protocol currently
795-
guild._remove_member(member) # type: ignore
796-
elif channel_id is not None:
797-
guild._add_member(member)
798-
799-
self.dispatch("voice_state_update", member, before, after)
800-
else:
801-
_log.debug(
802-
("VOICE_STATE_UPDATE referencing an unknown member ID: %s. Discarding."),
803-
data["user_id"],
804-
)
805-
806-
def parse_voice_server_update(self, data) -> None:
807-
try:
808-
key_id = int(data["guild_id"])
809-
except KeyError:
810-
key_id = int(data["channel_id"])
811-
812-
vc = self._get_voice_client(key_id)
813-
if vc is not None:
814-
coro = vc.on_voice_server_update(data)
815-
asyncio.create_task(logging_coroutine(coro, info="Voice Protocol voice server update handler"))
816-
817-
def parse_voice_channel_status_update(self, data) -> None:
818-
raw = RawVoiceChannelStatusUpdateEvent(data)
819-
self.dispatch("raw_voice_channel_status_update", raw)
820-
guild = self._get_guild(int(data["guild_id"]))
821-
channel_id = int(data["id"])
822-
if guild is not None:
823-
channel = guild.get_channel(channel_id)
824-
if channel is not None:
825-
old_status = channel.status
826-
channel.status = data.get("status", None)
827-
self.dispatch("voice_channel_status_update", channel, old_status, channel.status)
828-
else:
829-
_log.debug(
830-
"VOICE_CHANNEL_STATUS_UPDATE referencing an unknown channel ID: %s. Discarding.",
831-
channel_id,
832-
)
833-
else:
834-
_log.debug(
835-
"VOICE_CHANNEL_STATUS_UPDATE referencing unknown guild ID: %s. Discarding.",
836-
data["guild_id"],
837-
)
838-
839-
def parse_typing_start(self, data) -> None:
840-
raw = RawTypingEvent(data)
841-
842-
member_data = data.get("member")
843-
if member_data:
844-
guild = self._get_guild(raw.guild_id)
845-
if guild is not None:
846-
raw.member = Member(data=member_data, guild=guild, state=self)
847-
else:
848-
raw.member = None
849-
else:
850-
raw.member = None
851-
self.dispatch("raw_typing", raw)
852-
853-
channel, guild = self._get_guild_channel(data)
854-
if channel is not None:
855-
user = raw.member or self._get_typing_user(channel, raw.user_id)
856-
857-
if user is not None:
858-
self.dispatch("typing", channel, user, raw.when)
859-
860-
def _get_typing_user(self, channel: MessageableChannel | None, user_id: int) -> User | Member | None:
861-
if isinstance(channel, DMChannel):
862-
return channel.recipient or self.get_user(user_id)
863-
864-
elif isinstance(channel, (Thread, TextChannel)) and channel.guild is not None:
865-
return channel.guild.get_member(user_id) # type: ignore
866-
867-
elif isinstance(channel, GroupChannel):
868-
return utils.find(lambda x: x.id == user_id, channel.recipients)
869-
870-
return self.get_user(user_id)
871-
872551
async def _get_reaction_user(self, channel: MessageableChannel, user_id: int) -> User | Member | None:
873552
if isinstance(channel, TextChannel):
874553
return await channel.guild.get_member(user_id)

0 commit comments

Comments
 (0)