Skip to content

Commit

Permalink
Migrate code style to ruff
Browse files Browse the repository at this point in the history
Co-authored-by: Boris Muratov <8bee278@gmail.com>
Co-authored-by: wookie184 <wookie1840@gmail.com>
  • Loading branch information
3 people committed Apr 11, 2023
1 parent 2f5ea70 commit 8dca428
Show file tree
Hide file tree
Showing 126 changed files with 1,500 additions and 1,524 deletions.
2 changes: 1 addition & 1 deletion bot/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async def main() -> None:
asyncio.run(main())
except StartupError as e:
message = "Unknown Startup Error Occurred."
if isinstance(e.exception, (aiohttp.ClientConnectorError, aiohttp.ServerDisconnectedError)):
if isinstance(e.exception, aiohttp.ClientConnectorError | aiohttp.ServerDisconnectedError):
message = "Could not connect to site API. Is it running?"
elif isinstance(e.exception, OSError):
message = "Could not connect to Redis. Is it running?"
Expand Down
2 changes: 1 addition & 1 deletion bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from bot import constants, exts
from bot.log import get_logger

log = get_logger('bot')
log = get_logger("bot")


class StartupError(Exception):
Expand Down
52 changes: 29 additions & 23 deletions bot/constants.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
"""
Loads bot configuration from environment variables
and `.env` files. By default, this simply loads the
default configuration defined thanks to the `default`
keyword argument in each instance of the `Field` class
If two files called `.env` and `.env.server` are found
in the project directory, the values will be loaded
from both of them, thus overlooking the predefined defaults.
Any settings left out in the custom user configuration
will default to the values passed to the `default` kwarg.
Loads bot configuration from environment variables and `.env` files.
By default, the values defined in the classes are used, these can be overridden by an env var with the same name.
`.env` and `.env.server` files are used to populate env vars, if present.
"""
import os
from enum import Enum
Expand All @@ -16,10 +12,14 @@


class EnvConfig(BaseSettings):
"""Our default configuration for models that should load from .env files."""

class Config:
"""Specify what .env files to load, and how to load them."""

env_file = ".env.server", ".env",
env_file_encoding = 'utf-8'
env_nested_delimiter = '__'
env_file_encoding = "utf-8"
env_nested_delimiter = "__"


class _Miscellaneous(EnvConfig):
Expand Down Expand Up @@ -227,8 +227,9 @@ class _Guild(EnvConfig):

class Event(Enum):
"""
Event names. This does not include every event (for example, raw
events aren't here), but only events used in ModLog for now.
Discord.py event names.
This does not include every event (for example, raw events aren't here), only events used in ModLog for now.
"""

guild_channel_create = "guild_channel_create"
Expand All @@ -252,13 +253,17 @@ class Event(Enum):


class ThreadArchiveTimes(Enum):
"""The time periods threads can have the archive time set to."""

HOUR = 60
DAY = 1440
THREE_DAY = 4320
WEEK = 10080


class Webhook(BaseModel):
"""A base class for all webhooks."""

id: int
channel: int

Expand Down Expand Up @@ -317,7 +322,8 @@ class _Colours(EnvConfig):
yellow = 0xffd241

@root_validator(pre=True)
def parse_hex_values(cls, values):
def parse_hex_values(cls, values: dict) -> dict: # noqa: N805
"""Convert hex strings to ints."""
for key, value in values.items():
values[key] = int(value, 16)
return values
Expand Down Expand Up @@ -377,7 +383,7 @@ class _PythonNews(EnvConfig):

channel: int = Webhooks.python_news.channel
webhook: int = Webhooks.python_news.id
mail_lists = ['python-ideas', 'python-announce-list', 'pypi-announce', 'python-dev']
mail_lists = ["python-ideas", "python-announce-list", "pypi-announce", "python-dev"]


PythonNews = _PythonNews()
Expand Down Expand Up @@ -522,9 +528,9 @@ class _Emojis(EnvConfig):
verified_bot = "<:verified_bot:811645219220750347>"
bot = "<:bot:812712599464443914>"

