Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/lint-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
resolution-strategy: "lowest"
activate-environment: true

- name: Install dependencies
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ name: CI
on:
pull_request:
push:
branches: main
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ARG python_version=3.12-slim
ARG python_version=3.14-slim

FROM python:$python_version AS builder
COPY --from=ghcr.io/astral-sh/uv:0.7 /uv /bin/
COPY --from=ghcr.io/astral-sh/uv:0.9 /uv /bin/

ENV UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy
Expand Down
2 changes: 1 addition & 1 deletion bot/exts/advent_of_code/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ async def countdown_status(bot: SirRobin) -> None:
while arrow.now(EST) < end:
_, time_left = time_left_to_est_midnight()

aligned_seconds = int(math.ceil(time_left.seconds / COUNTDOWN_STEP)) * COUNTDOWN_STEP
aligned_seconds = math.ceil(time_left.seconds / COUNTDOWN_STEP) * COUNTDOWN_STEP
hours, minutes = aligned_seconds // 3600, aligned_seconds // 60 % 60

if aligned_seconds == 0:
Expand Down
4 changes: 2 additions & 2 deletions bot/exts/smart_eval/_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ async def improve_gpu_name(self, hardware_name: str) -> str:
async def donations(self, ctx: commands.Context) -> None:
"""Display the number of donations recieved so far."""
total_donations = await self.total_donations()
response_time, intelligence_level = await self.get_gpu_capabilities()
_response_time, intelligence_level = await self.get_gpu_capabilities()
msg = (
f"Currently, I have received {total_donations} GPU donations, "
f"and am at intelligence level {intelligence_level}! "
Expand Down Expand Up @@ -138,7 +138,7 @@ async def donate(self, ctx: commands.Context, *, hardware: str | None = None) ->
@commands.max_concurrency(1, commands.BucketType.user)
async def smart_eval(self, ctx: commands.Context, *, code: str) -> None:
"""Evaluate your Python code with PyDis's newest chatbot."""
response_time, intelligence_level = await self.get_gpu_capabilities()
response_time, _intelligence_level = await self.get_gpu_capabilities()

if match := FORMATTED_CODE_REGEX.match(code):
code = match.group("code")
Expand Down
25 changes: 15 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,34 @@
authors = [
{name = "Python Discord", email = "[email protected]"},
]
requires-python = "==3.12.*"
requires-python = "==3.14.*"
dependencies = [
"pydis-core[all]==11.5.1",
"arrow==1.3.0",
"sentry-sdk==2.19.0",
"pydantic-settings==2.6.1",
"pydis-core[all]==11.8.0",
"arrow==1.4.0",
"sentry-sdk==2.43.0",
"pydantic==2.12.4",
"pydantic-settings==2.11.0",
]
name = "sir-robin"
version = "0.1.0"
description = ""

[tool.uv]
prerelease = "allow"
required-version = ">=0.9.7"

[dependency-groups]
dev = [
"taskipy==1.14.1",
]
test = [
"hypothesis==6.122.0",
"pytest==8.3.3",
"pytest-asyncio==0.24.0",
"hypothesis==6.147.0",
"pytest==8.4.2",
"pytest-asyncio==1.2.0",
]
lint = [
"ruff==0.8.1",
"pre-commit==4.0.1",
"ruff==0.14.4",
"pre-commit==4.4.0",
]


Expand Down Expand Up @@ -59,6 +61,9 @@ ignore = [
"SIM102", "SIM108",
]

[tool.ruff.lint.flake8-tidy-imports.banned-api]
"__future__.annotations".msg = "No longer required in Python 3.14+, see https://docs.python.org/3/reference/compound_stmts.html#annotations"

[tool.ruff.lint.isort]
order-by-type = false
case-sensitive = true
Expand Down
84 changes: 40 additions & 44 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

import collections
import itertools
import logging
Expand Down Expand Up @@ -143,6 +141,46 @@ def _get_child_mock(self, **kw):
}
guild_instance = discord.Guild(data=guild_data, state=unittest.mock.MagicMock())

# Create a Role instance to get a realistic Mock of `discord.Role`
role_data = {"name": "role", "id": 1}
role_instance = discord.Role(guild=guild_instance, state=unittest.mock.MagicMock(), data=role_data)

class MockRole(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin):
"""
A Mock subclass to mock `discord.Role` objects.

Instances of this class will follow the specifications of `discord.Role` instances. For more
information, see the `MockGuild` docstring.
"""
spec_set = role_instance

def __init__(self, **kwargs) -> None:
default_kwargs = {
"id": next(self.discord_id),
"name": "role",
"position": 1,
"colour": discord.Colour(0xdeadbf),
"permissions": discord.Permissions(),
}
super().__init__(**collections.ChainMap(kwargs, default_kwargs))

if isinstance(self.colour, int):
self.colour = discord.Colour(self.colour)

if isinstance(self.permissions, int):
self.permissions = discord.Permissions(self.permissions)

if "mention" not in kwargs:
self.mention = f"&{self.name}"

def __lt__(self, other):
"""Simplified position-based comparisons similar to those of `discord.Role`."""
return self.position < other.position

def __ge__(self, other):
"""Simplified position-based comparisons similar to those of `discord.Role`."""
return self.position >= other.position


class MockGuild(CustomMockMixin, unittest.mock.Mock, HashableMixin):
"""
Expand Down Expand Up @@ -188,48 +226,6 @@ def roles(self) -> list[MockRole]:
return [MockRole(name="@everyone", position=1, id=0)]


# Create a Role instance to get a realistic Mock of `discord.Role`
role_data = {"name": "role", "id": 1}
role_instance = discord.Role(guild=guild_instance, state=unittest.mock.MagicMock(), data=role_data)


class MockRole(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin):
"""
A Mock subclass to mock `discord.Role` objects.

Instances of this class will follow the specifications of `discord.Role` instances. For more
information, see the `MockGuild` docstring.
"""
spec_set = role_instance

def __init__(self, **kwargs) -> None:
default_kwargs = {
"id": next(self.discord_id),
"name": "role",
"position": 1,
"colour": discord.Colour(0xdeadbf),
"permissions": discord.Permissions(),
}
super().__init__(**collections.ChainMap(kwargs, default_kwargs))

if isinstance(self.colour, int):
self.colour = discord.Colour(self.colour)

if isinstance(self.permissions, int):
self.permissions = discord.Permissions(self.permissions)

if "mention" not in kwargs:
self.mention = f"&{self.name}"

def __lt__(self, other):
"""Simplified position-based comparisons similar to those of `discord.Role`."""
return self.position < other.position

def __ge__(self, other):
"""Simplified position-based comparisons similar to those of `discord.Role`."""
return self.position >= other.position


# Create a Member instance to get a realistic Mock of `discord.Member`
member_data = {"user": "lemon", "roles": [1], "flags": 2}
state_mock = unittest.mock.MagicMock()
Expand Down
Loading
Loading