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
|
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:
|
With a persistence store so webhooks survive a restart:
|
||||||
|
|
||||||
```python
|
```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_or_create(channel, *, evict_oldest=False) -> discord.Webhook`
|
||||||
- `get(channel) -> discord.Webhook | None` — cache then store; never creates
|
- `get(channel) -> discord.Webhook | None` — cache then store; never creates
|
||||||
- `send(channel, **kwargs) -> discord.WebhookMessage` — get-or-create then send, with
|
- `send(channel, **kwargs) -> discord.WebhookMessage | None` — get-or-create then send, with
|
||||||
self-heal
|
self-heal; `None` unless `wait=True`
|
||||||
- `clear(channel) -> None` — delete server-side + store record (idempotent)
|
- `clear(channel) -> None` — delete server-side + store record (idempotent)
|
||||||
- `count(channel) -> int` — webhooks currently on the channel
|
- `count(channel) -> int` — webhooks currently on the channel
|
||||||
- `list(channel) -> list[discord.Webhook]` — all live webhooks on the channel (no create)
|
- `list(channel) -> list[discord.Webhook]` — all live webhooks on the channel (no create)
|
||||||
- `pick(channel, *, strategy="first") -> discord.Webhook | None` — select an existing one
|
- `pick(channel, *, strategy="first") -> discord.Webhook | None` — select an existing one
|
||||||
- `send_any(channel, *, strategy="round_robin", **kwargs) -> discord.WebhookMessage` — send
|
- `send_any(channel, *, strategy="round_robin", **kwargs) -> discord.WebhookMessage | None` —
|
||||||
via a picked existing webhook, falling back to `get_or_create`
|
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
|
**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
|
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
|
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
|
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
|
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
|
discover / select / rotate
|
||||||
--------------------------
|
--------------------------
|
||||||
@@ -267,10 +269,13 @@ class DPYWebhooks:
|
|||||||
*,
|
*,
|
||||||
strategy: str = "round_robin",
|
strategy: str = "round_robin",
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> discord.WebhookMessage:
|
) -> "Optional[discord.WebhookMessage]":
|
||||||
"""send via a picked EXISTING webhook, falling back to get_or_create when the channel
|
"""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
|
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)
|
webhook = await self.pick(channel, strategy=strategy)
|
||||||
picked_managed = webhook is None
|
picked_managed = webhook is None
|
||||||
if webhook is None:
|
if webhook is None:
|
||||||
@@ -313,9 +318,12 @@ class DPYWebhooks:
|
|||||||
self._rr[channel_id] = state
|
self._rr[channel_id] = state
|
||||||
return webhook
|
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,
|
"""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)
|
webhook = await self.get_or_create(channel)
|
||||||
try:
|
try:
|
||||||
return await webhook.send(**kwargs)
|
return await webhook.send(**kwargs)
|
||||||
|
|||||||
Reference in New Issue
Block a user