Skip to content

serializer

Module to serialize and deserialize JSON data and models.

Serializer

Deserializes JSON data to models.

Source code in barch\serializer.py
class Serializer:
    """Deserializes JSON data to models."""

    __slots__ = ()

    def _datetime_from_unix_ms(self, datetime_str: str | int | None) -> datetime | None:
        """Converts unix timestamp in milliseconds to UTC datetime."""

        return datetime.utcfromtimestamp(datetime_str / 1000) if datetime_str else None

    def _to_camel_case(self, attr: str) -> str:
        """Converts input arguments to camel case."""
        first, *rest = attr.split("_")
        return "".join((first.lower(), *map(str.title, rest)))

    def _set_attrs(
        self, model: Any, data: dict[str, Any], *attrs: str, camel_case: bool = False
    ) -> None:
        """Generate model from JSON payload."""

        if data:
            for attr in attrs:
                cased_attr = self._to_camel_case(attr) if camel_case else attr

                if data.get(cased_attr) is not None:
                    setattr(model, attr, data[cased_attr])
                else:
                    setattr(model, attr, None)

    def _set_attrs_cased(self, model: Any, data: dict[str, Any], *attrs: str) -> None:
        """Generate model from JSON payload when input arguments need to be changed to camel case."""

        return self._set_attrs(model, data, *attrs, camel_case=True)

    def _deserialize_terrain(self, data: dict[str, Any]) -> Terrain:
        """Deserializes JSON payload into `Terrain` model."""

        terrain = Terrain()

        terrain.urban = self._deserialize_terrain_details(data.get("urban", {}))
        terrain.outdoor = self._deserialize_terrain_details(data.get("outdoor", {}))
        terrain.indoor = self._deserialize_terrain_details(data.get("indoor", {}))

        return terrain

    def _deserialize_terrain_details(self, data: dict[str, Any]) -> TerrainDetails:
        """Deserializes JSON payload into `TerrainDetails` model."""

        terrain_details = TerrainDetails(
            data.get("DamageDealt", ""), data.get("ShieldBlockRate", "")
        )

        return terrain_details

    def deserialize_character(self, data: dict[str, Any]) -> Character:
        """Deserializes JSON payload into `Character` model."""

        character = Character()

        character.position = Position.from_str(data.get("position", None))
        character.role = Role.from_str(data.get("role", None))
        character.rarity = Rarity.try_from_str(data.get("rarity", None))

        character.terrain = self._deserialize_terrain(data.get("terrain", {}))

        self._set_attrs_cased(
            character,
            data,
            "id",
            "name",
            "profile",
            "base_star",
            "armor_type",
            "bullet_type",
            "weapon_type",
            "squad_type",
            "school",
        )

        return character

    def deserialize_character_info(self, data: dict[str, Any]) -> CharacterInfo:
        """Deserializes JSON payload into `CharacterInfo` model."""

        charcter_info = CharacterInfo()

        self._set_attrs_cased(
            charcter_info,
            data,
            "age",
            "birth_date",
            "height",
            "artist",
            "club",
            "school",
            "school_year",
            "voice_actor",
        )

        return charcter_info

    def deserialize_stats(self, data: dict[str, Any]) -> Stats:
        """Deserializes JSON payload into `Stats` model."""

        character_stats = Stats()

        self._set_attrs_cased(
            character_stats,
            data,
            "id",
            "attack_level1",
            "attack_level100",
            "defense_level1",
            "defense_level100",
            "heal_power_level1",
            "heal_power_level100",
            "def_penetrate_level1",
            "def_penetrate_level100",
            "ammo_count",
            "ammo_cost",
            "range",
            "move_speed",
            "street_mood",
            "outdoor_mood",
            "indoor_mood",
        )

        setattr(character_stats, "max_hp_level1", data["maxHPLevel1"])
        setattr(character_stats, "max_hp_level100", data["maxHPLevel100"])

        return character_stats

    def deserialize_skills_details(self, data: dict[str, Any]) -> CommonModel:
        """Deserializes JSON payload into `CommonModel` model."""

        return [
            CommonModel(skill.get("id"), skill.get("name"), skill.get("description", ""))
            for skill in data
        ]

    def deserialize_skills(self, data: dict[str, Any]) -> Skills:
        """Deserializes JSON payload into `Skills` model."""

        character_skills = Skills()

        character_skills.ex = (
            self.deserialize_skills_details(data.get("ex", [])[0])
            if data.get("ex", None)
            else None
        )

        character_skills.normal = (
            self.deserialize_skills_details(data.get("normal", [])[0])
            if data.get("normal", None)
            else None
        )

        character_skills.passive = (
            self.deserialize_skills_details(data.get("passive", [])[0])
            if data.get("passive", None)
            else None
        )

        character_skills.sub = (
            self.deserialize_skills_details(data.get("sub", [])[0])
            if data.get("sub", None)
            else None
        )

        return character_skills

    def deserialize_image(self, data: dict[str, Any]) -> Image:
        """Deserializes JSON payload into `Image` model."""

        return Image(
            data.get("icon", ""),
            data.get("portrait", ""),
            data.get("lobby", ""),
        )

    def deserialize_base_character(self, data: dict[str, Any]) -> BaseCharacter:
        """Deserializes JSON payload into `BaseCharacter` model."""

        character = BaseCharacter()

        character.position = Position.from_str(data.get("position", None))
        character.role = Role.from_str(data.get("role", None))
        character.rarity = Rarity.try_from_str(data.get("rarity", None))

        self._set_attrs_cased(
            character,
            data,
            "name",
            "profile",
            "base_star",
            "armor_type",
            "bullet_type",
            "weapon_type",
            "squad_type",
        )

        return character

    def deserialize_character_details(self, data: dict[str, Any]) -> CharacterDetails:
        """Deserializes JSON payload into `CharacterDetails` model."""

        charcter_details = CharacterDetails()

        charcter_details.character = self.deserialize_base_character(data.get("character", {}))

        charcter_details.info = self.deserialize_character_info(data.get("info", {}))
        charcter_details.stat = self.deserialize_stats(data.get("stat", {}))
        charcter_details.terrain = self._deserialize_terrain(data.get("terrain", {}))

        charcter_details.image = self.deserialize_image(data.get("image", {}))

        charcter_details.skills = self.deserialize_skills(data.get("skills", {}))

        self._set_attrs_cased(charcter_details, data, "id", "is_released", "is_playable")

        return charcter_details

    def deserialize_characters_from_query(self, data: dict[str, Any]) -> Characters:
        """Deserializes JSON payload into `Characters` model."""

        return Characters(data.get("id"), data.get("name"))

    def deserialize_raid(self, data: dict[str, Any]) -> Raid:
        """Deserializes JSON payload into `Raid` model."""

        raid = Raid()

        raid.start_at = self._datetime_from_unix_ms(data.get("startAt", None))
        raid.settle_at = self._datetime_from_unix_ms(data.get("settleAt", None))
        raid.end_at = self._datetime_from_unix_ms(data.get("endAt", None))

        self._set_attrs_cased(raid, data, "season_id", "boss_name")

        return raid

    def deserialize_raids(self, data: dict[str, Any]) -> Raids:
        """Deserializes JSON payload into `Raids` model."""

        raids = Raids()
        raids.current = [self.deserialize_raid(raid) for raid in data.get("current", [])]

        raids.upcoming = [self.deserialize_raid(raid) for raid in data.get("upcoming", [])]

        raids.ended = [self.deserialize_raid(raid) for raid in data.get("ended", [])]

        return raids

