step by step

This commit is contained in:
2025-10-09 22:01:06 +03:00
parent b3b5e2e8a8
commit 0a1d462090
5 changed files with 65 additions and 66 deletions
+1 -1
View File
@@ -2,4 +2,4 @@ import argparse
parser = argparse.ArgumentParser(prog='myprogram') parser = argparse.ArgumentParser(prog='myprogram')
_ = parser.add_argument('--foo', help='foo of the %(prog)s program') _ = parser.add_argument('--foo', help='foo of the %(prog)s program')
parser.print_help() print(vars(parser.parse_args()))
+6 -2
View File
@@ -3,6 +3,7 @@ import re
from contextlib import redirect_stdout from contextlib import redirect_stdout
from typing import Never, TypeAlias from typing import Never, TypeAlias
from argenta.orchestrator.argparser.entity import ArgSpace
from art import text2art # pyright: ignore[reportMissingTypeStubs, reportUnknownVariableType] from art import text2art # pyright: ignore[reportMissingTypeStubs, reportUnknownVariableType]
from rich.console import Console from rich.console import Console
from rich.markup import escape from rich.markup import escape
@@ -41,7 +42,8 @@ class BaseApp:
repeat_command_groups: bool, repeat_command_groups: bool,
override_system_messages: bool, override_system_messages: bool,
autocompleter: AutoCompleter, autocompleter: AutoCompleter,
print_func: Printer) -> None: print_func: Printer,
argspace: ArgSpace | None = None) -> None:
self._prompt: str = prompt self._prompt: str = prompt
self._print_func: Printer = print_func self._print_func: Printer = print_func
self._exit_command: Command = exit_command self._exit_command: Command = exit_command
@@ -51,6 +53,7 @@ class BaseApp:
self._repeat_command_groups_description: bool = repeat_command_groups self._repeat_command_groups_description: bool = repeat_command_groups
self._override_system_messages: bool = override_system_messages self._override_system_messages: bool = override_system_messages
self._autocompleter: AutoCompleter = autocompleter self._autocompleter: AutoCompleter = autocompleter
self._argspace: ArgSpace | None = argspace
self._farewell_message: str = farewell_message self._farewell_message: str = farewell_message
self._initial_message: str = initial_message self._initial_message: str = initial_message
@@ -392,11 +395,12 @@ class App(BaseApp):
print_func=print_func, print_func=print_func,
) )
def run_polling(self) -> None: def run_polling(self, argspace: ArgSpace | None) -> None:
""" """
Private. Starts the user input processing cycle Private. Starts the user input processing cycle
:return: None :return: None
""" """
self._argspace = argspace
self._pre_cycle_setup() self._pre_cycle_setup()
while True: while True:
if self._repeat_command_groups_description: if self._repeat_command_groups_description:
@@ -1,24 +1,26 @@
from abc import ABC, abstractmethod class BaseArgument:
from typing import Literal, override
class BaseArgument(ABC):
""" """
Private. Base class for all arguments Private. Base class for all arguments
""" """
@property def __init__(self, name: str, *,
@abstractmethod help: str,
def string_entity(self) -> str: is_required: bool,
is_deprecated: bool):
""" """
Public. Returns the string representation of the argument Public. Boolean argument, does not require a value
:return: the string representation as a str :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): class RequiredArgument(BaseArgument):
def __init__(self, name: str, *, def __init__(self, name: str, *,
prefix: Literal["-", "--", "---"] = "--",
help: str = "Help for required argument", help: str = "Help for required argument",
default: str | None = None, default: str | None = None,
possible_values: list[str] | None = None, possible_values: list[str] | None = None,
@@ -27,31 +29,20 @@ class RequiredArgument(BaseArgument):
""" """
Public. Required argument at startup Public. Required argument at startup
:param name: name of the argument, must not start with minus (-) :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 help: help message for the argument
:param default: default value for the argument :param default: default value for the argument
:param possible_values: list of possible values for the argument :param possible_values: list of possible values for the argument
:param is_required: whether the argument is required :param is_required: whether the argument is required
:param is_deprecated: whether the argument is deprecated :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.default: str | None = default
self.possible_values: list[str] | None = possible_values self.possible_values: list[str] | None = possible_values
self.is_required: bool = is_required
self.is_deprecated: bool = is_deprecated
self.action: str = "store" self.action: str = "store"
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 ValueArgument(BaseArgument): class ValueArgument(BaseArgument):
def __init__(self, name: str, *, def __init__(self, name: str, *,
prefix: Literal["-", "--", "---"] = "--",
help: str = "Help message for the value argument", help: str = "Help message for the value argument",
possible_values: list[str] | None = None, possible_values: list[str] | None = None,
default: str | None = None, default: str | None = None,
@@ -60,50 +51,41 @@ class ValueArgument(BaseArgument):
""" """
Public. Value argument, must have the value Public. Value argument, must have the value
:param name: name of the argument :param name: name of the argument
:param prefix: prefix of the argument
:param help: help message for the argument :param help: help message for the argument
:param possible_values: list of possible values for the argument :param possible_values: list of possible values for the argument
:param default: default value for the argument :param default: default value for the argument
:param is_required: whether the argument is required :param is_required: whether the argument is required
:param is_deprecated: whether the argument is deprecated :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.default: str | None = default
self.is_required: bool = is_required self.possible_values: list[str] | None = possible_values
self.is_deprecated: bool = is_deprecated
self.action: str = "store" self.action: str = "store"
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 BooleanArgument(BaseArgument): class BooleanArgument(BaseArgument):
def __init__(self, name: str, *, def __init__(self, name: str, *,
prefix: Literal["-", "--", "---"] = "--",
help: str = "Help message for the boolean argument", help: str = "Help message for the boolean argument",
is_required: bool = False, is_required: bool = False,
is_deprecated: bool = False): is_deprecated: bool = False):
""" """
Public. Boolean argument, does not require a value Public. Boolean argument, does not require a value
:param name: name of the argument :param name: name of the argument
:param prefix: prefix of the argument
:param help: help message for the argument :param help: help message for the argument
:param is_required: whether the argument is required :param is_required: whether the argument is required
:param is_deprecated: whether the argument is deprecated :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" self.action: str = "store_true"
super().__init__(name, help=help, is_required=is_required, is_deprecated=is_deprecated)
@property
@override class InputArgument:
def string_entity(self) -> str: def __init__(self, name: str,
return self.prefix + self.name 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}"
+24 -4
View File
@@ -1,12 +1,30 @@
from argparse import ArgumentParser, Namespace from argparse import ArgumentParser, Namespace
from typing import Self
from argenta.orchestrator.argparser.arguments.models import ( from argenta.orchestrator.argparser.arguments.models import (
BaseArgument,
BooleanArgument, BooleanArgument,
InputArgument,
ValueArgument, ValueArgument,
RequiredArgument, 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: class ArgParser:
def __init__( def __init__(
self, self,
@@ -31,13 +49,13 @@ class ArgParser:
for arg in processed_args: for arg in processed_args:
if isinstance(arg, BooleanArgument): if isinstance(arg, BooleanArgument):
_ = self._entity.add_argument(arg.string_entity, _ = self._entity.add_argument(arg.name,
action=arg.action, action=arg.action,
help=arg.help, help=arg.help,
required=arg.is_required, required=arg.is_required,
deprecated=arg.is_deprecated) deprecated=arg.is_deprecated)
else: else:
_ = self._entity.add_argument(arg.string_entity, _ = self._entity.add_argument(arg.name,
action=arg.action, action=arg.action,
help=arg.help, help=arg.help,
default=arg.default, default=arg.default,
@@ -45,5 +63,7 @@ class ArgParser:
required=arg.is_required, required=arg.is_required,
deprecated=arg.is_deprecated) deprecated=arg.is_deprecated)
def parse_args(self) -> Namespace: def parse_args(self) -> ArgSpace:
return self._entity.parse_args() return ArgSpace.from_namespace(namespace=self._entity.parse_args(),
processed_args=self._processed_args)
+5 -12
View File
@@ -1,7 +1,6 @@
from argparse import Namespace
from argenta.app import App from argenta.app import App
from argenta.orchestrator.argparser import ArgParser from argenta.orchestrator.argparser import ArgParser
from argenta.orchestrator.argparser.entity import ArgSpace
class Orchestrator: class Orchestrator:
@@ -19,14 +18,8 @@ class Orchestrator:
:param app: a running application :param app: a running application
:return: None :return: None
""" """
app.run_polling() if self._arg_parser is not None:
parsed_argspace: ArgSpace = self._arg_parser.parse_args()
def get_input_args(self) -> Namespace | None: app.run_polling(argspace=parsed_argspace)
"""
Public. Returns the arguments parsed
:return: None
"""
if self._arg_parser:
return self._arg_parser.parse_args()
else: else:
return None app.run_polling(argspace=None)