From 0a1d462090bdec63fcc1e3e8b5b281d2cd9e5d63 Mon Sep 17 00:00:00 2001 From: kolo Date: Thu, 9 Oct 2025 22:01:06 +0300 Subject: [PATCH] step by step --- mock/local_test.py | 2 +- src/argenta/app/models.py | 8 +- .../argparser/arguments/models.py | 76 +++++++------------ src/argenta/orchestrator/argparser/entity.py | 28 ++++++- src/argenta/orchestrator/entity.py | 17 ++--- 5 files changed, 65 insertions(+), 66 deletions(-) diff --git a/mock/local_test.py b/mock/local_test.py index e672a5a..0cfd245 100644 --- a/mock/local_test.py +++ b/mock/local_test.py @@ -2,4 +2,4 @@ import argparse parser = argparse.ArgumentParser(prog='myprogram') _ = parser.add_argument('--foo', help='foo of the %(prog)s program') -parser.print_help() \ No newline at end of file +print(vars(parser.parse_args())) \ No newline at end of file diff --git a/src/argenta/app/models.py b/src/argenta/app/models.py index 6c7da55..c8821dd 100644 --- a/src/argenta/app/models.py +++ b/src/argenta/app/models.py @@ -3,6 +3,7 @@ import re from contextlib import redirect_stdout from typing import Never, TypeAlias +from argenta.orchestrator.argparser.entity import ArgSpace from art import text2art # pyright: ignore[reportMissingTypeStubs, reportUnknownVariableType] from rich.console import Console from rich.markup import escape @@ -41,7 +42,8 @@ class BaseApp: repeat_command_groups: bool, override_system_messages: bool, autocompleter: AutoCompleter, - print_func: Printer) -> None: + print_func: Printer, + argspace: ArgSpace | None = None) -> None: self._prompt: str = prompt self._print_func: Printer = print_func self._exit_command: Command = exit_command @@ -51,6 +53,7 @@ class BaseApp: self._repeat_command_groups_description: bool = repeat_command_groups self._override_system_messages: bool = override_system_messages self._autocompleter: AutoCompleter = autocompleter + self._argspace: ArgSpace | None = argspace self._farewell_message: str = farewell_message self._initial_message: str = initial_message @@ -392,11 +395,12 @@ class App(BaseApp): print_func=print_func, ) - def run_polling(self) -> None: + def run_polling(self, argspace: ArgSpace | None) -> None: """ Private. Starts the user input processing cycle :return: None """ + self._argspace = argspace self._pre_cycle_setup() while True: if self._repeat_command_groups_description: diff --git a/src/argenta/orchestrator/argparser/arguments/models.py b/src/argenta/orchestrator/argparser/arguments/models.py index d922829..8cc2bca 100644 --- a/src/argenta/orchestrator/argparser/arguments/models.py +++ b/src/argenta/orchestrator/argparser/arguments/models.py @@ -1,24 +1,26 @@ -from abc import ABC, abstractmethod -from typing import Literal, override - - -class BaseArgument(ABC): +class BaseArgument: """ Private. Base class for all arguments """ - @property - @abstractmethod - def string_entity(self) -> str: + def __init__(self, name: str, *, + help: str, + is_required: bool, + is_deprecated: bool): """ - Public. Returns the string representation of the argument - :return: the string representation as a str + Public. Boolean argument, does not require a value + :param name: name of the argument + :param help: help message for the argument + :param is_required: whether the argument is required + :param is_deprecated: whether the argument is deprecated """ - raise NotImplementedError + self.name: str = name + self.help: str = help + self.is_required: bool = is_required + self.is_deprecated: bool = is_deprecated class RequiredArgument(BaseArgument): def __init__(self, name: str, *, - prefix: Literal["-", "--", "---"] = "--", help: str = "Help for required argument", default: str | None = None, possible_values: list[str] | None = None, @@ -27,31 +29,20 @@ class RequiredArgument(BaseArgument): """ Public. Required argument at startup :param name: name of the argument, must not start with minus (-) - :param prefix: prefix of the argument :param help: help message for the argument :param default: default value for the argument :param possible_values: list of possible values for the argument :param is_required: whether the argument is required :param is_deprecated: whether the argument is deprecated """ - self.name: str = name - self.prefix: Literal["-", "--", "---"] = prefix - self.help: str = help self.default: str | None = default self.possible_values: list[str] | None = possible_values - self.is_required: bool = is_required - self.is_deprecated: bool = is_deprecated self.action: str = "store" - - @property - @override - def string_entity(self) -> str: - return self.prefix + self.name + super().__init__(name, help=help, is_required=is_required, is_deprecated=is_deprecated) class ValueArgument(BaseArgument): def __init__(self, name: str, *, - prefix: Literal["-", "--", "---"] = "--", help: str = "Help message for the value argument", possible_values: list[str] | None = None, default: str | None = None, @@ -60,50 +51,41 @@ class ValueArgument(BaseArgument): """ Public. Value argument, must have the value :param name: name of the argument - :param prefix: prefix of the argument :param help: help message for the argument :param possible_values: list of possible values for the argument :param default: default value for the argument :param is_required: whether the argument is required :param is_deprecated: whether the argument is deprecated """ - self.name: str = name - self.prefix: Literal["-", "--", "---"] = prefix - self.help: str = help - self.possible_values: list[str] | None = possible_values self.default: str | None = default - self.is_required: bool = is_required - self.is_deprecated: bool = is_deprecated + self.possible_values: list[str] | None = possible_values self.action: str = "store" - - @property - @override - def string_entity(self) -> str: - return self.prefix + self.name + super().__init__(name, help=help, is_required=is_required, is_deprecated=is_deprecated) class BooleanArgument(BaseArgument): def __init__(self, name: str, *, - prefix: Literal["-", "--", "---"] = "--", help: str = "Help message for the boolean argument", is_required: bool = False, is_deprecated: bool = False): """ Public. Boolean argument, does not require a value :param name: name of the argument - :param prefix: prefix of the argument :param help: help message for the argument :param is_required: whether the argument is required :param is_deprecated: whether the argument is deprecated """ - self.name: str = name - self.prefix: Literal["-", "--", "---"] = prefix - self.help: str = help - self.is_required: bool = is_required - self.is_deprecated: bool = is_deprecated self.action: str = "store_true" + super().__init__(name, help=help, is_required=is_required, is_deprecated=is_deprecated) - @property - @override - def string_entity(self) -> str: - return self.prefix + self.name + +class InputArgument: + def __init__(self, name: str, + value: str | None, + founder_class: type[BaseArgument]) -> None: + self.name: str = name + self.value: str | None = value + self.founder_class: type[BaseArgument] = founder_class + + def __str__(self) -> str: + return f"{self.name}={self.value}" diff --git a/src/argenta/orchestrator/argparser/entity.py b/src/argenta/orchestrator/argparser/entity.py index a5def0e..520bf8c 100644 --- a/src/argenta/orchestrator/argparser/entity.py +++ b/src/argenta/orchestrator/argparser/entity.py @@ -1,11 +1,29 @@ from argparse import ArgumentParser, Namespace +from typing import Self from argenta.orchestrator.argparser.arguments.models import ( + BaseArgument, BooleanArgument, + InputArgument, ValueArgument, RequiredArgument, ) + +class ArgSpace: + def __init__(self, all_arguments: list[InputArgument]) -> None: + self.all_arguments = all_arguments + + @classmethod + def from_namespace(cls, namespace: Namespace, + processed_args: list[RequiredArgument | ValueArgument | BooleanArgument]) -> Self: + name_type_paired_args: dict[str, type[BaseArgument]] = { + arg.name: type(arg) + for arg in processed_args + } + return cls([InputArgument(name, value, name_type_paired_args[name]) + for name, value in vars(namespace).items()]) + class ArgParser: def __init__( @@ -31,13 +49,13 @@ class ArgParser: for arg in processed_args: if isinstance(arg, BooleanArgument): - _ = self._entity.add_argument(arg.string_entity, + _ = self._entity.add_argument(arg.name, action=arg.action, help=arg.help, required=arg.is_required, deprecated=arg.is_deprecated) else: - _ = self._entity.add_argument(arg.string_entity, + _ = self._entity.add_argument(arg.name, action=arg.action, help=arg.help, default=arg.default, @@ -45,5 +63,7 @@ class ArgParser: required=arg.is_required, deprecated=arg.is_deprecated) - def parse_args(self) -> Namespace: - return self._entity.parse_args() + def parse_args(self) -> ArgSpace: + return ArgSpace.from_namespace(namespace=self._entity.parse_args(), + processed_args=self._processed_args) + \ No newline at end of file diff --git a/src/argenta/orchestrator/entity.py b/src/argenta/orchestrator/entity.py index ff73623..e9d3dba 100644 --- a/src/argenta/orchestrator/entity.py +++ b/src/argenta/orchestrator/entity.py @@ -1,7 +1,6 @@ -from argparse import Namespace - from argenta.app import App from argenta.orchestrator.argparser import ArgParser +from argenta.orchestrator.argparser.entity import ArgSpace class Orchestrator: @@ -19,14 +18,8 @@ class Orchestrator: :param app: a running application :return: None """ - app.run_polling() - - def get_input_args(self) -> Namespace | None: - """ - Public. Returns the arguments parsed - :return: None - """ - if self._arg_parser: - return self._arg_parser.parse_args() + if self._arg_parser is not None: + parsed_argspace: ArgSpace = self._arg_parser.parse_args() + app.run_polling(argspace=parsed_argspace) else: - return None + app.run_polling(argspace=None)