deserialize_base_character

deserialize_base_character(
    data: dict[str, Any]
) -> BaseCharacter

Deserializes JSON payload into BaseCharacter model.

Source code in barch\serializer.py
def deserialize_base_character(self, data: dict[str, Any]) -> BaseCharacter:
    """Deserializes JSON payload into `BaseCharacter` model."""

    character = BaseCharacter()

    character.position = Position.from_str(data.get("position", None))
    character.role = Role.from_str(data.get("role", None))
    character.rarity = Rarity.try_from_str(data.get("rarity", None))

    self._set_attrs_cased(
        character,
        data,
        "name",
        "profile",
        "base_star",
        "armor_type",
        "bullet_type",
        "weapon_type",
        "squad_type",
    )

    return character

deserialize_character

deserialize_character(data: dict[str, Any]) -> Character

Deserializes JSON payload into Character model.

Source code in barch\serializer.py
def deserialize_character(self, data: dict[str, Any]) -> Character:
    """Deserializes JSON payload into `Character` model."""

    character = Character()

    character.position = Position.from_str(data.get("position", None))
    character.role = Role.from_str(data.get("role", None))
    character.rarity = Rarity.try_from_str(data.get("rarity", None))

    character.terrain = self._deserialize_terrain(data.get("terrain", {}))

    self._set_attrs_cased(
        character,
        data,
        "id",
        "name",
        "profile",
        "base_star",
        "armor_type",
        "bullet_type",
        "weapon_type",
        "squad_type",
        "school",
    )

    return character

deserialize_character_details

deserialize_character_details(
    data: dict[str, Any]
) -> CharacterDetails

Deserializes JSON payload into CharacterDetails model.

Source code in barch\serializer.py
def deserialize_character_details(self, data: dict[str, Any]) -> CharacterDetails:
    """Deserializes JSON payload into `CharacterDetails` model."""

    charcter_details = CharacterDetails()

    charcter_details.character = self.deserialize_base_character(data.get("character", {}))

    charcter_details.info = self.deserialize_character_info(data.get("info", {}))
    charcter_details.stat = self.deserialize_stats(data.get("stat", {}))
    charcter_details.terrain = self._deserialize_terrain(data.get("terrain", {}))

    charcter_details.image = self.deserialize_image(data.get("image", {}))

    charcter_details.skills = self.deserialize_skills(data.get("skills", {}))

    self._set_attrs_cased(charcter_details, data, "id", "is_released", "is_playable")

    return charcter_details

