Skip to content

Commit

Permalink
✨ 将处理过程中的 dataclass 换成 pydantic
Browse files Browse the repository at this point in the history
  • Loading branch information
shoucandanghehe committed Nov 20, 2023
1 parent 2f144ac commit 0d58945
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 74 deletions.
6 changes: 3 additions & 3 deletions nonebot_plugin_tetris_stats/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy import JSON, DateTime, PickleType, String
from sqlalchemy.orm import Mapped, MappedAsDataclass, mapped_column

from ..game_data_processor import ProcessedData, User
from ..game_data_processor.schemas import BaseProcessedData, BaseUser
from ..utils.typing import CommandType, GameType


Expand All @@ -28,6 +28,6 @@ class HistoricalData(MappedAsDataclass, Model):
game_platform: Mapped[GameType] = mapped_column(String(32), index=True, init=False)
command_type: Mapped[CommandType] = mapped_column(String(16), index=True, init=False)
command_args: Mapped[list[str]] = mapped_column(JSON, init=False)
game_user: Mapped[User] = mapped_column(PickleType, init=False)
processed_data: Mapped[ProcessedData] = mapped_column(PickleType, init=False)
game_user: Mapped[BaseUser] = mapped_column(PickleType, init=False)
processed_data: Mapped[BaseProcessedData] = mapped_column(PickleType, init=False)
finish_time: Mapped[datetime] = mapped_column(DateTime, init=False)
23 changes: 4 additions & 19 deletions nonebot_plugin_tetris_stats/game_data_processor/__init__.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,16 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import UTC, datetime
from typing import Any

from nonebot.matcher import Matcher
from nonebot_plugin_alconna import AlcMatches, AlconnaMatcher

from ..utils.exception import MessageFormatError
from ..utils.recorder import Recorder
from ..utils.typing import CommandType, GameType


@dataclass
class User:
"""游戏用户"""


@dataclass
class RawResponse:
"""原始请求数据"""


@dataclass
class ProcessedData:
"""处理/验证后的数据"""


from ..utils.recorder import Recorder # noqa: E402 避免循环导入
from .schemas import BaseProcessedData as ProcessedData
from .schemas import BaseRawResponse as RawResponse
from .schemas import BaseUser as User


