Feature/capr 21 purge branch update - #74
Conversation
Reviewer's GuideImplements a new /purge moderation slash command with count- and duration-based deletion modes, tightens type constraints for CallbackModal, and wires the purge flow through shared success/error embed helpers for consistent user feedback. Class diagram for PurgeCog and updated CallbackModalclassDiagram
class BaseModal
class CallbackModal~T~ {
}
class PurgeCog {
- commands.Bot bot
- logging.Logger log
+ __init__(bot: commands.Bot) None
+ parse_duration(duration: str) timedelta | None
+ _handle_purge_count(amount: int, channel: discord.TextChannel) tuple[bool, discord.Embed]
+ _handle_purge_duration(duration: str, channel: discord.TextChannel) tuple[bool, discord.Embed]
+ purge(interaction: discord.Interaction, amount: int | None, duration: str | None) None
}
class discord_TextChannel {
+ purge(limit: int) list[discord.Message]
+ purge(after: datetime) list[discord.Message]
}
class embeds_helpers {
+ error_embed(description: str) discord.Embed
+ success_embed(title: str, description: str) discord.Embed
}
BaseModal <|-- CallbackModal
commands_Cog <|-- PurgeCog
PurgeCog --> discord_TextChannel : uses
PurgeCog --> embeds_helpers : uses
note for CallbackModal "T is now constrained to CallbackModal"
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The new
CallbackModal[T: "CallbackModal"]type parameter constraint inui/modal.pyis self-referential and likely invalid in practice; consider reverting to a standardTypeVarbound or aGeneric-based approach that doesn’t refer to the class being defined. - In the purge cog, the
durationhelp text suggests formats like"1h 30m", butparse_durationonly accepts contiguous strings like"1h30m"; either relax the regex to allow spaces or update the user-facing description to match the accepted format. - Both
_handle_purge_countand_handle_purge_durationreturn a(bool, Embed)tuple, but the boolean is never used by callers; consider returning just the embed or raising a user-friendly error to simplify the API.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `CallbackModal[T: "CallbackModal"]` type parameter constraint in `ui/modal.py` is self-referential and likely invalid in practice; consider reverting to a standard `TypeVar` bound or a `Generic`-based approach that doesn’t refer to the class being defined.
- In the purge cog, the `duration` help text suggests formats like `"1h 30m"`, but `parse_duration` only accepts contiguous strings like `"1h30m"`; either relax the regex to allow spaces or update the user-facing description to match the accepted format.
- Both `_handle_purge_count` and `_handle_purge_duration` return a `(bool, Embed)` tuple, but the boolean is never used by callers; consider returning just the embed or raising a user-friendly error to simplify the API.
## Individual Comments
### Comment 1
<location> `capy_discord/ui/modal.py:25` </location>
<code_context>
-class CallbackModal[T](BaseModal):
+class CallbackModal[T: "CallbackModal"](BaseModal):
"""A modal that delegates submission logic to a callback function.
</code_context>
<issue_to_address>
**issue:** Revisit generic type parameter bound on `CallbackModal`.
`T: "CallbackModal"` makes the type parameter self-referential to the class being declared, which is probably not intended and can confuse type checkers. If you’re trying to model methods that return the instance type, consider using `Self` (PEP 673) where available, or keep `T = TypeVar("T", bound="CallbackModal")` defined externally and use `T` only in method signatures. The class-level type parameter doesn’t seem to add type-safety here and instead complicates the type model.
</issue_to_address>
### Comment 2
<location> `capy_discord/exts/tools/purge.py:92-98` </location>
<code_context>
+ return
+
+ channel = interaction.channel
+ if not isinstance(channel, discord.TextChannel):
+ await interaction.response.send_message(
+ embed=error_embed(description="This command can only be used in text channels."),
</code_context>
<issue_to_address>
**suggestion:** Channel type check excludes threads and other text-based channels.
Limiting this to `discord.TextChannel` prevents the command from working in text threads and other messageable channels that also support purging. To support those, check against a broader, message-capable type (e.g. `discord.abc.Messageable` or a union of `TextChannel`/`Thread` types) instead of only `TextChannel`.
```suggestion
channel = interaction.channel
if not isinstance(channel, (discord.TextChannel, discord.Thread)):
await interaction.response.send_message(
embed=error_embed(description="This command can only be used in text-based channels (e.g. channels and threads)."),
ephemeral=True,
)
return
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
|
||
|
|
||
| class CallbackModal[T](BaseModal): | ||
| class CallbackModal[T: "CallbackModal"](BaseModal): |
There was a problem hiding this comment.
issue: Revisit generic type parameter bound on CallbackModal.
T: "CallbackModal" makes the type parameter self-referential to the class being declared, which is probably not intended and can confuse type checkers. If you’re trying to model methods that return the instance type, consider using Self (PEP 673) where available, or keep T = TypeVar("T", bound="CallbackModal") defined externally and use T only in method signatures. The class-level type parameter doesn’t seem to add type-safety here and instead complicates the type model.
| channel = interaction.channel | ||
| if not isinstance(channel, discord.TextChannel): | ||
| await interaction.response.send_message( | ||
| embed=error_embed(description="This command can only be used in text channels."), | ||
| ephemeral=True, | ||
| ) | ||
| return |
There was a problem hiding this comment.
suggestion: Channel type check excludes threads and other text-based channels.
Limiting this to discord.TextChannel prevents the command from working in text threads and other messageable channels that also support purging. To support those, check against a broader, message-capable type (e.g. discord.abc.Messageable or a union of TextChannel/Thread types) instead of only TextChannel.
| channel = interaction.channel | |
| if not isinstance(channel, discord.TextChannel): | |
| await interaction.response.send_message( | |
| embed=error_embed(description="This command can only be used in text channels."), | |
| ephemeral=True, | |
| ) | |
| return | |
| channel = interaction.channel | |
| if not isinstance(channel, (discord.TextChannel, discord.Thread)): | |
| await interaction.response.send_message( | |
| embed=error_embed(description="This command can only be used in text-based channels (e.g. channels and threads)."), | |
| ephemeral=True, | |
| ) | |
| return |
Summary by Sourcery
Add a moderation purge command cog and update modal type constraints.
New Features:
Enhancements: