fix: reject duplicate-name uploads and rebuild fresh Files per send

cache() silently lost a FileRef when a list input had two sources
resolving to the same name (two paths with the same basename, or two
discord.File objects with the same .filename): both files were
uploaded (real cost) but the merge step kept only the last, orphaning
the first. _normalize now rejects a duplicate name with DPYCacheError
before any upload happens.

_to_file returned the same discord.File object for a discord.File
source, only mutating .filename. Reusing one File under two keys
swapped filename/URL between refs; reusing a BytesIO-backed File
re-sent 0 bytes; reusing a path-backed File after discord.py's own
close() raised ValueError. _to_file now builds a genuinely distinct
discord.File per send, re-opening a path-backed source or seeking and
copying a caller-supplied stream; an unrebuildable opaque stream now
raises DPYCacheError instead of corrupting or crashing a later send.

Also: lookup() accepts a digit-only message-id string (previously only
bare int fetched directly, a numeric string routed into the jump-url
parser and raised); dropped a redundant discord.Forbidden member from
an except tuple (Forbidden already subclasses HTTPException); tightened
_parse_jump_url's return type off a dead Optional and added `from err`
to its raise.

Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
2026-07-03 15:32:28 -04:00
parent 2e93a0bcee
commit 248d6ebb6b
3 changed files with 105 additions and 29 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "dpy_cache"
version = "0.1.0"
version = "0.1.1"
description = "Persist images/files to a Discord storage channel and get durable, re-resolvable CDN references — config-free, injectable, installable."
requires-python = ">=3.10"
dependencies = [