fix: safe_send routes embed= + fails loud on unknown kwargs; embed helpers deep-copy (no input mutation)
Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
@@ -7,7 +7,7 @@ text chunking, timestamp helpers, interactive await-prompts, and a limit-safe se
|
||||
## Install
|
||||
|
||||
```
|
||||
dpy_commons @ git+ssh://git@git.rethinkstudios.io/rethink-public/dpy_commons.git@v0.1.2
|
||||
dpy_commons @ git+ssh://git@git.rethinkstudios.io/rethink-public/dpy_commons.git@v0.1.3
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -91,7 +91,10 @@ apply to **every** chunked message, not just the first, so a suppressed `@everyo
|
||||
stays suppressed across the whole split. Once-only kwargs (`file`, `files`, `stickers`,
|
||||
`nonce`, `reference`, `mention_author`, `view`, `poll`, `delete_after`) still ride the first
|
||||
message only. A bare `safe_send(destination)` with no content/embeds sends a single message
|
||||
with `content=None`.
|
||||
with `content=None`. A singular `embed=` kwarg is folded into the `embeds` pipeline (fit +
|
||||
split like any other embed); passing both `embed` and `embeds` raises `TypeError`, matching
|
||||
discord.py's own `Messageable.send` rule. Any kwarg `safe_send` doesn't recognize also raises
|
||||
`TypeError` naming it, rather than being silently dropped.
|
||||
|
||||
## Notes / deviations
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "dpy_commons"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
description = "Shared discord.py utilities — message/embed parsing, limit-fitting, link extraction, chunking, timestamps, await-prompts, limit-safe send. Config-free, installable."
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
and split a list into sendable groups; none of these mutate their input"""
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import logging
|
||||
|
||||
import discord
|
||||
@@ -25,8 +26,12 @@ _ZWSP = ""
|
||||
|
||||
|
||||
def _copy(embed: discord.Embed) -> discord.Embed:
|
||||
"""deep copy via dict round-trip so the input is never mutated"""
|
||||
return discord.Embed.from_dict(embed.to_dict())
|
||||
"""deep copy via dict round-trip so the input is never mutated
|
||||
|
||||
discord.py 2.7.1's to_dict() reuses the embed's own _fields list rather than copying
|
||||
it, so from_dict(embed.to_dict()) would still share that list with the input; the
|
||||
explicit deepcopy breaks that aliasing"""
|
||||
return discord.Embed.from_dict(copy.deepcopy(embed.to_dict()))
|
||||
|
||||
|
||||
def fit_embed(embed: discord.Embed) -> discord.Embed:
|
||||
|
||||
+16
-2
@@ -34,14 +34,28 @@ async def safe_send(
|
||||
`view`, `poll`, `delete_after`) ride only on the FIRST message so they aren't duplicated
|
||||
across the split
|
||||
|
||||
a singular `embed=` kwarg is folded into the `embeds` pipeline (fit + split like any
|
||||
other embed); passing both `embed` and `embeds` raises `TypeError`, matching
|
||||
discord.py's own `Messageable.send` rule. Any other kwarg not recognized by either
|
||||
whitelist above also raises `TypeError` naming it, instead of being silently dropped
|
||||
|
||||
with no content and no embeds, one message is still sent (content=None) so a bare
|
||||
safe_send(destination) or a files/view-only call goes out as a single message rather than
|
||||
silently doing nothing"""
|
||||
content_chunks = chunk_text(content) if content else []
|
||||
embed_groups = split_embeds([fit_embed(embed) for embed in embeds]) if embeds else []
|
||||
embed = kwargs.pop("embed", None)
|
||||
if embed is not None:
|
||||
if embeds is not None:
|
||||
raise TypeError("safe_send() cannot mix embed and embeds")
|
||||
embeds = [embed]
|
||||
|
||||
per_chunk = {k: v for k, v in kwargs.items() if k in _PER_CHUNK_KWARGS}
|
||||
once_only = {k: v for k, v in kwargs.items() if k in _ONCE_ONLY_KWARGS}
|
||||
unexpected = [k for k in kwargs if k not in _PER_CHUNK_KWARGS and k not in _ONCE_ONLY_KWARGS]
|
||||
if unexpected:
|
||||
raise TypeError(f"safe_send() got unexpected keyword argument(s): {', '.join(unexpected)}")
|
||||
|
||||
content_chunks = chunk_text(content) if content else []
|
||||
embed_groups = split_embeds([fit_embed(e) for e in embeds]) if embeds else []
|
||||
|
||||
messages: "list[discord.Message]" = []
|
||||
first = True
|
||||
|
||||
Reference in New Issue
Block a user