fix: choose() select path emits null label for emoji-only keys

add_option(label=label, ...) passed label=None straight through for an
emoji-only key (_split_key returns (None, emoji)), serializing
{"label": null, ...} which Discord's select-option schema rejects
(1-100 char label required). The <=5-option button path is unaffected
(a button may be emoji-only). Fall back to the key's own text form
(or a single space) as the label when _split_key yields none, so the
emoji is still shown via emoji= but the option always carries a
non-empty label.

Bump 0.1.1 -> 0.1.2.

Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
2026-07-03 16:15:01 -04:00
parent f1f2ecf74a
commit b530affd6e
3 changed files with 8 additions and 5 deletions
+3 -1
View File
@@ -59,7 +59,9 @@ prompt stays live), disable their components after resolve/timeout, accept custo
anywhere an emoji goes, and take `cleanup=True` to delete the prompt afterward. `choose`
auto-switches to a select dropdown for more than 5 options or long labels, truncates select
option labels and the placeholder to Discord's caps, and raises `ValueError` for more than 25
options (Discord's per-select cap).
options (Discord's per-select cap). An emoji-only key is label-less on the button path (a
button may be emoji-only), but on the select path it gets a non-empty fallback label (the
key's own text form) alongside its emoji, since Discord rejects a select option with no label.
## What's inside
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "dpy_commons"
version = "0.1.1"
version = "0.1.2"
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 = [
+4 -3
View File
@@ -172,7 +172,9 @@ async def choose(
"""render a button per option (or a select dropdown for >5 options or long labels), await
the click, and return the chosen option's VALUE or None(timeout); options maps an emoji
(unicode / '<:name:id>' / Emoji) or a label to a return value; raises ValueError on empty
options or more than 25 (discord's per-select option cap)"""
options or more than 25 (discord's per-select option cap); on the select path an
emoji-only key gets a non-empty fallback label (the key's text form) alongside its emoji,
since discord's select options require a label but a button may be emoji-only"""
if not options:
raise ValueError("choose requires at least one option")
if len(options) > SELECT_MAX_OPTIONS:
@@ -190,8 +192,7 @@ async def choose(
token = str(i)
mapping[token] = options[key]
label, emoji = _split_key(key)
if label is not None:
label = truncate(label, SELECT_OPTION_LABEL_MAX)
label = truncate(label or str(key) or " ", SELECT_OPTION_LABEL_MAX)
select.add_option(label=label, value=token, emoji=emoji)
view.add_item(select)
else: