Skip to content

Commit

Permalink
fixed tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bomzheg committed Oct 4, 2024
1 parent 0531c40 commit be72d37
Show file tree
Hide file tree
Showing 19 changed files with 146 additions and 93 deletions.
7 changes: 5 additions & 2 deletions shvatka/api/models/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
from datetime import datetime
from typing import Sequence, Generic

from adaptix import Retort, dumper

from shvatka.core.games.dto import CurrentHints
from shvatka.core.models import dto, enums
from shvatka.core.models.dto import scn
from shvatka.core.models.enums import GameStatus

T = typing.TypeVar("T")
retort = Retort(recipe=[dumper(scn.HintsList, lambda x: x.hints)])


@dataclass
Expand Down Expand Up @@ -76,7 +79,7 @@ class Level:
db_id: int
name_id: str
author: Player
scenario: scn.LevelScenario
scenario: dict[str, typing.Any]
game_id: int | None = None
number_in_game: int | None = None

Expand All @@ -88,7 +91,7 @@ def from_core(cls, core: dto.Level | None = None):
db_id=core.db_id,
name_id=core.name_id,
author=Player.from_core(core.author),
scenario=core.scenario,
scenario=retort.dump(core.scenario),
game_id=core.game_id,
number_in_game=core.number_in_game,
)
Expand Down
38 changes: 31 additions & 7 deletions shvatka/common/factory.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import typing

import adaptix
import dataclass_factory
from adaptix import Retort, validator, P, name_mapping, loader, Chain, as_is_loader, constructor, bound
from adaptix import (
Retort,
validator,
P,
name_mapping,
loader,
Chain,
)
from adaptix.load_error import LoadError
from adaptix._internal.morphing.provider_template import ABCProxy
from dataclass_factory import Schema, NameStyle
from dishka import Provider, Scope, provide
from pyrogram.errors.exceptions.all import exceptions
from telegraph.aio import Telegraph

from shvatka.common.url_factory import UrlFactory
from shvatka.core.models.dto import scn
from shvatka.core.models.dto.scn import HintsList, TimeHint
from shvatka.core.models.schems import schemas
from shvatka.core.utils import exceptions
from shvatka.core.utils.input_validation import validate_level_id, is_multiple_keys_normal
from shvatka.core.views.texts import INVALID_KEY_ERROR
from shvatka.tgbot.config.models.bot import BotConfig
from shvatka.tgbot.views.hint_factory.hint_parser import HintParser


class TelegraphProvider(Provider):
Expand All @@ -26,6 +35,12 @@ def create_telegraph(self, bot_config: BotConfig) -> Telegraph:
return telegraph


REQUIRED_GAME_RECIPES = [
loader(HintsList, lambda x: HintsList(x), Chain.LAST),
ABCProxy(HintsList, list[TimeHint]), # internal class, can be broken in next version adaptix
]


class DCFProvider(Provider):
scope = Scope.APP

Expand All @@ -44,17 +59,26 @@ def create_retort(self) -> Retort:
name_mapping(
name_style=adaptix.NameStyle.LOWER_KEBAB,
),
loader(HintsList, lambda x: HintsList(x), Chain.LAST),
ABCProxy(HintsList, list[TimeHint]), # internal class, can be broken in next version adaptix
*REQUIRED_GAME_RECIPES,
validator(
pred=P[scn.LevelScenario].id,
func=lambda x: validate_level_id(x) is not None,
error=lambda x: exceptions.ScenarioNotCorrect(name_id=x, text=f"name_id ({x}) not correct")
error=lambda x: typing.cast(
LoadError,
exceptions.ScenarioNotCorrect(
name_id=x, text=f"name_id ({x}) not correct"
),
),
),
validator(
pred=P[scn.LevelScenario].keys,
func=is_multiple_keys_normal,
error=lambda x: exceptions.ScenarioNotCorrect(notify_user=INVALID_KEY_ERROR, text="invalid keys")
error=lambda x: typing.cast(
LoadError,
exceptions.ScenarioNotCorrect(
notify_user=INVALID_KEY_ERROR, text="invalid keys"
),
),
),
]
)
Expand Down
10 changes: 10 additions & 0 deletions shvatka/core/models/dto/scn/level.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ def __getitem__(self, index):
def __len__(self):
return len(self.hints)

def __eq__(self, other):
if isinstance(other, HintsList):
return self.hints == other.hints
if isinstance(other, list):
return self.hints == other
return NotImplemented

def __repr__(self):
return repr(self.hints)


@dataclass
class LevelScenario:
Expand Down
6 changes: 3 additions & 3 deletions shvatka/core/services/game.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime

from dataclass_factory import Factory
from adaptix import Retort

