aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/backend
diff options
context:
space:
mode:
Diffstat (limited to 'bot/exts/backend')
-rw-r--r--bot/exts/backend/branding/_cog.py10
-rw-r--r--bot/exts/backend/branding/_repository.py36
-rw-r--r--bot/exts/backend/error_handler.py6
-rw-r--r--bot/exts/backend/sync/_cog.py50
-rw-r--r--bot/exts/backend/sync/_syncers.py16
5 files changed, 59 insertions, 59 deletions
diff --git a/bot/exts/backend/branding/_cog.py b/bot/exts/backend/branding/_cog.py
index 94429c172..5d194ec3e 100644
--- a/bot/exts/backend/branding/_cog.py
+++ b/bot/exts/backend/branding/_cog.py
@@ -269,7 +269,7 @@ class Branding(commands.Cog):
log.debug(f"Sending event information event to channel: {channel_id} ({is_notification=}).")
await self.bot.wait_until_guild_available()
- channel: t.Optional[discord.TextChannel] = self.bot.get_channel(channel_id)
+ channel: discord.TextChannel | None = self.bot.get_channel(channel_id)
if channel is None:
log.warning(f"Cannot send event information: channel {channel_id} not found!")
@@ -291,7 +291,7 @@ class Branding(commands.Cog):
await channel.send(content=content, embed=embed)
- async def enter_event(self, event: Event) -> t.Tuple[bool, bool]:
+ async def enter_event(self, event: Event) -> tuple[bool, bool]:
"""
Apply `event` assets and update information cache.
@@ -331,7 +331,7 @@ class Branding(commands.Cog):
return banner_success, icon_success
- async def synchronise(self) -> t.Tuple[bool, bool]:
+ async def synchronise(self) -> tuple[bool, bool]:
"""
Fetch the current event and delegate to `enter_event`.
@@ -353,7 +353,7 @@ class Branding(commands.Cog):
return await self.enter_event(current_event)
- async def populate_cache_events(self, events: t.List[Event]) -> None:
+ async def populate_cache_events(self, events: list[Event]) -> None:
"""
Clear `cache_events` and re-populate with names and durations of `events`.
@@ -402,7 +402,7 @@ class Branding(commands.Cog):
"""
log.debug("Checking whether daemon should start.")
- should_begin: t.Optional[bool] = await self.cache_information.get("daemon_active") # None if never set!
+ should_begin: bool | None = await self.cache_information.get("daemon_active") # None if never set!
if should_begin:
self.daemon_loop.start()
diff --git a/bot/exts/backend/branding/_repository.py b/bot/exts/backend/branding/_repository.py
index e14f0a1ef..db2061faa 100644
--- a/bot/exts/backend/branding/_repository.py
+++ b/bot/exts/backend/branding/_repository.py
@@ -1,11 +1,11 @@
import typing as t
-from datetime import date, datetime
+from datetime import UTC, date, datetime
import frontmatter
from bot.bot import Bot
from bot.constants import Keys
-from bot.errors import BrandingMisconfiguration
+from bot.errors import BrandingMisconfigurationError
from bot.log import get_logger
# Base URL for requests into the branding repository.
@@ -39,9 +39,9 @@ class RemoteObject:
name: str # Filename.
path: str # Path from repo root.
type: str # Either 'file' or 'dir'.
- download_url: t.Optional[str] # If type is 'dir', this is None!
+ download_url: str | None # If type is 'dir', this is None!
- def __init__(self, dictionary: t.Dict[str, t.Any]) -> None:
+ def __init__(self, dictionary: dict[str, t.Any]) -> None:
"""Initialize by grabbing annotated attributes from `dictionary`."""
missing_keys = self.__annotations__.keys() - dictionary.keys()
if missing_keys:
@@ -54,8 +54,8 @@ class MetaFile(t.NamedTuple):
"""Attributes defined in a 'meta.md' file."""
is_fallback: bool
- start_date: t.Optional[date]
- end_date: t.Optional[date]
+ start_date: date | None
+ end_date: date | None
description: str # Markdown event description.
@@ -93,7 +93,7 @@ class BrandingRepository:
def __init__(self, bot: Bot) -> None:
self.bot = bot
- async def fetch_directory(self, path: str, types: t.Container[str] = ("file", "dir")) -> t.Dict[str, RemoteObject]:
+ async def fetch_directory(self, path: str, types: t.Container[str] = ("file", "dir")) -> dict[str, RemoteObject]:
"""
Fetch directory found at `path` in the branding repository.
@@ -137,7 +137,7 @@ class BrandingRepository:
attrs, description = frontmatter.parse(raw_file, encoding="UTF-8")
if not description:
- raise BrandingMisconfiguration("No description found in 'meta.md'!")
+ raise BrandingMisconfigurationError("No description found in 'meta.md'!")
if attrs.get("fallback", False):
return MetaFile(is_fallback=True, start_date=None, end_date=None, description=description)
@@ -146,12 +146,12 @@ class BrandingRepository:
end_date_raw = attrs.get("end_date")
if None in (start_date_raw, end_date_raw):
- raise BrandingMisconfiguration("Non-fallback event doesn't have start and end dates defined!")
+ raise BrandingMisconfigurationError("Non-fallback event doesn't have start and end dates defined!")
# We extend the configured month & day with an arbitrary leap year, allowing a datetime object to exist.
# This may raise errors if misconfigured. We let the caller handle such cases.
- start_date = datetime.strptime(f"{start_date_raw} {ARBITRARY_YEAR}", DATE_FMT).date()
- end_date = datetime.strptime(f"{end_date_raw} {ARBITRARY_YEAR}", DATE_FMT).date()
+ start_date = datetime.strptime(f"{start_date_raw} {ARBITRARY_YEAR}", DATE_FMT).replace(tzinfo=UTC).date()
+ end_date = datetime.strptime(f"{end_date_raw} {ARBITRARY_YEAR}", DATE_FMT).replace(tzinfo=UTC).date()
return MetaFile(is_fallback=False, start_date=start_date, end_date=end_date, description=description)
@@ -166,15 +166,15 @@ class BrandingRepository:
missing_assets = {"meta.md", "server_icons", "banners"} - contents.keys()
if missing_assets:
- raise BrandingMisconfiguration(f"Directory is missing following assets: {missing_assets}")
+ raise BrandingMisconfigurationError(f"Directory is missing following assets: {missing_assets}")
server_icons = await self.fetch_directory(contents["server_icons"].path, types=("file",))
banners = await self.fetch_directory(contents["banners"].path, types=("file",))
if len(server_icons) == 0:
- raise BrandingMisconfiguration("Found no server icons!")
+ raise BrandingMisconfigurationError("Found no server icons!")
if len(banners) == 0:
- raise BrandingMisconfiguration("Found no server banners!")
+ raise BrandingMisconfigurationError("Found no server banners!")
meta_bytes = await self.fetch_file(contents["meta.md"].download_url)
@@ -182,7 +182,7 @@ class BrandingRepository:
return Event(directory.path, meta_file, list(banners.values()), list(server_icons.values()))
- async def get_events(self) -> t.List[Event]:
+ async def get_events(self) -> list[Event]:
"""
Discover available events in the branding repository.
@@ -196,7 +196,7 @@ class BrandingRepository:
log.exception("Failed to fetch 'events' directory.")
return []
- instances: t.List[Event] = []
+ instances: list[Event] = []
for event_directory in event_directories.values():
log.trace(f"Attempting to construct event from directory: '{event_directory.path}'.")
@@ -209,7 +209,7 @@ class BrandingRepository:
return instances
- async def get_current_event(self) -> t.Tuple[t.Optional[Event], t.List[Event]]:
+ async def get_current_event(self) -> tuple[Event | None, list[Event]]:
"""
Get the currently active event, or the fallback event.
@@ -218,7 +218,7 @@ class BrandingRepository:
The current event may be None in the case that no event is active, and no fallback event is found.
"""
- utc_now = datetime.utcnow()
+ utc_now = datetime.now(tz=UTC)
log.debug(f"Finding active event for: {utc_now}.")
# Construct an object in the arbitrary year for the purpose of comparison.
diff --git a/bot/exts/backend/error_handler.py b/bot/exts/backend/error_handler.py
index 8883f7566..0c8938918 100644
--- a/bot/exts/backend/error_handler.py
+++ b/bot/exts/backend/error_handler.py
@@ -75,7 +75,7 @@ class ErrorHandler(Cog):
elif isinstance(e, errors.CheckFailure):
log.debug(debug_message)
await self.handle_check_failure(ctx, e)
- elif isinstance(e, (errors.CommandOnCooldown, errors.MaxConcurrencyReached)):
+ elif isinstance(e, errors.CommandOnCooldown | errors.MaxConcurrencyReached):
log.debug(debug_message)
await ctx.send(e)
elif isinstance(e, errors.CommandInvokeError):
@@ -154,7 +154,7 @@ class ErrorHandler(Cog):
if command.startswith("shh"):
await ctx.invoke(silence_command, duration_or_channel=channel, duration=duration, kick=kick)
return True
- elif command.startswith("unshh"):
+ if command.startswith("unshh"):
await ctx.invoke(self.bot.get_command("unsilence"), channel=channel)
return True
return False
@@ -319,7 +319,7 @@ class ErrorHandler(Cog):
await ctx.send(
"Sorry, it looks like I don't have the permissions or roles I need to do that."
)
- elif isinstance(e, (ContextCheckFailure, errors.NoPrivateMessage)):
+ elif isinstance(e, ContextCheckFailure | errors.NoPrivateMessage):
ctx.bot.stats.incr("errors.wrong_channel_or_dm_error")
await ctx.send(e)
diff --git a/bot/exts/backend/sync/_cog.py b/bot/exts/backend/sync/_cog.py
index 8c7dbb54e..83ebb70d2 100644
--- a/bot/exts/backend/sync/_cog.py
+++ b/bot/exts/backend/sync/_cog.py
@@ -1,5 +1,5 @@
import asyncio
-from typing import Any, Dict
+from typing import Any
from discord import Member, Role, User
from discord.ext import commands
@@ -48,7 +48,7 @@ class Sync(Cog):
for syncer in (_syncers.RoleSyncer, _syncers.UserSyncer):
await syncer.sync(guild)
- async def patch_user(self, user_id: int, json: Dict[str, Any], ignore_404: bool = False) -> None:
+ async def patch_user(self, user_id: int, json: dict[str, Any], ignore_404: bool = False) -> None:
"""Send a PATCH request to partially update a user in the database."""
try:
await self.bot.api_client.patch(f"bot/users/{user_id}", json=json)
@@ -65,13 +65,13 @@ class Sync(Cog):
return
await self.bot.api_client.post(
- 'bot/roles',
+ "bot/roles",
json={
- 'colour': role.colour.value,
- 'id': role.id,
- 'name': role.name,
- 'permissions': role.permissions.value,
- 'position': role.position,
+ "colour": role.colour.value,
+ "id": role.id,
+ "name": role.name,
+ "permissions": role.permissions.value,
+ "position": role.position,
}
)
@@ -81,7 +81,7 @@ class Sync(Cog):
if role.guild.id != constants.Guild.id:
return
- await self.bot.api_client.delete(f'bot/roles/{role.id}')
+ await self.bot.api_client.delete(f"bot/roles/{role.id}")
@Cog.listener()
async def on_guild_role_update(self, before: Role, after: Role) -> None:
@@ -98,13 +98,13 @@ class Sync(Cog):
if was_updated:
await self.bot.api_client.put(
- f'bot/roles/{after.id}',
+ f"bot/roles/{after.id}",
json={
- 'colour': after.colour.value,
- 'id': after.id,
- 'name': after.name,
- 'permissions': after.permissions.value,
- 'position': after.position,
+ "colour": after.colour.value,
+ "id": after.id,
+ "name": after.name,
+ "permissions": after.permissions.value,
+ "position": after.position,
}
)
@@ -121,11 +121,11 @@ class Sync(Cog):
return
packed = {
- 'discriminator': int(member.discriminator),
- 'id': member.id,
- 'in_guild': True,
- 'name': member.name,
- 'roles': sorted(role.id for role in member.roles)
+ "discriminator": int(member.discriminator),
+ "id": member.id,
+ "in_guild": True,
+ "name": member.name,
+ "roles": sorted(role.id for role in member.roles)
}
got_error = False
@@ -133,7 +133,7 @@ class Sync(Cog):
try:
# First try an update of the user to set the `in_guild` field and other
# fields that may have changed since the last time we've seen them.
- await self.bot.api_client.put(f'bot/users/{member.id}', json=packed)
+ await self.bot.api_client.put(f"bot/users/{member.id}", json=packed)
except ResponseCodeError as e:
# If we didn't get 404, something else broke - propagate it up.
@@ -144,7 +144,7 @@ class Sync(Cog):
if got_error:
# If we got `404`, the user is new. Create them.
- await self.bot.api_client.post('bot/users', json=packed)
+ await self.bot.api_client.post("bot/users", json=packed)
@Cog.listener()
async def on_member_remove(self, member: Member) -> None:
@@ -176,18 +176,18 @@ class Sync(Cog):
# A 404 likely means the user is in another guild.
await self.patch_user(after.id, json=updated_information, ignore_404=True)
- @commands.group(name='sync')
+ @commands.group(name="sync")
@commands.has_permissions(administrator=True)
async def sync_group(self, ctx: Context) -> None:
"""Run synchronizations between the bot and site manually."""
- @sync_group.command(name='roles')
+ @sync_group.command(name="roles")
@commands.has_permissions(administrator=True)
async def sync_roles_command(self, ctx: Context) -> None:
"""Manually synchronise the guild's roles with the roles on the site."""
await _syncers.RoleSyncer.sync(ctx.guild, ctx)
- @sync_group.command(name='users')
+ @sync_group.command(name="users")
@commands.has_permissions(administrator=True)
async def sync_users_command(self, ctx: Context) -> None:
"""Manually synchronise the guild's users with the users on the site."""
diff --git a/bot/exts/backend/sync/_syncers.py b/bot/exts/backend/sync/_syncers.py
index f68674f8d..cd7f5040d 100644
--- a/bot/exts/backend/sync/_syncers.py
+++ b/bot/exts/backend/sync/_syncers.py
@@ -17,8 +17,8 @@ CHUNK_SIZE = 1000
# These objects are declared as namedtuples because tuples are hashable,
# something that we make use of when diffing site roles against guild roles.
-_Role = namedtuple('Role', ('id', 'name', 'colour', 'permissions', 'position'))
-_Diff = namedtuple('Diff', ('created', 'updated', 'deleted'))
+_Role = namedtuple("Role", ("id", "name", "colour", "permissions", "position"))
+_Diff = namedtuple("Diff", ("created", "updated", "deleted"))
# Implementation of static abstract methods are not enforced if the subclass is never instantiated.
@@ -46,7 +46,7 @@ class Syncer(abc.ABC):
raise NotImplementedError # pragma: no cover
@classmethod
- async def sync(cls, guild: Guild, ctx: t.Optional[Context] = None) -> None:
+ async def sync(cls, guild: Guild, ctx: Context | None = None) -> None:
"""
Synchronise the database with the cache of `guild`.
@@ -89,7 +89,7 @@ class RoleSyncer(Syncer):
async def _get_diff(guild: Guild) -> _Diff:
"""Return the difference of roles between the cache of `guild` and the database."""
log.trace("Getting the diff for roles.")
- roles = await bot.instance.api_client.get('bot/roles')
+ roles = await bot.instance.api_client.get("bot/roles")
# Pack DB roles and guild roles into one common, hashable format.
# They're hashable so that they're easily comparable with sets later.
@@ -123,15 +123,15 @@ class RoleSyncer(Syncer):
"""Synchronise the database with the role cache of `guild`."""
log.trace("Syncing created roles...")
for role in diff.created:
- await bot.instance.api_client.post('bot/roles', json=role._asdict())
+ await bot.instance.api_client.post("bot/roles", json=role._asdict())
log.trace("Syncing updated roles...")
for role in diff.updated:
- await bot.instance.api_client.put(f'bot/roles/{role.id}', json=role._asdict())
+ await bot.instance.api_client.put(f"bot/roles/{role.id}", json=role._asdict())
log.trace("Syncing deleted roles...")
for role in diff.deleted:
- await bot.instance.api_client.delete(f'bot/roles/{role.id}')
+ await bot.instance.api_client.delete(f"bot/roles/{role.id}")
class UserSyncer(Syncer):
@@ -152,7 +152,7 @@ class UserSyncer(Syncer):
# Store user fields which are to be updated.
updated_fields = {}
- def maybe_update(db_field: str, guild_value: t.Union[str, int]) -> None:
+ def maybe_update(db_field: str, guild_value: str | int) -> None:
# Equalize DB user and guild user attributes.
if db_user[db_field] != guild_value: # noqa: B023
updated_fields[db_field] = guild_value # noqa: B023