deserialize_character_info

deserialize_character_info(
    data: dict[str, Any]
) -> CharacterInfo

Deserializes JSON payload into CharacterInfo model.

Source code in barch\serializer.py
def deserialize_character_info(self, data: dict[str, Any]) -> CharacterInfo:
    """Deserializes JSON payload into `CharacterInfo` model."""

    charcter_info = CharacterInfo()

    self._set_attrs_cased(
        charcter_info,
        data,
        "age",
        "birth_date",
        "height",
        "artist",
        "club",
        "school",
        "school_year",
        "voice_actor",
    )

    return charcter_info

deserialize_characters_from_query

deserialize_characters_from_query(
    data: dict[str, Any]
) -> Characters

Deserializes JSON payload into Characters model.

Source code in barch\serializer.py
def deserialize_characters_from_query(self, data: dict[str, Any]) -> Characters:
    """Deserializes JSON payload into `Characters` model."""

    return Characters(data.get("id"), data.get("name"))

deserialize_image

deserialize_image(data: dict[str, Any]) -> Image

Deserializes JSON payload into Image model.

Source code in barch\serializer.py
def deserialize_image(self, data: dict[str, Any]) -> Image:
    """Deserializes JSON payload into `Image` model."""

    return Image(
        data.get("icon", ""),
        data.get("portrait", ""),
        data.get("lobby", ""),
    )

deserialize_raid

deserialize_raid(data: dict[str, Any]) -> Raid

Deserializes JSON payload into Raid model.

Source code in barch\serializer.py
def deserialize_raid(self, data: dict[str, Any]) -> Raid:
    """Deserializes JSON payload into `Raid` model."""

    raid = Raid()

    raid.start_at = self._datetime_from_unix_ms(data.get("startAt", None))
    raid.settle_at = self._datetime_from_unix_ms(data.get("settleAt", None))
    raid.end_at = self._datetime_from_unix_ms(data.get("endAt", None))

    self._set_attrs_cased(raid, data, "season_id", "boss_name")

    return raid

deserialize_raids

deserialize_raids(data: dict[str, Any]) -> Raids

Deserializes JSON payload into Raids model.

Source code in barch\serializer.py
def deserialize_raids(self, data: dict[str, Any]) -> Raids:
    """Deserializes JSON payload into `Raids` model."""

    raids = Raids()
    raids.current = [self.deserialize_raid(raid) for raid in data.get("current", [])]

    raids.upcoming = [self.deserialize_raid(raid) for raid in data.get("upcoming", [])]

    raids.ended = [self.deserialize_raid(raid) for raid in data.get("ended", [])]

    return raids

deserialize_skills

deserialize_skills(data: dict[str, Any]) -> Skills

Deserializes JSON payload into Skills model.

Source code in barch\serializer.py
def deserialize_skills(self, data: dict[str, Any]) -> Skills:
    """Deserializes JSON payload into `Skills` model."""

    character_skills = Skills()

    character_skills.ex = (
        self.deserialize_skills_details(data.get("ex", [])[0])
        if data.get("ex", None)
        else None
    )

    character_skills.normal = (
        self.deserialize_skills_details(data.get("normal", [])[0])
        if data.get("normal", None)
        else None
    )

    character_skills.passive = (
        self.deserialize_skills_details(data.get("passive", [])[0])
        if data.get("passive", None)
        else None
    )

    character_skills.sub = (
        self.deserialize_skills_details(data.get("sub", [])[0])
        if data.get("sub", None)
        else None
    )

    return character_skills

deserialize_skills_details

deserialize_skills_details(
    data: dict[str, Any]
) -> CommonModel

Deserializes JSON payload into CommonModel model.

Source code in barch\serializer.py
def deserialize_skills_details(self, data: dict[str, Any]) -> CommonModel:
    """Deserializes JSON payload into `CommonModel` model."""

    return [
        CommonModel(skill.get("id"), skill.get("name"), skill.get("description", ""))
        for skill in data
    ]

deserialize_stats

deserialize_stats(data: dict[str, Any]) -> Stats

Deserializes JSON payload into Stats model.

Source code in barch\serializer.py
def deserialize_stats(self, data: dict[str, Any]) -> Stats:
    """Deserializes JSON payload into `Stats` model."""

    character_stats = Stats()

    self._set_attrs_cased(
        character_stats,
        data,
        "id",
        "attack_level1",
        "attack_level100",
        "defense_level1",
        "defense_level100",
        "heal_power_level1",
        "heal_power_level100",
        "def_penetrate_level1",
        "def_penetrate_level100",
        "ammo_count",
        "ammo_cost",
        "range",
        "move_speed",
        "street_mood",
        "outdoor_mood",
        "indoor_mood",
    )

    setattr(character_stats, "max_hp_level1", data["maxHPLevel1"])
    setattr(character_stats, "max_hp_level100", data["maxHPLevel100"])

    return character_stats