Files
dpy_appemojis/README.md
T
dsql d59bdcc9b9 fix: fail loud on missing emoji dir, stem collisions, and corrupt images
refresh() previously treated a missing assets/emojis folder (wrong cwd,
missing WorkingDirectory=/WORKDIR) as an empty one, silently deleting
every application emoji on the app every restart with no signal and no
way back (recreated emojis get new IDs). _scan_folder now raises
DPYAppEmojisError naming the absent path instead; a present-but-empty
folder still mirrors as before.

Two files sharing a name stem across extensions (check.png + check.gif)
used to silently collapse to one synced emoji via last-write-wins,
breaking the documented delete+re-add replace workflow with no error.
_scan_folder now raises DPYAppEmojisError naming both colliding files.

A valid extension with unrecognized magic bytes (truncated download,
mismatched format) made discord.py raise an anonymous
ValueError('Unsupported image type given') from create_application_emoji,
which the lib's (Forbidden, HTTPException) catch didn't cover, leaving
no way to tell which file in a large folder was broken. _scan_folder now
pre-flights the same magic-byte check discord.py itself uses and raises
ValueError naming the offending file before any create is attempted.

Also collapses the redundant Forbidden member in the create/delete except
clauses (Forbidden already subclasses HTTPException); log-then-raise
behavior is unchanged.

Bump 0.1.0 -> 0.1.1.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-03 15:32:16 -04:00

3.6 KiB
Raw Blame History

dpy_appemojis

Mirror a project folder onto your bot's application emojis (bot-owned, usable in any guild the app is in — not guild emojis) for discord.py. Drop an image in assets/emojis, call refresh(), and it becomes an application emoji named after the file. The folder is the source of truth: a file removed means its emoji is deleted.

Install

dpy_appemojis @ git+ssh://git@git.rethinkstudios.io/rethink-public/dpy_appemojis.git@v0.1.0

Usage

from dpy_appemojis import DPYAppEmojis

appmojis = DPYAppEmojis(bot)
await appmojis.refresh()                 # e.g. in setup_hook / on_ready

await ctx.send(f"done {appmojis.get.success_mark}")   # dot-access -> discord.Emoji
appmojis.emoji("success_mark").url                    # explicit accessor
appmojis.list()                                       # ["success_mark", ...]

refresh() makes the app's emoji set mirror assets/emojis:

  • a new file → the emoji is created (name = filename stem)
  • a removed file → its emoji is deleted server-side
  • a same-name emoji → left alone (this lib does not diff image content; to replace an image, rename the file or delete + re-add)

Call refresh() at startup, or from a command, to re-sync on demand — the lib adds no commands of its own.

A missing assets/emojis folder is not the same as an empty one: if the folder doesn't exist (wrong cwd, missing WorkingDirectory=/WORKDIR), refresh() raises DPYAppEmojisError naming the path instead of mirroring an empty desired set — which would otherwise delete every application emoji on the next restart. An empty-but-present folder is still honored as "delete everything."

Dot-access vs emoji()

self.get is a namespace whose attribute lookup returns the emoji by name. It lives apart from the methods, so an emoji named list or refresh can't shadow them. For names that aren't valid Python identifiers, use emoji("name"). .url comes free — get.x / emoji("x") return a real discord.Emoji.

Fixed constants (not configurable)

Folder assets/emojis (relative to cwd)
Extensions .png .jpg .jpeg .gif .webp
Max file size 256 KB (Discord's emoji limit)
Name rules 232 chars, [A-Za-z0-9_]
App emoji cap 2000

What you inject

Your discord.Client / commands.Bot. Application-emoji methods live on the client (fetch_application_emojis / create_application_emoji, added in discord.py 2.5), so this targets discord.py>=2.5.

Contract (fail-loud)

The module docstring (help(dpy_appemojis) / IDE hover) is the source of truth. Nothing is swallowed:

  • an invalid emoji name from a bad filename, an oversized file, or a file whose bytes aren't a recognized PNG/JPEG/GIF/WEBP image (corrupt, truncated, or mismatched extension) raises ValueError naming the file
  • two files sharing a name stem across extensions (e.g. check.png and check.gif) raise DPYAppEmojisError naming both files, instead of silently syncing one and dropping the other
  • a missing assets/emojis folder raises DPYAppEmojisError naming the path (see above) rather than mirroring an empty set
  • exceeding the 2000 cap raises DPYAppEmojisError before any create
  • a discord API error (HTTPException, which covers Forbidden) propagates unwrapped so a partial sync never hides behind a silent success

emoji(name) / get.<name> for a name that wasn't synced raise KeyError / AttributeError (call refresh() first).

Versioning

Tagged vX.Y.Z; pin a tag in your install line. Targets discord.py>=2.5 (not discord.py-self).