ModConfig have been converted to a dataclass to improve readability (no redundant __init__, __slots__ and from_json)

This commit is contained in:
Faraphel 2022-08-18 21:34:27 +02:00
parent 95f3943b02
commit 025d985316

View file

@ -1,4 +1,5 @@
import shutil import shutil
from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from typing import Generator, Callable, Iterator, Iterable, TYPE_CHECKING from typing import Generator, Callable, Iterator, Iterable, TYPE_CHECKING
import json import json
@ -66,65 +67,50 @@ def merge_dict(dict1: dict[str, dict] | None, dict2: dict[str, dict] | None,
return {key: dict1.get(key, {}) | dict2.get(key, {}) for key in dict_keys} return {key: dict1.get(key, {}) | dict2.get(key, {}) for key in dict_keys}
@dataclass(init=True, slots=True)
class ModConfig: class ModConfig:
""" """
Representation of a mod Representation of a mod
""" """
__slots__ = ("name", "path", "nickname", "variant", "_tracks", "arenas", "version", path: Path | str
"original_track_prefix", "swap_original_order", "keep_original_track", name: str
"enable_random_cup", "tags_cups", "track_file_template", nickname: str = None
"multiplayer_disable_if", "macros", "messages", "global_settings", version: str = "v1.0.0"
"specific_settings", "lpar_template", "tags_templates") variant: str = "01"
def __init__(self, path: Path | str, name: str, nickname: str = None, version: str = None, variant: str = None, _tracks: list["Track | TrackGroup"] = field(default_factory=list)
tags_cups: list[Tag] = None, tracks: list["Track | TrackGroup"] = None, _arenas: list["Arena"] = field(default_factory=list)
original_track_prefix: bool = None, swap_original_order: bool = None, keep_original_track: bool = None, track_file_template: "TemplateMultipleSafeEval" = "{{ getattr(track, 'sha1', '_') }}"
enable_random_cup: bool = None, track_file_template: "TemplateMultipleSafeEval" = None, multiplayer_disable_if: "TemplateSafeEval" = "False"
multiplayer_disable_if: "TemplateSafeEval" = None, macros: dict[str, "TemplateSafeEval"] = None,
messages: dict[str, dict[str, "TemplateMultipleSafeEval"]] = None,
global_settings: dict[str, dict[str, str]] = None, specific_settings: dict[str, dict[str, str]] = None,
lpar_template: "TemplateMultipleSafeEval" = None,
tags_templates: dict[str, "TemplateMultipleSafeEval"] = None, arenas: list["Arena"] = None):
self.path = Path(path) tags_cups: list[Tag] = field(default_factory=list)
self.macros = macros if macros is not None else {} tags_templates: dict[str, "TemplateMultipleSafeEval"] = field(default_factory=dict)
self.messages = messages if messages is not None else {}
self.global_settings = {name: AbstractModSettings.get(data) for name, data in merge_dict( original_track_prefix: bool = True
# Avoid modder to add their own settings to globals one swap_original_order: bool = True
default_global_settings, global_settings, dict_keys=default_global_settings.keys() keep_original_track: bool = True
).items()} enable_random_cup: bool = True
self.specific_settings = {name: AbstractModSettings.get(data) for name, data in ( macros: dict[str, "TemplateSafeEval"] = field(default_factory=dict)
specific_settings if specific_settings is not None else {} messages: dict[str, dict[str, "TemplateMultipleSafeEval"]] = field(default_factory=dict)
).items()}
self.name = name global_settings: dict[str, "AbstractModSettings"] = field(default_factory=dict)
self.nickname = nickname if nickname is not None else name specific_settings: dict[str, "AbstractModSettings"] = field(default_factory=dict)
self.version = version if version is not None else "v1.0.0"
self.variant = variant if variant is not None else "01"
self.tags_templates = tags_templates if tags_templates is not None else {} lpar_template: "TemplateMultipleSafeEval" = "normal.lpar"
self.tags_cups = tags_cups if tags_cups is not None else []
self._tracks = tracks if tracks is not None else [] def __post_init__(self):
self.track_file_template = track_file_template \ self.path = Path(self.path)
if track_file_template is not None else "{{ getattr(track, 'sha1', '_') }}" if self.nickname is None: self.nickname = self.name
self.multiplayer_disable_if = multiplayer_disable_if if multiplayer_disable_if is not None else "False"
self.lpar_template = lpar_template if lpar_template is not None else "normal.lpar"
self.arenas = arenas if arenas is not None else [] def __hash__(self) -> int:
return hash(self.name)
self.original_track_prefix = original_track_prefix if original_track_prefix is not None else True def __repr__(self) -> str:
self.swap_original_order = swap_original_order if swap_original_order is not None else True
self.keep_original_track = keep_original_track if keep_original_track is not None else True
self.enable_random_cup = enable_random_cup if enable_random_cup is not None else True
def __repr__(self):
return f"<ModConfig name={self.name} version={self.version}>" return f"<ModConfig name={self.name} version={self.version}>"
def __str__(self): def __str__(self) -> str:
return f"{self.name} {self.version}" return f"{self.name} {self.version}"
@classmethod @classmethod
@ -137,24 +123,27 @@ class ModConfig:
:param macros: macro that can be used for safe_eval :param macros: macro that can be used for safe_eval
:return: ModConfig :return: ModConfig
""" """
kwargs = { kwargs = config_dict | {
attr: config_dict.get(attr) "path": path,
for attr in cls.__slots__
if attr not in ["name", "_tracks", "tracks", "arenas", "path", "macros", "messages"] "_tracks": [CustomTrack.from_dict(track) for track in config_dict.pop("tracks", [])],
# these keys are treated after or are reserved "_arenas": [Arena.from_dict(arena) for arena in config_dict.pop("arenas", [])],
"macros": macros,
"messages": messages,
"global_settings": {name: AbstractModSettings.get(data) for name, data in merge_dict(
default_global_settings,
config_dict.get("global_settings", {}),
dict_keys=default_global_settings.keys() # Avoid modder to add their own settings to globals one
).items()},
"specific_settings": {name: AbstractModSettings.get(data) for name, data in config_dict.get(
"specific_settings", {}
).items()},
} }
return cls( return cls(**kwargs)
path=Path(path),
name=config_dict["name"],
**kwargs,
tracks=[CustomTrack.from_dict(track) for track in config_dict.get("tracks", [])],
arenas=[Arena.from_dict(arena) for arena in config_dict.get("arenas", [])],
macros=macros,
messages=messages,
)
@classmethod @classmethod
def from_file(cls, config_file: str | Path) -> "ModConfig": def from_file(cls, config_file: str | Path) -> "ModConfig":
@ -214,7 +203,13 @@ class ModConfig:
Same as get_all_tracks, but arenas are included Same as get_all_tracks, but arenas are included
""" """
yield from self.get_all_tracks(*args, **kwargs) yield from self.get_all_tracks(*args, **kwargs)
yield from self.arenas yield from self.get_arenas()
def get_arenas(self) -> Generator["Arena", None, None]:
"""
Yield all arenas of the mod
"""
yield from self._arenas
def get_all_tracks(self, *args, **kwargs) -> Generator["CustomTrack", None, None]: def get_all_tracks(self, *args, **kwargs) -> Generator["CustomTrack", None, None]:
""" """
@ -338,7 +333,7 @@ class ModConfig:
ctfile += cup.get_ctfile(mod_config=self, template=template) ctfile += cup.get_ctfile(mod_config=self, template=template)
ctfile_override_property = "[SETUP-ARENA]\n" ctfile_override_property = "[SETUP-ARENA]\n"
for arena in self.arenas: for arena in self.get_arenas():
arena_definition, arena_override_property = arena.get_ctfile(mod_config=self, template=template) arena_definition, arena_override_property = arena.get_ctfile(mod_config=self, template=template)
ctfile += arena_definition ctfile += arena_definition
ctfile_override_property += arena_override_property ctfile_override_property += arena_override_property