class Processor(ABC):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from collections import defaultdict
from collections.abc import Callable
from dataclasses import asdict, dataclass
from datetime import UTC, datetime, timedelta
from math import floor
from re import match
Expand All @@ -16,15 +15,14 @@
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
from ...utils.request import Request, splice_url
from ...utils.typing import GameType
from .. import ProcessedData as ProcessedDataMeta
from .. import Processor as ProcessorMeta
from .. import RawResponse as RawResponseMeta
from .. import User as UserMeta
from ..schemas import BaseUser
from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE
from .model import IORank
from .schemas.league_all import FailedModel as LeagueAllFailed
from .schemas.league_all import LeagueAll
from .schemas.league_all import ValidUser as LeagueAllUser
from .schemas.response import ProcessedData, RawResponse
from .schemas.user_info import FailedModel as InfoFailed
from .schemas.user_info import (
NeverPlayedLeague,
Expand All @@ -40,22 +38,15 @@
driver = get_driver()


@dataclass
class User(UserMeta):
class User(BaseUser):
ID: str | None = None
name: str | None = None


@dataclass
class RawResponse(RawResponseMeta):
user_info: bytes | None = None
user_records: bytes | None = None


@dataclass
class ProcessedData(ProcessedDataMeta):
user_info: InfoSuccess | None = None
user_records: RecordsSuccess | None = None
@property
def unique_identifier(self) -> str:
if self.ID is None:
raise ValueError('不完整的User!')
return self.ID


def identify_user_info(info: str) -> User | MessageFormatError:
Expand Down Expand Up @@ -214,7 +205,7 @@ def build_extremes_data(
sort: Callable[[list[LeagueAllUser], Callable[[LeagueAllUser], float]], LeagueAllUser],
) -> tuple[dict[str, str], float]:
user = sort(users, field)
return asdict(User(ID=user.id, name=user.username)), field(user)
return User(ID=user.id, name=user.username).dict(), field(user)

users = [i for i in league_all.data.users if isinstance(i, LeagueAllUser)]
rank_to_users: defaultdict[Rank, list[LeagueAllUser]] = defaultdict(list)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from ... import ProcessedData as ProcessedDataMeta
from ... import RawResponse as RawResponseMeta
from .user_info import SuccessModel as InfoSuccess
from .user_records import SuccessModel as RecordsSuccess


class RawResponse(RawResponseMeta):
user_info: bytes | None = None
user_records: bytes | None = None


class ProcessedData(ProcessedDataMeta):
user_info: InfoSuccess | None = None
user_records: RecordsSuccess | None = None
24 changes: 24 additions & 0 deletions nonebot_plugin_tetris_stats/game_data_processor/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from abc import ABC, abstractmethod
from typing import Self

from pydantic import BaseModel


class BaseUser(ABC, BaseModel):
"""游戏用户"""

def __eq__(self, __value: Self) -> bool:
return self.unique_identifier == __value.unique_identifier

@property
@abstractmethod
def unique_identifier(self) -> str:
raise NotImplementedError


class BaseRawResponse(BaseModel):
"""原始请求数据"""


class BaseProcessedData(BaseModel):
"""处理/验证后的数据"""
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,18 @@
from ...utils.exception import MessageFormatError, RequestError
from ...utils.request import Request, splice_url
from ...utils.typing import GameType
from .. import ProcessedData as ProcessedDataMeta
from .. import Processor as ProcessorMeta
from .. import RawResponse as RawResponseMeta
from .. import User as UserMeta
from ..schemas import BaseUser
from .constant import BASE_URL, GAME_TYPE
from .schemas.response import ProcessedData, RawResponse


@dataclass
class User(UserMeta):
class User(BaseUser):
name: str


@dataclass
class RawResponse(RawResponseMeta):
user_profile: bytes | None = None


@dataclass
class ProcessedData(ProcessedDataMeta):
user_profile: str | None = None
@property
def unique_identifier(self) -> str:
return self.name


@dataclass
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from ...schemas import BaseProcessedData, BaseRawResponse


class RawResponse(BaseRawResponse):
user_profile: bytes | None = None


class ProcessedData(BaseProcessedData):
user_profile: str | None = None
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from dataclasses import dataclass
from re import match
from typing import Any
from urllib.parse import urlencode

from nonebot_plugin_orm import get_session
Expand All @@ -10,32 +9,24 @@
from ...utils.exception import MessageFormatError, RequestError
from ...utils.request import Request, splice_url
from ...utils.typing import GameType
from .. import ProcessedData as ProcessedDataMeta
from .. import Processor as ProcessorMeta
from .. import RawResponse as RawResponseMeta
from .. import User as UserMeta
from ..schemas import BaseUser
from .constant import BASE_URL, GAME_TYPE
from .schemas.response import ProcessedData, RawResponse
from .schemas.user_info import SuccessModel as InfoSuccess
from .schemas.user_info import UserInfo
from .schemas.user_profile import UserProfile


@dataclass
class User(UserMeta):
class User(BaseUser):
teaid: str | None = None
name: str | None = None


@dataclass
class RawResponse(RawResponseMeta):
user_profile: dict[frozenset[tuple[str, Any]], bytes]
user_info: bytes | None = None


@dataclass
class ProcessedData(ProcessedDataMeta):
user_profile: dict[frozenset[tuple[str, Any]], UserProfile]
user_info: InfoSuccess | None = None
@property
def unique_identifier(self) -> str:
if self.teaid is None:
raise ValueError('不完整的User!')
return self.teaid


@dataclass
Expand Down Expand Up @@ -135,18 +126,18 @@ async def get_user_info(self) -> InfoSuccess:
self.processed_data.user_info = user_info
return self.processed_data.user_info

async def get_user_profile(self, other_parameter: dict[str, Any] | None = None) -> UserProfile:
async def get_user_profile(self, other_parameter: dict[str, str | bytes] | None = None) -> UserProfile:
"""获取用户数据"""
if other_parameter is None:
other_parameter = {}
fset = frozenset(other_parameter.items())
fset: frozenset[tuple[str, str | bytes]] = frozenset(other_parameter.items())
if self.processed_data.user_profile.get(fset) is None:
self.raw_response.user_profile[fset] = await Request.request(
splice_url(
[
BASE_URL,
'getProfile',
f'?{urlencode({"id":self.user.teaid or self.user.name},**other_parameter)}',
f'?{urlencode({"id":self.user.teaid or self.user.name,**other_parameter})}',
]
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from ...schemas import BaseProcessedData, BaseRawResponse
from .user_info import SuccessModel as InfoSuccess
from .user_profile import UserProfile


class RawResponse(BaseRawResponse):
user_profile: dict[frozenset[tuple[str, str | bytes]], bytes]
user_info: bytes | None = None


class ProcessedData(BaseProcessedData):
user_profile: dict[frozenset[tuple[str, str | bytes]], UserProfile]
user_info: InfoSuccess | None = None

0 comments on commit 0d58945

Please sign in to comment.