Update documentation and code snippets

This commit is contained in:
2025-12-04 20:23:11 +03:00
parent 723ed2210f
commit 087c76fed3
19 changed files with 278 additions and 114 deletions
@@ -0,0 +1,24 @@
from argenta import Router, Response
from argenta.command import Command, Flag, PossibleValues
from argenta.command.flag import ValidationStatus
router = Router()
@router.command(Command(
"deploy",
flags=Flag("verbose", possible_values=PossibleValues.NEITHER)
))
def deploy_handler(response: Response):
# Check for toggle flag presence
verbose_flag = response.input_flags.get_flag_by_name("verbose")
if verbose_flag and verbose_flag.status == ValidationStatus.VALID:
print("Deploying with verbose output...")
# Detailed logic
elif verbose_flag and verbose_flag.status == ValidationStatus.INVALID:
print("Incorrect flag value")
return
else:
print("Deploying...")
# Normal logic
+16
View File
@@ -0,0 +1,16 @@
from argenta import Router, Response
from argenta.command import Command, Flag
router = Router()
@router.command(Command("greet", flags=Flag("name")))
def greet_handler(response: Response):
# Get flag by name
name_flag = response.input_flags.get_flag_by_name("name")
# Check if flag was passed
if name_flag:
print(f"Hello, {name_flag.input_value}!")
else:
print("Hello, stranger!")
+2 -2
View File
@@ -5,9 +5,9 @@ flag_with_value = InputFlag(
)
flag_without_value = InputFlag(
name="help", prefix="-", input_value=None, status=ValidationStatus.VALID
name="help", prefix="-", input_value='', status=ValidationStatus.VALID
)
# String representation includes value
print(str(flag_with_value)) # --output result.txt
print(str(flag_without_value)) # -help None
print(str(flag_without_value)) # -help
@@ -0,0 +1,68 @@
import operator
import re
from argenta import App, Orchestrator, Response, Router
from argenta.app import DynamicDividingLine
from argenta.command import Command, Flag, Flags
from argenta.response.status import ResponseStatus
router = Router("Calculator")
operations = {
'mul': operator.mul,
'sub': operator.sub,
'add': operator.add
}
@router.command(
Command(
"calc",
description="Calculator with two numbers",
flags=Flags(
[
Flag("a", possible_values=re.compile(r"^\d{,5}$")), # First number
Flag("b", possible_values=re.compile(r"^\d{,5}$")), # Second number
Flag("operation", possible_values=["add", "sub", "mul"]), # Operation: add, sub, mul
]
),
)
)
def calc_handler(response: Response):
# Get flag values
a_flag = response.input_flags.get_flag_by_name("a")
b_flag = response.input_flags.get_flag_by_name("b")
op_flag = response.input_flags.get_flag_by_name("op")
# Check that all flags are provided
if response.status != ResponseStatus.ALL_FLAGS_VALID or not all([a_flag, b_flag, op_flag]):
print("Error: must specify --a, --b and --op")
return
a = float(a_flag.input_value)
b = float(b_flag.input_value)
operation = op_flag.input_value
try:
result = operations[operation](a, b)
except ZeroDivisionError:
print("Can't divide by zero")
else:
print(f"Result: {result}")
app = App(
initial_message="Calculator",
repeat_command_groups_printing=False,
prompt=">> ",
dividing_line=DynamicDividingLine("~"),
)
orchestrator = Orchestrator()
def main():
app.include_router(router)
orchestrator.start_polling(app)
if __name__ == "__main__":
main()
+2 -2
View File
@@ -17,9 +17,9 @@ Argenta
.. image:: https://github.com/koloideal/Argenta/blob/main/imgs/mock_app_preview4.png?raw=True
:alt: App example
Argenta предназначена для создания приложений, работающих в собственном контексте (scope). Это означает, что при запуске пользователь входит в интерактивную сессию, где ему доступна вся реализованная вами функциональность.
Argenta предназначена для создания приложений, работающих в собственном контексте (scope). Это означает, что приложение запускается один раз и создаёт интерактивную сессию, похожую на Python REPL или MySQL консоль. При запуске пользователь входит в эту сессию, где ему доступна вся реализованная вами функциональность.
Один из ключевых принципов библиотеки — цикличность. После выполнения команды пользователь остаётся в интерактивной сессии, в отличие от таких библиотек, как ``argparse``, ``click`` и ``typer``. Выход из сессии контролируется пользователем.
Один из ключевых принципов библиотеки — цикличность. После выполнения команды пользователь остаётся в интерактивной сессии и имеет доступ к созданной вами функциональности, в отличие от таких библиотек, как ``argparse``, ``click`` и ``typer``. Выход из сессии контролируется пользователем.
**Ключевые особенности:**
@@ -64,7 +64,7 @@ msgid ""
"к БД или API-клиентов) в DI-контейнер."
msgstr ""
"``custom_providers``: List of custom ``dishka.Provider`` providers for adding your services "
"(e.g., database connections or API clients) to the DI container."
"(e.g., database connections or API clients) to the``di``container."
#: ../../root/api/orchestrator/index.rst:32
msgid ""
@@ -93,7 +93,7 @@ msgid "Как это работает?"
msgstr "How Does It Work?"
#: ../../root/dependency_injection.rst:48
msgid "В основе DI в Argenta лежат **провайдеры** и **контейнер**."
msgid "В основе``di``в Argenta лежат **провайдеры** и **контейнер**."
msgstr "DI in Argenta is based on **providers** and a **container**."
#: ../../root/dependency_injection.rst:50
+1 -1
View File
@@ -30,7 +30,7 @@ InputFlag
.. py:attribute:: input_value
Значение, переданное с флагом. Может быть `None` для флагов без значений.
Значение, переданное с флагом. Может быть ``''`` (пустой строкой) для флагов без значений.
.. py:attribute:: status
:no-index:
+1 -1
View File
@@ -44,7 +44,7 @@ ArgParser
Лучшие практики
---------------
Использовать атрибут ``parsed_argspace`` рекомендуется только на этапе настройки приложения. В обработчиках лучшей практикой является получение ``ArgSpace`` через DI. Подробнее см. :ref:`здесь <root_dependency_injection>`.
Использовать атрибут ``parsed_argspace`` рекомендуется только на этапе настройки приложения. В обработчиках лучшей практикой является получение ``ArgSpace`` через ``di``. Подробнее см. :ref:`здесь <root_dependency_injection>`.
**Пример использования:**
+1 -1
View File
@@ -28,7 +28,7 @@ Orchestrator
Создаёт и конфигурирует экземпляр ``Orchestrator``.
* ``arg_parser``: Экземпляр ``ArgParser``, отвечающий за парсинг аргументов командной строки при запуске скрипта (не путать с командами в интерактивном режиме).
* ``custom_providers``: Список пользовательских провайдеров ``dishka.Provider`` для добавления ваших сервисов (например, подключений к БД или API-клиентов) в DI-контейнер.
* ``custom_providers``: Список пользовательских провайдеров ``dishka.Provider`` для добавления ваших сервисов (например, подключений к БД или API-клиентов) в di-контейнер.
* ``auto_inject_handlers``: Если **True** (по умолчанию), ``dishka`` автоматически внедрит зависимости в обработчики команд, инспектируя их сигнатуры.
-----
+8 -5
View File
@@ -3,9 +3,9 @@
Внедрение зависимостей
=======================
Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования, который помогает писать слабосвязанный, легко тестируемый и расширяемый код. Вместо того чтобы обработчики сами создавали нужные им объекты (зависимости), они получают их извне.
Внедрение зависимостей (Dependency Injection, ``di`` ) — это паттерн проектирования, который помогает писать слабосвязанный, легко тестируемый и расширяемый код. Вместо того чтобы обработчики сами создавали нужные им объекты (зависимости), они получают их извне.
``Argenta`` использует библиотеку ``dishka`` для реализации DI, что позволяет декларативно объявлять зависимости прямо в сигнатурах ваших обработчиков.
``Argenta`` использует библиотеку ``dishka`` для реализации ``di``, что позволяет декларативно объявлять зависимости прямо в сигнатурах ваших обработчиков.
Подробнее о **DI**, **IoC** и API для создания провайдеров можно прочитать в `официальной документации dishka <https://dishka.readthedocs.io/en/stable/di_intro.html>`_.
-----
@@ -32,7 +32,10 @@
:language: python
:linenos:
После создания провайдера его необходимо зарегистрировать в оркестраторе:
После создания провайдера его необходимо зарегистрировать в оркестраторе.
.. note::
Провайдеры регистрируются в ``Orchestrator``, а не в ``App``, так как оркестратор отвечает за настройку di-контейнера на уровне всего приложения. Вы можете передать список из нескольких провайдеров через параметр ``custom_providers``.
**Пример использования:**
@@ -45,7 +48,7 @@
Как это работает?
-----------------
В основе DI в Argenta лежат **провайдеры** и **контейнер**.
В основе ``di`` в Argenta лежат **провайдеры** и **контейнер**.
* **Провайдер (Provider)** — это "рецепт", который объясняет, как создавать и настраивать ту или иную зависимость (например, подключение к БД, API-клиент или любой другой сервис).
* **Контейнер (IoC Container)** — это "фабрика", которая хранит все рецепты (провайдеры) и по запросу создаёт и выдаёт готовые зависимости.
@@ -68,7 +71,7 @@
Обмен данными между обработчиками
----------------------------------
Помимо DI, обработчики могут обмениваться данными в рамках сессии через **объект контекста**. В ``Argenta`` эту роль выполняет объект ``DataBridge``.
Помимо ``di``, обработчики могут обмениваться данными в рамках сессии через **объект контекста**. В ``Argenta`` эту роль выполняет объект ``DataBridge``.
Каждый обработчик может записывать в него данные, а также читать, обновлять и удалять их.
+32 -2
View File
@@ -1,7 +1,7 @@
.. _root_flags:
Флаги вводимых команд
=====================
Флаги команд
============
Флаги — это специальные параметры, которые пользователь может добавлять к командам для управления их поведением.
@@ -56,6 +56,36 @@
Флаг состоит из префикса (``-``, ``--`` или ``---``), имени и, опционально, значения, которое указывается через пробел.
**Примеры:**
.. code-block:: shell
greet --name John # Flag with value
deploy --verbose # Flag without value (switch)
backup -f --compress # Several flags
-----
Работа с флагами в обработчиках
--------------------------------
Чтобы получить значение флага в обработчике, используйте объект ``response.input_flags`` типа :ref:`InputFlags <root_api_command_input_flags>`.
**Пример с флагом, имеющим значение:**
.. literalinclude:: ../code_snippets/flags/greet_handler.py
:language: python
:linenos:
**Пример с флагом-переключателем:**
.. literalinclude:: ../code_snippets/flags/deploy_handler.py
:language: python
:linenos:
.. seealso::
Подробнее о работе с объектом ``InputFlags`` см. в разделе :ref:`InputFlags <root_api_command_input_flags>`.
-----
Два типа флагов
+30 -2
View File
@@ -23,6 +23,14 @@
:language: python
:linenos:
**Запуск**
Сохраните код в файл (например, ``main.py``) и запустите:
.. code-block:: shell
python main.py
**Результат**
.. image:: https://i.ibb.co/35q24Bh8/image.png
@@ -30,10 +38,30 @@
-----
Более сложный пример: Менеджер задач
Промежуточный пример: Калькулятор с флагами
--------------------------------------------
Прежде чем перейти к сложному примеру с ``di``, рассмотрим промежуточный вариант — калькулятор, который использует флаги для управления поведением.
.. literalinclude:: ../code_snippets/quickstart/calculator_app.py
:language: python
:linenos:
**Использование:**
.. code-block:: shell
calc --a 10 --b 5 --operation add # Result: 15.0
calc --a 10 --b 5 --operation mul # Result: 50.0
Этот пример показывает, как работать с флагами без использования ``di``. Теперь перейдём к более сложному примеру.
-----
Сложный пример: Менеджер задач с ``di``
--------------------------------------
В этом руководстве мы создадим простое, но полнофункциональное CLI-приложение «Менеджер задач», которое продемонстрирует ключевые возможности Argenta.
В этом руководстве мы создадим полнофункциональное CLI-приложение «Менеджер задач», которое продемонстрирует работу с внедрением зависимостей.
1. **Установка**
+14
View File
@@ -7,6 +7,20 @@
-----
Когда нужно отключать перехват stdout
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Отключайте перехват ``stdout`` (``disable_redirect_stdout=True`` в ``Router``), если ваши команды:
✓ Используют ``input()`` для интерактивного ввода данных от пользователя
✓ Используют прогресс-бары (``tqdm``, ``rich.progress``)
✓ Выводят данные в реальном времени (streaming, логи)
✓ Используют библиотеки, которые напрямую работают с ``stdout``
Для обычных команд с ``print()`` перехват можно оставить включённым — это не влияет на их работу.
-----
Механизм перехвата ``stdout``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~