from shvatka.core.interfaces.clients.file_storage import FileGateway
from shvatka.core.interfaces.dal.complex import GameCompleter, GamePackager
Expand Down Expand Up @@ -37,7 +37,7 @@ async def upsert_game(
raw_scn: scn.RawGameScenario,
author: dto.Player,
dao: GameUpserter,
dcf: Factory,
dcf: Retort,
file_gateway: FileGateway,
) -> dto.FullGame:
check_allow_be_author(author)
Expand Down Expand Up @@ -121,7 +121,7 @@ async def get_game_package(
id_: int,
author: dto.Player,
dao: GamePackager,
dcf: Factory,
dcf: Retort,
file_gateway: FileGateway,
) -> scn.RawGameScenario:
game = await dao.get_full(id_=id_)
Expand Down
6 changes: 3 additions & 3 deletions shvatka/core/services/level.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclass_factory import Factory
from adaptix import Retort

from shvatka.core.interfaces.dal.level import (
LevelUpserter,
Expand All @@ -15,10 +15,10 @@


async def upsert_raw_level(
level_data: dict, author: dto.Player, dcf: Factory, dao: LevelUpserter
level_data: dict, author: dto.Player, retort: Retort, dao: LevelUpserter
) -> dto.Level:
check_allow_be_author(author)
scenario = load_level(level_data, dcf)
scenario = load_level(level_data, retort)
return await upsert_level(author, scenario, dao)


Expand Down
10 changes: 5 additions & 5 deletions shvatka/infrastructure/crawler/game_scn/loader/load_scns.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import BinaryIO, Any, Callable, Coroutine
from zipfile import Path as ZipPath

from dataclass_factory import Factory
from adaptix import Retort
from dishka import make_async_container

from shvatka.common.config.parser.logging_config import setup_logging
Expand Down Expand Up @@ -50,7 +50,7 @@ async def main():
bot_player=bot_player,
dao=dao,
file_gateway=file_gateway,
dcf=await dishka.get(Factory),
dcf=await dishka.get(Retort),
path=config.file_storage_config.path.parent / "scn",
)
finally:
Expand All @@ -61,7 +61,7 @@ async def load_scns(
bot_player: dto.Player,
dao: HolderDao,
file_gateway: FileGateway,
dcf: Factory,
dcf: Retort,
path: Path,
):
files = sorted(path.glob("*.zip"), key=lambda p: int(p.stem))
Expand Down Expand Up @@ -192,7 +192,7 @@ async def transfer_ownership(game: dto.FullGame, bot_player: dto.Player, dao: Ho
await dao.game.transfer(game, bot_player)


def load_results(game_zip_scn: BinaryIO, dcf: Factory) -> GameStat:
def load_results(game_zip_scn: BinaryIO, dcf: Retort) -> GameStat:
zip_path = ZipPath(game_zip_scn)
for unpacked_file in zip_path.iterdir():
if not unpacked_file.is_file():
Expand All @@ -209,7 +209,7 @@ async def load_scn(
player: dto.Player,
dao: HolderDao,
file_gateway: FileGateway,
dcf: Factory,
dcf: Retort,
zip_scn: BinaryIO,
) -> dto.FullGame | None:
try:
Expand Down
21 changes: 12 additions & 9 deletions shvatka/infrastructure/db/models/level.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import typing
from typing import Any

from dataclass_factory import Factory
from adaptix import Retort, dumper
from sqlalchemy import Integer, Text, ForeignKey, JSON, TypeDecorator, UniqueConstraint
from sqlalchemy.engine import Dialect
from sqlalchemy.orm import relationship, mapped_column, Mapped

from shvatka.common.factory import REQUIRED_GAME_RECIPES
from shvatka.core.models import dto
from shvatka.core.models.dto.scn.level import LevelScenario
from shvatka.core.models.dto import scn
from shvatka.infrastructure.db.models import Base

if typing.TYPE_CHECKING:
Expand All @@ -18,20 +19,22 @@
class ScenarioField(TypeDecorator):
impl = JSON
cache_ok = True
dcf = Factory()
retort = Retort(
recipe=[*REQUIRED_GAME_RECIPES, dumper(set, lambda x: list(x))],
)

def coerce_compared_value(self, op: Any, value: Any):
if isinstance(value, LevelScenario):
if isinstance(value, scn.LevelScenario):
return self
return self.impl().coerce_compared_value(op=op, value=value)

def process_bind_param(self, value: LevelScenario | None, dialect: Dialect):
return self.dcf.dump(value, LevelScenario)
def process_bind_param(self, value: scn.LevelScenario | None, dialect: Dialect):
return self.retort.dump(value, scn.LevelScenario)

def process_result_value(self, value: Any, dialect: Dialect) -> LevelScenario | None:
def process_result_value(self, value: Any, dialect: Dialect) -> scn.LevelScenario | None:
if value is None:
return None
return self.dcf.load(value, LevelScenario)
return self.retort.load(value, scn.LevelScenario)


class Level(Base):
Expand All @@ -52,7 +55,7 @@ class Level(Base):
back_populates="my_levels",
)
number_in_game = mapped_column(Integer, nullable=True)
scenario: Mapped[LevelScenario] = mapped_column(ScenarioField)
scenario: Mapped[scn.LevelScenario] = mapped_column(ScenarioField)

__table_args__ = (UniqueConstraint("author_id", "name_id"),)

Expand Down
6 changes: 3 additions & 3 deletions shvatka/tgbot/dialogs/game_manage/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from io import BytesIO
from typing import Any

from adaptix import Retort
from aiogram.types import CallbackQuery, Message, BufferedInputFile
from aiogram_dialog import DialogManager
from aiogram_dialog.widgets.kbd import Button
from dataclass_factory import Factory

from shvatka.core.interfaces.clients.file_storage import FileGateway
from shvatka.core.interfaces.scheduler import Scheduler
Expand Down Expand Up @@ -80,9 +80,9 @@ async def show_my_zip_scn(c: CallbackQuery, widget: Button, manager: DialogManag
async def common_show_zip(c: CallbackQuery, game_id: int, manager: DialogManager):
player: dto.Player = manager.middleware_data["player"]
dao: HolderDao = manager.middleware_data["dao"]
dcf: Factory = manager.middleware_data["dcf"]
retort: Retort = manager.middleware_data["retort"]
file_gateway: FileGateway = manager.middleware_data["file_gateway"]
game_ = await game.get_game_package(game_id, player, dao.game_packager, dcf, file_gateway)
game_ = await game.get_game_package(game_id, player, dao.game_packager, retort, file_gateway)
zip_ = pack_scn(game_)
assert isinstance(c.message, Message)
await c.message.answer_document(BufferedInputFile(file=zip_.read(), filename="scenario.zip"))
Expand Down
6 changes: 3 additions & 3 deletions shvatka/tgbot/dialogs/game_scn/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from typing import Any
from zipfile import Path as ZipPath

from adaptix import Retort
from aiogram import Bot
from aiogram.types import Message, CallbackQuery
from aiogram.utils.text_decorations import html_decoration as hd
from aiogram_dialog import DialogManager
from aiogram_dialog.widgets.kbd import Button, ManagedMultiselect
from dataclass_factory import Factory

from shvatka.core.interfaces.clients.file_storage import FileGateway
from shvatka.core.models import dto
Expand Down Expand Up @@ -57,12 +57,12 @@ async def process_zip_scn(m: Message, dialog_: Any, manager: DialogManager):
dao: HolderDao = manager.middleware_data["dao"]
bot: Bot = manager.middleware_data["bot"]
file_gateway: FileGateway = manager.middleware_data["file_gateway"]
dcf: Factory = manager.middleware_data["dcf"]
retort: Retort = manager.middleware_data["retort"]
assert m.document
document = await bot.download(m.document.file_id)
try:
with unpack_scn(ZipPath(document)).open() as scenario: # type: scn.RawGameScenario
game = await upsert_game(scenario, player, dao.game_upserter, dcf, file_gateway)
game = await upsert_game(scenario, player, dao.game_upserter, retort, file_gateway)
except ScenarioNotCorrect as e:
await m.reply(f"Ошибка {e}\n попробуйте исправить файл")
logger.error("game scenario from player %s has problems", player.id, exc_info=e)
Expand Down
13 changes: 7 additions & 6 deletions shvatka/tgbot/dialogs/level_scn/getters.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from adaptix import Retort
from aiogram_dialog import DialogManager
from dataclass_factory import Factory

Expand All @@ -19,19 +20,19 @@ async def get_keys(dialog_manager: DialogManager, **_):


async def get_bonus_keys(dialog_manager: DialogManager, **_):
dcf: Factory = dialog_manager.middleware_data["dcf"]
retort: Retort = dialog_manager.middleware_data["retort"]
keys_raw = dialog_manager.dialog_data.get(
"bonus_keys", dialog_manager.start_data.get("bonus_keys", [])
)
return {
"bonus_keys": dcf.load(keys_raw, list[scn.BonusKey]),
"bonus_keys": retort.load(keys_raw, list[scn.BonusKey]),
}


async def get_level_data(dialog_manager: DialogManager, **_):
dialog_data = dialog_manager.dialog_data
dcf: Factory = dialog_manager.middleware_data["dcf"]
hints = dcf.load(dialog_data.get("time_hints", []), list[TimeHint])
retort: Retort = dialog_manager.middleware_data["retort"]
hints = retort.load(dialog_data.get("time_hints", []), list[TimeHint])
return {
"level_id": dialog_data["level_id"],
"keys": dialog_data.get("keys", []),
Expand All @@ -42,8 +43,8 @@ async def get_level_data(dialog_manager: DialogManager, **_):

async def get_time_hints(dialog_manager: DialogManager, **_):
dialog_data = dialog_manager.dialog_data
dcf: Factory = dialog_manager.middleware_data["dcf"]
hints = dcf.load(dialog_data.get("time_hints", []), list[TimeHint])
retort: Retort = dialog_manager.middleware_data["retort"]
hints = retort.load(dialog_data.get("time_hints", []), list[TimeHint])
return {
"level_id": dialog_manager.start_data["level_id"],
"time_hints": hints,
Expand Down
Loading

0 comments on commit be72d37

Please sign in to comment.