mirror of
https://github.com/PaiGramTeam/PaiGram.git
synced 2024-11-30 19:31:47 +00:00
⬆️ upgrade Pydantic to V2
This commit is contained in:
parent
4362f515cb
commit
5319fc116d
@ -1,7 +1,6 @@
|
||||
import datetime
|
||||
from typing import Dict, List
|
||||
|
||||
from pytz import timezone
|
||||
from simnet.models.genshin.chronicle.abyss import SpiralAbyss
|
||||
from simnet.models.genshin.chronicle.img_theater import ImgTheaterData
|
||||
from simnet.models.genshin.diary import Diary
|
||||
@ -29,14 +28,6 @@ __all__ = (
|
||||
"HistoryDataImgTheaterServices",
|
||||
)
|
||||
|
||||
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):
|
||||
DATA_TYPE = HistoryDataTypeEnum.ABYSS.value
|
||||
@ -49,7 +40,7 @@ class HistoryDataAbyssServices(BaseService, HistoryDataBaseServices):
|
||||
@staticmethod
|
||||
def create(user_id: int, abyss_data: SpiralAbyss, character_data: Dict[int, int]):
|
||||
data = HistoryDataAbyss(abyss_data=abyss_data, character_data=character_data)
|
||||
json_data = data.json(by_alias=True, encoder=json_encoder)
|
||||
json_data = data.model_dump_json(by_alias=True)
|
||||
return HistoryData(
|
||||
user_id=user_id,
|
||||
data_id=abyss_data.season,
|
||||
@ -65,7 +56,7 @@ class HistoryDataLedgerServices(BaseService, HistoryDataBaseServices):
|
||||
@staticmethod
|
||||
def create(user_id: int, diary_data: Diary):
|
||||
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(
|
||||
user_id=user_id,
|
||||
data_id=diary_data.data_id,
|
||||
@ -86,7 +77,7 @@ class HistoryDataImgTheaterServices(BaseService, HistoryDataBaseServices):
|
||||
@staticmethod
|
||||
def create(user_id: int, abyss_data: ImgTheaterData, character_data: Dict[int, int]):
|
||||
data = HistoryDataImgTheater(abyss_data=abyss_data, character_data=character_data)
|
||||
json_data = data.json(by_alias=True, encoder=json_encoder)
|
||||
json_data = data.model_dump_json(by_alias=True)
|
||||
return HistoryData(
|
||||
user_id=user_id,
|
||||
data_id=abyss_data.schedule.id,
|
||||
|
@ -50,7 +50,7 @@ class WeaponEntry(BaseEntry):
|
||||
|
||||
|
||||
class WeaponsEntry(BaseModel):
|
||||
data: Optional[List[WeaponEntry]]
|
||||
data: Optional[List[WeaponEntry]] = None
|
||||
|
||||
|
||||
class StrategyEntry(BaseEntry):
|
||||
@ -69,4 +69,4 @@ class StrategyEntry(BaseEntry):
|
||||
|
||||
|
||||
class StrategyEntryList(BaseModel):
|
||||
data: Optional[List[StrategyEntry]]
|
||||
data: Optional[List[StrategyEntry]] = None
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 112b2e92d8492df17dbae23024fa805e3510a56e
|
||||
Subproject commit bf5b153001defd150d4dcc17b9baf06a3769adf0
|
@ -1,6 +1,6 @@
|
||||
from typing import List, Optional, Any
|
||||
|
||||
from pydantic import BaseModel, validator
|
||||
from pydantic import field_validator, BaseModel
|
||||
|
||||
__all__ = ("Member", "TeamRate", "FullTeamRate", "TeamRateResult")
|
||||
|
||||
@ -14,9 +14,10 @@ class Member(BaseModel):
|
||||
class TeamRate(BaseModel):
|
||||
rate: float
|
||||
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
|
||||
return float(v.replace("%", "")) / 100.0 if isinstance(v, str) else v
|
||||
|
||||
@ -24,8 +25,8 @@ class TeamRate(BaseModel):
|
||||
class FullTeamRate(BaseModel):
|
||||
up: TeamRate
|
||||
down: TeamRate
|
||||
owner_num: Optional[int]
|
||||
nice: Optional[float]
|
||||
owner_num: Optional[int] = None
|
||||
nice: Optional[float] = None
|
||||
|
||||
@property
|
||||
def rate(self) -> float:
|
||||
|
@ -2,7 +2,8 @@ from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import Field
|
||||
from simnet.models.base import APIModel as BaseModel
|
||||
|
||||
|
||||
class AkashaSubStat(str, Enum):
|
||||
@ -38,7 +39,7 @@ class AkashaRankCal(BaseModel):
|
||||
class AkashaRank(BaseModel):
|
||||
_id: str
|
||||
characterId: int
|
||||
uid = int
|
||||
uid: int
|
||||
constellation: int
|
||||
icon: str
|
||||
|
||||
@ -90,7 +91,7 @@ class AkashaLeaderboardArtifactSet(BaseModel):
|
||||
class AkashaLeaderboardOwner(BaseModel):
|
||||
nickname: str
|
||||
adventureRank: float
|
||||
profilePicture: Any
|
||||
profilePicture: Any = None
|
||||
nameCard: str
|
||||
patreon: Dict[str, Any]
|
||||
region: str
|
||||
@ -121,7 +122,7 @@ class AkashaLeaderboardStats(BaseModel):
|
||||
healingBonus: AkashaLeaderboardStatsValue
|
||||
critRate: AkashaLeaderboardStatsValue
|
||||
critDamage: AkashaLeaderboardStatsValue
|
||||
electroDamageBonus: Optional[AkashaLeaderboardStatsValue]
|
||||
electroDamageBonus: Optional[AkashaLeaderboardStatsValue] = None
|
||||
|
||||
|
||||
class AkashaLeaderboardWeaponInfo(BaseModel):
|
||||
|
@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, validator
|
||||
from pydantic import field_validator, BaseModel
|
||||
|
||||
__all__ = ("GachaInfo",)
|
||||
|
||||
@ -12,6 +12,7 @@ class GachaInfo(BaseModel):
|
||||
gacha_name: str
|
||||
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):
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
@ -2,7 +2,7 @@ import datetime
|
||||
from enum import Enum
|
||||
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, weaponToId
|
||||
from modules.gacha_log.const import UIGF_VERSION
|
||||
@ -42,26 +42,30 @@ class GachaItem(BaseModel):
|
||||
rank_type: str
|
||||
time: datetime.datetime
|
||||
|
||||
@validator("name")
|
||||
@field_validator("name")
|
||||
@classmethod
|
||||
def name_validator(cls, v):
|
||||
if item_id := (roleToId(v) or weaponToId(v)):
|
||||
if item_id not in not_real_roles:
|
||||
return v
|
||||
raise ValueError(f"Invalid name {v}")
|
||||
|
||||
@validator("gacha_type")
|
||||
@field_validator("gacha_type")
|
||||
@classmethod
|
||||
def check_gacha_type(cls, v):
|
||||
if v not in {"100", "200", "301", "302", "400", "500"}:
|
||||
raise ValueError(f"gacha_type must be 200, 301, 302, 400, 500, invalid value: {v}")
|
||||
return v
|
||||
|
||||
@validator("item_type")
|
||||
@field_validator("item_type")
|
||||
@classmethod
|
||||
def check_item_type(cls, item):
|
||||
if item not in {"角色", "武器"}:
|
||||
raise ValueError(f"error item type {item}")
|
||||
return item
|
||||
|
||||
@validator("rank_type")
|
||||
@field_validator("rank_type")
|
||||
@classmethod
|
||||
def check_rank_type(cls, rank):
|
||||
if rank not in {"5", "4", "3"}:
|
||||
raise ValueError(f"error rank type {rank}")
|
||||
|
@ -7,7 +7,7 @@ from httpx import HTTPError
|
||||
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
|
||||
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
|
||||
|
||||
|
||||
@ -17,8 +17,7 @@ class GachaLogWebConfig(Settings):
|
||||
url: Optional[str] = ""
|
||||
token: Optional[str] = ""
|
||||
|
||||
class Config(Settings.Config):
|
||||
env_prefix = "gacha_log_web_"
|
||||
model_config = SettingsConfigDict(env_prefix="gacha_log_web_")
|
||||
|
||||
|
||||
gacha_log_web_config = GachaLogWebConfig()
|
||||
|
@ -1,23 +1,11 @@
|
||||
import datetime
|
||||
from typing import Any, List
|
||||
|
||||
from pydantic import BaseModel, BaseConfig
|
||||
from pydantic import BaseModel
|
||||
from simnet.models.genshin.transaction import BaseTransaction
|
||||
|
||||
try:
|
||||
import ujson as jsonlib
|
||||
|
||||
except ImportError:
|
||||
import json as jsonlib
|
||||
|
||||
|
||||
class _ModelConfig(BaseConfig):
|
||||
json_dumps = jsonlib.dumps
|
||||
json_loads = jsonlib.loads
|
||||
|
||||
|
||||
class BaseInfo(BaseModel):
|
||||
Config = _ModelConfig
|
||||
uid: str = "0"
|
||||
lang: str = "zh-cn"
|
||||
export_time: str = ""
|
||||
@ -35,6 +23,5 @@ class BaseInfo(BaseModel):
|
||||
|
||||
|
||||
class PayLog(BaseModel):
|
||||
Config = _ModelConfig
|
||||
info: BaseInfo
|
||||
list: List[BaseTransaction]
|
||||
|
@ -9,7 +9,6 @@ from typing import AsyncIterator, ClassVar, List, Optional, Tuple, Union
|
||||
import anyio
|
||||
from bs4 import BeautifulSoup
|
||||
from httpx import URL, AsyncClient, HTTPError, Response
|
||||
from pydantic import BaseConfig as PydanticBaseConfig
|
||||
from pydantic import BaseModel as PydanticBaseModel
|
||||
|
||||
from utils.log import logger
|
||||
@ -29,14 +28,9 @@ class Model(PydanticBaseModel):
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
# 让每次new的时候都解析
|
||||
cls.update_forward_refs()
|
||||
cls.model_rebuild()
|
||||
return super(Model, cls).__new__(cls) # pylint: disable=E1120
|
||||
|
||||
class Config(PydanticBaseConfig):
|
||||
# 使用 ujson 作为解析库
|
||||
json_dumps = jsonlib.dumps
|
||||
json_loads = jsonlib.loads
|
||||
|
||||
|
||||
class WikiModel(Model):
|
||||
# noinspection PyUnresolvedReferences
|
||||
|
@ -57,7 +57,7 @@ class CharacterIcon(Model):
|
||||
icon: str
|
||||
side: str
|
||||
gacha: str
|
||||
splash: Optional[str]
|
||||
splash: Optional[str] = None
|
||||
|
||||
|
||||
class Character(WikiModel):
|
||||
@ -83,7 +83,7 @@ class Character(WikiModel):
|
||||
association: Association
|
||||
weapon_type: WeaponType
|
||||
element: Element
|
||||
birth: Optional[Birth]
|
||||
birth: Optional[Birth] = None
|
||||
constellation: str
|
||||
cn_cv: str
|
||||
jp_cv: str
|
||||
|
@ -34,7 +34,7 @@ class WeaponAffix(Model):
|
||||
class WeaponState(Model):
|
||||
level: str
|
||||
ATK: float
|
||||
bonus: Optional[str]
|
||||
bonus: Optional[str] = None
|
||||
|
||||
|
||||
class WeaponIcon(Model):
|
||||
@ -58,11 +58,11 @@ class Weapon(WikiModel):
|
||||
|
||||
weapon_type: WeaponType
|
||||
attack: float
|
||||
attribute: Optional[WeaponAttribute]
|
||||
affix: Optional[WeaponAffix]
|
||||
attribute: Optional[WeaponAttribute] = None
|
||||
affix: Optional[WeaponAffix] = None
|
||||
description: str
|
||||
ascension: List[str]
|
||||
story: Optional[str]
|
||||
story: Optional[str] = None
|
||||
|
||||
stats: List[WeaponState]
|
||||
|
||||
|
@ -14,8 +14,8 @@ class GenshinBannerType(Enum):
|
||||
|
||||
|
||||
class GachaBanner(BaseModel):
|
||||
weight4 = ((1, 510), (8, 510), (10, 10000))
|
||||
weight5 = ((1, 60), (73, 60), (90, 10000))
|
||||
weight4: tuple[tuple[int, int]] = ((1, 510), (8, 510), (10, 10000))
|
||||
weight5: tuple[tuple[int, int]] = ((1, 60), (73, 60), (90, 10000))
|
||||
fallback_items3: List[int] = [
|
||||
11301,
|
||||
11302,
|
||||
|
@ -25,7 +25,7 @@ from telegram.helpers import escape_markdown
|
||||
|
||||
from core.config import config
|
||||
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 modules.apihelper.client.components.hoyolab import Hoyolab
|
||||
from modules.apihelper.client.components.hyperion import Hyperion, HyperionBase
|
||||
@ -55,8 +55,7 @@ class PostConfig(Settings):
|
||||
|
||||
chat_id: Optional[int] = 0
|
||||
|
||||
class Config(Settings.Config):
|
||||
env_prefix = "post_"
|
||||
model_config = SettingsConfigDict(env_prefix="post_")
|
||||
|
||||
|
||||
CHECK_POST, SEND_POST, CHECK_COMMAND, GTE_DELETE_PHOTO = range(10900, 10904)
|
||||
|
@ -11,7 +11,7 @@ from utils.log import logger
|
||||
|
||||
class WebAppData(BaseModel):
|
||||
path: str
|
||||
data: Optional[dict]
|
||||
data: Optional[dict] = None
|
||||
code: int
|
||||
message: str
|
||||
|
||||
|
@ -3,12 +3,10 @@
|
||||
import asyncio
|
||||
import math
|
||||
import re
|
||||
from datetime import datetime
|
||||
from functools import lru_cache, partial
|
||||
from typing import Any, Coroutine, List, Optional, Tuple, Union, Dict
|
||||
|
||||
from arkowrapper import ArkoWrapper
|
||||
from pytz import timezone
|
||||
from simnet import GenshinClient
|
||||
from simnet.models.genshin.chronicle.abyss import SpiralAbyss
|
||||
from telegram import Message, Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
@ -36,8 +34,6 @@ try:
|
||||
except ImportError:
|
||||
import json as jsonlib
|
||||
|
||||
TZ = timezone("Asia/Shanghai")
|
||||
|
||||
get_args_pattern = re.compile(r"\d+")
|
||||
|
||||
|
||||
@ -206,11 +202,6 @@ class AbyssPlugin(Plugin):
|
||||
bytes格式的图片
|
||||
"""
|
||||
|
||||
def json_encoder(value):
|
||||
if isinstance(value, datetime):
|
||||
return value.astimezone(TZ).strftime("%Y-%m-%d %H:%M:%S")
|
||||
return value
|
||||
|
||||
if not abyss_data.unlocked:
|
||||
raise AbyssUnlocked
|
||||
if not abyss_data.ranks.most_kills:
|
||||
@ -220,13 +211,13 @@ class AbyssPlugin(Plugin):
|
||||
if (total or (floor > 0)) and len(abyss_data.floors[0].chambers[0].battles) == 0:
|
||||
raise AbyssNotFoundError
|
||||
|
||||
start_time = abyss_data.start_time.astimezone(TZ)
|
||||
start_time = abyss_data.start_time
|
||||
time = start_time.strftime("%Y年%m月") + ("上" if start_time.day <= 15 else "下")
|
||||
stars = [i.stars for i in filter(lambda x: x.floor > 8, abyss_data.floors)]
|
||||
total_stars = f"{sum(stars)} ({'-'.join(map(str, stars))})"
|
||||
|
||||
render_data = {}
|
||||
result = abyss_data.json(encoder=json_encoder)
|
||||
result = abyss_data.model_dump_json()
|
||||
|
||||
render_data["time"] = time
|
||||
render_data["stars"] = total_stars
|
||||
@ -340,7 +331,7 @@ class AbyssPlugin(Plugin):
|
||||
|
||||
@staticmethod
|
||||
def get_season_data_name(data: "HistoryDataAbyss"):
|
||||
start_time = data.abyss_data.start_time.astimezone(TZ)
|
||||
start_time = data.abyss_data.start_time
|
||||
time = start_time.strftime("%Y.%m ")[2:] + ("上" if start_time.day <= 15 else "下")
|
||||
honor = ""
|
||||
if data.abyss_data.total_stars == 36:
|
||||
|
@ -16,7 +16,7 @@ import bs4
|
||||
import pydantic
|
||||
from arkowrapper import ArkoWrapper
|
||||
from httpx import AsyncClient, HTTPError, TimeoutException
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, RootModel
|
||||
from simnet.errors import BadRequest as SimnetBadRequest
|
||||
from simnet.errors import InvalidCookies
|
||||
from simnet.models.genshin.chronicle.characters import Character
|
||||
@ -118,16 +118,66 @@ def get_material_serial_name(names: Iterable[str]) -> str:
|
||||
return result
|
||||
|
||||
|
||||
class MaterialsData(BaseModel):
|
||||
__root__: Optional[List[Dict[str, "AreaDailyMaterialsData"]]] = None
|
||||
class AreaDailyMaterialsData(BaseModel):
|
||||
"""
|
||||
AreaDailyMaterialsData 储存某一天某个国家所有可以刷的突破素材以及可以突破的角色和武器
|
||||
对应 /daily_material 命令返回的图中一个国家横向这一整条的信息
|
||||
"""
|
||||
|
||||
avatar_materials: List[str] = []
|
||||
"""
|
||||
avatar_materials 是当日该国所有可以刷的精通和炼武素材的 ID 列表
|
||||
举个例子:稻妻周三可以刷「天光」系列材料
|
||||
(不用蒙德璃月举例是因为它们每天的角色武器太多了,等稻妻多了再换)
|
||||
那么 avatar_materials 将会包括
|
||||
- 104326 「天光」的教导
|
||||
- 104327 「天光」的指引
|
||||
- 104328 「天光」的哲学
|
||||
"""
|
||||
avatar: List[str] = []
|
||||
"""
|
||||
avatar 是排除旅行者后该国当日可以突破天赋的角色 ID 列表
|
||||
举个例子:稻妻周三可以刷「天光」系列精通素材
|
||||
需要用到「天光」系列的角色有
|
||||
- 10000052 雷电将军
|
||||
- 10000053 早柚
|
||||
- 10000055 五郎
|
||||
- 10000058 八重神子
|
||||
"""
|
||||
weapon_materials: List[str] = []
|
||||
"""
|
||||
weapon_materials 是当日该国所有可以刷的炼武素材的 ID 列表
|
||||
举个例子:稻妻周三可以刷今昔剧画系列材料
|
||||
那么 weapon_materials 将会包括
|
||||
- 114033 今昔剧画之恶尉
|
||||
- 114034 今昔剧画之虎啮
|
||||
- 114035 今昔剧画之一角
|
||||
- 114036 今昔剧画之鬼人
|
||||
"""
|
||||
weapon: List[str] = []
|
||||
"""
|
||||
weapon 是该国当日可以突破天赋的武器 ID 列表
|
||||
举个例子:稻妻周三可以刷今昔剧画系列炼武素材
|
||||
需要用到今昔剧画系列的武器有
|
||||
- 11416 笼钓瓶一心
|
||||
- 13414 喜多院十文字
|
||||
- 13415 「渔获」
|
||||
- 13416 断浪长鳍
|
||||
- 13509 薙草之稻光
|
||||
- 14509 神乐之真意
|
||||
"""
|
||||
|
||||
|
||||
class MaterialsData(RootModel):
|
||||
root: Optional[List[Dict[str, "AreaDailyMaterialsData"]]] = None
|
||||
|
||||
def weekday(self, weekday: int) -> Dict[str, "AreaDailyMaterialsData"]:
|
||||
if self.__root__ is None:
|
||||
if self.root is None:
|
||||
return {}
|
||||
return self.__root__[weekday]
|
||||
return self.root[weekday]
|
||||
|
||||
def is_empty(self) -> bool:
|
||||
return self.__root__ is None
|
||||
return self.root is None
|
||||
|
||||
|
||||
class DailyMaterial(Plugin):
|
||||
@ -681,7 +731,7 @@ def _parse_honey_impact_source(source: bytes) -> MaterialsData:
|
||||
ascendable_items = everyday_materials[weekday][current_country]
|
||||
ascendable_items = ascendable_items.weapon if item_is_weapon else ascendable_items.avatar
|
||||
ascendable_items.append(item_id)
|
||||
return MaterialsData(__root__=everyday_materials)
|
||||
return MaterialsData.model_validate(everyday_materials)
|
||||
|
||||
|
||||
class FragileGenshinClient:
|
||||
@ -716,7 +766,7 @@ class AreaData(BaseModel):
|
||||
name: str # 区域名
|
||||
material_name: str # 区域的材料系列名
|
||||
materials: List[ItemData] = [] # 区域材料
|
||||
items: Iterable[ItemData] = [] # 可培养的角色或武器
|
||||
items: List[ItemData] = [] # 可培养的角色或武器
|
||||
|
||||
|
||||
class RenderData(BaseModel):
|
||||
@ -735,56 +785,3 @@ class UserOwned(BaseModel):
|
||||
"""角色 ID 到角色对象的映射"""
|
||||
weapon: Dict[str, List[ItemData]] = {}
|
||||
"""用户同时可以拥有多把同名武器,因此是 ID 到 List 的映射"""
|
||||
|
||||
|
||||
class AreaDailyMaterialsData(BaseModel):
|
||||
"""
|
||||
AreaDailyMaterialsData 储存某一天某个国家所有可以刷的突破素材以及可以突破的角色和武器
|
||||
对应 /daily_material 命令返回的图中一个国家横向这一整条的信息
|
||||
"""
|
||||
|
||||
avatar_materials: List[str] = []
|
||||
"""
|
||||
avatar_materials 是当日该国所有可以刷的精通和炼武素材的 ID 列表
|
||||
举个例子:稻妻周三可以刷「天光」系列材料
|
||||
(不用蒙德璃月举例是因为它们每天的角色武器太多了,等稻妻多了再换)
|
||||
那么 avatar_materials 将会包括
|
||||
- 104326 「天光」的教导
|
||||
- 104327 「天光」的指引
|
||||
- 104328 「天光」的哲学
|
||||
"""
|
||||
avatar: List[str] = []
|
||||
"""
|
||||
avatar 是排除旅行者后该国当日可以突破天赋的角色 ID 列表
|
||||
举个例子:稻妻周三可以刷「天光」系列精通素材
|
||||
需要用到「天光」系列的角色有
|
||||
- 10000052 雷电将军
|
||||
- 10000053 早柚
|
||||
- 10000055 五郎
|
||||
- 10000058 八重神子
|
||||
"""
|
||||
weapon_materials: List[str] = []
|
||||
"""
|
||||
weapon_materials 是当日该国所有可以刷的炼武素材的 ID 列表
|
||||
举个例子:稻妻周三可以刷今昔剧画系列材料
|
||||
那么 weapon_materials 将会包括
|
||||
- 114033 今昔剧画之恶尉
|
||||
- 114034 今昔剧画之虎啮
|
||||
- 114035 今昔剧画之一角
|
||||
- 114036 今昔剧画之鬼人
|
||||
"""
|
||||
weapon: List[str] = []
|
||||
"""
|
||||
weapon 是该国当日可以突破天赋的武器 ID 列表
|
||||
举个例子:稻妻周三可以刷今昔剧画系列炼武素材
|
||||
需要用到今昔剧画系列的武器有
|
||||
- 11416 笼钓瓶一心
|
||||
- 13414 喜多院十文字
|
||||
- 13415 「渔获」
|
||||
- 13416 断浪长鳍
|
||||
- 13509 薙草之稻光
|
||||
- 14509 神乐之真意
|
||||
"""
|
||||
|
||||
|
||||
MaterialsData.update_forward_refs()
|
||||
|
@ -2,7 +2,7 @@ from decimal import Decimal
|
||||
from enum import Enum
|
||||
from typing import Optional, List, NewType
|
||||
|
||||
from pydantic import BaseModel, Field, validator
|
||||
from pydantic import field_validator, BaseModel, Field, ValidationInfo
|
||||
|
||||
# TODO: 考虑自动生成Enum
|
||||
Character = NewType("Character", str)
|
||||
@ -72,15 +72,17 @@ class WeaponInfo(BaseModel):
|
||||
refinement: int = 0
|
||||
ascension: int = 0
|
||||
|
||||
@validator("max_level")
|
||||
def validate_max_level(cls, v, values):
|
||||
@field_validator("max_level")
|
||||
@classmethod
|
||||
def validate_max_level(cls, v, info: ValidationInfo):
|
||||
if v == 0:
|
||||
return values["level"]
|
||||
if v < values["level"]:
|
||||
return info.data["level"]
|
||||
if v < info.data["level"]:
|
||||
raise ValueError("max_level must be greater than or equal to level")
|
||||
return v
|
||||
|
||||
@validator("refinement")
|
||||
@field_validator("refinement")
|
||||
@classmethod
|
||||
def validate_refinement(cls, v):
|
||||
if v < 0 or v > 5:
|
||||
raise ValueError("refinement must be between 1 and 5")
|
||||
@ -96,19 +98,22 @@ class Artifact(BaseModel):
|
||||
main_attribute: ArtifactAttribute
|
||||
sub_attributes: List[ArtifactAttribute] = []
|
||||
|
||||
@validator("level")
|
||||
@field_validator("level")
|
||||
@classmethod
|
||||
def validate_level(cls, v):
|
||||
if v < 0 or v > 20:
|
||||
raise ValueError("level must be between 0 and 20")
|
||||
return v
|
||||
|
||||
@validator("rarity")
|
||||
@field_validator("rarity")
|
||||
@classmethod
|
||||
def validate_rarity(cls, v):
|
||||
if v < 0 or v > 5:
|
||||
raise ValueError("rarity must be between 0 and 5")
|
||||
return v
|
||||
|
||||
@validator("sub_attributes")
|
||||
@field_validator("sub_attributes")
|
||||
@classmethod
|
||||
def validate_sub_attributes(cls, v):
|
||||
if len(v) > 4:
|
||||
raise ValueError("sub_attributes must not be greater than 4")
|
||||
@ -183,15 +188,17 @@ class CharacterInfo(BaseModel):
|
||||
rarity: int = 0
|
||||
stats: CharacterStats = CharacterStats()
|
||||
|
||||
@validator("max_level")
|
||||
def validate_max_level(cls, v, values):
|
||||
@field_validator("max_level")
|
||||
@classmethod
|
||||
def validate_max_level(cls, v, info: ValidationInfo):
|
||||
if v == 0:
|
||||
return values["level"]
|
||||
if v < values["level"]:
|
||||
return info.data["level"]
|
||||
if v < info.data["level"]:
|
||||
raise ValueError("max_level must be greater than or equal to level")
|
||||
return v
|
||||
|
||||
@validator("skills")
|
||||
@field_validator("skills")
|
||||
@classmethod
|
||||
def validate_skills(cls, v):
|
||||
if len(v) > 3:
|
||||
raise ValueError("skills must not be greater than 3")
|
||||
|
@ -3,7 +3,7 @@ from typing import Any, NewType, List, Optional, Tuple, Dict
|
||||
|
||||
from gcsim_pypi.aliases import ARTIFACT_ALIASES, CHARACTER_ALIASES, WEAPON_ALIASES
|
||||
from gcsim_pypi.availability import AVAILABLE_ARTIFACTS, AVAILABLE_CHARACTERS, AVAILABLE_WEAPONS
|
||||
from pydantic import BaseModel, validator
|
||||
from pydantic import field_validator, BaseModel
|
||||
|
||||
GCSimCharacter = NewType("GCSimCharacter", str)
|
||||
GCSimWeapon = NewType("GCSimWeapon", str)
|
||||
@ -17,7 +17,8 @@ class GCSimWeaponInfo(BaseModel):
|
||||
max_level: int = 20
|
||||
params: List[str] = []
|
||||
|
||||
@validator("weapon")
|
||||
@field_validator("weapon")
|
||||
@classmethod
|
||||
def validate_weapon(cls, v):
|
||||
if v not in AVAILABLE_WEAPONS or v not in WEAPON_ALIASES:
|
||||
raise ValueError(f"Not supported weapon: {v}")
|
||||
@ -29,7 +30,8 @@ class GCSimSetInfo(BaseModel):
|
||||
count: int = 2
|
||||
params: List[str] = []
|
||||
|
||||
@validator("set")
|
||||
@field_validator("set")
|
||||
@classmethod
|
||||
def validate_set(cls, v):
|
||||
if v not in AVAILABLE_ARTIFACTS or v not in ARTIFACT_ALIASES:
|
||||
raise ValueError(f"Not supported set: {v}")
|
||||
@ -70,7 +72,8 @@ class GCSimCharacterInfo(BaseModel):
|
||||
stats: GCSimCharacterStats = GCSimCharacterStats()
|
||||
params: List[str] = []
|
||||
|
||||
@validator("character")
|
||||
@field_validator("character")
|
||||
@classmethod
|
||||
def validate_character(cls, v):
|
||||
if v not in AVAILABLE_CHARACTERS or v not in CHARACTER_ALIASES:
|
||||
raise ValueError(f"Not supported character: {v}")
|
||||
|
@ -2,7 +2,7 @@ import base64
|
||||
from datetime import datetime
|
||||
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.errors import BadRequest as SimnetBadRequest, InvalidCookies, TimedOut as SimnetTimedOut
|
||||
from sqlalchemy.orm.exc import StaleDataError
|
||||
@ -30,7 +30,8 @@ class TaskDataBase(BaseModel):
|
||||
class ResinData(TaskDataBase):
|
||||
notice_num: Optional[int] = 140
|
||||
|
||||
@validator("notice_num")
|
||||
@field_validator("notice_num")
|
||||
@classmethod
|
||||
def notice_num_validator(cls, v):
|
||||
if v < 60 or v > 200:
|
||||
raise ValueError("树脂提醒数值必须在 60 ~ 200 之间")
|
||||
@ -40,7 +41,8 @@ class ResinData(TaskDataBase):
|
||||
class RealmData(TaskDataBase):
|
||||
notice_num: Optional[int] = 2000
|
||||
|
||||
@validator("notice_num")
|
||||
@field_validator("notice_num")
|
||||
@classmethod
|
||||
def notice_num_validator(cls, v):
|
||||
if v < 100 or v > 2400:
|
||||
raise ValueError("洞天宝钱提醒数值必须在 100 ~ 2400 之间")
|
||||
@ -54,7 +56,8 @@ class ExpeditionData(TaskDataBase):
|
||||
class DailyData(TaskDataBase):
|
||||
notice_hour: Optional[int] = 22
|
||||
|
||||
@validator("notice_hour")
|
||||
@field_validator("notice_hour")
|
||||
@classmethod
|
||||
def notice_hour_validator(cls, v):
|
||||
if v < 0 or v > 23:
|
||||
raise ValueError("每日任务提醒时间必须在 0 ~ 23 之间")
|
||||
@ -65,10 +68,10 @@ class WebAppData(BaseModel):
|
||||
user_id: int
|
||||
player_id: int
|
||||
|
||||
resin: Optional[ResinData]
|
||||
realm: Optional[RealmData]
|
||||
expedition: Optional[ExpeditionData]
|
||||
daily: Optional[DailyData]
|
||||
resin: Optional[ResinData] = None
|
||||
realm: Optional[RealmData] = None
|
||||
expedition: Optional[ExpeditionData] = None
|
||||
daily: Optional[DailyData] = None
|
||||
|
||||
|
||||
class DailyNoteTaskUser:
|
||||
|
@ -13,7 +13,7 @@ authors = [
|
||||
{name = "SiHuaN"},
|
||||
]
|
||||
dependencies = [
|
||||
"httpx<1.0.0,>=0.25.0",
|
||||
"httpx<1.0.0,>=0.28.0",
|
||||
"ujson<6.0.0,>=5.9.0",
|
||||
"Jinja2<4.0.0,>=3.1.2",
|
||||
"python-telegram-bot[ext,rate-limiter]<22.0,>=21.7",
|
||||
@ -43,9 +43,11 @@ dependencies = [
|
||||
"playwright==1.48.0",
|
||||
"aiosqlite<1.0.0,>=0.20.0",
|
||||
"simnet @ git+https://github.com/PaiGramTeam/SIMNet",
|
||||
"gcsim-pypi<3.0.0,>=2.23.0",
|
||||
"gcsim-pypi<3.0.0,>=2.29.0",
|
||||
"psutil<7.0.0,>=6.0.0",
|
||||
"influxdb-client[async,ciso]>=1.43.0",
|
||||
"influxdb-client[async,ciso]>=1.48.0",
|
||||
"pydantic>=2.0.0,<3.0.0",
|
||||
"pydantic-settings>=2.6.1",
|
||||
]
|
||||
requires-python = "<4.0,>=3.9"
|
||||
readme = "README.md"
|
||||
|
@ -3,16 +3,17 @@
|
||||
aiocsv==1.3.2
|
||||
aiofiles==24.1.0
|
||||
aiohappyeyeballs==2.4.3
|
||||
aiohttp==3.10.10
|
||||
aiohttp==3.11.8
|
||||
aiolimiter==1.1.0
|
||||
aiosignal==1.3.1
|
||||
aiosqlite==0.20.0
|
||||
alembic==1.14.0
|
||||
annotated-types==0.7.0
|
||||
anyio==4.6.2.post1
|
||||
apscheduler==3.10.4
|
||||
arko-wrapper==0.3.0
|
||||
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
|
||||
attrs==24.2.0
|
||||
beautifulsoup4==4.12.3
|
||||
@ -25,23 +26,23 @@ click==8.1.7
|
||||
colorama==0.4.6 ; sys_platform == 'win32' or platform_system == 'Windows'
|
||||
colorlog==6.9.0
|
||||
cryptography==43.0.3
|
||||
enkanetwork-py @ git+https://github.com/PaiGramTeam/EnkaNetwork.py@0889dc2de8f216a0bcbe983bcc4ed71cd7917d6a
|
||||
enkanetwork-py @ git+https://github.com/PaiGramTeam/EnkaNetwork.py@28ca9bc889589699b543782a82c17584b33e537d
|
||||
et-xmlfile==2.0.0
|
||||
exceptiongroup==1.2.2 ; python_full_version < '3.11'
|
||||
fakeredis==2.26.1
|
||||
fastapi==0.115.4
|
||||
fastapi==0.115.5
|
||||
flaky==3.8.1
|
||||
frozenlist==1.5.0
|
||||
gcsim-pypi==2.25.6
|
||||
gcsim-pypi==2.29.2
|
||||
gitdb==4.0.11
|
||||
gitpython==3.1.43
|
||||
greenlet==3.1.1
|
||||
h11==0.14.0
|
||||
httpcore==1.0.6
|
||||
httpcore==1.0.7
|
||||
httptools==0.6.4
|
||||
httpx==0.27.2
|
||||
httpx==0.28.0
|
||||
idna==3.10
|
||||
influxdb-client==1.47.0
|
||||
influxdb-client==1.48.0
|
||||
iniconfig==2.0.0
|
||||
jinja2==3.1.4
|
||||
lxml==5.3.0
|
||||
@ -62,7 +63,9 @@ propcache==0.2.0
|
||||
psutil==6.1.0
|
||||
pyaes==1.6.1
|
||||
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
|
||||
pygments==2.18.0
|
||||
pyrogram==2.0.106
|
||||
@ -79,9 +82,9 @@ rapidfuzz==3.10.1
|
||||
reactivex==4.0.4
|
||||
redis==5.2.0
|
||||
rich==13.9.4
|
||||
sentry-sdk==2.18.0
|
||||
setuptools==75.3.0
|
||||
simnet @ git+https://github.com/PaiGramTeam/SIMNet@745000612682f7b346d92b21f4d60502b92f477c
|
||||
sentry-sdk==2.19.0
|
||||
setuptools==75.6.0
|
||||
simnet @ git+https://github.com/PaiGramTeam/SIMNet@d7756addb558356adc65e7e14dc86e0a3cb5d8bd
|
||||
six==1.16.0
|
||||
smmap==5.0.1
|
||||
sniffio==1.3.1
|
||||
@ -89,18 +92,18 @@ sortedcontainers==2.4.0
|
||||
soupsieve==2.6
|
||||
sqlalchemy==2.0.36
|
||||
sqlmodel==0.0.22
|
||||
starlette==0.41.2
|
||||
starlette==0.41.3
|
||||
tgcrypto==1.2.5
|
||||
thefuzz==0.22.1
|
||||
tomli==2.0.2 ; python_full_version < '3.11'
|
||||
tornado==6.4.1
|
||||
tomli==2.2.1 ; python_full_version < '3.11'
|
||||
tornado==6.4.2
|
||||
typing-extensions==4.12.2
|
||||
tzdata==2024.2 ; platform_system == 'Windows'
|
||||
tzlocal==5.2
|
||||
ujson==5.10.0
|
||||
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'
|
||||
watchfiles==0.24.0
|
||||
websockets==13.1
|
||||
yarl==1.17.1
|
||||
watchfiles==1.0.0
|
||||
websockets==14.1
|
||||
yarl==1.18.0
|
||||
|
@ -1,8 +1,8 @@
|
||||
from multiprocessing import RLock as Lock
|
||||
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
|
||||
|
||||
@ -10,13 +10,13 @@ __all__ = ("LoggerConfig",)
|
||||
|
||||
|
||||
class LoggerConfig(BaseSettings):
|
||||
_lock = Lock()
|
||||
_instance: Optional["LoggerConfig"] = None
|
||||
_lock: ClassVar[Lock] = Lock()
|
||||
_instance: ClassVar[Optional["LoggerConfig"]] = None
|
||||
|
||||
def __new__(cls, *args, **kwargs) -> "LoggerConfig":
|
||||
with cls._lock:
|
||||
if cls._instance is None:
|
||||
cls.update_forward_refs()
|
||||
cls.model_rebuild()
|
||||
result = super(LoggerConfig, cls).__new__(cls) # pylint: disable=E1120
|
||||
result.__init__(*args, **kwargs)
|
||||
cls._instance = result
|
||||
|
Loading…
Reference in New Issue
Block a user