⬆️ upgrade Pydantic to V2

This commit is contained in:
omg-xtao 2024-11-30 22:31:42 +08:00 committed by GitHub
parent 6d9f07d1ba
commit 682cfb1f0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 612 additions and 488 deletions

View File

@ -1,7 +1,6 @@
import datetime import datetime
from typing import List from typing import List
from pytz import timezone
from simnet.models.starrail.chronicle.challenge import StarRailChallenge from simnet.models.starrail.chronicle.challenge import StarRailChallenge
from simnet.models.starrail.chronicle.challenge_boss import StarRailChallengeBoss, StarRailChallengeBossGroup from simnet.models.starrail.chronicle.challenge_boss import StarRailChallengeBoss, StarRailChallengeBossGroup
from simnet.models.starrail.chronicle.challenge_story import StarRailChallengeStory, StarRailChallengeStoryGroup from simnet.models.starrail.chronicle.challenge_story import StarRailChallengeStory, StarRailChallengeStoryGroup
@ -32,14 +31,6 @@ __all__ = (
"HistoryDataLedgerServices", "HistoryDataLedgerServices",
) )
TZ = timezone("Asia/Shanghai")
def json_encoder(value):
if isinstance(value, datetime.datetime):
return value.astimezone(TZ).strftime("%Y-%m-%d %H:%M:%S")
return value
class HistoryDataAbyssServices(BaseService, HistoryDataBaseServices): class HistoryDataAbyssServices(BaseService, HistoryDataBaseServices):
DATA_TYPE = HistoryDataTypeEnum.ABYSS.value DATA_TYPE = HistoryDataTypeEnum.ABYSS.value
@ -52,7 +43,7 @@ class HistoryDataAbyssServices(BaseService, HistoryDataBaseServices):
@staticmethod @staticmethod
def create(user_id: int, abyss_data: StarRailChallenge): def create(user_id: int, abyss_data: StarRailChallenge):
data = HistoryDataAbyss(abyss_data=abyss_data) data = HistoryDataAbyss(abyss_data=abyss_data)
json_data = data.json(by_alias=True, encoder=json_encoder) json_data = data.model_dump_json(by_alias=True)
return HistoryData( return HistoryData(
user_id=user_id, user_id=user_id,
data_id=abyss_data.season, data_id=abyss_data.season,
@ -73,7 +64,7 @@ class HistoryDataChallengeStoryServices(BaseService, HistoryDataBaseServices):
@staticmethod @staticmethod
def create(user_id: int, story_data: StarRailChallengeStory, group: StarRailChallengeStoryGroup): def create(user_id: int, story_data: StarRailChallengeStory, group: StarRailChallengeStoryGroup):
data = HistoryDataChallengeStory(story_data=story_data, group=group) data = HistoryDataChallengeStory(story_data=story_data, group=group)
json_data = data.json(by_alias=True, encoder=json_encoder) json_data = data.model_dump_json(by_alias=True)
dict_data = jsonlib.loads(json_data) dict_data = jsonlib.loads(json_data)
dict_data["story_data"]["groups"] = [] dict_data["story_data"]["groups"] = []
return HistoryData( return HistoryData(
@ -105,7 +96,7 @@ class HistoryDataChallengeBossServices(BaseService, HistoryDataBaseServices):
@staticmethod @staticmethod
def create(user_id: int, boss_data: StarRailChallengeBoss, group: StarRailChallengeBossGroup): def create(user_id: int, boss_data: StarRailChallengeBoss, group: StarRailChallengeBossGroup):
data = HistoryDataChallengeBoss(boss_data=boss_data, group=group) data = HistoryDataChallengeBoss(boss_data=boss_data, group=group)
json_data = data.json(by_alias=True, encoder=json_encoder) json_data = data.model_dump_json(by_alias=True)
dict_data = jsonlib.loads(json_data) dict_data = jsonlib.loads(json_data)
dict_data["boss_data"]["groups"] = [] dict_data["boss_data"]["groups"] = []
return HistoryData( return HistoryData(
@ -123,7 +114,7 @@ class HistoryDataLedgerServices(BaseService, HistoryDataBaseServices):
@staticmethod @staticmethod
def create(user_id: int, diary_data: StarRailDiary): def create(user_id: int, diary_data: StarRailDiary):
data = HistoryDataLedger(diary_data=diary_data) data = HistoryDataLedger(diary_data=diary_data)
json_data = data.json(by_alias=True, encoder=json_encoder) json_data = data.model_dump_json(by_alias=True)
return HistoryData( return HistoryData(
user_id=user_id, user_id=user_id,
data_id=diary_data.data_id, data_id=diary_data.data_id,

View File

@ -51,7 +51,7 @@ class WeaponEntry(BaseEntry):
class WeaponsEntry(BaseModel): class WeaponsEntry(BaseModel):
data: Optional[List[WeaponEntry]] data: Optional[List[WeaponEntry]] = None
class StrategyEntry(BaseEntry): class StrategyEntry(BaseEntry):
@ -70,4 +70,4 @@ class StrategyEntry(BaseEntry):
class StrategyEntryList(BaseModel): class StrategyEntryList(BaseModel):
data: Optional[List[StrategyEntry]] data: Optional[List[StrategyEntry]] = None

@ -1 +1 @@
Subproject commit 112b2e92d8492df17dbae23024fa805e3510a56e Subproject commit bf5b153001defd150d4dcc17b9baf06a3769adf0

View File

@ -37,7 +37,7 @@ class Relic(BaseModel):
tid: int tid: int
level: Optional[int] = 0 level: Optional[int] = 0
mainAffixId: int mainAffixId: int
subAffixList: Optional[List[SubAffix]] subAffixList: Optional[List[SubAffix]] = None
type: int type: int
@ -57,12 +57,12 @@ class Property(BaseModel):
class Avatar(BaseModel): class Avatar(BaseModel):
avatarId: int avatarId: int
skillTreeList: List[SkillTreePoint] skillTreeList: List[SkillTreePoint]
equipment: Optional[Equipment] equipment: Optional[Equipment] = None
level: int level: int
promotion: Optional[int] = 4 promotion: Optional[int] = 4
rank: Optional[int] = 0 rank: Optional[int] = 0
relicList: Optional[List[Relic]] relicList: Optional[List[Relic]] = None
property: Optional[List[Property]] property: Optional[List[Property]] = None
class RecordInfo(BaseModel): class RecordInfo(BaseModel):
@ -76,15 +76,15 @@ class RecordInfo(BaseModel):
class PlayerBaseInfo(BaseModel): class PlayerBaseInfo(BaseModel):
platform: Optional[str] platform: Optional[str] = None
friendCount: Optional[int] friendCount: Optional[int] = None
headIcon: Optional[int] headIcon: Optional[int] = None
isDisplayAvatar: bool isDisplayAvatar: bool
level: int level: int
worldLevel: Optional[int] worldLevel: Optional[int] = None
nickname: str nickname: str
recordInfo: RecordInfo recordInfo: RecordInfo
signature: Optional[str] signature: Optional[str] = None
uid: int uid: int

View File

@ -1,6 +1,6 @@
from typing import List, Optional, Any from typing import List, Optional, Any
from pydantic import BaseModel, validator from pydantic import field_validator, BaseModel
__all__ = ("Member", "TeamRate", "FullTeamRate", "TeamRateResult") __all__ = ("Member", "TeamRate", "FullTeamRate", "TeamRateResult")
@ -14,9 +14,10 @@ class Member(BaseModel):
class TeamRate(BaseModel): class TeamRate(BaseModel):
rate: float rate: float
formation: List[Member] formation: List[Member]
owner_num: Optional[int] owner_num: Optional[int] = None
@validator("rate", pre=True) @field_validator("rate", mode="before")
@classmethod
def str2float(cls, v): # pylint: disable=R0201 def str2float(cls, v): # pylint: disable=R0201
return float(v.replace("%", "")) / 100.0 if isinstance(v, str) else v return float(v.replace("%", "")) / 100.0 if isinstance(v, str) else v
@ -24,8 +25,8 @@ class TeamRate(BaseModel):
class FullTeamRate(BaseModel): class FullTeamRate(BaseModel):
up: TeamRate up: TeamRate
down: TeamRate down: TeamRate
owner_num: Optional[int] owner_num: Optional[int] = None
nice: Optional[float] nice: Optional[float] = None
@property @property
def rate(self) -> float: def rate(self) -> float:

View File

@ -1,6 +1,6 @@
from datetime import datetime from datetime import datetime
from pydantic import BaseModel, validator from pydantic import field_validator, BaseModel
__all__ = ("GachaInfo",) __all__ = ("GachaInfo",)
@ -12,6 +12,7 @@ class GachaInfo(BaseModel):
gacha_name: str gacha_name: str
gacha_type: int gacha_type: int
@validator("begin_time", "end_time", pre=True, allow_reuse=True) @field_validator("begin_time", "end_time", mode="before")
@classmethod
def validate_time(cls, v): def validate_time(cls, v):
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S") return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")

View File

@ -14,8 +14,8 @@ class BannerType(Enum):
class GachaBanner(BaseModel): class GachaBanner(BaseModel):
weight4 = ((1, 510), (8, 510), (10, 10000)) weight4: tuple[tuple[int, int]] = ((1, 510), (8, 510), (10, 10000))
weight5 = ((1, 60), (73, 60), (90, 10000)) weight5: tuple[tuple[int, int]] = ((1, 60), (73, 60), (90, 10000))
fallback_items3: List[int] = [ fallback_items3: List[int] = [
11301, 11301,
11302, 11302,

View File

@ -2,7 +2,7 @@ import datetime
from enum import Enum from enum import Enum
from typing import Any, Dict, List, Union from typing import Any, Dict, List, Union
from pydantic import BaseModel, validator from pydantic import field_validator, BaseModel
from metadata.shortname import not_real_roles, roleToId, lightConeToId from metadata.shortname import not_real_roles, roleToId, lightConeToId
from modules.gacha_log.const import SRGF_VERSION from modules.gacha_log.const import SRGF_VERSION
@ -42,26 +42,30 @@ class GachaItem(BaseModel):
rank_type: str rank_type: str
time: datetime.datetime time: datetime.datetime
@validator("name") @field_validator("name")
@classmethod
def name_validator(cls, v): def name_validator(cls, v):
if item_id := (roleToId(v) or lightConeToId(v)): if item_id := (roleToId(v) or lightConeToId(v)):
if item_id not in not_real_roles: if item_id not in not_real_roles:
return v return v
raise ValueError(f"Invalid name {v}") raise ValueError(f"Invalid name {v}")
@validator("gacha_type") @field_validator("gacha_type")
@classmethod
def check_gacha_type(cls, v): def check_gacha_type(cls, v):
if v not in {"1", "2", "11", "12"}: if v not in {"1", "2", "11", "12"}:
raise ValueError(f"gacha_type must be 1, 2, 11 or 12, invalid value: {v}") raise ValueError(f"gacha_type must be 1, 2, 11 or 12, invalid value: {v}")
return v return v
@validator("item_type") @field_validator("item_type")
@classmethod
def check_item_type(cls, item): def check_item_type(cls, item):
if item not in {"角色", "光锥"}: if item not in {"角色", "光锥"}:
raise ValueError(f"error item type {item}") raise ValueError(f"error item type {item}")
return item return item
@validator("rank_type") @field_validator("rank_type")
@classmethod
def check_rank_type(cls, rank): def check_rank_type(cls, rank):
if rank not in {"5", "4", "3"}: if rank not in {"5", "4", "3"}:
raise ValueError(f"error rank type {rank}") raise ValueError(f"error rank type {rank}")

View File

@ -7,7 +7,7 @@ from httpx import HTTPError
from telegram import InlineKeyboardMarkup, InlineKeyboardButton from telegram import InlineKeyboardMarkup, InlineKeyboardButton
from telegram.helpers import create_deep_linked_url from telegram.helpers import create_deep_linked_url
from gram_core.basemodel import Settings from gram_core.basemodel import Settings, SettingsConfigDict
from modules.gacha_log.error import GachaLogWebNotConfigError, GachaLogWebUploadError, GachaLogNotFound from modules.gacha_log.error import GachaLogWebNotConfigError, GachaLogWebUploadError, GachaLogNotFound
@ -17,8 +17,7 @@ class GachaLogWebConfig(Settings):
url: Optional[str] = "" url: Optional[str] = ""
token: Optional[str] = "" token: Optional[str] = ""
class Config(Settings.Config): model_config = SettingsConfigDict(env_prefix="gacha_log_web_")
env_prefix = "gacha_log_web_"
gacha_log_web_config = GachaLogWebConfig() gacha_log_web_config = GachaLogWebConfig()

View File

@ -23,16 +23,16 @@ class YattaAvatarCV(BaseModel):
class YattaAvatarFetter(BaseModel): class YattaAvatarFetter(BaseModel):
faction: Optional[str] faction: Optional[str] = None
description: Optional[str] description: Optional[str] = None
cv: Optional[YattaAvatarCV] cv: Optional[YattaAvatarCV] = None
class YattaAvatarEidolon(BaseModel): class YattaAvatarEidolon(BaseModel):
id: int id: int
rank: int rank: int
name: Optional[str] name: Optional[str] = None
description: Optional[str] description: Optional[str] = None
icon: str icon: str
@property @property

View File

@ -1,7 +1,7 @@
from decimal import Decimal from decimal import Decimal
from typing import Optional, Dict from typing import Optional, Dict
from pydantic import BaseModel, root_validator from pydantic import model_validator, BaseModel
from .enums import RelicAffix, RelicPosition from .enums import RelicAffix, RelicPosition
@ -38,7 +38,8 @@ class RelicAffixAll(BaseModel):
sub_affix: Dict[str, SingleRelicAffix] sub_affix: Dict[str, SingleRelicAffix]
""" 副词条 """ """ 副词条 """
@root_validator(pre=True) @model_validator(mode="before")
@classmethod
def transform_dicts(cls, values): def transform_dicts(cls, values):
for data in ["main_affix", "sub_affix"]: for data in ["main_affix", "sub_affix"]:
affix = values.get(data) affix = values.get(data)

View File

@ -34,7 +34,7 @@ class WeaponAffix(Model):
class WeaponState(Model): class WeaponState(Model):
level: str level: str
ATK: float ATK: float
bonus: Optional[str] bonus: Optional[str] = None
class WeaponIcon(Model): class WeaponIcon(Model):
@ -58,11 +58,11 @@ class Weapon(WikiModel):
weapon_type: WeaponType weapon_type: WeaponType
attack: float attack: float
attribute: Optional[WeaponAttribute] attribute: Optional[WeaponAttribute] = None
affix: Optional[WeaponAffix] affix: Optional[WeaponAffix] = None
description: str description: str
ascension: List[str] ascension: List[str]
story: Optional[str] story: Optional[str] = None
stats: List[WeaponState] stats: List[WeaponState]

View File

@ -25,7 +25,7 @@ from telegram.helpers import escape_markdown
from core.config import config from core.config import config
from core.plugin import Plugin, conversation, handler from core.plugin import Plugin, conversation, handler
from gram_core.basemodel import Settings from gram_core.basemodel import Settings, SettingsConfigDict
from gram_core.dependence.redisdb import RedisDB from gram_core.dependence.redisdb import RedisDB
from modules.apihelper.client.components.hoyolab import Hoyolab from modules.apihelper.client.components.hoyolab import Hoyolab
from modules.apihelper.client.components.hyperion import Hyperion, HyperionBase from modules.apihelper.client.components.hyperion import Hyperion, HyperionBase
@ -54,8 +54,7 @@ class PostConfig(Settings):
chat_id: Optional[int] = 0 chat_id: Optional[int] = 0
class Config(Settings.Config): model_config = SettingsConfigDict(env_prefix="post_")
env_prefix = "post_"
CHECK_POST, SEND_POST, CHECK_COMMAND, GTE_DELETE_PHOTO = range(10900, 10904) CHECK_POST, SEND_POST, CHECK_COMMAND, GTE_DELETE_PHOTO = range(10900, 10904)

View File

@ -11,7 +11,7 @@ from utils.log import logger
class WebAppData(BaseModel): class WebAppData(BaseModel):
path: str path: str
data: Optional[dict] data: Optional[dict] = None
code: int code: int
message: str message: str

View File

@ -7,7 +7,6 @@ from functools import lru_cache, partial
from typing import Any, List, Optional, Tuple, Union, TYPE_CHECKING from typing import Any, List, Optional, Tuple, Union, TYPE_CHECKING
from arkowrapper import ArkoWrapper from arkowrapper import ArkoWrapper
from pytz import timezone
from telegram import Message, Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram import Message, Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatAction, ParseMode from telegram.constants import ChatAction, ParseMode
from telegram.ext import CallbackContext, filters, ContextTypes from telegram.ext import CallbackContext, filters, ContextTypes
@ -38,7 +37,6 @@ if TYPE_CHECKING:
from simnet.models.starrail.chronicle.challenge import StarRailChallenge from simnet.models.starrail.chronicle.challenge import StarRailChallenge
TZ = timezone("Asia/Shanghai")
cmd_pattern = r"(?i)^/challenge(?:@[\w]+)?\s*((?:\d+)|(?:all))?\s*(pre)?" cmd_pattern = r"(?i)^/challenge(?:@[\w]+)?\s*((?:\d+)|(?:all))?\s*(pre)?"
msg_pattern = r"^混沌回忆数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$" msg_pattern = r"^混沌回忆数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$"
MAX_FLOOR = 12 MAX_FLOOR = 12
@ -205,7 +203,7 @@ class ChallengePlugin(Plugin):
raise AbyssFastPassed() raise AbyssFastPassed()
render_data = { render_data = {
"floor": floor_data, "floor": floor_data,
"floor_time": floor_data.node_1.challenge_time.datetime.astimezone(TZ).strftime("%Y-%m-%d %H:%M:%S"), "floor_time": floor_data.node_1.challenge_time.datetime.strftime("%Y-%m-%d %H:%M:%S"),
"floor_nodes": [floor_data.node_1, floor_data.node_2], "floor_nodes": [floor_data.node_1, floor_data.node_2],
"floor_num": floor, "floor_num": floor,
} }
@ -245,8 +243,8 @@ class ChallengePlugin(Plugin):
if not abyss_data.has_data: if not abyss_data.has_data:
raise AbyssUnlocked() raise AbyssUnlocked()
start_time = abyss_data.begin_time.datetime.astimezone(TZ).strftime("%m月%d%H:%M") start_time = abyss_data.begin_time.datetime.strftime("%m月%d%H:%M")
end_time = abyss_data.end_time.datetime.astimezone(TZ).strftime("%m月%d%H:%M") end_time = abyss_data.end_time.datetime.strftime("%m月%d%H:%M")
total_stars = f"{abyss_data.total_stars}" total_stars = f"{abyss_data.total_stars}"
render_data = { render_data = {
@ -344,7 +342,7 @@ class ChallengePlugin(Plugin):
@staticmethod @staticmethod
def get_season_data_name(data: "HistoryDataAbyss"): def get_season_data_name(data: "HistoryDataAbyss"):
last_battles = data.abyss_data.floors[0] last_battles = data.abyss_data.floors[0]
start_time = last_battles.node_1.challenge_time.datetime.astimezone(TZ) start_time = last_battles.node_1.challenge_time.datetime
time = start_time.strftime("%Y.%m.%d") time = start_time.strftime("%Y.%m.%d")
name = "" name = ""
if "" in last_battles.name: if "" in last_battles.name:

View File

@ -7,7 +7,6 @@ from functools import lru_cache, partial
from typing import Any, List, Optional, Tuple, Union, TYPE_CHECKING from typing import Any, List, Optional, Tuple, Union, TYPE_CHECKING
from arkowrapper import ArkoWrapper from arkowrapper import ArkoWrapper
from pytz import timezone
from telegram import Message, Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram import Message, Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatAction, ParseMode from telegram.constants import ChatAction, ParseMode
from telegram.ext import CallbackContext, filters, ContextTypes from telegram.ext import CallbackContext, filters, ContextTypes
@ -37,7 +36,6 @@ if TYPE_CHECKING:
from simnet import StarRailClient from simnet import StarRailClient
from simnet.models.starrail.chronicle.challenge_boss import StarRailChallengeBoss, StarRailChallengeBossGroup from simnet.models.starrail.chronicle.challenge_boss import StarRailChallengeBoss, StarRailChallengeBossGroup
TZ = timezone("Asia/Shanghai")
cmd_pattern = r"(?i)^/challenge_boss(?:@[\w]+)?\s*((?:\d+)|(?:all))?\s*(pre)?" cmd_pattern = r"(?i)^/challenge_boss(?:@[\w]+)?\s*((?:\d+)|(?:all))?\s*(pre)?"
msg_pattern = r"^末日幻影数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$" msg_pattern = r"^末日幻影数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$"
MAX_FLOOR = 4 MAX_FLOOR = 4
@ -204,7 +202,7 @@ class ChallengeBossPlugin(Plugin):
raise AbyssFastPassed() raise AbyssFastPassed()
render_data = { render_data = {
"floor": floor_data, "floor": floor_data,
"floor_time": floor_data.last_update_time.datetime.astimezone(TZ).strftime("%Y-%m-%d %H:%M:%S"), "floor_time": floor_data.last_update_time.datetime.strftime("%Y-%m-%d %H:%M:%S"),
"floor_nodes": [floor_data.node_1, floor_data.node_2], "floor_nodes": [floor_data.node_1, floor_data.node_2],
"floor_num": floor, "floor_num": floor,
} }
@ -260,8 +258,8 @@ class ChallengeBossPlugin(Plugin):
raise AbyssUnlocked() raise AbyssUnlocked()
if not season: if not season:
raise AbyssUnlocked() raise AbyssUnlocked()
start_time = season.begin_time.datetime.astimezone(TZ).strftime("%m月%d%H:%M") start_time = season.begin_time.datetime.strftime("%m月%d%H:%M")
end_time = season.end_time.datetime.astimezone(TZ).strftime("%m月%d%H:%M") end_time = season.end_time.datetime.strftime("%m月%d%H:%M")
total_stars = f"{abyss_data.total_stars}" total_stars = f"{abyss_data.total_stars}"
render_data = { render_data = {
@ -368,7 +366,7 @@ class ChallengeBossPlugin(Plugin):
@staticmethod @staticmethod
def get_season_data_name(data: "HistoryDataChallengeBoss"): def get_season_data_name(data: "HistoryDataChallengeBoss"):
last_battles = data.boss_data.floors[0] last_battles = data.boss_data.floors[0]
start_time = last_battles.last_update_time.datetime.astimezone(TZ) start_time = last_battles.last_update_time.datetime
time = start_time.strftime("%Y.%m.%d") time = start_time.strftime("%Y.%m.%d")
name = "" name = ""
if "" in last_battles.name: if "" in last_battles.name:

View File

@ -7,7 +7,6 @@ from functools import lru_cache, partial
from typing import Any, List, Optional, Tuple, Union, TYPE_CHECKING from typing import Any, List, Optional, Tuple, Union, TYPE_CHECKING
from arkowrapper import ArkoWrapper from arkowrapper import ArkoWrapper
from pytz import timezone
from telegram import Message, Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram import Message, Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatAction, ParseMode from telegram.constants import ChatAction, ParseMode
from telegram.ext import CallbackContext, filters, ContextTypes from telegram.ext import CallbackContext, filters, ContextTypes
@ -37,7 +36,6 @@ if TYPE_CHECKING:
from simnet import StarRailClient from simnet import StarRailClient
from simnet.models.starrail.chronicle.challenge_story import StarRailChallengeStory, StarRailChallengeStoryGroup from simnet.models.starrail.chronicle.challenge_story import StarRailChallengeStory, StarRailChallengeStoryGroup
TZ = timezone("Asia/Shanghai")
cmd_pattern = r"(?i)^/challenge_story(?:@[\w]+)?\s*((?:\d+)|(?:all))?\s*(pre)?" cmd_pattern = r"(?i)^/challenge_story(?:@[\w]+)?\s*((?:\d+)|(?:all))?\s*(pre)?"
msg_pattern = r"^虚构叙事数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$" msg_pattern = r"^虚构叙事数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$"
MAX_FLOOR = 4 MAX_FLOOR = 4
@ -204,7 +202,7 @@ class ChallengeStoryPlugin(Plugin):
raise AbyssFastPassed() raise AbyssFastPassed()
render_data = { render_data = {
"floor": floor_data, "floor": floor_data,
"floor_time": floor_data.node_1.challenge_time.datetime.astimezone(TZ).strftime("%Y-%m-%d %H:%M:%S"), "floor_time": floor_data.node_1.challenge_time.datetime.strftime("%Y-%m-%d %H:%M:%S"),
"floor_nodes": [floor_data.node_1, floor_data.node_2], "floor_nodes": [floor_data.node_1, floor_data.node_2],
"floor_num": floor, "floor_num": floor,
} }
@ -256,8 +254,8 @@ class ChallengeStoryPlugin(Plugin):
raise AbyssUnlocked() raise AbyssUnlocked()
if not season: if not season:
raise AbyssUnlocked() raise AbyssUnlocked()
start_time = season.begin_time.datetime.astimezone(TZ).strftime("%m月%d%H:%M") start_time = season.begin_time.datetime.strftime("%m月%d%H:%M")
end_time = season.end_time.datetime.astimezone(TZ).strftime("%m月%d%H:%M") end_time = season.end_time.datetime.strftime("%m月%d%H:%M")
total_stars = f"{abyss_data.total_stars}" total_stars = f"{abyss_data.total_stars}"
render_data = { render_data = {
@ -360,7 +358,7 @@ class ChallengeStoryPlugin(Plugin):
@staticmethod @staticmethod
def get_season_data_name(data: "HistoryDataChallengeStory"): def get_season_data_name(data: "HistoryDataChallengeStory"):
last_battles = data.story_data.floors[0] last_battles = data.story_data.floors[0]
start_time = last_battles.node_1.challenge_time.datetime.astimezone(TZ) start_time = last_battles.node_1.challenge_time.datetime
time = start_time.strftime("%Y.%m.%d") time = start_time.strftime("%Y.%m.%d")
name = "" name = ""
if "" in last_battles.name: if "" in last_battles.name:

View File

@ -2,7 +2,7 @@ import base64
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING, List, Optional, Union from typing import TYPE_CHECKING, List, Optional, Union
from pydantic import BaseModel, validator from pydantic import field_validator, BaseModel
from simnet import Region from simnet import Region
from simnet.errors import BadRequest as SimnetBadRequest, InvalidCookies, TimedOut as SimnetTimedOut from simnet.errors import BadRequest as SimnetBadRequest, InvalidCookies, TimedOut as SimnetTimedOut
from sqlalchemy.orm.exc import StaleDataError from sqlalchemy.orm.exc import StaleDataError
@ -30,7 +30,8 @@ class TaskDataBase(BaseModel):
class ResinData(TaskDataBase): class ResinData(TaskDataBase):
notice_num: Optional[int] = 140 notice_num: Optional[int] = 140
@validator("notice_num") @field_validator("notice_num")
@classmethod
def notice_num_validator(cls, v): def notice_num_validator(cls, v):
if v < 100 or v > 240: if v < 100 or v > 240:
raise ValueError("开拓力提醒数值必须在 100 ~ 240 之间") raise ValueError("开拓力提醒数值必须在 100 ~ 240 之间")
@ -44,7 +45,8 @@ class ExpeditionData(TaskDataBase):
class DailyData(TaskDataBase): class DailyData(TaskDataBase):
notice_hour: Optional[int] = 22 notice_hour: Optional[int] = 22
@validator("notice_hour") @field_validator("notice_hour")
@classmethod
def notice_hour_validator(cls, v): def notice_hour_validator(cls, v):
if v < 0 or v > 23: if v < 0 or v > 23:
raise ValueError("每日任务提醒时间必须在 0 ~ 23 之间") raise ValueError("每日任务提醒时间必须在 0 ~ 23 之间")
@ -55,9 +57,9 @@ class WebAppData(BaseModel):
user_id: int user_id: int
player_id: int player_id: int
resin: Optional[ResinData] resin: Optional[ResinData] = None
expedition: Optional[ExpeditionData] expedition: Optional[ExpeditionData] = None
daily: Optional[DailyData] daily: Optional[DailyData] = None
class DailyNoteTaskUser: class DailyNoteTaskUser:

View File

@ -15,7 +15,7 @@ authors = [
{name = "Nahida Buer"}, {name = "Nahida Buer"},
] ]
dependencies = [ dependencies = [
"httpx<1.0.0,>=0.25.0", "httpx<1.0.0,>=0.28.0",
"ujson<6.0.0,>=5.9.0", "ujson<6.0.0,>=5.9.0",
"Jinja2<4.0.0,>=3.1.2", "Jinja2<4.0.0,>=3.1.2",
"python-telegram-bot[ext,rate-limiter]<22.0,>=21.7", "python-telegram-bot[ext,rate-limiter]<22.0,>=21.7",
@ -45,9 +45,11 @@ dependencies = [
"aiosqlite<1.0.0,>=0.20.0", "aiosqlite<1.0.0,>=0.20.0",
"simnet @ git+https://github.com/PaiGramTeam/SIMNet", "simnet @ git+https://github.com/PaiGramTeam/SIMNet",
"psutil<7.0.0,>=6.0.0", "psutil<7.0.0,>=6.0.0",
"influxdb-client[async,ciso]>=1.43.0", "influxdb-client[async,ciso]>=1.48.0",
"starrail-damage-cal<2.0.0,>=1.7.0", "starrail-damage-cal<2.0.0,>=1.7.0",
"starrailrelicscore @ git+https://github.com/PaiGramTeam/StarRailRelicScore", "starrailrelicscore @ git+https://github.com/PaiGramTeam/StarRailRelicScore",
"pydantic>=2.0.0,<3.0.0",
"pydantic-settings>=2.6.1",
] ]
requires-python = "<4.0,>=3.9" requires-python = "<4.0,>=3.9"
readme = "README.md" readme = "README.md"

View File

@ -3,16 +3,17 @@
aiocsv==1.3.2 aiocsv==1.3.2
aiofiles==24.1.0 aiofiles==24.1.0
aiohappyeyeballs==2.4.3 aiohappyeyeballs==2.4.3
aiohttp==3.10.10 aiohttp==3.11.8
aiolimiter==1.1.0 aiolimiter==1.1.0
aiosignal==1.3.1 aiosignal==1.3.1
aiosqlite==0.20.0 aiosqlite==0.20.0
alembic==1.14.0 alembic==1.14.0
annotated-types==0.7.0
anyio==4.6.2.post1 anyio==4.6.2.post1
apscheduler==3.10.4 apscheduler==3.10.4
arko-wrapper==0.3.0 arko-wrapper==0.3.0
async-lru==2.0.4 async-lru==2.0.4
async-timeout==4.0.3 ; python_full_version < '3.11.3' async-timeout==5.0.1 ; python_full_version < '3.11.3'
asyncmy==0.2.9 asyncmy==0.2.9
attrs==24.2.0 attrs==24.2.0
beautifulsoup4==4.12.3 beautifulsoup4==4.12.3
@ -28,18 +29,18 @@ cryptography==43.0.3
et-xmlfile==2.0.0 et-xmlfile==2.0.0
exceptiongroup==1.2.2 ; python_full_version < '3.11' exceptiongroup==1.2.2 ; python_full_version < '3.11'
fakeredis==2.26.1 fakeredis==2.26.1
fastapi==0.115.4 fastapi==0.115.5
flaky==3.8.1 flaky==3.8.1
frozenlist==1.5.0 frozenlist==1.5.0
gitdb==4.0.11 gitdb==4.0.11
gitpython==3.1.43 gitpython==3.1.43
greenlet==3.1.1 greenlet==3.1.1
h11==0.14.0 h11==0.14.0
httpcore==1.0.6 httpcore==1.0.7
httptools==0.6.4 httptools==0.6.4
httpx==0.27.2 httpx==0.28.0
idna==3.10 idna==3.10
influxdb-client==1.47.0 influxdb-client==1.48.0
iniconfig==2.0.0 iniconfig==2.0.0
jinja2==3.1.4 jinja2==3.1.4
lxml==5.3.0 lxml==5.3.0
@ -61,7 +62,9 @@ propcache==0.2.0
psutil==6.1.0 psutil==6.1.0
pyaes==1.6.1 pyaes==1.6.1
pycparser==2.22 ; platform_python_implementation != 'PyPy' pycparser==2.22 ; platform_python_implementation != 'PyPy'
pydantic==1.10.19 pydantic==2.10.2
pydantic-core==2.27.1
pydantic-settings==2.6.1
pyee==12.0.0 pyee==12.0.0
pygments==2.18.0 pygments==2.18.0
pyrogram==2.0.106 pyrogram==2.0.106
@ -77,9 +80,9 @@ rapidfuzz==3.10.1
reactivex==4.0.4 reactivex==4.0.4
redis==5.2.0 redis==5.2.0
rich==13.9.4 rich==13.9.4
sentry-sdk==2.18.0 sentry-sdk==2.19.0
setuptools==75.3.0 setuptools==75.6.0
simnet @ git+https://github.com/PaiGramTeam/SIMNet@745000612682f7b346d92b21f4d60502b92f477c simnet @ git+https://github.com/PaiGramTeam/SIMNet@d7756addb558356adc65e7e14dc86e0a3cb5d8bd
six==1.16.0 six==1.16.0
smmap==5.0.1 smmap==5.0.1
sniffio==1.3.1 sniffio==1.3.1
@ -87,20 +90,20 @@ sortedcontainers==2.4.0
soupsieve==2.6 soupsieve==2.6
sqlalchemy==2.0.36 sqlalchemy==2.0.36
sqlmodel==0.0.22 sqlmodel==0.0.22
starlette==0.41.2 starlette==0.41.3
starrail-damage-cal==1.9.6 starrail-damage-cal==1.9.6
starrailrelicscore @ git+https://github.com/PaiGramTeam/StarRailRelicScore@92e728d82aea232a2974ba77e188e0331f7618b9 starrailrelicscore @ git+https://github.com/PaiGramTeam/StarRailRelicScore@e26509eac9b55875cf3c48a53ecef051403b8867
tgcrypto==1.2.5 tgcrypto==1.2.5
thefuzz==0.22.1 thefuzz==0.22.1
tomli==2.0.2 ; python_full_version < '3.11' tomli==2.2.1 ; python_full_version < '3.11'
tornado==6.4.1 tornado==6.4.2
typing-extensions==4.12.2 typing-extensions==4.12.2
tzdata==2024.2 ; platform_system == 'Windows' tzdata==2024.2 ; platform_system == 'Windows'
tzlocal==5.2 tzlocal==5.2
ujson==5.10.0 ujson==5.10.0
urllib3==2.2.3 urllib3==2.2.3
uvicorn==0.32.0 uvicorn==0.32.1
uvloop==0.21.0 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32' uvloop==0.21.0 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'
watchfiles==0.24.0 watchfiles==1.0.0
websockets==13.1 websockets==14.1
yarl==1.17.1 yarl==1.18.0

View File

@ -1,8 +1,8 @@
from multiprocessing import RLock as Lock from multiprocessing import RLock as Lock
from pathlib import Path from pathlib import Path
from typing import List, Literal, Optional, Union from typing import List, Literal, Optional, Union, ClassVar
from pydantic import BaseSettings from pydantic_settings import BaseSettings
from utils.const import PROJECT_ROOT from utils.const import PROJECT_ROOT
@ -10,13 +10,13 @@ __all__ = ("LoggerConfig",)
class LoggerConfig(BaseSettings): class LoggerConfig(BaseSettings):
_lock = Lock() _lock: ClassVar[Lock] = Lock()
_instance: Optional["LoggerConfig"] = None _instance: ClassVar[Optional["LoggerConfig"]] = None
def __new__(cls, *args, **kwargs) -> "LoggerConfig": def __new__(cls, *args, **kwargs) -> "LoggerConfig":
with cls._lock: with cls._lock:
if cls._instance is None: if cls._instance is None:
cls.update_forward_refs() cls.model_rebuild()
result = super(LoggerConfig, cls).__new__(cls) # pylint: disable=E1120 result = super(LoggerConfig, cls).__new__(cls) # pylint: disable=E1120
result.__init__(*args, **kwargs) result.__init__(*args, **kwargs)
cls._instance = result cls._instance = result

891
uv.lock

File diff suppressed because it is too large Load Diff