defcon_shutdown = "<:defcondisabled:470326273952972810>" # noqa: E704
defcon_unshutdown = "<:defconenabled:470326274213150730>" # noqa: E704
defcon_update = "<:defconsettingsupdated:470326274082996224>" # noqa: E704
defcon_shutdown = "<:defcondisabled:470326273952972810>"
defcon_unshutdown = "<:defconenabled:470326274213150730>"
defcon_update = "<:defconsettingsupdated:470326274082996224>"

failmail = "<:failmail:633660039931887616>"
failed_file = "<:failed_file:1073298441968562226>"
Expand Down Expand Up @@ -561,10 +567,10 @@ class _Icons(EnvConfig):
crown_green = "https://cdn.discordapp.com/emojis/469964154719961088.png"
crown_red = "https://cdn.discordapp.com/emojis/469964154879344640.png"

defcon_denied = "https://cdn.discordapp.com/emojis/472475292078964738.png" # noqa: E704
defcon_shutdown = "https://cdn.discordapp.com/emojis/470326273952972810.png" # noqa: E704
defcon_unshutdown = "https://cdn.discordapp.com/emojis/470326274213150730.png" # noqa: E704
defcon_update = "https://cdn.discordapp.com/emojis/472472638342561793.png" # noqa: E704
defcon_denied = "https://cdn.discordapp.com/emojis/472475292078964738.png"
defcon_shutdown = "https://cdn.discordapp.com/emojis/470326273952972810.png"
defcon_unshutdown = "https://cdn.discordapp.com/emojis/470326274213150730.png"
defcon_update = "https://cdn.discordapp.com/emojis/472472638342561793.png"

filtering = "https://cdn.discordapp.com/emojis/472472638594482195.png"

Expand Down Expand Up @@ -594,7 +600,7 @@ class _Icons(EnvConfig):
superstarify = "https://cdn.discordapp.com/emojis/636288153044516874.png"
unsuperstarify = "https://cdn.discordapp.com/emojis/636288201258172446.png"

token_removed = "https://cdn.discordapp.com/emojis/470326273298792469.png"
token_removed = "https://cdn.discordapp.com/emojis/470326273298792469.png" # noqa: S105

user_ban = "https://cdn.discordapp.com/emojis/469952898026045441.png"
user_timeout = "https://cdn.discordapp.com/emojis/472472640100106250.png"
Expand Down
81 changes: 39 additions & 42 deletions bot/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import re
import typing as t
from datetime import datetime, timezone
from datetime import UTC, datetime
from ssl import CertificateError

import dateutil.parser
Expand All @@ -17,7 +17,7 @@

from bot import exts, instance as bot_instance
from bot.constants import URLs
from bot.errors import InvalidInfraction
from bot.errors import InvalidInfractionError
from bot.exts.info.doc import _inventory_parser
from bot.exts.info.tags import TagIdentifier
from bot.log import get_logger
Expand Down Expand Up @@ -85,7 +85,8 @@ async def convert(self, ctx: Context, argument: str) -> str:

if argument in bot_instance.all_extensions:
return argument
elif (qualified_arg := f"{exts.__name__}.{argument}") in bot_instance.all_extensions:

if (qualified_arg := f"{exts.__name__}.{argument}") in bot_instance.all_extensions:
return qualified_arg

matches = []
Expand All @@ -100,10 +101,10 @@ async def convert(self, ctx: Context, argument: str) -> str:
f":x: `{argument}` is an ambiguous extension name. "
f"Please use one of the following fully-qualified names.```\n{names}```"
)
elif matches:

if matches:
return matches[0]
else:
raise BadArgument(f":x: Could not find the extension `{argument}`.")
raise BadArgument(f":x: Could not find the extension `{argument}`.")


