Skip to content

Commit c738772

Browse files
authored
Merge pull request #286 from VirtualLiveLab/sushichan044-202603241246-py313
feat: use Python3.13
2 parents 140578c + a12a697 commit c738772

12 files changed

Lines changed: 41 additions & 464 deletions

File tree

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.11
1+
3.13

Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
FROM python:3.11-bookworm AS builder
1+
# syntax=docker/dockerfile:1
2+
# check=error=true
3+
4+
FROM python:3.13-slim-trixie AS builder
25

36
WORKDIR /app
47
ENV UV_SYSTEM_PYTHON=true \
@@ -7,16 +10,16 @@ ENV UV_SYSTEM_PYTHON=true \
710
UV_LINK_MODE=copy
811

912
# Install dependencies
10-
RUN --mount=from=ghcr.io/astral-sh/uv:0.4.17,source=/uv,target=/bin/uv \
13+
RUN --mount=from=ghcr.io/astral-sh/uv:0.11.0,source=/uv,target=/bin/uv \
1114
--mount=type=cache,target=${UV_CACHE_DIR} \
1215
--mount=type=bind,source=uv.lock,target=uv.lock \
1316
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
1417
uv export --frozen --no-dev --format requirements-txt > requirements.txt \
1518
&& uv pip install -r requirements.txt --target /app/.uv-pip/site-packages
1619

1720
# https://github.com/GoogleContainerTools/distroless/blob/main/python3/BUILD
18-
# distroless/python3-debian12のPythonは3.11
19-
FROM gcr.io/distroless/python3-debian12:nonroot AS runner
21+
# distroless/python3-debian13のPythonは3.13
22+
FROM gcr.io/distroless/python3-debian13:nonroot AS runner
2023
WORKDIR /app
2124

2225
# distrolessのPythonはデフォルトではsite-packagesを参照しない

pyproject.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ dependencies = [
1111
"asyncer>=0.0.8",
1212
"result>=0.17.0",
1313
"notion-client>=2.5.0",
14-
"glom>=25.12.0"
14+
"glom>=25.12.0",
1515
]
1616
readme = "README.md"
17-
requires-python = ">= 3.11"
17+
requires-python = ">= 3.13"
1818

1919
[dependency-groups]
2020
dev = ["mypy>=1.17.1", "python-dotenv>=1.2.2", "ruff>=0.13.2"]
@@ -29,7 +29,7 @@ package = false
2929

3030
[tool.ruff]
3131
# https://qiita.com/yuji38kwmt/items/63e82126076204923520
32-
target-version = "py311"
32+
target-version = "py313"
3333
line-length = 125
3434

3535
[tool.ruff.lint]
@@ -43,7 +43,6 @@ ignore = [
4343
"ERA", # : 役立つこともあるが、コメントアウトしていないコードも警告されるので無視する
4444
"COM812", # recommended by ruff formatter
4545
"ISC001", # recommended by ruff formatter
46-
"UP040", # discord.py can not understand new type syntax
4746
]
4847
select = ["ALL"]
4948

@@ -69,7 +68,7 @@ line-ending = "auto"
6968

7069

7170
[tool.mypy]
72-
python_version = "3.11"
71+
python_version = "3.13"
7372
exclude = [".venv"]
7473
follow_imports = "normal"
7574
warn_redundant_casts = true

src/app/core/chat/cog.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import asyncio
22
import secrets
3-
from typing import TYPE_CHECKING, Literal, TypeAlias
3+
from typing import TYPE_CHECKING, Literal
44

55
import discord
66
from discord import app_commands
@@ -50,7 +50,7 @@ async def call_miku(self, interaction: discord.Interaction) -> None:
5050
await interaction.followup.send("MIKU!")
5151

5252

