docs: annotate send/send_any as Optional[WebhookMessage], document wait=True (dpywebhooks-2)
Both were annotated -> discord.WebhookMessage and README-documented that way, but discord.py's Webhook.send defaults wait=False and returns None unless the caller passes wait=True - so the annotation overpromised and a consumer chaining .id off the result without knowing to pass wait=True would get an AttributeError. Widen both annotations to Optional and add a one-line note (module docstring + README) on the wait=True requirement. Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
@@ -21,6 +21,10 @@ await hooks.send(channel, content="hi", embeds=[e]) # get-or-create + send
|
||||
wh = await hooks.get_or_create(channel) # reuse the webhook directly
|
||||
```
|
||||
|
||||
`send`/`send_any` forward `wait` straight to discord.py's `Webhook.send`, which defaults
|
||||
`wait=False` and returns `None` in that case; pass `wait=True` to get back the sent
|
||||
`discord.WebhookMessage` (e.g. to read `.id` or edit it later).
|
||||
|
||||
With a persistence store so webhooks survive a restart:
|
||||
|
||||
```python
|
||||
@@ -72,14 +76,15 @@ The module docstring (`help(dpy_webhooks)` / IDE hover) is the source of truth.
|
||||
|
||||
- `get_or_create(channel, *, evict_oldest=False) -> discord.Webhook`
|
||||
- `get(channel) -> discord.Webhook | None` — cache then store; never creates
|
||||
- `send(channel, **kwargs) -> discord.WebhookMessage` — get-or-create then send, with
|
||||
self-heal
|
||||
- `send(channel, **kwargs) -> discord.WebhookMessage | None` — get-or-create then send, with
|
||||
self-heal; `None` unless `wait=True`
|
||||
- `clear(channel) -> None` — delete server-side + store record (idempotent)
|
||||
- `count(channel) -> int` — webhooks currently on the channel
|
||||
- `list(channel) -> list[discord.Webhook]` — all live webhooks on the channel (no create)
|
||||
- `pick(channel, *, strategy="first") -> discord.Webhook | None` — select an existing one
|
||||
- `send_any(channel, *, strategy="round_robin", **kwargs) -> discord.WebhookMessage` — send
|
||||
via a picked existing webhook, falling back to `get_or_create`
|
||||
- `send_any(channel, *, strategy="round_robin", **kwargs) -> discord.WebhookMessage | None` —
|
||||
send via a picked existing webhook, falling back to `get_or_create`; `None` unless
|
||||
`wait=True`
|
||||
|
||||
**Self-heal.** If `send` hits a dead webhook (deleted server-side / invalid token), the lib
|
||||
clears the record, recreates the webhook, and retries the send **once**; a second failure
|
||||
|
||||
@@ -38,7 +38,9 @@ then raises loud. a retry carrying ``file=``/``files=`` rebuilds each ``discord.
|
||||
its source first, since discord.py closes a File's handle after the first send attempt and
|
||||
resending the same object would otherwise upload it as 0 bytes; a File that can't be safely
|
||||
rebuilt raises ``ValueError`` instead. store failures propagate — the store owns its own
|
||||
durability.
|
||||
durability. ``send``/``send_any`` forward ``wait`` straight to discord.py's
|
||||
``Webhook.send``, which defaults ``wait=False`` and returns ``None`` in that case; pass
|
||||
``wait=True`` to get back the sent :class:`discord.WebhookMessage`.
|
||||
|
||||
discover / select / rotate
|
||||
--------------------------
|
||||
@@ -267,10 +269,13 @@ class DPYWebhooks:
|
||||
*,
|
||||
strategy: str = "round_robin",
|
||||
**kwargs: Any,
|
||||
) -> discord.WebhookMessage:
|
||||
) -> "Optional[discord.WebhookMessage]":
|
||||
"""send via a picked EXISTING webhook, falling back to get_or_create when the channel
|
||||
has none; on a dead pick, deletes that dead webhook directly (clear() only when the
|
||||
pick IS the managed webhook) then recreates + retries the send once"""
|
||||
pick IS the managed webhook) then recreates + retries the send once
|
||||
|
||||
returns None unless kwargs includes wait=True, matching discord.py's own
|
||||
Webhook.send default (wait=False discards the response and returns None)"""
|
||||
webhook = await self.pick(channel, strategy=strategy)
|
||||
picked_managed = webhook is None
|
||||
if webhook is None:
|
||||
@@ -313,9 +318,12 @@ class DPYWebhooks:
|
||||
self._rr[channel_id] = state
|
||||
return webhook
|
||||
|
||||
async def send(self, channel: discord.TextChannel, **kwargs: Any) -> discord.WebhookMessage:
|
||||
async def send(self, channel: discord.TextChannel, **kwargs: Any) -> "Optional[discord.WebhookMessage]":
|
||||
"""get_or_create then send; on a dead-webhook failure, clear + recreate + retry once,
|
||||
then raise"""
|
||||
then raise
|
||||
|
||||
returns None unless kwargs includes wait=True, matching discord.py's own
|
||||
Webhook.send default (wait=False discards the response and returns None)"""
|
||||
webhook = await self.get_or_create(channel)
|
||||
try:
|
||||
return await webhook.send(**kwargs)
|
||||
|
||||
Reference in New Issue
Block a user