mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 18:15:28 +03:00
feat: impl docs (#4)
The entire public api is covered with documentation in two languages - Russian and English. the library now supports the latest three versions of python - 3.12, 3.13 and 3.14 minor design changes: now, when a Boolean flag is entered, its value is an empty string, not None. tests have been adapted to the supported versions of python, readmi has been redesigned in two languages, German is no longer available.
This commit is contained in:
@@ -1,4 +1,2 @@
|
||||
__all__ = ["ArgParser", "Orchestrator"]
|
||||
|
||||
from argenta.orchestrator.argparser.entity import ArgParser
|
||||
from argenta.orchestrator.entity import Orchestrator
|
||||
from argenta.orchestrator.argparser.entity import ArgParser as ArgParser
|
||||
from argenta.orchestrator.entity import Orchestrator as Orchestrator
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
__all__ = [
|
||||
"ArgParser",
|
||||
"BooleanArgument",
|
||||
"ValueArgument"
|
||||
]
|
||||
|
||||
|
||||
from argenta.orchestrator.argparser.entity import ArgParser
|
||||
from argenta.orchestrator.argparser.arguments import BooleanArgument, ValueArgument
|
||||
from argenta.orchestrator.argparser.arguments import BooleanArgument as BooleanArgument
|
||||
from argenta.orchestrator.argparser.arguments import ValueArgument as ValueArgument
|
||||
from argenta.orchestrator.argparser.entity import ArgParser as ArgParser
|
||||
from argenta.orchestrator.argparser.entity import ArgSpace as ArgSpace
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
__all__ = ["BooleanArgument", "ValueArgument", "InputArgument"]
|
||||
|
||||
|
||||
from argenta.orchestrator.argparser.arguments.models import (
|
||||
BooleanArgument,
|
||||
ValueArgument,
|
||||
InputArgument
|
||||
)
|
||||
from argenta.orchestrator.argparser.arguments.models import BooleanArgument as BooleanArgument
|
||||
from argenta.orchestrator.argparser.arguments.models import InputArgument as InputArgument
|
||||
from argenta.orchestrator.argparser.arguments.models import ValueArgument as ValueArgument
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
__all__ = ["BooleanArgument", "ValueArgument", "InputArgument"]
|
||||
|
||||
from typing import Literal
|
||||
|
||||
|
||||
@@ -5,10 +7,8 @@ class BaseArgument:
|
||||
"""
|
||||
Private. Base class for all arguments
|
||||
"""
|
||||
def __init__(self, name: str, *,
|
||||
help: str,
|
||||
is_deprecated: bool,
|
||||
prefix: Literal["-", "--", "---"]):
|
||||
|
||||
def __init__(self, name: str, *, help: str, is_deprecated: bool, prefix: Literal["-", "--", "---"]):
|
||||
"""
|
||||
Public. Boolean argument, does not require a value
|
||||
:param name: name of the argument
|
||||
@@ -20,20 +20,24 @@ class BaseArgument:
|
||||
self.help: str = help
|
||||
self.is_deprecated: bool = is_deprecated
|
||||
self.prefix: Literal["-", "--", "---"] = prefix
|
||||
|
||||
|
||||
@property
|
||||
def string_entity(self) -> str:
|
||||
return self.prefix + self.name
|
||||
|
||||
|
||||
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,
|
||||
is_required: bool = False,
|
||||
is_deprecated: bool = False):
|
||||
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,
|
||||
is_required: bool = False,
|
||||
is_deprecated: bool = False,
|
||||
):
|
||||
"""
|
||||
Public. Value argument, must have the value
|
||||
:param name: name of the argument
|
||||
@@ -52,10 +56,14 @@ class ValueArgument(BaseArgument):
|
||||
|
||||
|
||||
class BooleanArgument(BaseArgument):
|
||||
def __init__(self, name: str, *,
|
||||
prefix: Literal["-", "--", "---"] = "--",
|
||||
help: str = "Help message for the boolean argument",
|
||||
is_deprecated: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
*,
|
||||
prefix: Literal["-", "--", "---"] = "--",
|
||||
help: str = "Help message for the boolean argument",
|
||||
is_deprecated: bool = False,
|
||||
):
|
||||
"""
|
||||
Public. Boolean argument, does not require a value
|
||||
:param name: name of the argument
|
||||
@@ -68,15 +76,13 @@ class BooleanArgument(BaseArgument):
|
||||
|
||||
|
||||
class InputArgument:
|
||||
def __init__(self, name: str,
|
||||
value: str | None,
|
||||
founder_class: type[BaseArgument]) -> None:
|
||||
def __init__(self, name: str, value: str | Literal[True], founder_class: type[BaseArgument]) -> None:
|
||||
self.name: str = name
|
||||
self.value: str | None = value
|
||||
self.value: str | Literal[True] = value
|
||||
self.founder_class: type[BaseArgument] = founder_class
|
||||
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"InputArgument({self.name}={self.value})"
|
||||
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"InputArgument<name={self.name}, value={self.value}, founder_class={self.founder_class.__name__}>"
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
__all__ = [
|
||||
"ArgSpace",
|
||||
"ArgParser",
|
||||
]
|
||||
|
||||
import sys
|
||||
from argparse import ArgumentParser, Namespace
|
||||
from typing import Never, Self
|
||||
|
||||
@@ -5,40 +11,63 @@ from argenta.orchestrator.argparser.arguments.models import (
|
||||
BaseArgument,
|
||||
BooleanArgument,
|
||||
InputArgument,
|
||||
ValueArgument
|
||||
ValueArgument,
|
||||
)
|
||||
|
||||
|
||||
|
||||
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[ValueArgument | BooleanArgument]) -> Self:
|
||||
name_type_paired_args: dict[str, type[BaseArgument]] = {
|
||||
arg.name: type(arg)
|
||||
for arg in processed_args
|
||||
|
||||
self._name_object_paired_args: dict[str, InputArgument] = {}
|
||||
self._type_object_paired_args: dict[type[BaseArgument], list[InputArgument]] = {
|
||||
BooleanArgument: [],
|
||||
ValueArgument: []
|
||||
}
|
||||
return cls([InputArgument(name=name,
|
||||
value=value,
|
||||
founder_class=name_type_paired_args[name])
|
||||
for name, value in vars(namespace).items()])
|
||||
|
||||
|
||||
self._setup_getters()
|
||||
|
||||
@classmethod
|
||||
def from_namespace(
|
||||
cls,
|
||||
namespace: Namespace,
|
||||
processed_args: list[ValueArgument | BooleanArgument]
|
||||
) -> Self:
|
||||
name_type_paired_processed_args: dict[str, type[BaseArgument]] = {
|
||||
arg.name: type(arg) for arg in processed_args
|
||||
}
|
||||
parsed_arguments: list[InputArgument] = []
|
||||
|
||||
for name, value in vars(namespace).items():
|
||||
parsed_arguments.append(
|
||||
InputArgument(
|
||||
name=name,
|
||||
value=value,
|
||||
founder_class=name_type_paired_processed_args[name]
|
||||
)
|
||||
)
|
||||
|
||||
return cls(parsed_arguments)
|
||||
|
||||
def _setup_getters(self) -> None:
|
||||
if not self.all_arguments:
|
||||
return
|
||||
for input_arg in self.all_arguments:
|
||||
self._name_object_paired_args[input_arg.name] = input_arg
|
||||
self._type_object_paired_args[input_arg.founder_class].append(input_arg)
|
||||
|
||||
def get_by_name(self, name: str) -> InputArgument | None:
|
||||
for arg in self.all_arguments:
|
||||
if arg.name == name:
|
||||
return arg
|
||||
return None
|
||||
|
||||
return self._name_object_paired_args.get(name)
|
||||
|
||||
def get_by_type(self, arg_type: type[BaseArgument]) -> list[InputArgument] | list[Never]:
|
||||
return [arg for arg in self.all_arguments if arg.founder_class is arg_type]
|
||||
|
||||
return self._type_object_paired_args.get(arg_type, [])
|
||||
|
||||
|
||||
class ArgParser:
|
||||
def __init__(
|
||||
self,
|
||||
processed_args: list[ValueArgument | BooleanArgument], *,
|
||||
processed_args: list[ValueArgument | BooleanArgument],
|
||||
*,
|
||||
name: str = "Argenta",
|
||||
description: str = "Argenta available arguments",
|
||||
epilog: str = "github.com/koloideal/Argenta | made by kolo",
|
||||
@@ -55,24 +84,51 @@ class ArgParser:
|
||||
self.epilog: str = epilog
|
||||
self.processed_args: list[ValueArgument | BooleanArgument] = processed_args
|
||||
|
||||
self._core: ArgumentParser = ArgumentParser(prog=name, description=description, epilog=epilog)
|
||||
|
||||
for arg in processed_args:
|
||||
if isinstance(arg, BooleanArgument):
|
||||
_ = self._core.add_argument(arg.string_entity,
|
||||
action=arg.action,
|
||||
help=arg.help,
|
||||
deprecated=arg.is_deprecated)
|
||||
else:
|
||||
_ = self._core.add_argument(arg.string_entity,
|
||||
action=arg.action,
|
||||
help=arg.help,
|
||||
default=arg.default,
|
||||
choices=arg.possible_values,
|
||||
required=arg.is_required,
|
||||
deprecated=arg.is_deprecated)
|
||||
self.parsed_argspace: ArgSpace = ArgSpace([])
|
||||
|
||||
def parse_args(self) -> ArgSpace:
|
||||
return ArgSpace.from_namespace(namespace=self._core.parse_args(),
|
||||
processed_args=self.processed_args)
|
||||
|
||||
self._core: ArgumentParser = ArgumentParser(prog=name, description=description, epilog=epilog)
|
||||
self._register_args(processed_args)
|
||||
|
||||
def _parse_args(self) -> None:
|
||||
self.parsed_argspace = ArgSpace.from_namespace(
|
||||
namespace=self._core.parse_args(), processed_args=self.processed_args
|
||||
)
|
||||
|
||||
def _register_args(self, processed_args: list[ValueArgument | BooleanArgument]) -> None:
|
||||
if sys.version_info >= (3, 13):
|
||||
for arg in processed_args:
|
||||
if isinstance(arg, BooleanArgument):
|
||||
_ = self._core.add_argument(
|
||||
arg.string_entity,
|
||||
action=arg.action,
|
||||
help=arg.help,
|
||||
deprecated=arg.is_deprecated
|
||||
)
|
||||
else:
|
||||
_ = self._core.add_argument(
|
||||
arg.string_entity,
|
||||
action=arg.action,
|
||||
help=arg.help,
|
||||
default=arg.default,
|
||||
choices=arg.possible_values,
|
||||
required=arg.is_required,
|
||||
deprecated=arg.is_deprecated,
|
||||
)
|
||||
else:
|
||||
for arg in processed_args:
|
||||
if isinstance(arg, BooleanArgument):
|
||||
_ = self._core.add_argument(
|
||||
arg.string_entity,
|
||||
action=arg.action,
|
||||
help=arg.help,
|
||||
)
|
||||
else:
|
||||
_ = self._core.add_argument(
|
||||
arg.string_entity,
|
||||
action=arg.action,
|
||||
help=arg.help,
|
||||
default=arg.default,
|
||||
choices=arg.possible_values,
|
||||
required=arg.is_required
|
||||
)
|
||||
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
from argenta.app import App
|
||||
from argenta.response import Response
|
||||
|
||||
from argenta.orchestrator.argparser import ArgParser
|
||||
from argenta.di.integration import setup_dishka
|
||||
from argenta.di.providers import SystemProvider
|
||||
__all__ = ["Orchestrator"]
|
||||
|
||||
from dishka import Provider, make_container
|
||||
|
||||
from argenta.app import App
|
||||
from argenta.di.integration import setup_dishka
|
||||
from argenta.di.providers import SystemProvider
|
||||
from argenta.orchestrator.argparser import ArgParser
|
||||
|
||||
DEFAULT_ARGPARSER: ArgParser = ArgParser(processed_args=[])
|
||||
|
||||
|
||||
class Orchestrator:
|
||||
def __init__(self, arg_parser: ArgParser = DEFAULT_ARGPARSER,
|
||||
custom_providers: list[Provider] = [],
|
||||
auto_inject_handlers: bool = True):
|
||||
def __init__(
|
||||
self,
|
||||
arg_parser: ArgParser = DEFAULT_ARGPARSER,
|
||||
custom_providers: list[Provider] = [],
|
||||
auto_inject_handlers: bool = True,
|
||||
):
|
||||
"""
|
||||
Public. An orchestrator and configurator that defines the behavior of an integrated system, one level higher than the App
|
||||
:param arg_parser: Cmd argument parser and configurator at startup
|
||||
@@ -24,14 +26,17 @@ class Orchestrator:
|
||||
self._custom_providers: list[Provider] = custom_providers
|
||||
self._auto_inject_handlers: bool = auto_inject_handlers
|
||||
|
||||
self._arg_parser._parse_args()
|
||||
|
||||
def start_polling(self, app: App) -> None:
|
||||
"""
|
||||
Public. Starting the user input processing cycle
|
||||
:param app: a running application
|
||||
:return: None
|
||||
"""
|
||||
container = make_container(SystemProvider(self._arg_parser), *self._custom_providers)
|
||||
Response.patch_by_container(container)
|
||||
setup_dishka(app, auto_inject=self._auto_inject_handlers)
|
||||
container = make_container(
|
||||
SystemProvider(), *self._custom_providers, context={ArgParser: self._arg_parser}
|
||||
)
|
||||
setup_dishka(app, container, auto_inject=self._auto_inject_handlers)
|
||||
|
||||
app.run_polling()
|
||||
|
||||
Reference in New Issue
Block a user