From c874413e1f215b4918046daa25d3bf1781d18032 Mon Sep 17 00:00:00 2001 From: Gavin Borne Date: Sun, 1 Mar 2026 15:49:09 -0500 Subject: [PATCH 1/2] add CI workflow --- .github/workflows/ci.yml | 52 ++++++++++++++++++++++++++++++++++++++++ pyrightconfig.json | 8 +++++++ 2 files changed, 60 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 pyrightconfig.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1f794b8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: CI (Python) + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + ci: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: ["3.12"] # docker uses 3.12 slim, change if docker changes + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: pip + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi + pip install ruff pyright pytest + + - name: Ruff format check + run: ruff format --check + + - name: Ruff lint + run: ruff check . + + - name: Type check (Pyright) + run: pyright + + - name: Tests (pytest) + run: | + if [ -d tests]; then pytest -q; else echo "No tests found"; fi \ No newline at end of file diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..d3bfc0c --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,8 @@ +{ + "typeCheckingMode": "basic", + "reportMissingTypeStubs": "none", + "reportUnknownMemberType": "none", + "reportUnknownVariableType": "none", + "venvPath": ".", + "exclude": ["**/__pycache__", ".venv", "dist", "build"] +} \ No newline at end of file From b479c92087e48755b3216c45eafb87ac32878fee Mon Sep 17 00:00:00 2001 From: Gavin Borne Date: Sun, 1 Mar 2026 16:00:13 -0500 Subject: [PATCH 2/2] fix ruff errors --- fizzbuzz/db/settings.py | 6 +-- .../extensions/public/color/color_cog.py | 54 +++++++++++++------ .../extensions/public/color/color_tools.py | 5 +- .../extensions/public/fun/inaturalist_api.py | 6 +-- .../extensions/public/metrics/logger.py | 13 +++-- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/fizzbuzz/db/settings.py b/fizzbuzz/db/settings.py index 792b6a7..082aac9 100644 --- a/fizzbuzz/db/settings.py +++ b/fizzbuzz/db/settings.py @@ -213,11 +213,11 @@ async def get_admin_role_ids(self, guild_id: int, /) -> list[int]: Args: guild_id (int): The ID of the guild. - Raises: - DatabaseError: If the IDs were not properly stored. - Returns: list[int]: The list of admin role IDs. + + Raises: + DatabaseError: If the IDs were not properly stored. """ admin_role_ids = ( await self.get_value("guild", guild_id, "admin_role_ids") diff --git a/fizzbuzz/discord/extensions/public/color/color_cog.py b/fizzbuzz/discord/extensions/public/color/color_cog.py index ce611c0..9cdd864 100644 --- a/fizzbuzz/discord/extensions/public/color/color_cog.py +++ b/fizzbuzz/discord/extensions/public/color/color_cog.py @@ -71,6 +71,41 @@ async def _check_enhanced_role_colors( return True +async def _handle_colorrole_set_gradient( + interaction: discord.Interaction, + member: discord.Member, + guild: discord.Guild, + hex6: str | None, + hex62: str | None, +) -> None: + if not await _check_enhanced_role_colors(interaction, guild): + return + + if not hex6 or not validate_hex(hex6): + await report(interaction, "Provide a valid hex color.", Status.FAILURE) + return + if not hex62 or not validate_hex(hex62): + await report(interaction, "Provide a valid second hex color.", Status.FAILURE) + return + + hex_norm = hex6.lstrip("#").lower() + hex_norm2 = hex62.lstrip("#").lower() + discord_color = Color3.from_hex6(hex_norm).as_discord_color() + discord_color2 = Color3.from_hex6(hex_norm2).as_discord_color() + color_repr = f"#{hex_norm} -> #{hex_norm2}" + + await update_color_role( + member, + guild, + discord_color, + discord_color2, + None, + color_repr, + interaction, + logger, + ) + + async def _handle_colorrole_set( interaction: discord.Interaction, member: discord.Member, @@ -92,23 +127,8 @@ async def _handle_colorrole_set( color_repr = f"#{hex_norm}" elif kind == "gradient": - if not await _check_enhanced_role_colors(interaction, guild): - return - - if not hex6 or not validate_hex(hex6): - await report(interaction, "Provide a valid hex color.", Status.FAILURE) - return - if not hex62 or not validate_hex(hex62): - await report( - interaction, "Provide a valid second hex color.", Status.FAILURE - ) - return - - hex_norm = hex6.lstrip("#").lower() - hex_norm2 = hex62.lstrip("#").lower() - discord_color = Color3.from_hex6(hex_norm).as_discord_color() - discord_color2 = Color3.from_hex6(hex_norm2).as_discord_color() - color_repr = f"#{hex_norm} -> #{hex_norm2}" + await _handle_colorrole_set_gradient(interaction, member, guild, hex6, hex62) + return elif kind == "holographic": if not await _check_enhanced_role_colors(interaction, guild): diff --git a/fizzbuzz/discord/extensions/public/color/color_tools.py b/fizzbuzz/discord/extensions/public/color/color_tools.py index bace8bd..f15740a 100644 --- a/fizzbuzz/discord/extensions/public/color/color_tools.py +++ b/fizzbuzz/discord/extensions/public/color/color_tools.py @@ -3,6 +3,7 @@ from __future__ import annotations from io import BytesIO +import math import re import secrets @@ -675,7 +676,7 @@ def as_hsl(self) -> tuple[float, float, float]: if abs(delta) < tiny: delta = 0.0 - if delta == 0.0: + if math.isclose(delta, 0.0): h = 0.0 elif rp == c_max: h = 60.0 * _rem_euclid((gp - bp) / delta, 6.0) @@ -685,7 +686,7 @@ def as_hsl(self) -> tuple[float, float, float]: h = 60.0 * ((rp - gp) / delta + 4.0) l = (c_max - c_min) / 2.0 # noqa: E741 (ambiguous name) - s = 0.0 if delta == 0.0 else delta / (1.0 - abs(2.0 * l - 1.0)) + s = 0.0 if math.isclose(delta, 0.0) else delta / (1.0 - abs(2.0 * l - 1.0)) return h, s, l diff --git a/fizzbuzz/discord/extensions/public/fun/inaturalist_api.py b/fizzbuzz/discord/extensions/public/fun/inaturalist_api.py index f52b0d3..d278a7b 100644 --- a/fizzbuzz/discord/extensions/public/fun/inaturalist_api.py +++ b/fizzbuzz/discord/extensions/public/fun/inaturalist_api.py @@ -346,11 +346,11 @@ async def fetch_inat_animal( images (ImageFetchAmount, optional): The number of images to fetch. Defaults to 1. - Raises: - ApiError: If the animal kind provided has no images on iNaturalist. - Returns: AnimalResult: The result of the search. + + Raises: + ApiError: If the animal kind provided has no images on iNaturalist. """ kind = kind.strip().lower() resolved_query, taxon = await _resolve_inat_taxon(kind) diff --git a/fizzbuzz/discord/extensions/public/metrics/logger.py b/fizzbuzz/discord/extensions/public/metrics/logger.py index 60f8048..9f1fe49 100644 --- a/fizzbuzz/discord/extensions/public/metrics/logger.py +++ b/fizzbuzz/discord/extensions/public/metrics/logger.py @@ -8,6 +8,9 @@ from .....db.wrapped import metric_store +# temporary flag to disable this module, until the DB is fully implemented +DISABLED = True + CAT_GUILD_ID = 0 # placeholder COMMIT_EVERY = 512 @@ -139,10 +142,10 @@ async def _log_single_message( @commands.Cog.listener() async def on_message(self, message: discord.Message) -> None: """Log messages as they come in.""" - # try: - # await self._log_single_message(message, commit=True) - # except Exception: - # logger.exception("Failed to log message for wrapped") + try: + await self._log_single_message(message, commit=True) + except Exception: + logger.exception("Failed to log message for wrapped") @commands.Cog.listener() async def on_ready(self) -> None: @@ -249,4 +252,6 @@ async def _catchup_channel( async def setup(bot: commands.Bot) -> None: """Load the WrappedLogger cog.""" + if DISABLED: + return await bot.add_cog(WrappedLoggerCog(bot))