class PackageName(Converter):
Expand Down Expand Up @@ -143,7 +144,7 @@ async def convert(ctx: Context, url: str) -> str:
f"HTTP GET on `{url}` returned status `{resp.status}`, expected 200"
)
except CertificateError:
if url.startswith('https'):
if url.startswith("https"):
raise BadArgument(
f"Got a `CertificateError` for URL `{url}`. Does it support HTTPS?"
)
Expand All @@ -166,7 +167,7 @@ class Inventory(Converter):
"""

@staticmethod
async def convert(ctx: Context, url: str) -> t.Tuple[str, _inventory_parser.InventoryDict]:
async def convert(ctx: Context, url: str) -> tuple[str, _inventory_parser.InventoryDict]:
"""Convert url to Intersphinx inventory URL."""
await ctx.typing()
try:
Expand Down Expand Up @@ -213,7 +214,7 @@ async def convert(self, ctx: Context, arg: str) -> int:

if time < DISCORD_EPOCH_DT:
raise BadArgument(f"{error}: timestamp is before the Discord epoch.")
elif (datetime.now(timezone.utc) - time).days < -1:
if (datetime.now(UTC) - time).days < -1:
raise BadArgument(f"{error}: timestamp is too far into the future.")

return snowflake
Expand Down Expand Up @@ -286,7 +287,7 @@ async def convert(self, ctx: Context, duration: str) -> datetime:
The converter supports the same symbols for each unit of time as its parent class.
"""
delta = await super().convert(ctx, duration)
now = datetime.now(timezone.utc)
now = datetime.now(UTC)

try:
return now + delta
Expand All @@ -304,7 +305,7 @@ async def convert(self, ctx: Context, duration: str) -> datetime:
The converter supports the same symbols for each unit of time as its parent class.
"""
delta = await super().convert(ctx, duration)
now = datetime.now(timezone.utc)
now = datetime.now(UTC)

try:
return now - delta
Expand All @@ -316,7 +317,7 @@ class OffTopicName(Converter):
"""A converter that ensures an added off-topic name is valid."""

ALLOWED_CHARACTERS = r"ABCDEFGHIJKLMNOPQRSTUVWXYZ!?'`-<>\/"
TRANSLATED_CHARACTERS = "𝖠𝖡𝖢𝖣𝖤𝖥𝖦𝖧𝖨𝖩𝖪𝖫𝖬𝖭𝖮𝖯𝖰𝖱𝖲𝖳𝖴𝖵𝖶𝖷𝖸𝖹ǃ?’’-<>⧹⧸"
TRANSLATED_CHARACTERS = "𝖠𝖡𝖢𝖣𝖤𝖥𝖦𝖧𝖨𝖩𝖪𝖫𝖬𝖭𝖮𝖯𝖰𝖱𝖲𝖳𝖴𝖵𝖶𝖷𝖸𝖹ǃ?’’-<>⧹⧸" # noqa: RUF001

@classmethod
def translate_name(cls, name: str, *, from_unicode: bool = True) -> str:
Expand All @@ -340,7 +341,7 @@ async def convert(self, ctx: Context, argument: str) -> str:
if not (2 <= len(argument) <= 96):
raise BadArgument("Channel name must be between 2 and 96 chars long")

elif not all(c.isalnum() or c in self.ALLOWED_CHARACTERS for c in argument):
if not all(c.isalnum() or c in self.ALLOWED_CHARACTERS for c in argument):
raise BadArgument(
"Channel name must only consist of "
"alphanumeric characters, minus signs or apostrophes."
Expand Down Expand Up @@ -386,9 +387,9 @@ async def convert(self, ctx: Context, datetime_string: str) -> datetime:
raise BadArgument(f"`{datetime_string}` is not a valid ISO-8601 datetime string")

if dt.tzinfo:
dt = dt.astimezone(timezone.utc)
dt = dt.astimezone(UTC)
else: # Without a timezone, assume it represents UTC.
dt = dt.replace(tzinfo=timezone.utc)
dt = dt.replace(tzinfo=UTC)

return dt

Expand Down Expand Up @@ -426,8 +427,8 @@ def _is_an_unambiguous_user_argument(argument: str) -> bool:
has_id_or_mention = bool(IDConverter()._get_id_match(argument) or RE_USER_MENTION.match(argument))

# Check to see if the author passed a username (a discriminator exists)
argument = argument.removeprefix('@')
has_username = len(argument) > 5 and argument[-5] == '#'
argument = argument.removeprefix("@")
has_username = len(argument) > 5 and argument[-5] == "#"

return has_id_or_mention or has_username

Expand All @@ -448,8 +449,7 @@ async def convert(self, ctx: Context, argument: str) -> discord.User:
"""Convert the `argument` to a `discord.User`."""
if _is_an_unambiguous_user_argument(argument):
return await super().convert(ctx, argument)
else:
raise BadArgument(AMBIGUOUS_ARGUMENT_MSG.format(argument=argument))
raise BadArgument(AMBIGUOUS_ARGUMENT_MSG.format(argument=argument))


class UnambiguousMember(MemberConverter):
Expand All @@ -464,8 +464,7 @@ async def convert(self, ctx: Context, argument: str) -> discord.Member:
"""Convert the `argument` to a `discord.Member`."""
if _is_an_unambiguous_user_argument(argument):
return await super().convert(ctx, argument)
else:
raise BadArgument(AMBIGUOUS_ARGUMENT_MSG.format(argument=argument))
raise BadArgument(AMBIGUOUS_ARGUMENT_MSG.format(argument=argument))


class Infraction(Converter):
Expand All @@ -476,7 +475,7 @@ class Infraction(Converter):
obtain the most recent infraction by the actor.
"""