53-
OmikujiResult: TypeAlias = Literal["大吉", "中吉", "小吉", "吉", "末吉", "凶", "大凶"]
53+
type OmikujiResult = Literal["大吉", "中吉", "小吉", "吉", "末吉", "凶", "大凶"]
5454
OMKIJI_RESULT_DICT: dict[OmikujiResult, str] = {
5555
"大吉": "大吉だよ!",
5656
"中吉": "中吉だよ!",

src/app/help/const.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from typing import Literal, TypeAlias
1+
from typing import Literal
22

3-
FeatureLabel: TypeAlias = Literal["メッセージ展開", "投票", "その他", "ヘルプ"]
3+
type FeatureLabel = Literal["メッセージ展開", "投票", "その他", "ヘルプ"]
44
FEATURE_LABEL_LIST: list[FeatureLabel] = [
55
"メッセージ展開",
66
"投票",

src/app/vote/manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
from typing import Annotated, TypeAlias
1+
from typing import Annotated
22
from uuid import uuid4
33

44
from pydantic import UUID4, BaseModel, Field
55

6-
OptionId: TypeAlias = Annotated[UUID4, "OptionId"]
7-
VotedUserId: TypeAlias = Annotated[int, "VotedUserId"]
6+
type OptionId = Annotated[UUID4, "OptionId"]
7+
type VotedUserId = Annotated[int, "VotedUserId"]
88

99

1010
class VoteOption(BaseModel):

src/app/wol/fn.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import os
22
from enum import Enum
3-
from typing import Literal, TypeAlias, TypedDict
3+
from typing import Literal, TypedDict
44

55
import aiohttp
66

77
# https://www.notion.so/virtual-live-lab/ddf6d9708a2e45469f675c37e6d09e28
8-
ComputerType: TypeAlias = Literal["left", "right", "stream"]
8+
type ComputerType = Literal["left", "right", "stream"]
99

1010

1111
class ComputerStatus(TypedDict):

src/packages/url_extractor/extractor.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import TYPE_CHECKING, Generic, LiteralString, TypeVar
1+
from typing import TYPE_CHECKING, LiteralString
22

33
from asyncer import asyncify
44
from result import Err, Ok
@@ -12,25 +12,22 @@
1212

1313
from result import Result
1414

15-
_K = TypeVar("_K", bound=LiteralString)
16-
_PLUGIN = TypeVar("_PLUGIN", bound=IUrlExtractorPlugin)
1715

18-
19-
class UrlExtractor(Generic[_K, _PLUGIN]):
16+
class UrlExtractor[K: LiteralString, PLUGIN: IUrlExtractorPlugin]:
2017
"""A class for extracting URLs using plugins."""
2118

22-
def __init__(self, plugins: dict[_K, _PLUGIN], /) -> None:
19+
def __init__(self, plugins: dict[K, PLUGIN], /) -> None:
2320
self.__plugins = {k: InternalPlugin(k, p, index=i) for i, (k, p) in enumerate(plugins.items())}
2421
self.__logger = get_my_logger(self.__class__.__name__)
2522

26-
def find_all(self, string: str) -> "dict[_K, set[Match[str]] | None]":
23+
def find_all(self, string: str) -> "dict[K, set[Match[str]] | None]":
2724
"""Find all occurrences of URLs in the given string using the registered plugins.
2825
2926
Args:
3027
string `str`: The input string to search for URLs.
3128
3229
Returns:
33-
`dict[_K, set[Match[str]] | None]`: A dictionary containing the plugin keys as keys and
30+
`dict[K, set[Match[str]] | None]`: A dictionary containing the plugin keys as keys and
3431
a set of matches or None as values. Each set of matches represents the URLs found
3532
by the corresponding plugin.
3633
"""
@@ -39,14 +36,14 @@ def find_all(self, string: str) -> "dict[_K, set[Match[str]] | None]":
3936
for k, plugin in self.__plugins.items()
4037
}
4138

42-
async def find_all_async(self, string: str) -> "dict[_K, set[Match[str]] | None]":
39+
async def find_all_async(self, string: str) -> "dict[K, set[Match[str]] | None]":
4340
"""Find all occurrences of URLs in the given string using the registered plugins asynchronously.
4441
4542
Args:
4643
string `str`: The input string to search for URLs.
4744
4845
Returns:
49-
`dict[_K, set[Match[str]] | None]`: A dictionary containing the plugin keys as keys and
46+
`dict[K, set[Match[str]] | None]`: A dictionary containing the plugin keys as keys and
5047
a set of matches or None as values. Each set of matches represents the URLs found
5148
by the corresponding plugin.
5249
"""

src/packages/url_extractor/internal/interface.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
from abc import ABC, abstractmethod
2-
from typing import TYPE_CHECKING, Generic, TypeVar
2+
from typing import TYPE_CHECKING
33

44
if TYPE_CHECKING:
55
from collections.abc import Iterable
66
from re import Match, Pattern
77

8-
_R = TypeVar("_R")
9-
108

119
class IUrlExtractorPlugin(ABC):
1210
"""
@@ -21,26 +19,26 @@ def url_pattern(self) -> "Pattern[str] | str":
2119
raise NotImplementedError
2220

2321

24-
class IUrlSyncProcessor(ABC, Generic[_R]):
22+
class IUrlSyncProcessor[R](ABC):
2523
"""
2624
Interface for URL processors.
2725
"""
2826

2927
@abstractmethod
30-
def from_matches_sync(self, matches: "Iterable[Match[str]]") -> list[_R]:
28+
def from_matches_sync(self, matches: "Iterable[Match[str]]") -> list[R]:
3129
"""
3230
Extracts information from the given matches.
3331
"""
3432
raise NotImplementedError
3533

3634

37-
class IUrlAsyncProcessor(ABC, Generic[_R]):
35+
class IUrlAsyncProcessor[R](ABC):
3836
"""
3937
Interface for URL processors. For asynchronous processing.
4038
"""
4139

4240
@abstractmethod
43-
async def from_matches_async(self, matches: "Iterable[Match[str]]") -> list[_R]:
41+
async def from_matches_async(self, matches: "Iterable[Match[str]]") -> list[R]:
4442
"""
4543
Extracts information from the given matches.
4644
"""

src/utils/chunk.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
from collections.abc import Generator, Iterable
2-
from typing import LiteralString, TypeVar
2+
from typing import LiteralString
33

4-
_T = TypeVar("_T")
54

6-
7-
def chunks(iterable: list[_T], *, size: int) -> Generator[list[_T], None, None]:
5+
def chunks[T](iterable: list[T], *, size: int) -> Generator[list[T]]:
86
"""Yield successive chunks from iterable of size."""
97
for i in range(0, len(iterable), size):
108
yield iterable[i : i + size]
@@ -31,7 +29,7 @@ def chunk_str_iter_with_max_length(
3129
max_length: int,
3230
separator: LiteralString,
3331
ignore_oversize_fragment: bool = True,
34-
) -> Generator[str, None, None]:
32+
) -> Generator[str]:
3533
"""
3634
Chunk the iterable of strings into strings with a maximum length.
3735

0 commit comments

Comments
 (0)