From c97c6d0a70efa534c76a875686b54e98f7689eb1 Mon Sep 17 00:00:00 2001 From: Auric Vente Date: Thu, 25 Jul 2024 05:41:47 -0600 Subject: [PATCH] Mods --- cromulant/args.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ cromulant/argspec.py | 83 ++++++++++++++++++++++++++++++++++++++++ cromulant/game.py | 11 ++++-- cromulant/main.py | 2 + cromulant/storage.py | 9 ++++- cromulant/utils.py | 22 +++++++++++ 6 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 cromulant/args.py create mode 100644 cromulant/argspec.py diff --git a/cromulant/args.py b/cromulant/args.py new file mode 100644 index 0000000..9798d09 --- /dev/null +++ b/cromulant/args.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +import argparse +from pathlib import Path +from typing import Any + +from .config import Config +from .argspec import ArgSpec + + +class Args: + names: Path + images: bool = True + + @staticmethod + def prepare() -> None: + ArgSpec.prepare() + ArgParser.prepare(Config.title, ArgSpec.arguments) + + for attr_name, attr_value in vars(Args).items(): + ArgSpec.defaults[attr_name] = attr_value + + other_name = [ + ("no_images", "images"), + ] + + for r_item in other_name: + ArgParser.get_value(*r_item) + + paths = [ + "names", + ] + + for n_item in paths: + ArgParser.get_value(n_item, path=True) + + +class ArgParser: + parser: argparse.ArgumentParser + args: argparse.Namespace + + @staticmethod + def prepare(title: str, argdefs: dict[str, Any]) -> None: + parser = argparse.ArgumentParser(description=title) + argdefs["string_arg"] = {"nargs": "*"} + + for key in argdefs: + item = argdefs[key] + + if key == "string_arg": + name = key + else: + name = ArgParser.under_to_dash(key) + name = f"--{name}" + + tail = {key: value for key, value in item.items() if value is not None} + parser.add_argument(name, **tail) + + ArgParser.parser = parser + ArgParser.args = parser.parse_args() + + @staticmethod + def string_arg() -> str: + return " ".join(ArgParser.args.string_arg) + + @staticmethod + def get_value( + attr: str, key: str | None = None, no_strip: bool = False, path: bool = False + ) -> None: + value = getattr(ArgParser.args, attr) + + if value is not None: + if not no_strip: + if isinstance(value, str): + value = value.strip() + + obj = key if key else attr + + if path: + value = Path(value) + + ArgParser.set(obj, value) + + @staticmethod + def set(attr: str, value: Any) -> None: + setattr(Args, attr, value) + + @staticmethod + def under_to_dash(s: str) -> str: + return s.replace("_", "-") diff --git a/cromulant/argspec.py b/cromulant/argspec.py new file mode 100644 index 0000000..4f49264 --- /dev/null +++ b/cromulant/argspec.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from typing import Any + +from .config import Config + + +class DuplicateArgumentError(Exception): + def __init__(self, key: str) -> None: + self.message = f"Duplicate argument: {key}" + + def __str__(self) -> str: + return self.message + + +class MissingInfoError(Exception): + def __init__(self, key: str) -> None: + self.message = f"Missing info for argument: {key}" + + def __str__(self) -> str: + return self.message + + +class DuplicateInfoError(Exception): + def __init__(self, key: str) -> None: + self.message = f"Duplicate info for argument: {key}" + + def __str__(self) -> str: + return self.message + + +class ArgSpec: + vinfo: str + defaults: dict[str, Any] + arguments: dict[str, Any] + infos: list[str] + + @staticmethod + def prepare() -> None: + ArgSpec.vinfo = f"{Config.title} {Config.version}" + ArgSpec.defaults = {} + ArgSpec.arguments = {} + ArgSpec.infos = [] + ArgSpec.add_arguments() + + @staticmethod + def add_argument(key: str, info: str, **kwargs: Any) -> None: + if key in ArgSpec.arguments: + raise DuplicateArgumentError(key) + + if not info: + raise MissingInfoError(key) + + if info in ArgSpec.infos: + raise DuplicateInfoError(key) + + ArgSpec.arguments[key] = { + "help": info, + **kwargs, + } + + ArgSpec.infos.append(info) + + @staticmethod + def add_arguments() -> None: + ArgSpec.add_argument( + "version", + action="version", + info="Check the version of the program", + version=ArgSpec.vinfo, + ) + + ArgSpec.add_argument( + "names", + type=str, + info="Path to a JSON files with a list of names. The game will use these names instead of the default ones", + ) + + ArgSpec.add_argument( + "no_images", + action="store_false", + info="Don't show the images on the left", + ) diff --git a/cromulant/game.py b/cromulant/game.py index bb88415..9972a11 100644 --- a/cromulant/game.py +++ b/cromulant/game.py @@ -17,6 +17,7 @@ from PySide6.QtCore import QTimer # type: ignore from PySide6.QtCore import Qt from .config import Config +from .args import Args from .utils import Utils from .ants import Ant from .ants import Ants @@ -91,11 +92,15 @@ class Game: container = QHBoxLayout() root.setContentsMargins(0, 0, 0, 0) container.setContentsMargins(0, 0, 0, 0) - image_label = Game.get_image(ant) + + if Args.images: + image_label = Game.get_image(ant) + container.addWidget(image_label) + right_container = Game.make_right_container(ant) - container.addWidget(image_label) - container.addSpacing(Config.space_1) container.addWidget(right_container) + + container.addSpacing(Config.space_1) root.setLayout(container) Game.add_item(root) diff --git a/cromulant/main.py b/cromulant/main.py index 088bf60..03e79f8 100644 --- a/cromulant/main.py +++ b/cromulant/main.py @@ -13,10 +13,12 @@ from .window import Window from .game import Game from .settings import Settings from .filter import Filter +from .args import Args def main() -> None: Config.prepare() + Args.prepare() program = Config.program title = Config.title diff --git a/cromulant/storage.py b/cromulant/storage.py index dec65fe..6333d58 100644 --- a/cromulant/storage.py +++ b/cromulant/storage.py @@ -8,6 +8,7 @@ from .config import Config if TYPE_CHECKING: from .ants import Ant +from .args import Args from .utils import Utils @@ -30,7 +31,13 @@ class Storage: @staticmethod def get_names() -> Any: - with Config.names_json.open() as file: + path = Config.names_json + + if Args.names: + if Args.names.exists(): + path = Args.names + + with path.open() as file: return json.load(file) @staticmethod diff --git a/cromulant/utils.py b/cromulant/utils.py index ef2e300..6ba6306 100644 --- a/cromulant/utils.py +++ b/cromulant/utils.py @@ -17,6 +17,8 @@ class Utils: countries: ClassVar[list[str]] = [] rand_word: RandomWord rand_sentence: RandomSentence + vowels = "aeiou" + consonants = "bcdfghjklmnpqrstvwxyz" @staticmethod def prepare() -> None: @@ -103,6 +105,10 @@ class Utils: names.append(name) filtered = [name for name in Utils.names if name not in ignore] + + if not filtered: + return Utils.make_name() + return random.choice(filtered) @staticmethod @@ -185,3 +191,19 @@ class Utils: @staticmethod def words_4() -> str: return str(Utils.rand_sentence.sentence()) + + @staticmethod + def make_word() -> str: + name = "" + name += random.choice(Utils.consonants) + name += random.choice(Utils.vowels) + name += random.choice(Utils.consonants) + name += random.choice(Utils.vowels) + return name + + @staticmethod + def make_name() -> str: + word_1 = Utils.make_word() + word_2 = Utils.make_word() + + return f"{Utils.capitalize(word_1)} {Utils.capitalize(word_2)}"