aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps
diff options
context:
space:
mode:
Diffstat (limited to 'pydis_site/apps')
-rw-r--r--pydis_site/apps/api/admin.py29
-rw-r--r--pydis_site/apps/api/github_utils.py13
-rw-r--r--pydis_site/apps/api/models/bot/message.py7
-rw-r--r--pydis_site/apps/api/models/bot/metricity.py19
-rw-r--r--pydis_site/apps/api/tests/base.py3
-rw-r--r--pydis_site/apps/api/tests/test_bumped_threads.py2
-rw-r--r--pydis_site/apps/api/tests/test_deleted_messages.py11
-rw-r--r--pydis_site/apps/api/tests/test_documentation_links.py2
-rw-r--r--pydis_site/apps/api/tests/test_filters.py12
-rw-r--r--pydis_site/apps/api/tests/test_github_utils.py41
-rw-r--r--pydis_site/apps/api/tests/test_infractions.py110
-rw-r--r--pydis_site/apps/api/tests/test_models.py4
-rw-r--r--pydis_site/apps/api/tests/test_nominations.py2
-rw-r--r--pydis_site/apps/api/tests/test_off_topic_channel_names.py2
-rw-r--r--pydis_site/apps/api/tests/test_offensive_message.py10
-rw-r--r--pydis_site/apps/api/tests/test_reminders.py4
-rw-r--r--pydis_site/apps/api/tests/test_roles.py2
-rw-r--r--pydis_site/apps/api/tests/test_rules.py2
-rw-r--r--pydis_site/apps/api/tests/test_users.py29
-rw-r--r--pydis_site/apps/api/tests/test_validators.py4
-rw-r--r--pydis_site/apps/api/views.py4
-rw-r--r--pydis_site/apps/api/viewsets/bot/filters.py4
-rw-r--r--pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py7
-rw-r--r--pydis_site/apps/api/viewsets/bot/user.py5
-rw-r--r--pydis_site/apps/content/models/tag.py3
-rw-r--r--pydis_site/apps/content/resources/guides/pydis-guides/contributing/linting.md2
-rw-r--r--pydis_site/apps/content/tests/helpers.py20
-rw-r--r--pydis_site/apps/content/urls.py2
-rw-r--r--pydis_site/apps/content/utils.py16
-rw-r--r--pydis_site/apps/content/views/tags.py3
-rw-r--r--pydis_site/apps/events/urls.py2
-rw-r--r--pydis_site/apps/events/views/page.py3
-rw-r--r--pydis_site/apps/home/tests/test_repodata_helpers.py2
-rw-r--r--pydis_site/apps/home/views.py13
-rw-r--r--pydis_site/apps/redirect/urls.py25
-rw-r--r--pydis_site/apps/redirect/views.py3
-rw-r--r--pydis_site/apps/resources/views.py7
-rw-r--r--pydis_site/apps/staff/templatetags/deletedmessage_filters.py3
-rw-r--r--pydis_site/apps/staff/tests/test_deletedmessage_filters.py2
39 files changed, 218 insertions, 216 deletions
diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py
index e123d150..f3cc0405 100644
--- a/pydis_site/apps/api/admin.py
+++ b/pydis_site/apps/api/admin.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import json
-from typing import Iterable, Optional, Tuple
+from collections.abc import Iterable
from django import urls
from django.contrib import admin
@@ -62,16 +62,16 @@ class InfractionActorFilter(admin.SimpleListFilter):
title = "Actor"
parameter_name = "actor"
- def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[Tuple[int, str]]:
+ def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[tuple[int, str]]:
"""Selectable values for viewer to filter by."""
actor_ids = Infraction.objects.order_by().values_list("actor").distinct()
actors = User.objects.filter(id__in=actor_ids)
return ((a.id, a.username) for a in actors)
- def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]:
+ def queryset(self, request: HttpRequest, queryset: QuerySet) -> QuerySet | None:
"""Query to filter the list of Users against."""
if not self.value():
- return
+ return None
return queryset.filter(actor__id=self.value())
@@ -149,7 +149,7 @@ class DeletedMessageAdmin(admin.ModelAdmin):
list_display = ("id", "author", "channel_id")
- def embed_data(self, message: DeletedMessage) -> Optional[str]:
+ def embed_data(self, message: DeletedMessage) -> str | None:
"""Format embed data in a code block for better readability."""
if message.embeds:
return format_html(
@@ -157,6 +157,7 @@ class DeletedMessageAdmin(admin.ModelAdmin):
"<code>{0}</code></pre>",
json.dumps(message.embeds, indent=4)
)
+ return None
embed_data.short_description = "Embeds"
@@ -229,16 +230,16 @@ class NominationActorFilter(admin.SimpleListFilter):
title = "Actor"
parameter_name = "actor"
- def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[Tuple[int, str]]:
+ def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[tuple[int, str]]:
"""Selectable values for viewer to filter by."""
actor_ids = NominationEntry.objects.order_by().values_list("actor").distinct()
actors = User.objects.filter(id__in=actor_ids)
return ((a.id, a.username) for a in actors)
- def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]:
+ def queryset(self, request: HttpRequest, queryset: QuerySet) -> QuerySet | None:
"""Query to filter the list of Users against."""
if not self.value():
- return
+ return None
nomination_ids = NominationEntry.objects.filter(
actor__id=self.value()
).values_list("nomination_id").distinct()
@@ -292,16 +293,16 @@ class NominationEntryActorFilter(admin.SimpleListFilter):
title = "Actor"
parameter_name = "actor"
- def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[Tuple[int, str]]:
+ def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[tuple[int, str]]:
"""Selectable values for viewer to filter by."""
actor_ids = NominationEntry.objects.order_by().values_list("actor").distinct()
actors = User.objects.filter(id__in=actor_ids)
return ((a.id, a.username) for a in actors)
- def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]:
+ def queryset(self, request: HttpRequest, queryset: QuerySet) -> QuerySet | None:
"""Query to filter the list of Users against."""
if not self.value():
- return
+ return None
return queryset.filter(actor__id=self.value())
@@ -425,15 +426,15 @@ class UserRoleFilter(admin.SimpleListFilter):
title = "Role"
parameter_name = "role"
- def lookups(self, request: HttpRequest, model: UserAdmin) -> Iterable[Tuple[str, str]]:
+ def lookups(self, request: HttpRequest, model: UserAdmin) -> Iterable[tuple[str, str]]:
"""Selectable values for viewer to filter by."""
roles = Role.objects.all()
return ((r.name, r.name) for r in roles)
- def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]:
+ def queryset(self, request: HttpRequest, queryset: QuerySet) -> QuerySet | None:
"""Query to filter the list of Users against."""
if not self.value():
- return
+ return None
role = Role.objects.get(name=self.value())
return queryset.filter(roles__contains=[role.id])
diff --git a/pydis_site/apps/api/github_utils.py b/pydis_site/apps/api/github_utils.py
index 44c571c3..af659195 100644
--- a/pydis_site/apps/api/github_utils.py
+++ b/pydis_site/apps/api/github_utils.py
@@ -82,7 +82,7 @@ def generate_token() -> str:
Refer to:
https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app
"""
- now = datetime.datetime.now()
+ now = datetime.datetime.now(tz=datetime.timezone.utc)
return jwt.encode(
{
"iat": math.floor((now - datetime.timedelta(seconds=60)).timestamp()), # Issued at
@@ -145,8 +145,12 @@ def authorize(owner: str, repo: str) -> httpx.Client:
def check_run_status(run: WorkflowRun) -> str:
"""Check if the provided run has been completed, otherwise raise an exception."""
- created_at = datetime.datetime.strptime(run.created_at, settings.GITHUB_TIMESTAMP_FORMAT)
- run_time = datetime.datetime.utcnow() - created_at
+ created_at = (
+ datetime.datetime
+ .strptime(run.created_at, settings.GITHUB_TIMESTAMP_FORMAT)
+ .replace(tzinfo=datetime.timezone.utc)
+ )
+ run_time = datetime.datetime.now(tz=datetime.timezone.utc) - created_at
if run.status != "completed":
if run_time <= MAX_RUN_TIME:
@@ -154,8 +158,7 @@ def check_run_status(run: WorkflowRun) -> str:
f"The requested run is still pending. It was created "
f"{run_time.seconds // 60}:{run_time.seconds % 60 :>02} minutes ago."
)
- else:
- raise RunTimeoutError("The requested workflow was not ready in time.")
+ raise RunTimeoutError("The requested workflow was not ready in time.")
if run.conclusion != "success":
# The action failed, or did not run
diff --git a/pydis_site/apps/api/models/bot/message.py b/pydis_site/apps/api/models/bot/message.py
index 89ae27e4..d8147cd4 100644
--- a/pydis_site/apps/api/models/bot/message.py
+++ b/pydis_site/apps/api/models/bot/message.py
@@ -61,9 +61,10 @@ class Message(ModelReprMixin, models.Model):
@property
def timestamp(self) -> datetime.datetime:
"""Attribute that represents the message timestamp as derived from the snowflake id."""
- return datetime.datetime.utcfromtimestamp(
- ((self.id >> 22) + 1420070400000) / 1000
- ).replace(tzinfo=datetime.timezone.utc)
+ return datetime.datetime.fromtimestamp(
+ ((self.id >> 22) + 1420070400000) / 1000,
+ tz=datetime.timezone.utc,
+ )
class Meta:
"""Metadata provided for Django's ORM."""
diff --git a/pydis_site/apps/api/models/bot/metricity.py b/pydis_site/apps/api/models/bot/metricity.py
index f53dd33c..a55f5e5b 100644
--- a/pydis_site/apps/api/models/bot/metricity.py
+++ b/pydis_site/apps/api/models/bot/metricity.py
@@ -1,4 +1,3 @@
-from typing import List, Tuple
from django.db import connections
@@ -10,10 +9,9 @@ EXCLUDE_CHANNELS = (
)
-class NotFoundError(Exception): # noqa: N818
+class NotFoundError(Exception):
"""Raised when an entity cannot be found."""
- pass
class Metricity:
@@ -31,15 +29,14 @@ class Metricity:
def user(self, user_id: str) -> dict:
"""Query a user's data."""
# TODO: Swap this back to some sort of verified at date
- columns = ["joined_at"]
- query = f"SELECT {','.join(columns)} FROM users WHERE id = '%s'"
+ query = "SELECT joined_at FROM users WHERE id = '%s'"
self.cursor.execute(query, [user_id])
values = self.cursor.fetchone()
if not values:
- raise NotFoundError()
+ raise NotFoundError
- return dict(zip(columns, values))
+ return {'joined_at': values[0]}
def total_messages(self, user_id: str) -> int:
"""Query total number of messages for a user."""
@@ -58,7 +55,7 @@ class Metricity:
values = self.cursor.fetchone()
if not values:
- raise NotFoundError()
+ raise NotFoundError
return values[0]
@@ -88,11 +85,11 @@ class Metricity:
values = self.cursor.fetchone()
if not values:
- raise NotFoundError()
+ raise NotFoundError
return values[0]
- def top_channel_activity(self, user_id: str) -> List[Tuple[str, int]]:
+ def top_channel_activity(self, user_id: str) -> list[tuple[str, int]]:
"""
Query the top three channels in which the user is most active.
@@ -127,7 +124,7 @@ class Metricity:
values = self.cursor.fetchall()
if not values:
- raise NotFoundError()
+ raise NotFoundError
return values
diff --git a/pydis_site/apps/api/tests/base.py b/pydis_site/apps/api/tests/base.py
index c9f3cb7e..704b22cf 100644
--- a/pydis_site/apps/api/tests/base.py
+++ b/pydis_site/apps/api/tests/base.py
@@ -61,6 +61,7 @@ class AuthenticatedAPITestCase(APITestCase):
... self.assertEqual(response.status_code, 200)
"""
- def setUp(self):
+ def setUp(self) -> None:
+ """Bootstrap the user and authenticate it."""
super().setUp()
self.client.force_authenticate(test_user)
diff --git a/pydis_site/apps/api/tests/test_bumped_threads.py b/pydis_site/apps/api/tests/test_bumped_threads.py
index 316e3f0b..2e3892c7 100644
--- a/pydis_site/apps/api/tests/test_bumped_threads.py
+++ b/pydis_site/apps/api/tests/test_bumped_threads.py
@@ -1,7 +1,7 @@
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import BumpedThread
+from pydis_site.apps.api.models import BumpedThread
class UnauthedBumpedThreadAPITests(AuthenticatedAPITestCase):
diff --git a/pydis_site/apps/api/tests/test_deleted_messages.py b/pydis_site/apps/api/tests/test_deleted_messages.py
index 1eb535d8..62d17e58 100644
--- a/pydis_site/apps/api/tests/test_deleted_messages.py
+++ b/pydis_site/apps/api/tests/test_deleted_messages.py
@@ -1,10 +1,9 @@
-from datetime import datetime
+from datetime import datetime, timezone
from django.urls import reverse
-from django.utils import timezone
from .base import AuthenticatedAPITestCase
-from ..models import MessageDeletionContext, User
+from pydis_site.apps.api.models import MessageDeletionContext, User
class DeletedMessagesWithoutActorTests(AuthenticatedAPITestCase):
@@ -18,7 +17,7 @@ class DeletedMessagesWithoutActorTests(AuthenticatedAPITestCase):
cls.data = {
'actor': None,
- 'creation': datetime.utcnow().isoformat(),
+ 'creation': datetime.now(tz=timezone.utc).isoformat(),
'deletedmessage_set': [
{
'author': cls.author.id,
@@ -58,7 +57,7 @@ class DeletedMessagesWithActorTests(AuthenticatedAPITestCase):
cls.data = {
'actor': cls.actor.id,
- 'creation': datetime.utcnow().isoformat(),
+ 'creation': datetime.now(tz=timezone.utc).isoformat(),
'deletedmessage_set': [
{
'author': cls.author.id,
@@ -90,7 +89,7 @@ class DeletedMessagesLogURLTests(AuthenticatedAPITestCase):
cls.deletion_context = MessageDeletionContext.objects.create(
actor=cls.actor,
- creation=timezone.now()
+ creation=datetime.now(tz=timezone.utc),
)
def test_valid_log_url(self):
diff --git a/pydis_site/apps/api/tests/test_documentation_links.py b/pydis_site/apps/api/tests/test_documentation_links.py
index 4e238cbb..f4a332cb 100644
--- a/pydis_site/apps/api/tests/test_documentation_links.py
+++ b/pydis_site/apps/api/tests/test_documentation_links.py
@@ -1,7 +1,7 @@
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import DocumentationLink
+from pydis_site.apps.api.models import DocumentationLink
class UnauthedDocumentationLinkAPITests(AuthenticatedAPITestCase):
diff --git a/pydis_site/apps/api/tests/test_filters.py b/pydis_site/apps/api/tests/test_filters.py
index 5059d651..4cef1c8f 100644
--- a/pydis_site/apps/api/tests/test_filters.py
+++ b/pydis_site/apps/api/tests/test_filters.py
@@ -1,7 +1,7 @@
import contextlib
from dataclasses import dataclass
from datetime import timedelta
-from typing import Any, Dict, Tuple, Type
+from typing import Any
from django.db.models import Model
from django.urls import reverse
@@ -12,22 +12,22 @@ from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
@dataclass()
class TestSequence:
- model: Type[Model]
+ model: type[Model]
route: str
- object: Dict[str, Any]
- ignored_fields: Tuple[str, ...] = ()
+ object: dict[str, Any]
+ ignored_fields: tuple[str, ...] = ()
def url(self, detail: bool = False) -> str:
return reverse(f'api:bot:{self.route}-{"detail" if detail else "list"}')
-FK_FIELDS: Dict[Type[Model], Tuple[str, ...]] = {
+FK_FIELDS: dict[type[Model], tuple[str, ...]] = {
FilterList: (),
Filter: ("filter_list",),
}
-def get_test_sequences() -> Dict[str, TestSequence]:
+def get_test_sequences() -> dict[str, TestSequence]:
filter_list1_deny_dict = {
"name": "testname",
"list_type": 0,
diff --git a/pydis_site/apps/api/tests/test_github_utils.py b/pydis_site/apps/api/tests/test_github_utils.py
index 95bafec0..34fae875 100644
--- a/pydis_site/apps/api/tests/test_github_utils.py
+++ b/pydis_site/apps/api/tests/test_github_utils.py
@@ -12,7 +12,7 @@ import rest_framework.test
from django.urls import reverse
from pydis_site import settings
-from .. import github_utils
+from pydis_site.apps.api import github_utils
class GeneralUtilityTests(unittest.TestCase):
@@ -39,7 +39,8 @@ class GeneralUtilityTests(unittest.TestCase):
delta = datetime.timedelta(minutes=10)
self.assertAlmostEqual(decoded["exp"] - decoded["iat"], delta.total_seconds())
- self.assertLess(decoded["exp"], (datetime.datetime.now() + delta).timestamp())
+ then = datetime.datetime.now(tz=datetime.timezone.utc) + delta
+ self.assertLess(decoded["exp"], then.timestamp())
class CheckRunTests(unittest.TestCase):
@@ -50,7 +51,7 @@ class CheckRunTests(unittest.TestCase):
"head_sha": "sha",
"status": "completed",
"conclusion": "success",
- "created_at": datetime.datetime.utcnow().strftime(settings.GITHUB_TIMESTAMP_FORMAT),
+ "created_at": datetime.datetime.now(tz=datetime.timezone.utc).strftime(settings.GITHUB_TIMESTAMP_FORMAT),
"artifacts_url": "url",
}
@@ -74,7 +75,8 @@ class CheckRunTests(unittest.TestCase):
# Set the creation time to well before the MAX_RUN_TIME
# to guarantee the right conclusion
kwargs["created_at"] = (
- datetime.datetime.utcnow() - github_utils.MAX_RUN_TIME - datetime.timedelta(minutes=10)
+ datetime.datetime.now(tz=datetime.timezone.utc)
+ - github_utils.MAX_RUN_TIME - datetime.timedelta(minutes=10)
).strftime(settings.GITHUB_TIMESTAMP_FORMAT)
with self.assertRaises(github_utils.RunTimeoutError):
@@ -103,29 +105,26 @@ def get_response_authorize(_: httpx.Client, request: httpx.Request, **__) -> htt
"account": {"login": "VALID_OWNER"},
"access_tokens_url": "https://example.com/ACCESS_TOKEN_URL"
}])
- else:
- return httpx.Response(
- 401, json={"error": "auth app/installations"}, request=request
- )
+ return httpx.Response(
+ 401, json={"error": "auth app/installations"}, request=request
+ )
- elif path == "/installation/repositories":
+ elif path == "/installation/repositories": # noqa: RET505
if auth == "bearer app access token":
return httpx.Response(200, request=request, json={
"repositories": [{
"name": "VALID_REPO"
}]
})
- else: # pragma: no cover
- return httpx.Response(
- 401, json={"error": "auth installation/repositories"}, request=request
- )
+ return httpx.Response( # pragma: no cover
+ 401, json={"error": "auth installation/repositories"}, request=request
+ )
- elif request.method == "POST":
+ elif request.method == "POST": # noqa: RET505
if path == "/ACCESS_TOKEN_URL":
if auth == "bearer JWT initial token":
return httpx.Response(200, request=request, json={"token": "app access token"})
- else: # pragma: no cover
- return httpx.Response(401, json={"error": "auth access_token"}, request=request)
+ return httpx.Response(401, json={"error": "auth access_token"}, request=request) # pragma: no cover
# Reaching this point means something has gone wrong
return httpx.Response(500, request=request) # pragma: no cover
@@ -138,7 +137,7 @@ class AuthorizeTests(unittest.TestCase):
def test_invalid_apps_auth(self):
"""Test that an exception is raised if authorization was attempted with an invalid token."""
- with mock.patch.object(github_utils, "generate_token", return_value="Invalid token"):
+ with mock.patch.object(github_utils, "generate_token", return_value="Invalid token"): # noqa: SIM117
with self.assertRaises(httpx.HTTPStatusError) as error:
github_utils.authorize("VALID_OWNER", "VALID_REPO")
@@ -179,7 +178,11 @@ class ArtifactFetcherTests(unittest.TestCase):
run = github_utils.WorkflowRun(
name="action_name",
head_sha="action_sha",
- created_at=datetime.datetime.now().strftime(settings.GITHUB_TIMESTAMP_FORMAT),
+ created_at=(
+ datetime.datetime
+ .now(tz=datetime.timezone.utc)
+ .strftime(settings.GITHUB_TIMESTAMP_FORMAT)
+ ),
status="completed",
conclusion="success",
artifacts_url="artifacts_url"
@@ -187,7 +190,7 @@ class ArtifactFetcherTests(unittest.TestCase):
return httpx.Response(
200, request=request, json={"workflow_runs": [dataclasses.asdict(run)]}
)
- elif path == "/artifact_url":
+ elif path == "/artifact_url": # noqa: RET505
return httpx.Response(
200, request=request, json={"artifacts": [{
"name": "artifact_name",
diff --git a/pydis_site/apps/api/tests/test_infractions.py b/pydis_site/apps/api/tests/test_infractions.py
index ceb5591b..71611ee9 100644
--- a/pydis_site/apps/api/tests/test_infractions.py
+++ b/pydis_site/apps/api/tests/test_infractions.py
@@ -8,8 +8,8 @@ from django.db.utils import IntegrityError
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import Infraction, User
-from ..serializers import InfractionSerializer
+from pydis_site.apps.api.models import Infraction, User
+from pydis_site.apps.api.serializers import InfractionSerializer
class UnauthenticatedTests(AuthenticatedAPITestCase):
@@ -152,8 +152,8 @@ class InfractionTests(AuthenticatedAPITestCase):
def test_filter_after(self):
url = reverse('api:bot:infraction-list')
- target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
- response = self.client.get(f'{url}?type=superstar&expires_after={target_time.isoformat()}')
+ target_time = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=5)
+ response = self.client.get(url, {'type': 'superstar', 'expires_after': target_time.isoformat()})
self.assertEqual(response.status_code, 200)
infractions = response.json()
@@ -161,8 +161,8 @@ class InfractionTests(AuthenticatedAPITestCase):
def test_filter_before(self):
url = reverse('api:bot:infraction-list')
- target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
- response = self.client.get(f'{url}?type=superstar&expires_before={target_time.isoformat()}')
+ target_time = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=5)
+ response = self.client.get(url, {'type': 'superstar', 'expires_before': target_time.isoformat()})
self.assertEqual(response.status_code, 200)
infractions = response.json()
@@ -185,11 +185,12 @@ class InfractionTests(AuthenticatedAPITestCase):
def test_after_before_before(self):
url = reverse('api:bot:infraction-list')
- target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=4)
- target_time_late = datetime.datetime.utcnow() + datetime.timedelta(hours=6)
+ target_time = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=4)
+ target_time_late = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=6)
response = self.client.get(
- f'{url}?expires_before={target_time_late.isoformat()}'
- f'&expires_after={target_time.isoformat()}'
+ url,
+ {'expires_before': target_time_late.isoformat(),
+ 'expires_after': target_time.isoformat()},
)
self.assertEqual(response.status_code, 200)
@@ -198,11 +199,12 @@ class InfractionTests(AuthenticatedAPITestCase):
def test_after_after_before_invalid(self):
url = reverse('api:bot:infraction-list')
- target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
- target_time_late = datetime.datetime.utcnow() + datetime.timedelta(hours=9)
+ target_time = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=5)
+ target_time_late = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=9)
response = self.client.get(
- f'{url}?expires_before={target_time.isoformat()}'
- f'&expires_after={target_time_late.isoformat()}'
+ url,
+ {'expires_before': target_time.isoformat(),
+ 'expires_after': target_time_late.isoformat()},
)
self.assertEqual(response.status_code, 400)
@@ -212,8 +214,11 @@ class InfractionTests(AuthenticatedAPITestCase):
def test_permanent_after_invalid(self):
url = reverse('api:bot:infraction-list')
- target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
- response = self.client.get(f'{url}?permanent=true&expires_after={target_time.isoformat()}')
+ target_time = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=5)
+ response = self.client.get(
+ url,
+ {'permanent': 'true', 'expires_after': target_time.isoformat()},
+ )
self.assertEqual(response.status_code, 400)
errors = list(response.json())
@@ -221,8 +226,11 @@ class InfractionTests(AuthenticatedAPITestCase):
def test_permanent_before_invalid(self):
url = reverse('api:bot:infraction-list')
- target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
- response = self.client.get(f'{url}?permanent=true&expires_before={target_time.isoformat()}')
+ target_time = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=5)
+ response = self.client.get(
+ url,
+ {'permanent': 'true', 'expires_before': target_time.isoformat()},
+ )
self.assertEqual(response.status_code, 400)
errors = list(response.json())
@@ -230,9 +238,10 @@ class InfractionTests(AuthenticatedAPITestCase):
def test_nonpermanent_before(self):
url = reverse('api:bot:infraction-list')
- target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=6)
+ target_time = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=6)
response = self.client.get(
- f'{url}?permanent=false&expires_before={target_time.isoformat()}'
+ url,
+ {'permanent': 'false', 'expires_before': target_time.isoformat()},
)
self.assertEqual(response.status_code, 200)
@@ -522,39 +531,38 @@ class CreationTests(AuthenticatedAPITestCase):
active_infraction_types = ('timeout', 'ban', 'superstar')
for infraction_type in active_infraction_types:
- with self.subTest(infraction_type=infraction_type):
- with transaction.atomic():
- first_active_infraction = {
- 'user': self.user.id,
- 'actor': self.user.id,
- 'type': infraction_type,
- 'reason': 'Take me on!',
- 'active': True,
- 'expires_at': '2019-10-04T12:52:00+00:00'
- }
+ with self.subTest(infraction_type=infraction_type), transaction.atomic():
+ first_active_infraction = {
+ 'user': self.user.id,
+ 'actor': self.user.id,
+ 'type': infraction_type,
+ 'reason': 'Take me on!',
+ 'active': True,
+ 'expires_at': '2019-10-04T12:52:00+00:00'
+ }
+
+ # Post the first active infraction of a type and confirm it's accepted.
+ first_response = self.client.post(url, data=first_active_infraction)
+ self.assertEqual(first_response.status_code, 201)
- # Post the first active infraction of a type and confirm it's accepted.
- first_response = self.client.post(url, data=first_active_infraction)
- self.assertEqual(first_response.status_code, 201)
-
- second_active_infraction = {
- 'user': self.user.id,
- 'actor': self.user.id,
- 'type': infraction_type,
- 'reason': 'Take on me!',
- 'active': True,
- 'expires_at': '2019-10-04T12:52:00+00:00'
+ second_active_infraction = {
+ 'user': self.user.id,
+ 'actor': self.user.id,
+ 'type': infraction_type,
+ 'reason': 'Take on me!',
+ 'active': True,
+ 'expires_at': '2019-10-04T12:52:00+00:00'
+ }
+ second_response = self.client.post(url, data=second_active_infraction)
+ self.assertEqual(second_response.status_code, 400)
+ self.assertEqual(
+ second_response.json(),
+ {
+ 'non_field_errors': [
+ 'This user already has an active infraction of this type.'
+ ]
}
- second_response = self.client.post(url, data=second_active_infraction)
- self.assertEqual(second_response.status_code, 400)
- self.assertEqual(
- second_response.json(),
- {
- 'non_field_errors': [
- 'This user already has an active infraction of this type.'
- ]
- }
- )
+ )
def test_returns_201_for_second_active_infraction_of_different_type(self):
"""Test if the API accepts a second active infraction of a different type than the first."""
diff --git a/pydis_site/apps/api/tests/test_models.py b/pydis_site/apps/api/tests/test_models.py
index d3341b35..1cca133d 100644
--- a/pydis_site/apps/api/tests/test_models.py
+++ b/pydis_site/apps/api/tests/test_models.py
@@ -118,7 +118,7 @@ class StringDunderMethodTests(SimpleTestCase):
OffensiveMessage(
id=602951077675139072,
channel_id=291284109232308226,
- delete_date=dt(3000, 1, 1)
+ delete_date=dt(3000, 1, 1, tzinfo=timezone.utc)
),
OffTopicChannelName(name='bob-the-builders-playground'),
Role(
@@ -132,7 +132,7 @@ class StringDunderMethodTests(SimpleTestCase):
name='shawn',
discriminator=555,
),
- creation=dt.utcnow()
+ creation=dt.now(tz=timezone.utc)
),
User(
id=5,
diff --git a/pydis_site/apps/api/tests/test_nominations.py b/pydis_site/apps/api/tests/test_nominations.py
index b3742cdd..ee6b1fbd 100644
--- a/pydis_site/apps/api/tests/test_nominations.py
+++ b/pydis_site/apps/api/tests/test_nominations.py
@@ -3,7 +3,7 @@ from datetime import datetime as dt, timedelta, timezone
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import Nomination, NominationEntry, User
+from pydis_site.apps.api.models import Nomination, NominationEntry, User
class CreationTests(AuthenticatedAPITestCase):
diff --git a/pydis_site/apps/api/tests/test_off_topic_channel_names.py b/pydis_site/apps/api/tests/test_off_topic_channel_names.py
index 34098c92..315f707d 100644
--- a/pydis_site/apps/api/tests/test_off_topic_channel_names.py
+++ b/pydis_site/apps/api/tests/test_off_topic_channel_names.py
@@ -1,7 +1,7 @@
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import OffTopicChannelName
+from pydis_site.apps.api.models import OffTopicChannelName
class UnauthenticatedTests(AuthenticatedAPITestCase):
diff --git a/pydis_site/apps/api/tests/test_offensive_message.py b/pydis_site/apps/api/tests/test_offensive_message.py
index 3cf95b75..53f9cb48 100644
--- a/pydis_site/apps/api/tests/test_offensive_message.py
+++ b/pydis_site/apps/api/tests/test_offensive_message.py
@@ -3,13 +3,13 @@ import datetime
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import OffensiveMessage
+from pydis_site.apps.api.models import OffensiveMessage
class CreationTests(AuthenticatedAPITestCase):
def test_accept_valid_data(self):
url = reverse('api:bot:offensivemessage-list')
- delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
+ delete_at = datetime.datetime.now() + datetime.timedelta(days=1) # noqa: DTZ005
data = {
'id': '602951077675139072',
'channel_id': '291284109232308226',
@@ -32,7 +32,7 @@ class CreationTests(AuthenticatedAPITestCase):
def test_returns_400_on_non_future_date(self):
url = reverse('api:bot:offensivemessage-list')
- delete_at = datetime.datetime.now() - datetime.timedelta(days=1)
+ delete_at = datetime.datetime.now() - datetime.timedelta(days=1) # noqa: DTZ005
data = {
'id': '602951077675139072',
'channel_id': '291284109232308226',
@@ -46,7 +46,7 @@ class CreationTests(AuthenticatedAPITestCase):
def test_returns_400_on_negative_id_or_channel_id(self):
url = reverse('api:bot:offensivemessage-list')
- delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
+ delete_at = datetime.datetime.now() + datetime.timedelta(days=1) # noqa: DTZ005
data = {
'id': '602951077675139072',
'channel_id': '291284109232308226',
@@ -72,7 +72,7 @@ class CreationTests(AuthenticatedAPITestCase):
class ListTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
- delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
+ delete_at = datetime.datetime.now() + datetime.timedelta(days=1) # noqa: DTZ005
aware_delete_at = delete_at.replace(tzinfo=datetime.timezone.utc)
cls.messages = [
diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py
index e17569f0..9bb5fe4d 100644
--- a/pydis_site/apps/api/tests/test_reminders.py
+++ b/pydis_site/apps/api/tests/test_reminders.py
@@ -4,7 +4,7 @@ from django.forms.models import model_to_dict
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import Reminder, User
+from pydis_site.apps.api.models import Reminder, User
class UnauthedReminderAPITests(AuthenticatedAPITestCase):
@@ -59,7 +59,7 @@ class ReminderCreationTests(AuthenticatedAPITestCase):
data = {
'author': self.author.id,
'content': 'Remember to...wait what was it again?',
- 'expiration': datetime.utcnow().isoformat(),
+ 'expiration': datetime.now(tz=timezone.utc).isoformat(),
'jump_url': "https://www.google.com",
'channel_id': 123,
'mentions': [8888, 9999],
diff --git a/pydis_site/apps/api/tests/test_roles.py b/pydis_site/apps/api/tests/test_roles.py
index 73c80c77..d3031990 100644
--- a/pydis_site/apps/api/tests/test_roles.py
+++ b/pydis_site/apps/api/tests/test_roles.py
@@ -1,7 +1,7 @@
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import Role, User
+from pydis_site.apps.api.models import Role, User
class CreationTests(AuthenticatedAPITestCase):
diff --git a/pydis_site/apps/api/tests/test_rules.py b/pydis_site/apps/api/tests/test_rules.py
index 3ee2d4e0..662fb8e9 100644
--- a/pydis_site/apps/api/tests/test_rules.py
+++ b/pydis_site/apps/api/tests/test_rules.py
@@ -5,7 +5,7 @@ from pathlib import Path
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..views import RulesView
+from pydis_site.apps.api.views import RulesView
class RuleAPITests(AuthenticatedAPITestCase):
diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py
index d86e80bb..cff4a825 100644
--- a/pydis_site/apps/api/tests/test_users.py
+++ b/pydis_site/apps/api/tests/test_users.py
@@ -4,9 +4,9 @@ from unittest.mock import Mock, patch
from django.urls import reverse
from .base import AuthenticatedAPITestCase
-from ..models import Infraction, Role, User
-from ..models.bot.metricity import NotFoundError
-from ..viewsets.bot.user import UserListPagination
+from pydis_site.apps.api.models import Infraction, Role, User
+from pydis_site.apps.api.models.bot.metricity import NotFoundError
+from pydis_site.apps.api.viewsets.bot.user import UserListPagination
class UnauthedUserAPITests(AuthenticatedAPITestCase):
@@ -469,18 +469,17 @@ class UserMetricityTests(AuthenticatedAPITestCase):
with self.subTest(
voice_infractions=case['voice_infractions'],
voice_gate_blocked=case['voice_gate_blocked']
- ):
- with patch("pydis_site.apps.api.viewsets.bot.user.Infraction.objects.filter") as p:
- p.return_value = case['voice_infractions']
-
- url = reverse('api:bot:user-metricity-data', args=[0])
- response = self.client.get(url)
-
- self.assertEqual(response.status_code, 200)
- self.assertEqual(
- response.json()["voice_gate_blocked"],
- case["voice_gate_blocked"]
- )
+ ), patch("pydis_site.apps.api.viewsets.bot.user.Infraction.objects.filter") as p:
+ p.return_value = case['voice_infractions']
+
+ url = reverse('api:bot:user-metricity-data', args=[0])
+ response = self.client.get(url)
+
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(
+ response.json()["voice_gate_blocked"],
+ case["voice_gate_blocked"]
+ )
def test_metricity_review_data(self):
# Given
diff --git a/pydis_site/apps/api/tests/test_validators.py b/pydis_site/apps/api/tests/test_validators.py
index 8c46fcbc..a7ec6e38 100644
--- a/pydis_site/apps/api/tests/test_validators.py
+++ b/pydis_site/apps/api/tests/test_validators.py
@@ -3,8 +3,8 @@ from datetime import datetime, timezone
from django.core.exceptions import ValidationError
from django.test import TestCase
-from ..models.bot.bot_setting import validate_bot_setting_name
-from ..models.bot.offensive_message import future_date_validator
+from pydis_site.apps.api.models.bot.bot_setting import validate_bot_setting_name
+from pydis_site.apps.api.models.bot.offensive_message import future_date_validator
REQUIRED_KEYS = (
diff --git a/pydis_site/apps/api/views.py b/pydis_site/apps/api/views.py
index b1b7dc0f..32f41667 100644
--- a/pydis_site/apps/api/views.py
+++ b/pydis_site/apps/api/views.py
@@ -93,7 +93,7 @@ class RulesView(APIView):
"""
if target == 'html':
return f'<a href="{link}">{description}</a>'
- elif target == 'md':
+ elif target == 'md': # noqa: RET505
return f'[{description}]({link})'
else:
raise ValueError(
@@ -101,7 +101,7 @@ class RulesView(APIView):
)
# `format` here is the result format, we have a link format here instead.
- def get(self, request, format=None): # noqa: D102,ANN001,ANN201
+ def get(self, request, format=None): # noqa: ANN001, ANN201
"""
Returns a list of our community rules coupled with their keywords.
diff --git a/pydis_site/apps/api/viewsets/bot/filters.py b/pydis_site/apps/api/viewsets/bot/filters.py
index d6c2d18c..9c9e8338 100644
--- a/pydis_site/apps/api/viewsets/bot/filters.py
+++ b/pydis_site/apps/api/viewsets/bot/filters.py
@@ -1,10 +1,10 @@
from rest_framework.viewsets import ModelViewSet
-from pydis_site.apps.api.models.bot.filters import ( # noqa: I101 - Preserving the filter order
+from pydis_site.apps.api.models.bot.filters import ( # - Preserving the filter order
FilterList,
Filter
)
-from pydis_site.apps.api.serializers import ( # noqa: I101 - Preserving the filter order
+from pydis_site.apps.api.serializers import ( # - Preserving the filter order
FilterListSerializer,
FilterSerializer,
)
diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py
index d0519e86..1774004c 100644
--- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py
+++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py
@@ -85,10 +85,9 @@ class OffTopicChannelNameViewSet(ModelViewSet):
serializer.save()
return Response(create_data, status=HTTP_201_CREATED)
- else:
- raise ParseError(detail={
- 'name': ["This query parameter is required."]
- })
+ raise ParseError(detail={
+ 'name': ["This query parameter is required."]
+ })
def list(self, request: Request, *args, **kwargs) -> Response:
"""
diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py
index db73a83c..88fa3415 100644
--- a/pydis_site/apps/api/viewsets/bot/user.py
+++ b/pydis_site/apps/api/viewsets/bot/user.py
@@ -1,4 +1,3 @@
-import typing
from collections import OrderedDict
from django.db.models import Q
@@ -24,14 +23,14 @@ class UserListPagination(PageNumberPagination):
page_size = 2500
page_size_query_param = "page_size"
- def get_next_page_number(self) -> typing.Optional[int]:
+ def get_next_page_number(self) -> int | None:
"""Get the next page number."""
if not self.page.has_next():
return None
page_number = self.page.next_page_number()
return page_number
- def get_previous_page_number(self) -> typing.Optional[int]:
+ def get_previous_page_number(self) -> int | None:
"""Get the previous page number."""
if not self.page.has_previous():
return None
diff --git a/pydis_site/apps/content/models/tag.py b/pydis_site/apps/content/models/tag.py
index 1a20d775..7c49902f 100644
--- a/pydis_site/apps/content/models/tag.py
+++ b/pydis_site/apps/content/models/tag.py
@@ -30,8 +30,7 @@ class Commit(models.Model):
def lines(self) -> collections.abc.Iterable[str]:
"""Return each line in the commit message."""
- for line in self.message.split("\n"):
- yield line
+ yield from self.message.split("\n")
def format_authors(self) -> collections.abc.Iterable[str]:
"""Return a nice representation of the author(s)' name and email."""
diff --git a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/linting.md b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/linting.md
index f6f8a5f2..b634f513 100644
--- a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/linting.md
+++ b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/linting.md
@@ -4,7 +4,7 @@ description: A guide for linting and setting up pre-commit.
---
Your commit will be rejected by the build server if it fails to lint.
-On most of our projects, we use `flake8` and `pre-commit` to ensure that the code style is consistent across the code base.
+On most of our projects, we use `ruff` and `pre-commit` to ensure that the code style is consistent across the code base.
`pre-commit` is a powerful tool that helps you automatically lint before you commit.
If the linter complains, the commit is aborted so that you can fix the linting errors before committing again.
diff --git a/pydis_site/apps/content/tests/helpers.py b/pydis_site/apps/content/tests/helpers.py
index fad91050..0e7562e8 100644
--- a/pydis_site/apps/content/tests/helpers.py
+++ b/pydis_site/apps/content/tests/helpers.py
@@ -62,19 +62,19 @@ class MockPagesTestCase(TestCase):
├── not_a_page.md
├── tmp.md
├── tmp
- |   ├── _info.yml
- |   └── category
- |    ├── _info.yml
- |      └── subcategory_without_info
+ | ├── _info.yml
+ | └── category
+ | ├── _info.yml
+ | └── subcategory_without_info
└── category
-    ├── _info.yml
-    ├── with_metadata.md
-    └── subcategory
-    ├── with_metadata.md
-       └── without_metadata.md
+ ├── _info.yml
+ ├── with_metadata.md
+ └── subcategory
+ ├── with_metadata.md
+ └── without_metadata.md
"""
- def setUp(self):
+ def setUp(self) -> None:
"""Create the fake filesystem."""
Path(f"{BASE_PATH}/_info.yml").write_text(CATEGORY_INFO)
Path(f"{BASE_PATH}/root.md").write_text(MARKDOWN_WITH_METADATA)
diff --git a/pydis_site/apps/content/urls.py b/pydis_site/apps/content/urls.py
index a7695a27..baae154d 100644
--- a/pydis_site/apps/content/urls.py
+++ b/pydis_site/apps/content/urls.py
@@ -8,7 +8,7 @@ from . import utils, views
app_name = "content"
-def __get_all_files(root: Path, folder: typing.Optional[Path] = None) -> list[str]:
+def __get_all_files(root: Path, folder: Path | None = None) -> list[str]:
"""Find all folders and markdown files recursively starting from `root`."""
if not folder:
folder = root
diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py
index c12893ef..347640dd 100644
--- a/pydis_site/apps/content/utils.py
+++ b/pydis_site/apps/content/utils.py
@@ -151,8 +151,11 @@ def set_tag_commit(tag: Tag) -> None:
commit = data["commit"]
author, committer = commit["author"], commit["committer"]
- date = datetime.datetime.strptime(committer["date"], settings.GITHUB_TIMESTAMP_FORMAT)
- date = date.replace(tzinfo=datetime.timezone.utc)
+ date = (
+ datetime.datetime
+ .strptime(committer["date"], settings.GITHUB_TIMESTAMP_FORMAT)
+ .replace(tzinfo=datetime.timezone.utc)
+ )
if author["email"] == committer["email"]:
authors = [author]
@@ -212,9 +215,8 @@ def get_tags() -> list[Tag]:
record_tags(tags)
return tags
- else:
- # Get tags from database
- return list(Tag.objects.all())
+
+ return list(Tag.objects.all())
def get_tag(path: str, *, skip_sync: bool = False) -> Tag | list[Tag]:
@@ -242,13 +244,13 @@ def get_tag(path: str, *, skip_sync: bool = False) -> Tag | list[Tag]:
if tag.last_commit is None and not skip_sync:
set_tag_commit(tag)
return tag
- elif tag.group == name and group is None:
+ elif tag.group == name and group is None: # noqa: RET505
matches.append(tag)
if matches:
return matches
- raise Tag.DoesNotExist()
+ raise Tag.DoesNotExist
def get_tag_category(tags: list[Tag] | None = None, *, collapse_groups: bool) -> dict[str, dict]:
diff --git a/pydis_site/apps/content/views/tags.py b/pydis_site/apps/content/views/tags.py
index 4f4bb5a2..8d3e3321 100644
--- a/pydis_site/apps/content/views/tags.py
+++ b/pydis_site/apps/content/views/tags.py
@@ -1,5 +1,4 @@
import re
-import typing
import frontmatter
import markdown
@@ -22,7 +21,7 @@ COMMAND_REGEX = re.compile(r"`*!tags? (?P<first>[\w-]+)(?P<second> [\w-]+)?`*")
class TagView(TemplateView):
"""Handles tag pages."""
- tag: typing.Union[Tag, list[Tag]]
+ tag: Tag | list[Tag]
is_group: bool
def setup(self, *args, **kwargs) -> None:
diff --git a/pydis_site/apps/events/urls.py b/pydis_site/apps/events/urls.py
index 7ea65a31..6121d264 100644
--- a/pydis_site/apps/events/urls.py
+++ b/pydis_site/apps/events/urls.py
@@ -8,7 +8,7 @@ from pydis_site.apps.events.views import IndexView, PageView
app_name = "events"
-def __get_all_files(root: Path, folder: typing.Optional[Path] = None) -> list[str]:
+def __get_all_files(root: Path, folder: Path | None = None) -> list[str]:
"""Find all folders and HTML files recursively starting from `root`."""
if not folder:
folder = root
diff --git a/pydis_site/apps/events/views/page.py b/pydis_site/apps/events/views/page.py
index 1622ad70..adf9e952 100644
--- a/pydis_site/apps/events/views/page.py
+++ b/pydis_site/apps/events/views/page.py
@@ -1,4 +1,3 @@
-from typing import List
from django.conf import settings
from django.http import Http404
@@ -8,7 +7,7 @@ from django.views.generic import TemplateView
class PageView(TemplateView):
"""Handles event pages showing."""
- def get_template_names(self) -> List[str]:
+ def get_template_names(self) -> list[str]:
"""Get specific template names."""
path: str = self.kwargs['path']
page_path = settings.EVENTS_PAGES_PATH / path
diff --git a/pydis_site/apps/home/tests/test_repodata_helpers.py b/pydis_site/apps/home/tests/test_repodata_helpers.py
index a963f733..acf4a817 100644
--- a/pydis_site/apps/home/tests/test_repodata_helpers.py
+++ b/pydis_site/apps/home/tests/test_repodata_helpers.py
@@ -22,7 +22,7 @@ def mocked_requests_get(*args, **kwargs) -> "MockResponse": # noqa: F821
if args[0] == HomeView.github_api:
json_path = Path(__file__).resolve().parent / "mock_github_api_response.json"
- with open(json_path, 'r') as json_file:
+ with open(json_path) as json_file:
mock_data = json.load(json_file)
return MockResponse(mock_data, 200)
diff --git a/pydis_site/apps/home/views.py b/pydis_site/apps/home/views.py
index 8a165682..bfa9e02d 100644
--- a/pydis_site/apps/home/views.py
+++ b/pydis_site/apps/home/views.py
@@ -1,5 +1,4 @@
import logging
-from typing import Dict, List
import httpx
from django.core.handlers.wsgi import WSGIRequest
@@ -45,7 +44,7 @@ class HomeView(View):
else:
self.headers = {}
- def _get_api_data(self) -> Dict[str, Dict[str, str]]:
+ def _get_api_data(self) -> dict[str, dict[str, str]]:
"""
Call the GitHub API and get information about our repos.
@@ -54,7 +53,7 @@ class HomeView(View):
repo_dict = {}
try:
# Fetch the data from the GitHub API
- api_data: List[dict] = httpx.get(
+ api_data: list[dict] = httpx.get(
self.github_api,
headers=self.headers,
timeout=settings.TIMEOUT_PERIOD
@@ -89,7 +88,7 @@ class HomeView(View):
return repo_dict
- def _get_repo_data(self) -> List[RepositoryMetadata]:
+ def _get_repo_data(self) -> list[RepositoryMetadata]:
"""Build a list of RepositoryMetadata objects that we can use to populate the front page."""
# First off, load the timestamp of the least recently updated entry.
if settings.STATIC_BUILD:
@@ -121,8 +120,7 @@ class HomeView(View):
if settings.STATIC_BUILD:
return data
- else:
- return RepositoryMetadata.objects.bulk_create(data)
+ return RepositoryMetadata.objects.bulk_create(data)
# If the data is stale, we should refresh it.
if (timezone.now() - last_update).seconds > self.repository_cache_ttl:
@@ -149,8 +147,7 @@ class HomeView(View):
return database_repositories
# Otherwise, if the data is fresher than 2 minutes old, we should just return it.
- else:
- return RepositoryMetadata.objects.all()
+ return RepositoryMetadata.objects.all()
def get(self, request: WSGIRequest) -> HttpResponse:
"""Collect repo data and render the homepage view."""
diff --git a/pydis_site/apps/redirect/urls.py b/pydis_site/apps/redirect/urls.py
index 067cccc3..a221ea12 100644
--- a/pydis_site/apps/redirect/urls.py
+++ b/pydis_site/apps/redirect/urls.py
@@ -83,22 +83,21 @@ def map_redirect(name: str, data: Redirect) -> list[URLPattern]:
return paths
+ redirect_path_name = "pages" if new_app_name == "content" else new_app_name
+ if len(data.redirect_arguments) > 0:
+ redirect_arg = data.redirect_arguments[0]
else:
- redirect_path_name = "pages" if new_app_name == "content" else new_app_name
- if len(data.redirect_arguments) > 0:
- redirect_arg = data.redirect_arguments[0]
- else:
- redirect_arg = "resources/"
- new_redirect = f"/{redirect_path_name}/{redirect_arg}"
+ redirect_arg = "resources/"
+ new_redirect = f"/{redirect_path_name}/{redirect_arg}"
- if new_redirect == "/resources/resources/":
- new_redirect = "/resources/"
+ if new_redirect == "/resources/resources/":
+ new_redirect = "/resources/"
- return [distill_path(
- data.original_path,
- lambda *args: HttpResponse(REDIRECT_TEMPLATE.format(url=new_redirect)),
- name=name,
- )]
+ return [distill_path(
+ data.original_path,
+ lambda *args: HttpResponse(REDIRECT_TEMPLATE.format(url=new_redirect)),
+ name=name,
+ )]
urlpatterns = []
diff --git a/pydis_site/apps/redirect/views.py b/pydis_site/apps/redirect/views.py
index 21180cdf..374daf2b 100644
--- a/pydis_site/apps/redirect/views.py
+++ b/pydis_site/apps/redirect/views.py
@@ -1,4 +1,3 @@
-import typing as t
from django.views.generic import RedirectView
@@ -15,7 +14,7 @@ class CustomRedirectView(RedirectView):
"""Overwrites original as_view to add static args."""
return super().as_view(**initkwargs)
- def get_redirect_url(self, *args, **kwargs) -> t.Optional[str]:
+ def get_redirect_url(self, *args, **kwargs) -> str | None:
"""Extends default behaviour to use static args."""
args = self.static_args + args + tuple(kwargs.values())
if self.prefix_redirect:
diff --git a/pydis_site/apps/resources/views.py b/pydis_site/apps/resources/views.py
index 2375f722..a2cd8d0c 100644
--- a/pydis_site/apps/resources/views.py
+++ b/pydis_site/apps/resources/views.py
@@ -1,5 +1,4 @@
import json
-import typing as t
from pathlib import Path
import yaml
@@ -22,7 +21,7 @@ class ResourceView(View):
"""Sort a tuple by its key alphabetically, disregarding 'the' as a prefix."""
name, resource = tuple_
name = name.casefold()
- if name.startswith("the ") or name.startswith("the_"):
+ if name.startswith(("the ", "the_")):
return name[4:]
return name
@@ -48,7 +47,7 @@ class ResourceView(View):
}
for resource_name, resource in self.resources.items():
css_classes = []
- for tag_type in resource_tags.keys():
+ for tag_type in resource_tags:
# Store the tags into `resource_tags`
tags = resource.get("tags", {}).get(tag_type, [])
for tag in tags:
@@ -102,7 +101,7 @@ class ResourceView(View):
"difficulty": [to_kebabcase(tier) for tier in self.filters["Difficulty"]["filters"]],
}
- def get(self, request: WSGIRequest, resource_type: t.Optional[str] = None) -> HttpResponse:
+ def get(self, request: WSGIRequest, resource_type: str | None = None) -> HttpResponse:
"""List out all the resources, and any filtering options from the URL."""
# Add type filtering if the request is made to somewhere like /resources/video.
# We also convert all spaces to dashes, so they'll correspond with the filters.
diff --git a/pydis_site/apps/staff/templatetags/deletedmessage_filters.py b/pydis_site/apps/staff/templatetags/deletedmessage_filters.py
index 9d8f1819..c6638a3b 100644
--- a/pydis_site/apps/staff/templatetags/deletedmessage_filters.py
+++ b/pydis_site/apps/staff/templatetags/deletedmessage_filters.py
@@ -1,5 +1,4 @@
from datetime import datetime
-from typing import Union
from django import template
@@ -7,7 +6,7 @@ register = template.Library()
@register.filter
-def hex_colour(colour: Union[str, int]) -> str:
+def hex_colour(colour: str | int) -> str:
"""
Converts the given representation of a colour to its RGB hex string.
diff --git a/pydis_site/apps/staff/tests/test_deletedmessage_filters.py b/pydis_site/apps/staff/tests/test_deletedmessage_filters.py
index 31215784..5e49f103 100644
--- a/pydis_site/apps/staff/tests/test_deletedmessage_filters.py
+++ b/pydis_site/apps/staff/tests/test_deletedmessage_filters.py
@@ -3,7 +3,7 @@ import enum
from django.test import TestCase
from django.utils import timezone
-from ..templatetags import deletedmessage_filters
+from pydis_site.apps.staff.templatetags import deletedmessage_filters
class Colour(enum.IntEnum):