refactor and optimize argspace

This commit is contained in:
2025-11-28 14:31:51 +03:00
parent 1eaf2b6333
commit be178b10c7
7 changed files with 68 additions and 31 deletions
+5 -2
View File
@@ -1,10 +1,13 @@
from argenta import App, Orchestrator from argenta import App, Orchestrator
from argenta.orchestrator.argparser import ArgParser, BooleanArgument from argenta.orchestrator.argparser import ArgParser, BooleanArgument, ValueArgument
arg_parser = ArgParser(processed_args=[BooleanArgument("config")]) arg_parser = ArgParser(processed_args=[BooleanArgument("dev"), ValueArgument('some', possible_values=['fuck', 'cruck'])])
orchestrator = Orchestrator( orchestrator = Orchestrator(
arg_parser=arg_parser, arg_parser=arg_parser,
) )
if __name__ == "__main__": if __name__ == "__main__":
if arg_parser.parsed_argspace.get_by_name('dev'):
orchestrator.start_polling(App(initial_message='ArgentaDev'))
else:
orchestrator.start_polling(App()) orchestrator.start_polling(App())
+6 -6
View File
@@ -25,7 +25,7 @@ ArgParser
* ``description``: Описание приложения для отображения в справке. * ``description``: Описание приложения для отображения в справке.
* ``epilog``: Дополнительная информация для отображения в конце справки. * ``epilog``: Дополнительная информация для отображения в конце справки.
Основные методы и атрибуты Атрибуты
--------------------------- ---------------------------
.. py:attribute:: parsed_argspace: ArgSpace .. py:attribute:: parsed_argspace: ArgSpace
@@ -64,16 +64,16 @@ ArgParser
.. code-block:: bash .. code-block:: bash
$ python app.py $ python app.py
usage: MyApp [-h] --config CONFIG usage: Argenta [-h] --config CONFIG
MyApp: error: the following arguments are required: --config Argenta: error: the following arguments are required: --config
**Недопустимое значение из списка choices:** **Недопустимое значение из списка possible_values:**
.. code-block:: bash .. code-block:: bash
$ python app.py --config app.yaml --log-level TRACE $ python app.py --config app.yaml --log-level TRACE
usage: MyApp [-h] --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL} usage: Argenta [-h] --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
MyApp: error: argument --log-level: invalid choice: 'TRACE' Argenta: error: argument --log-level: invalid choice: 'TRACE'
**Использование устаревшего аргумента:** **Использование устаревшего аргумента:**
+1 -1
View File
@@ -5,7 +5,7 @@ Arguments
Модуль ``Arguments`` предоставляет классы для работы с аргументами командной строки. Они позволяют настраивать поведение приложения в момент его запуска, передавая различные параметры конфигурации. Модуль ``Arguments`` предоставляет классы для работы с аргументами командной строки. Они позволяют настраивать поведение приложения в момент его запуска, передавая различные параметры конфигурации.
Аргументы регистрируются в `ArgParser` и после обработки становятся доступными в объекте `ArgSpace`. Аргументы регистрируются в ``ArgParser`` и после обработки становятся доступными в объекте ``ArgSpace``.
----- -----
+10 -2
View File
@@ -1,3 +1,11 @@
arg = '-repeat' from argenta.orchestrator.argparser import ArgSpace, BooleanArgument, ValueArgument
from argenta.orchestrator.argparser.arguments import InputArgument
print(arg[:arg.rfind('-')+1]) argspace = ArgSpace([
InputArgument(name="arg1", value="val1", founder_class=ValueArgument),
InputArgument(name="arg2", value=True, founder_class=BooleanArgument),
InputArgument(name="arg3", value="val3", founder_class=ValueArgument),
])
print(argspace._name_object_paired_args)
print(argspace.get_by_type(ValueArgument))
+4 -3
View File
@@ -1,13 +1,16 @@
from argenta import App, Orchestrator from argenta import App, Orchestrator
from argenta.app import PredefinedMessages from argenta.app import PredefinedMessages
from argenta.orchestrator.argparser import ArgParser, BooleanArgument
from argenta.app.dividing_line.models import StaticDividingLine, DynamicDividingLine from argenta.app.dividing_line.models import StaticDividingLine, DynamicDividingLine
from mock.mock_app.routers import work_router from mock.mock_app.routers import work_router
app: App = App( app: App = App(
dividing_line=DynamicDividingLine('^'), dividing_line=DynamicDividingLine('^'),
) )
orchestrator: Orchestrator = Orchestrator() argparser = ArgParser([BooleanArgument('some')])
orchestrator: Orchestrator = Orchestrator(argparser)
print(argparser.parsed_argspace.get_by_type(BooleanArgument))
def main(): def main():
app.include_router(work_router) app.include_router(work_router)
@@ -19,7 +22,5 @@ def main():
orchestrator.start_polling(app) orchestrator.start_polling(app)
if __name__ == "__main__":
main()
+1 -1
View File
@@ -45,7 +45,7 @@ exclude = [
".__pycache__", ".__pycache__",
"tests" "tests"
] ]
line-length=110 line-length=100
[tool.pyright] [tool.pyright]
typeCheckingMode = "strict" typeCheckingMode = "strict"
+38 -13
View File
@@ -18,26 +18,48 @@ class ArgSpace:
def __init__(self, all_arguments: list[InputArgument]) -> None: def __init__(self, all_arguments: list[InputArgument]) -> None:
self.all_arguments = all_arguments self.all_arguments = all_arguments
self._name_object_paired_args: dict[str, InputArgument] = {}
self._type_object_paired_args: dict[type[BaseArgument], list[InputArgument]] = {
BooleanArgument: [],
ValueArgument: []
}
self._setup_getters()
@classmethod @classmethod
def from_namespace( def from_namespace(
cls, namespace: Namespace, processed_args: list[ValueArgument | BooleanArgument] cls,
namespace: Namespace,
processed_args: list[ValueArgument | BooleanArgument]
) -> Self: ) -> Self:
name_type_paired_args: dict[str, type[BaseArgument]] = {arg.name: type(arg) for arg in processed_args} name_type_paired_processed_args: dict[str, type[BaseArgument]] = {
return cls( arg.name: type(arg) for arg in processed_args
[ }
InputArgument(name=name, value=value, founder_class=name_type_paired_args[name]) parsed_arguments: list[InputArgument] = []
for name, value in vars(namespace).items()
] 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):
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: def get_by_name(self, name: str) -> InputArgument | None:
for arg in self.all_arguments: return self._name_object_paired_args.get(name)
if arg.name == name:
return arg
return None
def get_by_type(self, arg_type: type[BaseArgument]) -> list[InputArgument] | list[Never]: 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: class ArgParser:
@@ -75,7 +97,10 @@ class ArgParser:
for arg in processed_args: for arg in processed_args:
if isinstance(arg, BooleanArgument): if isinstance(arg, BooleanArgument):
_ = self._core.add_argument( _ = self._core.add_argument(
arg.string_entity, action=arg.action, help=arg.help, deprecated=arg.is_deprecated arg.string_entity,
action=arg.action,
help=arg.help,
deprecated=arg.is_deprecated
) )
else: else:
_ = self._core.add_argument( _ = self._core.add_argument(