Fix types
This commit is contained in:
parent
6f6116c3c7
commit
c092d3089f
13 changed files with 48 additions and 18 deletions
|
|
@ -12,7 +12,6 @@ from config import settings
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from collections.abc import Iterator
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
|
||||||
|
|
@ -28,7 +27,7 @@ def reload_settings_module() -> Generator[Callable[..., ModuleType]]:
|
||||||
original_env: dict[str, str] = os.environ.copy()
|
original_env: dict[str, str] = os.environ.copy()
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def temporary_env(env: dict[str, str]) -> Iterator[None]:
|
def temporary_env(env: dict[str, str]) -> Generator[None]:
|
||||||
previous_env: dict[str, str] = os.environ.copy()
|
previous_env: dict[str, str] = os.environ.copy()
|
||||||
os.environ.clear()
|
os.environ.clear()
|
||||||
os.environ.update(env)
|
os.environ.update(env)
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@ if TYPE_CHECKING:
|
||||||
from os import stat_result
|
from os import stat_result
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from debug_toolbar.utils import QueryDict
|
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
from django.http.request import QueryDict
|
||||||
|
|
||||||
|
|
||||||
logger: logging.Logger = logging.getLogger("ttvdrops.views")
|
logger: logging.Logger = logging.getLogger("ttvdrops.views")
|
||||||
|
|
@ -309,7 +309,7 @@ def docs_rss_view(request: HttpRequest) -> HttpResponse:
|
||||||
# Add limit=1 to GET parameters
|
# Add limit=1 to GET parameters
|
||||||
get_data: QueryDict = request.GET.copy()
|
get_data: QueryDict = request.GET.copy()
|
||||||
get_data["limit"] = "1"
|
get_data["limit"] = "1"
|
||||||
limited_request.GET = get_data # pyright: ignore[reportAttributeAccessIssue]
|
limited_request.GET = get_data
|
||||||
|
|
||||||
response: HttpResponse = feed_view(limited_request, *args)
|
response: HttpResponse = feed_view(limited_request, *args)
|
||||||
return _pretty_example(response.content.decode("utf-8"))
|
return _pretty_example(response.content.decode("utf-8"))
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ class KickDropCampaign(auto_prefetch.Model):
|
||||||
"""Return the image URL for the campaign."""
|
"""Return the image URL for the campaign."""
|
||||||
# Image from first drop
|
# Image from first drop
|
||||||
if self.rewards.exists(): # pyright: ignore[reportAttributeAccessIssue]
|
if self.rewards.exists(): # pyright: ignore[reportAttributeAccessIssue]
|
||||||
first_reward: KickReward = self.rewards.first() # pyright: ignore[reportAttributeAccessIssue]
|
first_reward: KickReward | None = self.rewards.first() # pyright: ignore[reportAttributeAccessIssue]
|
||||||
if first_reward and first_reward.image_url:
|
if first_reward and first_reward.image_url:
|
||||||
return first_reward.full_image_url
|
return first_reward.full_image_url
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,8 @@ class ImportKickDropsCommandTest(TestCase):
|
||||||
campaign: KickDropCampaign = KickDropCampaign.objects.get()
|
campaign: KickDropCampaign = KickDropCampaign.objects.get()
|
||||||
assert campaign.name == "PUBG 9th Anniversary"
|
assert campaign.name == "PUBG 9th Anniversary"
|
||||||
assert campaign.status == "active"
|
assert campaign.status == "active"
|
||||||
|
assert campaign.organization is not None
|
||||||
|
assert campaign.category is not None
|
||||||
assert campaign.organization.name == "KRAFTON"
|
assert campaign.organization.name == "KRAFTON"
|
||||||
assert campaign.category.name == "PUBG: Battlegrounds"
|
assert campaign.category.name == "PUBG: Battlegrounds"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,9 @@ class TTVDropsAtomBaseFeed(TTVDropsBaseFeed):
|
||||||
feed_type = BrowserFriendlyAtom1Feed
|
feed_type = BrowserFriendlyAtom1Feed
|
||||||
|
|
||||||
|
|
||||||
def _with_campaign_related(queryset: QuerySet[DropCampaign]) -> QuerySet[DropCampaign]:
|
def _with_campaign_related(
|
||||||
|
queryset: QuerySet[DropCampaign, DropCampaign],
|
||||||
|
) -> QuerySet[DropCampaign, DropCampaign]:
|
||||||
"""Apply related-selects/prefetches needed by feed rendering to avoid N+1 queries.
|
"""Apply related-selects/prefetches needed by feed rendering to avoid N+1 queries.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
||||||
|
|
@ -631,6 +631,9 @@ class Command(BaseCommand):
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if game_obj.box_art_file is None:
|
||||||
|
return
|
||||||
|
|
||||||
game_obj.box_art_file.save(file_name, ContentFile(response.content), save=True)
|
game_obj.box_art_file.save(file_name, ContentFile(response.content), save=True)
|
||||||
|
|
||||||
def _get_or_create_channel(self, channel_info: ChannelInfoSchema) -> Channel:
|
def _get_or_create_channel(self, channel_info: ChannelInfoSchema) -> Channel:
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ from twitch.models import Game
|
||||||
from twitch.models import Organization
|
from twitch.models import Organization
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from debug_toolbar.panels.templates.panel import QuerySet
|
|
||||||
from django.core.management.base import CommandParser
|
from django.core.management.base import CommandParser
|
||||||
|
from django.db.models import QuerySet
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class Command(BaseCommand):
|
||||||
help="Re-download even if a local box art file already exists.",
|
help="Re-download even if a local box art file already exists.",
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle(self, *_args: object, **options: object) -> None:
|
def handle(self, *_args: object, **options: object) -> None: # noqa: PLR0914
|
||||||
"""Download Twitch box art images for all games."""
|
"""Download Twitch box art images for all games."""
|
||||||
limit_value: object | None = options.get("limit")
|
limit_value: object | None = options.get("limit")
|
||||||
limit: int | None = limit_value if isinstance(limit_value, int) else None
|
limit: int | None = limit_value if isinstance(limit_value, int) else None
|
||||||
|
|
@ -92,6 +92,10 @@ class Command(BaseCommand):
|
||||||
skipped += 1
|
skipped += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if game.box_art_file is None:
|
||||||
|
failed += 1
|
||||||
|
continue
|
||||||
|
|
||||||
game.box_art_file.save(
|
game.box_art_file.save(
|
||||||
file_name,
|
file_name,
|
||||||
ContentFile(response.content),
|
ContentFile(response.content),
|
||||||
|
|
@ -99,7 +103,9 @@ class Command(BaseCommand):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Auto-convert to WebP and AVIF
|
# Auto-convert to WebP and AVIF
|
||||||
self._convert_to_modern_formats(game.box_art_file.path)
|
box_art_path: str | None = getattr(game.box_art_file, "path", None)
|
||||||
|
if box_art_path:
|
||||||
|
self._convert_to_modern_formats(box_art_path)
|
||||||
|
|
||||||
downloaded += 1
|
downloaded += 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ class Command(BaseCommand):
|
||||||
client: httpx.Client,
|
client: httpx.Client,
|
||||||
image_url: str,
|
image_url: str,
|
||||||
twitch_id: str,
|
twitch_id: str,
|
||||||
file_field: FieldFile,
|
file_field: FieldFile | None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Download a single image and save it to the file field.
|
"""Download a single image and save it to the file field.
|
||||||
|
|
||||||
|
|
@ -281,6 +281,9 @@ class Command(BaseCommand):
|
||||||
suffix: str = Path(parsed_url.path).suffix or ".jpg"
|
suffix: str = Path(parsed_url.path).suffix or ".jpg"
|
||||||
file_name: str = f"{twitch_id}{suffix}"
|
file_name: str = f"{twitch_id}{suffix}"
|
||||||
|
|
||||||
|
if file_field is None:
|
||||||
|
return "failed"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response: httpx.Response = client.get(image_url)
|
response: httpx.Response = client.get(image_url)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
@ -299,7 +302,9 @@ class Command(BaseCommand):
|
||||||
file_field.save(file_name, ContentFile(response.content), save=True)
|
file_field.save(file_name, ContentFile(response.content), save=True)
|
||||||
|
|
||||||
# Auto-convert to WebP and AVIF
|
# Auto-convert to WebP and AVIF
|
||||||
self._convert_to_modern_formats(file_field.path)
|
image_path: str | None = getattr(file_field, "path", None)
|
||||||
|
if image_path:
|
||||||
|
self._convert_to_modern_formats(image_path)
|
||||||
|
|
||||||
return "downloaded"
|
return "downloaded"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,7 @@ class RSSFeedTestCase(TestCase):
|
||||||
def test_campaign_and_game_feeds_use_absolute_media_enclosure_urls(self) -> None:
|
def test_campaign_and_game_feeds_use_absolute_media_enclosure_urls(self) -> None:
|
||||||
"""Campaign/game RSS+Atom enclosures should use absolute URLs for local media files."""
|
"""Campaign/game RSS+Atom enclosures should use absolute URLs for local media files."""
|
||||||
self.game.box_art = ""
|
self.game.box_art = ""
|
||||||
|
assert self.game.box_art_file is not None
|
||||||
self.game.box_art_file.save(
|
self.game.box_art_file.save(
|
||||||
"box.png",
|
"box.png",
|
||||||
ContentFile(b"game-image-bytes"),
|
ContentFile(b"game-image-bytes"),
|
||||||
|
|
@ -289,6 +290,7 @@ class RSSFeedTestCase(TestCase):
|
||||||
self.game.save()
|
self.game.save()
|
||||||
|
|
||||||
self.campaign.image_url = ""
|
self.campaign.image_url = ""
|
||||||
|
assert self.campaign.image_file is not None
|
||||||
self.campaign.image_file.save(
|
self.campaign.image_file.save(
|
||||||
"campaign.png",
|
"campaign.png",
|
||||||
ContentFile(b"campaign-image-bytes"),
|
ContentFile(b"campaign-image-bytes"),
|
||||||
|
|
@ -712,6 +714,7 @@ class RSSFeedTestCase(TestCase):
|
||||||
name="File Game",
|
name="File Game",
|
||||||
display_name="File Game",
|
display_name="File Game",
|
||||||
)
|
)
|
||||||
|
assert game2.box_art_file is not None
|
||||||
game2.box_art_file.save("sample.png", ContentFile(b"hello"))
|
game2.box_art_file.save("sample.png", ContentFile(b"hello"))
|
||||||
game2.save()
|
game2.save()
|
||||||
|
|
||||||
|
|
@ -723,6 +726,7 @@ class RSSFeedTestCase(TestCase):
|
||||||
end_at=timezone.now() + timedelta(days=1),
|
end_at=timezone.now() + timedelta(days=1),
|
||||||
operation_names=["DropCampaignDetails"],
|
operation_names=["DropCampaignDetails"],
|
||||||
)
|
)
|
||||||
|
assert campaign2.image_file is not None
|
||||||
campaign2.image_file.save("camp.jpg", ContentFile(b"world"))
|
campaign2.image_file.save("camp.jpg", ContentFile(b"world"))
|
||||||
campaign2.save()
|
campaign2.save()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1067,9 +1067,18 @@ class TestSEOHelperFunctions:
|
||||||
def test_build_seo_context_with_all_parameters(self) -> None:
|
def test_build_seo_context_with_all_parameters(self) -> None:
|
||||||
"""Test _build_seo_context with all parameters."""
|
"""Test _build_seo_context with all parameters."""
|
||||||
now: datetime.datetime = timezone.now()
|
now: datetime.datetime = timezone.now()
|
||||||
breadcrumb: list[dict[str, int | str]] = [
|
breadcrumb: dict[str, Any] = {
|
||||||
{"position": 1, "name": "Home", "url": "/"},
|
"@context": "https://schema.org",
|
||||||
]
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{
|
||||||
|
"@type": "ListItem",
|
||||||
|
"position": 1,
|
||||||
|
"name": "Home",
|
||||||
|
"item": "/",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
context: dict[str, Any] = _build_seo_context(
|
context: dict[str, Any] = _build_seo_context(
|
||||||
page_title="Test",
|
page_title="Test",
|
||||||
|
|
@ -1077,7 +1086,7 @@ class TestSEOHelperFunctions:
|
||||||
page_image="https://example.com/img.jpg",
|
page_image="https://example.com/img.jpg",
|
||||||
og_type="article",
|
og_type="article",
|
||||||
schema_data={},
|
schema_data={},
|
||||||
breadcrumb_schema=breadcrumb, # pyright: ignore[reportArgumentType]
|
breadcrumb_schema=breadcrumb,
|
||||||
pagination_info=[{"rel": "next", "url": "/page/2/"}],
|
pagination_info=[{"rel": "next", "url": "/page/2/"}],
|
||||||
published_date=now.isoformat(),
|
published_date=now.isoformat(),
|
||||||
modified_date=now.isoformat(),
|
modified_date=now.isoformat(),
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ def normalize_twitch_box_art_url(url: str) -> str:
|
||||||
return url
|
return url
|
||||||
|
|
||||||
normalized_path: str = TWITCH_BOX_ART_SIZE_PATTERN.sub("", parsed.path)
|
normalized_path: str = TWITCH_BOX_ART_SIZE_PATTERN.sub("", parsed.path)
|
||||||
return urlunparse(parsed._replace(path=normalized_path))
|
return str(urlunparse(parsed._replace(path=normalized_path)))
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=40 * 40 * 1024)
|
@lru_cache(maxsize=40 * 40 * 1024)
|
||||||
|
|
|
||||||
|
|
@ -1396,7 +1396,7 @@ def reward_campaign_detail_view(request: HttpRequest, twitch_id: str) -> HttpRes
|
||||||
class GamesListView(GamesGridView):
|
class GamesListView(GamesGridView):
|
||||||
"""List view for games in simple list format."""
|
"""List view for games in simple list format."""
|
||||||
|
|
||||||
template_name: str = "twitch/games_list.html"
|
template_name: str | None = "twitch/games_list.html"
|
||||||
|
|
||||||
|
|
||||||
# MARK: /channels/
|
# MARK: /channels/
|
||||||
|
|
@ -1748,7 +1748,7 @@ def badge_set_detail_view(request: HttpRequest, set_id: str) -> HttpResponse:
|
||||||
)
|
)
|
||||||
return ChatBadge.objects.filter(pk__in=badge_ids).order_by(preserved_order)
|
return ChatBadge.objects.filter(pk__in=badge_ids).order_by(preserved_order)
|
||||||
|
|
||||||
badges = get_sorted_badges(badge_set)
|
badges: QuerySet[ChatBadge, ChatBadge] = get_sorted_badges(badge_set)
|
||||||
|
|
||||||
# Attach award_campaigns attribute to each badge for template use
|
# Attach award_campaigns attribute to each badge for template use
|
||||||
for badge in badges:
|
for badge in badges:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue