Skip to content

Commit

Permalink
migrate to adaptix for scn-models dump-restore
Browse files Browse the repository at this point in the history
  • Loading branch information
bomzheg committed Oct 4, 2024
1 parent 737a496 commit 7860d74
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 25 deletions.
27 changes: 27 additions & 0 deletions shvatka/common/factory.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import adaptix
import dataclass_factory
from adaptix import Retort, validator, P, name_mapping
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.schems import schemas
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


Expand All @@ -28,6 +34,27 @@ def create_dataclass_factory(self) -> dataclass_factory.Factory:
)
return dcf

@provide
def create_retort(self) -> Retort:
retort = Retort(
recipe=[
name_mapping(
name_style=adaptix.NameStyle.LOWER_KEBAB,
),
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")
),
validator(
pred=P[scn.LevelScenario].keys,
func=is_multiple_keys_normal,
error=lambda x: exceptions.ScenarioNotCorrect(notify_user=INVALID_KEY_ERROR, text="invalid keys")
),
]
)
return retort


class UrlProvider(Provider):
scope = Scope.APP
Expand Down
14 changes: 7 additions & 7 deletions shvatka/core/services/scenario/game_ops.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
from dataclass_factory import Factory
from adaptix import Retort

from shvatka.core.models.dto import scn
from shvatka.core.services.scenario.level_ops import (
check_all_files_saved as check_all_in_level_saved,
)


def parse_game(game: scn.RawGameScenario, dcf: Factory) -> scn.GameScenario:
return dcf.load(game.scn, scn.GameScenario)
def parse_game(game: scn.RawGameScenario, retort: Retort) -> scn.GameScenario:
return retort.load(game.scn, scn.GameScenario)


def parse_uploaded_game(game: scn.RawGameScenario, dcf: Factory) -> scn.UploadedGameScenario:
return dcf.load(game.scn, scn.UploadedGameScenario)
def parse_uploaded_game(game: scn.RawGameScenario, retort: Retort) -> scn.UploadedGameScenario:
return retort.load(game.scn, scn.UploadedGameScenario)


def serialize(game: scn.FullGameScenario, dcf: Factory) -> dict:
return dcf.dump(game)
def serialize(game: scn.FullGameScenario, retort: Retort) -> dict:
return retort.dump(game)


def check_all_files_saved(game: scn.GameScenario, guids: set[str]):
Expand Down
10 changes: 5 additions & 5 deletions shvatka/core/services/scenario/level_ops.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import dataclass_factory
from dataclass_factory import Factory
from adaptix import Retort
from adaptix.load_error import LoadError

from shvatka.core.models.dto import scn
from shvatka.core.utils import exceptions


def load_level(dct: dict, dcf: Factory) -> scn.LevelScenario:
def load_level(dct: dict, retort: Retort) -> scn.LevelScenario:
try:
return dcf.load(dct, scn.LevelScenario)
except dataclass_factory.PARSER_EXCEPTIONS as e:
return retort.load(dct, scn.LevelScenario)
except LoadError as e:
raise exceptions.ScenarioNotCorrect(notify_user="невалидный уровень") from e


Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

Expand Down Expand Up @@ -41,3 +42,9 @@ def event_loop():
async def dcf():
dishka = make_async_container(DCFProvider())
return await dishka.get(Factory)


@pytest_asyncio.fixture(scope="session")
async def retort() -> Retort:
dishka = make_async_container(DCFProvider())
return await dishka.get(Retort)
26 changes: 13 additions & 13 deletions tests/unit/serialization/test_deserialize.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from copy import deepcopy

import pytest
from dataclass_factory import Factory
from adaptix import Retort

from shvatka.core.models.dto.scn import TextHint, GPSHint, PhotoHint, ContactHint
from shvatka.core.models.dto.scn.game import RawGameScenario
Expand All @@ -22,41 +22,41 @@
from shvatka.tgbot.views.utils import render_hints


def test_deserialize_game(simple_scn: RawGameScenario, dcf: Factory):
game = parse_game(simple_scn, dcf)
def test_deserialize_game(simple_scn: RawGameScenario, retort: Retort):
game = parse_game(simple_scn, retort)
assert "My new game" == game.name
assert HintType.text.name == game.levels[0].time_hints[0].hint[0].type
assert "загадка" == game.levels[0].time_hints[0].hint[0].text
assert HintType.gps.name == game.levels[0].time_hints[2].hint[0].type


def test_deserialize_level(simple_scn: RawGameScenario, dcf: Factory):
level = load_level(simple_scn.scn["levels"][0], dcf)
def test_deserialize_level(simple_scn: RawGameScenario, retort: Retort):
level = load_level(simple_scn.scn["levels"][0], retort)
assert "first" == level.id
assert HintType.text.name == level.time_hints[0].hint[0].type
assert "загадка" == level.time_hints[0].hint[0].text
assert HintType.gps.name == level.time_hints[2].hint[0].type


def test_deserialize_invalid_level(simple_scn: RawGameScenario, dcf: Factory):
def test_deserialize_invalid_level(simple_scn: RawGameScenario, retort: Retort):
level_source = simple_scn.scn["levels"][0]
level = deepcopy(level_source)
level["id"] = "привет"
with pytest.raises(ScenarioNotCorrect):
load_level(level, dcf)
load_level(level, retort)

level["keys"] = {"SHCamelCase"}
with pytest.raises(ScenarioNotCorrect):
load_level(level, dcf)
load_level(level, retort)

level = deepcopy(level_source)
level["time_hints"] = level.pop("time-hints")
with pytest.raises(ScenarioNotCorrect):
load_level(level, dcf)
load_level(level, retort)


def test_deserialize_all_types(all_types_scn: RawGameScenario, dcf: Factory):
game_scn = parse_game(all_types_scn, dcf)
def test_deserialize_all_types(all_types_scn: RawGameScenario, retort: Retort):
game_scn = parse_game(all_types_scn, retort)
hints = game_scn.levels[0].time_hints
assert 12 == len(hints)
for i, type_ in enumerate(
Expand All @@ -79,8 +79,8 @@ def test_deserialize_all_types(all_types_scn: RawGameScenario, dcf: Factory):
assert hints[i].hint[0].type == type_.type # type: ignore[attr-defined]


def test_render_all_types(all_types_scn: RawGameScenario, dcf: Factory):
game_scn = parse_game(all_types_scn, dcf)
def test_render_all_types(all_types_scn: RawGameScenario, retort: Retort):
game_scn = parse_game(all_types_scn, retort)
hints = [time_hint.hint[0] for time_hint in game_scn.levels[0].time_hints]
assert 12 == len(hints)
assert "📃📡🧭📷🎼🎬📎🌀🎤🤳🪪🏷" == render_hints(hints)

0 comments on commit 7860d74

Please sign in to comment.