Repository navigation
Split modlogformats into a package of event-keyed renderers - #293
Conversation
Co-authored-by: celveren <46062298+celveren@users.noreply.github.com>
Co-authored-by: celveren <46062298+celveren@users.noreply.github.com>
…sses Co-authored-by: celveren <46062298+celveren@users.noreply.github.com>
Co-authored-by: celveren <46062298+celveren@users.noreply.github.com>
Co-authored-by: celveren <46062298+celveren@users.noreply.github.com>
Co-authored-by: celveren <46062298+celveren@users.noreply.github.com>
Reviewer's GuideThe PR decomposes modlog formatting into a package of event-keyed renderers registered by event type, adds a shared emission pipeline and supporting event models/helpers, and covers registry behavior plus output regressions with focused tests while preserving public helper imports. Sequence diagram for unified modlog emissionsequenceDiagram
participant Listener as Modlog listener
participant Cog as ModlogCog
participant Registry as get_renderer
participant Renderer as Event renderer
participant Emitter as TextChannelEmitter
Listener->>Cog: _emit(emitter, record, event)
Cog->>FormatContext: from_setting(record.format)
FormatContext-->>Cog: FormatContext
Cog->>Registry: get_renderer(event)
Registry-->>Cog: Renderer(event)
Cog->>Renderer: render(ctx)
Renderer-->>Cog: str or discord.Embed
Cog->>Renderer: mentions()
Cog->>Emitter: put(rendered output, optional embeds and mentions)
Flow diagram for renderer lookup and format selectionflowchart TD
Start[Event supplied to get_renderer] --> MRO[Walk event class MRO]
MRO --> Match{Registered renderer found?}
Match -- No --> Error[Raise LookupError]
Match -- Yes --> Renderer[Instantiate event renderer]
Renderer --> Setting[FormatContext.from_setting]
Setting --> Valid{Format setting valid?}
Valid -- No --> ValueError[Raise ValueError]
Valid -- Yes --> Format{Selected format}
Format --> Emoji[renderer.emoji]
Format --> Minimal["renderer.minimal(ctx)"]
Format --> Embed[renderer.embed]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Co-authored-by: celveren <46062298+celveren@users.noreply.github.com>
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="lightning/modlogformats/moderation.py" line_range="215-216" />
<code_context>
+ base = [f"\N{MEMO} **Infraction update**: ID: {event.after.id}"]
+
+ if self.moderator_changed:
+ base.append(f"\n__Old Moderator__: {escape_markdown_and_mentions(event.before.moderator)}"
+ f"\n__New Moderator__: {escape_markdown_and_mentions(event.after.moderator)}")
+
+ if self.reason_changed:
</code_context>
<issue_to_address>
**Infraction updates stop logging**
When an infraction's moderator changes and emoji format is configured, `InfractionUpdate.emoji()` passes moderator objects to `escape_markdown_and_mentions()`, whose `escape_markdown()` expects text and raises `TypeError`, so the update is not logged.
Convert the moderator values to text before passing them to `escape_markdown_and_mentions()`.
</issue_to_address>Sourcery assessment
Needs a human reviewer. 1 finding to address first, and this replaces the modlog formatting and dispatch path across many event types, so a renderer or format regression could send incorrect notifications to Discord channels. Reverting restores the old behavior but cannot retract messages that were already sent; subsequent messages would need to be corrected normally.
Blocking findings: lightning/modlogformats/moderation.py:216
modlogformats.pywas one 600-line file with three parallel classes (EmojiFormat,MinimalisticFormat,EmbedFormat) of static methods, and the modlog cog repeated an if/elif chain per event. This replaces them with one renderer per event, in the style of the AutoModPunishmentregistry. Each renderer is keyed by the event model.Package layout (
lightning/utils/modlogformats/)base.py:FormatContext,Renderer, the@rendersregistry andget_renderer.member.py: join, leave, screening, nick change and role change.moderation.py:ModAction, timed-action expiry, timeout expiry, infraction update and delete.commands.py: command ran.__init__.pyre-exports the public helpers, so existing imports keep working.Renderer API
emoji(),minimal(ctx),embed()andmentions().get_renderer(event)walks the event's MRO, so a subclass gets its own renderer if it has one and its parent's otherwise.Action. The cog passesevent.action, which also covers automod events.FormatContext.from_setting()parses the stored format string into a format name pluswith_timestamp. An unknown format raisesValueError.Events (
lightning/events.py)MemberJoinEvent,MemberLeaveEvent,MemberScreeningEventandTimedActionExpiredEvent.CommandEventis now used. The new events are built by the modlog cog and aren't dispatched anywhere.timed_action_expired) go away.Helpers (
lightning/formatters.py)base_user_format,escape_markdown_and_mentions,action_format,format_timestampandconstruct_dm_messagemoved here.events↔modlogformatsimport cycle.Modlog cog
_emit(emitter, record, event)call._emitpicks the renderer and sends a message or embed.allowed_mentionsonly for the emoji format.Behaviour changes to check
(in the emoji screening output.minimal without timestamp, as before.bot_addition, which had no callers.EmojiFormat,MinimalisticFormat,EmbedFormatandBaseFormat.Misc
LICENSE.header.__all__lists one name per line.tests/test_modlogformats.py.