aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/events
diff options
context:
space:
mode:
authorGravatar ChrisJL <[email protected]>2023-05-09 16:01:01 +0100
committerGravatar GitHub <[email protected]>2023-05-09 16:01:01 +0100
commitc3e23e60278d34658f801bd7d7ed721d5a272637 (patch)
treee159a0fae7850d706d713cf2b49dfed2140ce655 /bot/exts/events
parentBump sentry-sdk from 1.21.1 to 1.22.1 (#1273) (diff)
parentMove unshared contants inside modules (diff)
Merge pull request #1270 from python-discord/migrate-to-ruff
Migrate to ruff
Diffstat (limited to 'bot/exts/events')
-rw-r--r--bot/exts/events/hacktoberfest/hacktober_issue_finder.py (renamed from bot/exts/events/hacktoberfest/hacktober-issue-finder.py)9
-rw-r--r--bot/exts/events/hacktoberfest/hacktoberstats.py37
-rw-r--r--bot/exts/events/hacktoberfest/timeleft.py14
-rw-r--r--bot/exts/events/trivianight/_game.py23
-rw-r--r--bot/exts/events/trivianight/_questions.py12
-rw-r--r--bot/exts/events/trivianight/trivianight.py16
6 files changed, 51 insertions, 60 deletions
diff --git a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py b/bot/exts/events/hacktoberfest/hacktober_issue_finder.py
index 4f7bef5d..69aa3924 100644
--- a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py
+++ b/bot/exts/events/hacktoberfest/hacktober_issue_finder.py
@@ -1,7 +1,6 @@
-import datetime
import logging
import random
-from typing import Optional
+from datetime import UTC, datetime
import discord
from discord.ext import commands
@@ -28,9 +27,9 @@ class HacktoberIssues(commands.Cog):
def __init__(self, bot: Bot):
self.bot = bot
self.cache_normal = None
- self.cache_timer_normal = datetime.datetime(1, 1, 1)
+ self.cache_timer_normal = datetime(1, 1, 1, tzinfo=UTC)
self.cache_beginner = None
- self.cache_timer_beginner = datetime.datetime(1, 1, 1)
+ self.cache_timer_beginner = datetime(1, 1, 1, tzinfo=UTC)
@in_month(Month.OCTOBER)
@commands.command()
@@ -49,7 +48,7 @@ class HacktoberIssues(commands.Cog):
embed = self.format_embed(issue)
await ctx.send(embed=embed)
- async def get_issues(self, ctx: commands.Context, option: str) -> Optional[dict]:
+ async def get_issues(self, ctx: commands.Context, option: str) -> dict | None:
"""Get a list of the python issues with the label 'hacktoberfest' from the Github api."""
if option == "beginner":
if (ctx.message.created_at.replace(tzinfo=None) - self.cache_timer_beginner).seconds <= 60:
diff --git a/bot/exts/events/hacktoberfest/hacktoberstats.py b/bot/exts/events/hacktoberfest/hacktoberstats.py
index 5bfac93f..c7fd3601 100644
--- a/bot/exts/events/hacktoberfest/hacktoberstats.py
+++ b/bot/exts/events/hacktoberfest/hacktoberstats.py
@@ -2,8 +2,7 @@ import logging
import random
import re
from collections import Counter
-from datetime import datetime, timedelta
-from typing import Optional, Union
+from datetime import UTC, datetime, timedelta
from urllib.parse import quote_plus
import discord
@@ -16,7 +15,7 @@ from bot.utils.decorators import in_month
log = logging.getLogger(__name__)
-CURRENT_YEAR = datetime.now().year # Used to construct GH API query
+CURRENT_YEAR = datetime.now(tz=UTC).year # Used to construct GH API query
PRS_FOR_SHIRT = 4 # Minimum number of PRs before a shirt is awarded
REVIEW_DAYS = 14 # number of days needed after PR can be mature
@@ -185,7 +184,7 @@ class HacktoberStats(commands.Cog):
logging.info(f"Hacktoberfest PR built for GitHub user '{github_username}'")
return stats_embed
- async def get_october_prs(self, github_username: str) -> Optional[list[dict]]:
+ async def get_october_prs(self, github_username: str) -> list[dict] | None:
"""
Query GitHub's API for PRs created during the month of October by github_username.
@@ -234,9 +233,8 @@ class HacktoberStats(commands.Cog):
# Ignore logging non-existent users or users we do not have permission to see
if api_message == GITHUB_NONEXISTENT_USER_MESSAGE:
log.debug(f"No GitHub user found named '{github_username}'")
- return
- else:
- log.error(f"GitHub API request for '{github_username}' failed with message: {api_message}")
+ return None
+ log.error(f"GitHub API request for '{github_username}' failed with message: {api_message}")
return [] # No October PRs were found due to error
if jsonresp["total_count"] == 0:
@@ -246,7 +244,7 @@ class HacktoberStats(commands.Cog):
logging.info(f"Found {len(jsonresp['items'])} Hacktoberfest PRs for GitHub user: '{github_username}'")
outlist = [] # list of pr information dicts that will get returned
- oct3 = datetime(int(CURRENT_YEAR), 10, 3, 23, 59, 59, tzinfo=None)
+ oct3 = datetime(int(CURRENT_YEAR), 10, 3, 23, 59, 59, tzinfo=UTC)
hackto_topics = {} # cache whether each repo has the appropriate topic (bool values)
for item in jsonresp["items"]:
shortname = self._get_shortname(item["repository_url"])
@@ -255,15 +253,14 @@ class HacktoberStats(commands.Cog):
"repo_shortname": shortname,
"created_at": datetime.strptime(
item["created_at"], "%Y-%m-%dT%H:%M:%SZ"
- ),
+ ).replace(tzinfo=UTC),
"number": item["number"]
}
# If the PR has 'invalid' or 'spam' labels, the PR must be
# either merged or approved for it to be included
- if self._has_label(item, ["invalid", "spam"]):
- if not await self._is_accepted(itemdict):
- continue
+ if self._has_label(item, ["invalid", "spam"]) and not await self._is_accepted(itemdict):
+ continue
# PRs before oct 3 no need to check for topics
# continue the loop if 'hacktoberfest-accepted' is labelled then
@@ -302,7 +299,7 @@ class HacktoberStats(commands.Cog):
return await resp.json()
@staticmethod
- def _has_label(pr: dict, labels: Union[list[str], str]) -> bool:
+ def _has_label(pr: dict, labels: list[str] | str) -> bool:
"""
Check if a PR has label 'labels'.
@@ -313,7 +310,7 @@ class HacktoberStats(commands.Cog):
return False
if isinstance(labels, str) and any(label["name"].casefold() == labels for label in pr["labels"]):
return True
- for item in labels:
+ for item in labels: # noqa: SIM110
if any(label["name"].casefold() == item for label in pr["labels"]):
return True
return False
@@ -350,10 +347,7 @@ class HacktoberStats(commands.Cog):
return False
# loop through reviews and check for approval
- for item in jsonresp2:
- if item.get("status") == "APPROVED":
- return True
- return False
+ return any(item.get("status") == "APPROVED" for item in jsonresp2)
@staticmethod
def _get_shortname(in_url: str) -> str:
@@ -378,8 +372,8 @@ class HacktoberStats(commands.Cog):
PRs that are accepted must either be merged, approved, or labelled
'hacktoberfest-accepted.
"""
- now = datetime.now()
- oct3 = datetime(CURRENT_YEAR, 10, 3, 23, 59, 59, tzinfo=None)
+ now = datetime.now(tz=UTC)
+ oct3 = datetime(CURRENT_YEAR, 10, 3, 23, 59, 59, tzinfo=UTC)
in_review = []
accepted = []
for pr in prs:
@@ -420,8 +414,7 @@ class HacktoberStats(commands.Cog):
"""Return "contribution" or "contributions" based on the value of n."""
if n == 1:
return "contribution"
- else:
- return "contributions"
+ return "contributions"
@staticmethod
def _author_mention_from_context(ctx: commands.Context) -> tuple[str, str]:
diff --git a/bot/exts/events/hacktoberfest/timeleft.py b/bot/exts/events/hacktoberfest/timeleft.py
index f470e932..8f46d798 100644
--- a/bot/exts/events/hacktoberfest/timeleft.py
+++ b/bot/exts/events/hacktoberfest/timeleft.py
@@ -1,5 +1,5 @@
import logging
-from datetime import datetime
+from datetime import UTC, datetime
from discord.ext import commands
@@ -9,25 +9,25 @@ log = logging.getLogger(__name__)
class TimeLeft(commands.Cog):
- """A Cog that tells you how long left until Hacktober is over!"""
+ """A Cog that tells users how long left until Hacktober is over!"""
def in_hacktober(self) -> bool:
"""Return True if the current time is within Hacktoberfest."""
_, end, start = self.load_date()
- now = datetime.utcnow()
+ now = datetime.now(tz=UTC)
return start <= now <= end
@staticmethod
def load_date() -> tuple[datetime, datetime, datetime]:
- """Return of a tuple of the current time and the end and start times of the next October."""
- now = datetime.utcnow()
+ """Return of a tuple of the current time and the end and start times of the next Hacktober."""
+ now = datetime.now(tz=UTC)
year = now.year
if now.month > 10:
year += 1
- end = datetime(year, 11, 1, 12) # November 1st 12:00 (UTC-12:00)
- start = datetime(year, 9, 30, 10) # September 30th 10:00 (UTC+14:00)
+ end = datetime(year, 11, 1, 12, tzinfo=UTC) # November 1st 12:00 (UTC-12:00)
+ start = datetime(year, 9, 30, 10, tzinfo=UTC) # September 30th 10:00 (UTC+14:00)
return now, end, start
@commands.command()
diff --git a/bot/exts/events/trivianight/_game.py b/bot/exts/events/trivianight/_game.py
index 8b012a17..15126f60 100644
--- a/bot/exts/events/trivianight/_game.py
+++ b/bot/exts/events/trivianight/_game.py
@@ -1,7 +1,8 @@
import time
+from collections.abc import Iterable
from random import randrange
from string import ascii_uppercase
-from typing import Iterable, NamedTuple, Optional, TypedDict
+from typing import NamedTuple, TypedDict
DEFAULT_QUESTION_POINTS = 10
DEFAULT_QUESTION_TIME = 20
@@ -14,8 +15,8 @@ class QuestionData(TypedDict):
description: str
answers: list[str]
correct: str
- points: Optional[int]
- time: Optional[int]
+ points: int | None
+ time: int | None
class UserGuess(NamedTuple):
@@ -26,15 +27,15 @@ class UserGuess(NamedTuple):
elapsed: float
-class QuestionClosed(RuntimeError):
+class QuestionClosedError(RuntimeError):
"""Exception raised when the question is not open for guesses anymore."""
-class AlreadyUpdated(RuntimeError):
+class AlreadyUpdatedError(RuntimeError):
"""Exception raised when the user has already updated their guess once."""
-class AllQuestionsVisited(RuntimeError):
+class AllQuestionsVisitedError(RuntimeError):
"""Exception raised when all of the questions have been visited."""
@@ -90,10 +91,10 @@ class Question:
def _update_guess(self, user: int, answer: str) -> UserGuess:
"""Update an already existing guess."""
if self._started is None:
- raise QuestionClosed("Question is not open for answers.")
+ raise QuestionClosedError("Question is not open for answers.")
if self._guesses[user][1] is False:
- raise AlreadyUpdated(f"User({user}) has already updated their guess once.")
+ raise AlreadyUpdatedError(f"User({user}) has already updated their guess once.")
self._guesses[user] = (answer, False, time.perf_counter() - self._started)
return self._guesses[user]
@@ -104,7 +105,7 @@ class Question:
return self._update_guess(user, answer)
if self._started is None:
- raise QuestionClosed("Question is not open for answers.")
+ raise QuestionClosedError("Question is not open for answers.")
self._guesses[user] = (answer, True, time.perf_counter() - self._started)
return self._guesses[user]
@@ -126,7 +127,7 @@ class TriviaNightGame:
self._questions = [Question(q) for q in data]
# A copy of the questions to keep for `.trivianight list`
self._all_questions = list(self._questions)
- self.current_question: Optional[Question] = None
+ self.current_question: Question | None = None
self._points = {}
self._speed = {}
@@ -148,7 +149,7 @@ class TriviaNightGame:
except IndexError:
raise ValueError(f"Question number {number} does not exist.")
elif len(self._questions) == 0:
- raise AllQuestionsVisited("All of the questions have been visited.")
+ raise AllQuestionsVisitedError("All of the questions have been visited.")
else:
question = self._questions.pop(randrange(len(self._questions)))
diff --git a/bot/exts/events/trivianight/_questions.py b/bot/exts/events/trivianight/_questions.py
index 5f1046dc..a0dd545e 100644
--- a/bot/exts/events/trivianight/_questions.py
+++ b/bot/exts/events/trivianight/_questions.py
@@ -7,7 +7,7 @@ from discord.ui import Button, View
from bot.constants import Colours, NEGATIVE_REPLIES
-from ._game import AlreadyUpdated, Question, QuestionClosed
+from ._game import AlreadyUpdatedError, Question, QuestionClosedError
from ._scoreboard import Scoreboard
@@ -29,7 +29,7 @@ class AnswerButton(Button):
"""
try:
guess = self.question.guess(interaction.user.id, self.label)
- except AlreadyUpdated:
+ except AlreadyUpdatedError:
await interaction.response.send_message(
embed=Embed(
title=choice(NEGATIVE_REPLIES),
@@ -39,7 +39,7 @@ class AnswerButton(Button):
ephemeral=True
)
return
- except QuestionClosed:
+ except QuestionClosedError:
await interaction.response.send_message(
embed=Embed(
title=choice(NEGATIVE_REPLIES),
@@ -91,7 +91,7 @@ class QuestionView(View):
- text: A string that represents the question description to 'unicodeify'
"""
return "".join(
- f"{letter}\u200b" if letter not in ('\n', '\t', '`', 'p', 'y') else letter
+ f"{letter}\u200b" if letter not in ("\n", "\t", "`", "p", "y") else letter
for idx, letter in enumerate(text)
)
@@ -127,13 +127,13 @@ class QuestionView(View):
if len(guesses) != 0:
answers_chosen = {
answer_choice: len(
- tuple(filter(lambda x: x[0] == answer_choice, guesses.values())) # noqa: B023
+ tuple(filter(lambda x: x[0] == answer_choice, guesses.values()))
)
for answer_choice in labels
}
answers_chosen = dict(
- sorted(list(answers_chosen.items()), key=lambda item: item[1], reverse=True)
+ sorted(answers_chosen.items(), key=lambda item: item[1], reverse=True)
)
for answer, people_answered in answers_chosen.items():
diff --git a/bot/exts/events/trivianight/trivianight.py b/bot/exts/events/trivianight/trivianight.py
index 10435551..f90d32e0 100644
--- a/bot/exts/events/trivianight/trivianight.py
+++ b/bot/exts/events/trivianight/trivianight.py
@@ -1,7 +1,6 @@
import asyncio
from json import JSONDecodeError, loads
from random import choice
-from typing import Optional
from discord import Embed
from discord.ext import commands
@@ -10,7 +9,7 @@ from bot.bot import Bot
from bot.constants import Colours, NEGATIVE_REPLIES, POSITIVE_REPLIES, Roles
from bot.utils.pagination import LinePaginator
-from ._game import AllQuestionsVisited, TriviaNightGame
+from ._game import AllQuestionsVisitedError, TriviaNightGame
from ._questions import QuestionView
from ._scoreboard import Scoreboard
@@ -23,8 +22,8 @@ class TriviaNightCog(commands.Cog):
def __init__(self, bot: Bot):
self.bot = bot
- self.game: Optional[TriviaNightGame] = None
- self.scoreboard: Optional[Scoreboard] = None
+ self.game: TriviaNightGame | None = None
+ self.scoreboard: Scoreboard | None = None
self.question_closed: asyncio.Event = None
@commands.group(aliases=["tn"], invoke_without_command=True)
@@ -46,7 +45,7 @@ class TriviaNightCog(commands.Cog):
@trivianight.command()
@commands.has_any_role(*TRIVIA_NIGHT_ROLES)
- async def load(self, ctx: commands.Context, *, to_load: Optional[str]) -> None:
+ async def load(self, ctx: commands.Context, *, to_load: str | None) -> None:
"""
Loads a JSON file from the provided attachment or argument.
@@ -76,8 +75,7 @@ class TriviaNightCog(commands.Cog):
elif not to_load:
raise commands.BadArgument("You didn't attach an attachment nor link a message!")
elif (
- to_load.startswith("https://discord.com/channels")
- or to_load.startswith("https://discordapp.com/channels")
+ to_load.startswith(("https://discord.com/channels", "https://discordapp.com/channels"))
):
channel_id, message_id = to_load.split("/")[-2:]
channel = await ctx.guild.fetch_channel(int(channel_id))
@@ -107,7 +105,7 @@ class TriviaNightCog(commands.Cog):
await ctx.send(embed=success_embed)
- @trivianight.command(aliases=('next',))
+ @trivianight.command(aliases=("next",))
@commands.has_any_role(*TRIVIA_NIGHT_ROLES)
async def question(self, ctx: commands.Context, question_number: str = None) -> None:
"""
@@ -135,7 +133,7 @@ class TriviaNightCog(commands.Cog):
try:
next_question = self.game.next_question(question_number)
- except AllQuestionsVisited:
+ except AllQuestionsVisitedError:
error_embed = Embed(
title=choice(NEGATIVE_REPLIES),
description="All of the questions have been used.",