EasyCord v5.60.0 — DRY Refactor: GuildLockManager, send_safe, require_admin, EmbedBuilder
LatestWhat's Changed
This release ships a comprehensive DRY pass across the plugin layer — no new features or behaviour changes. All 1,813 tests pass on Python 3.10, 3.11, and 3.12.
GuildLockManager
Extracted the per-guild asyncio.Lock dict + idle-eviction logic that was copy-pasted across 13 plugins into a single GuildLockManager class in easycord/plugins/_shared.py. Plugins migrated: auto_role, birthday, economy, giveaway, juicewrld, polls, reminder, reputation, scheduled_announcements, server_stats, tags, tickets, verification, word_filter.
Features of the shared implementation:
- Idle eviction after 7 days (never evicts a held lock)
- Hard cap of 5,000 tracked guilds with 25% LRU eviction when exceeded
- Drop-in:
self._locks = GuildLockManager()+async with self._locks.lock(guild_id):
Removes ~250 lines of copy-pasted boilerplate across the codebase.
send_safe adoption
Replaced ~20 bare await channel.send(...) calls and inline try/except discord.Forbidden/HTTPException blocks with the existing send_safe helper from easycord/helpers/channel.py across 12 plugins. The ai_moderator._execute_action governed path was not touched.
@slash(require_admin=True)
Replaced 6 inline admin-gate blocks (if not ctx.is_admin: respond_error; return) with the require_admin=True decorator parameter. The gate now fires before the command body runs. Affected commands: ticket_setup, stats_setup, stats_teardown, verification_setup, verification_panel, verification_question.
EmbedBuilder adoption
Migrated discord.Embed(...) construction to EmbedBuilder at opportunistic sites already being edited: _ticket_embed() and the ticket-close log embed in tickets.py; _build_panel_embed() in verification.py.
Merged PR
- DRY refactor phases 2-4 (#123)
Full Changelog: v5.58.0...v5.60.0