Refactor: discord.py 2.x migration, async DB, OAuth, and test suite#544
Merged
cheran-senthil merged 24 commits intomasterfrom Feb 16, 2026
Merged
Refactor: discord.py 2.x migration, async DB, OAuth, and test suite#544cheran-senthil merged 24 commits intomasterfrom
cheran-senthil merged 24 commits intomasterfrom
Conversation
Delete the deactivated CSES cog and its scraper utility — both were unused dead code with a known bug (unclosed module-level aiohttp session). Update README to remove CSES references. Add ARCHITECTURE.md, AUDIT.md, ROADMAP.md, and TESTING_PLAN.md as part of the effort to modernize and revive the project. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The restart command relied on a shell script wrapper (exit code 42) that no longer exists after the Docker migration. The kill command now uses bot.close() + sys.exit() instead of os._exit() for proper cleanup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add timeout=10 to subprocess communicate() in git_history() (SEC-03) - Replace bare except with except Exception in logging cog (CQ-04) - Remove inner while True loop in presence task; let task waiter control the 10-minute repeat interval instead (CQ-07) - Change ALL_DIRS from generator expression to tuple so it survives multiple iterations (constants bug) - Fix docstring typo "corouting asuch" -> "coroutine such" (CQ-06) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pin all dependencies to compatible version ranges - Bump requires-python to >= 3.10 (code uses str | int syntax) - Add python-dotenv and call load_dotenv() for .env support - Update CI actions to checkout@v4 and setup-python@v5 - Pin ruff==0.9.7 in lint CI for reproducible builds - Create .dockerignore to exclude .git, .env, data/, logs/, etc. - Multi-stage Dockerfile: builder with build tools, runtime with only libraries, running as non-root botuser - Remove stale E722 per-file-ignore for logging.py in ruff.toml Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate entire database layer from synchronous sqlite3 to aiosqlite, eliminating event loop blocking on every DB call. This is the single highest-impact change for bot responsiveness. Key changes: - Replace sqlite3 with aiosqlite in both user_db_conn.py and cache_db_conn.py - Two-step init pattern: __init__ stores path, async connect() opens connection - All ~80 DB methods converted to async, all ~150 call sites updated to await - Add asyncio.Event-based wait_for_initialize() to prevent cog on_ready race condition (workaround for discord.py 1.x; remove in Step 6d with setup_hook) - Close both DB connections on bot shutdown via bot.close override - Security: parameterized SQL queries replacing f-string interpolation (SEC-01) - Security: allowlist validation for table/column names in _insert_one/_insert_many (SEC-02) - Fix: cursor-level row_factory instead of mutating conn.row_factory (DB-04) - Fix: namedtuple_factory raises ValueError on non-identifier columns (DB-03) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migrate tle/constants.py from os.path to pathlib.Path - Replace temp file I/O with io.BytesIO in graph_common.py, add plt.close() - Split 850-line cache_system2.py into tle/util/cache/ package with focused modules - Move user_db, cf_cache, event_sys onto bot instance via initialize(bot, nodb) - Update ~175 call sites in cogs to use self.bot.* instead of cf_common.* globals - Rename cache2 to cf_cache throughout for clarity - Replace sequential API calls with asyncio.gather() in get_visited_contests() - Delete unused cache_system2.py backward-compat shim Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Install fonts-noto-cjk as a system package in the Docker image instead of downloading ~40MB of fonts from GitHub on first startup. This removes startup latency, an external download dependency, and unnecessary code. - Dockerfile: add fonts-noto-cjk package, remove FONTCONFIG_FILE env var - tle/constants.py: point font paths to system location, remove ASSETS_DIR/FONTS_DIR - tle/__main__.py: remove font_downloader import and call - Delete tle/util/font_downloader.py and extra/fonts.conf - Update ARCHITECTURE.md to reflect changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pretty command duplicated functionality already available via ;handle list. Removing it also eliminates the Pillow dependency entirely (and its native libjpeg/zlib build deps from Docker). Updates ARCHITECTURE.md to reflect recent audit changes: async database layer (aiosqlite), modular cache package, service attachment to bot instance, and multi-stage Docker build. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 226 tests (unit + component) covering pure functions and async database operations as a safety net before the discord.py 2.x migration. - pytest/pytest-asyncio/pytest-cov/pytest-mock in pyproject.toml - Unit tests for table, handledict, codeforces_api, codeforces_common, and rating_calculator - Component tests for user_db and cache_db (in-memory aiosqlite) - CI test workflow (Python 3.10/3.11/3.12) and pip-audit lint job - Move fix_urls to codeforces_api.py (belongs with User type it operates on), breaking circular import chain architecturally - Fix SQL queries using non-identifier column names (SELECT 1 → AS x, SELECT COUNT(*) → AS cnt) that broke namedtuple_factory from Step 4 - Update ROADMAP.md and TESTING_PLAN.md to reflect completion Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate from discord.py 1.7.3 to 2.x, the largest breaking-API change in the modernization roadmap. Key changes: - Update discord.py dependency to >=2.3,<3 and remove aiohttp pin - Create TLEBot subclass with setup_hook() and proper close() override - Add intents.message_content for prefix command support in 2.x - Rename avatar_url → display_avatar.url, Embed.Empty → None, guild.icon_url → guild.icon.url - Add get_role()/has_role() helpers supporting both name and ID lookups - Convert all 9 cog setup functions to async - Remove wait_for_initialize pattern (replaced by setup_hook guarantees) - Remove obsolete discriminator #0 stripping hack - Update ARCHITECTURE.md, ROADMAP.md, and TESTING_PLAN.md All 226 tests pass. No ruff regressions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace direct cf_common.user_db/cf_common.cf_cache access with self.bot.user_db/self.bot.cf_cache in cog code. Move module-level functions into their cog classes and convert @staticmethod helpers to instance methods where they accessed globals: - __main__: TLEBot.close() uses self attributes via getattr - duel: move get_cf_user/complete_duel into Dueling cog as methods - contests: move _get_ongoing_vc_participants into cog; convert _get_remind_role and _make_vc_rating_changes_embed to methods - handles: convert _make_rankup_embeds to instance method - cache/problemset: use self.cache_master.contest_cache, drop cf_common import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, and cog integration (Steps 7-10) Brings total from 226 to 355 passing tests. Covers events.py (25 tests), tasks.py (28 tests), paginator.py (18 tests), API response parsing with fixture JSON files (18 tests), cache sub-system data management (20 tests), and first cog integration tests for Codeforces cog (8 tests). Adds shared fixtures (make_member, make_party, make_submission, event_system, mock_ctx) and patch_cf_common helper to conftest.py. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert commands to hybrid_command/hybrid_group for dual prefix+slash support, add TLEContext that makes prefix command responses reply to the invoking message, and sync command tree on startup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces the legacy Paginated class (emoji reactions + bot.wait_for) with PaginatorView (discord.ui.Button) for modern UX and no manage_messages permission requirement. Makes paginate() async and removes the bot parameter from all 13 callers across 4 cog files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the blocking asyncio.sleep(300) in the challenge command with a DuelChallengeView that provides interactive Accept, Decline, and Withdraw buttons. Buttons are restricted so only the correct user can click each one. Standalone text commands kept as fallback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The old ;handle identify required submitting a compilation error and waiting 60 seconds. This replaces it with Codeforces OpenID Connect (OAuth 2.0), giving users a one-click authorization link instead. - Add tle/util/oauth.py: OAuthStateStore (5-min TTL, single-use), OAuthServer (aiohttp /callback), token exchange + HS256 JWT decode - Refactor _set into _set_from_oauth (guild arg instead of ctx) so the OAuth callback can call it directly - Rewrite identify: sends ephemeral link button (slash) or DM (prefix), revokes previous state on re-invocation, falls back gracefully when DMs are disabled - Integrate OAuthServer lifecycle in TLEBot (setup_hook / close) - Add OAuth constants, PyJWT dependency, docker port, env docs - Add 17 unit tests for state store, auth URL, JWT decode, exchange - Update ARCHITECTURE.md and ROADMAP.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive type annotations across 32 files covering all util modules and cogs. Modernize Optional[X] to X | None (PEP 604), fix invalid annotations like [str] to list[str], and add mypy config to pyproject.toml. Update ROADMAP.md to reflect progress. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplify startup banner to a single message, skip command/jump URL when not available, and use ANSI code blocks for color-coded log levels (yellow=warning, red=error, bold red=critical, green=info). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…odes Extract ANSI escape constants into a shared tle/util/ansi module, colorize handle list rows by Codeforces rank, and extend table.Data with per-cell color rendering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…stion Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add explicit package include for setuptools to resolve the "Multiple top-level packages" build error, and fix all 23 ruff violations (E501 line length, F401 unused import, I001 import sorting). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cf_commonglobals, split monolithiccache_system2.pyinto focused modules undertle/util/cache/handle prettycommand, and Pillow dependencyTest plan
pytestto validate test suite passes🤖 Generated with Claude Code