# 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 ```python 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 | 2–32 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.` 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`).