async def convert(self, ctx: Context, arg: str) -> t.Optional[dict]:
async def convert(self, ctx: Context, arg: str) -> dict | None:
"""Attempts to convert `arg` into an infraction `dict`."""
if arg in ("l", "last", "recent"):
params = {
Expand All @@ -490,32 +489,30 @@ async def convert(self, ctx: Context, arg: str) -> t.Optional[dict]:
raise BadArgument(
"Couldn't find most recent infraction; you have never given an infraction."
)
else:
return infractions[0]
return infractions[0]

else:
try:
return await ctx.bot.api_client.get(f"bot/infractions/{arg}/expanded")
except ResponseCodeError as e:
if e.status == 404:
raise InvalidInfraction(
converter=Infraction,
original=e,
infraction_arg=arg
)
raise e
try:
return await ctx.bot.api_client.get(f"bot/infractions/{arg}/expanded")
except ResponseCodeError as e:
if e.status == 404:
raise InvalidInfractionError(
converter=Infraction,
original=e,
infraction_arg=arg
)
raise e


if t.TYPE_CHECKING:
ValidDiscordServerInvite = dict # noqa: F811
ValidFilterListType = str # noqa: F811
ValidFilterListType = str
Extension = str # noqa: F811
PackageName = str # noqa: F811
ValidURL = str # noqa: F811
Inventory = t.Tuple[str, _inventory_parser.InventoryDict] # noqa: F811
Inventory = tuple[str, _inventory_parser.InventoryDict] # noqa: F811
Snowflake = int # noqa: F811
SourceConverter = SourceType # noqa: F811
DurationDelta = relativedelta # noqa: F811
DurationDelta = relativedelta
Duration = datetime # noqa: F811
Age = datetime # noqa: F811
OffTopicName = str # noqa: F811
Expand All @@ -525,7 +522,7 @@ async def convert(self, ctx: Context, arg: str) -> t.Optional[dict]:
UnambiguousMember = discord.Member # noqa: F811
Infraction = t.Optional[dict] # noqa: F811

Expiry = t.Union[Duration, ISODateTime]
DurationOrExpiry = t.Union[DurationDelta, ISODateTime]
MemberOrUser = t.Union[discord.Member, discord.User]
UnambiguousMemberOrUser = t.Union[UnambiguousMember, UnambiguousUser]
Expiry = Duration | ISODateTime
DurationOrExpiry = DurationDelta | ISODateTime
MemberOrUser = discord.Member | discord.User
UnambiguousMemberOrUser = UnambiguousMember | UnambiguousUser
Loading

0 comments on commit 8dca428

Please sign in to comment.