mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 10:05: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:
@@ -0,0 +1,49 @@
|
||||
.. _root_api_app_autocompleter:
|
||||
|
||||
AutoCompleter
|
||||
=====================
|
||||
|
||||
``AutoCompleter`` — это компонент, отвечающий за интерактивное автодополнение команд. Он улучшает пользовательский опыт, предлагая подсказки и завершая ввод на основе истории команд, что ускоряет работу и снижает вероятность опечаток.
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
__init__(self, history_filename: str | None = None,
|
||||
autocomplete_button: str = "tab") -> None
|
||||
|
||||
Создаёт и настраивает экземпляр ``AutoCompleter``.
|
||||
|
||||
* ``history_filename``: Имя файла для сохранения истории команд. Если указано, история будет сохраняться между сессиями. При значении ``None`` история хранится только в контексте сессии.
|
||||
* ``autocomplete_button``: Клавиша, активирующая автодополнение. По умолчанию — **Tab**.
|
||||
|
||||
-----
|
||||
|
||||
Назначение и возможности
|
||||
-------------------------
|
||||
|
||||
Основные возможности ``AutoCompleter``:
|
||||
|
||||
* **Автодополнение по истории**: При нажатии клавиши автодополнения (по умолчанию **Tab**) система ищет в истории команды, начинающиеся с уже введённого текста.
|
||||
|
||||
* **Общий префикс**: Если найдено несколько команд с общим префиксом, будет подставлена только общая часть. Например, для команд ``show_users`` и ``show_profile`` при вводе ``sho`` и нажатии **Tab** ввод дополнится до ``show_``.
|
||||
|
||||
* **Постоянная история**: Если указан ``history_filename``, история команд сохраняется в файл при выходе и загружается при следующем запуске. Это делает автодополнение со временем «умнее».
|
||||
|
||||
* **Очистка истории**: При сохранении ``AutoCompleter`` удаляет дубликаты и несуществующие команды, поддерживая историю в актуальном состоянии.
|
||||
|
||||
* **Настройка клавиши**: Клавишу автодополнения можно изменить с помощью параметра ``autocomplete_button``.
|
||||
|
||||
-----
|
||||
|
||||
Пример использования
|
||||
--------------------
|
||||
|
||||
``AutoCompleter`` передаётся как аргумент при инициализации `App`.
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/autocompleter/snippet.py
|
||||
:language: python
|
||||
:linenos:
|
||||
@@ -0,0 +1,65 @@
|
||||
.. _root_api_app_dividing_lines:
|
||||
|
||||
Dividing Lines
|
||||
==============
|
||||
|
||||
Разделительные линии в ``Argenta`` используются для визуального структурирования вывода и отделения блоков информации друг от друга. Библиотека предлагает два типа линий: статическую и динамическую.
|
||||
|
||||
-----
|
||||
|
||||
``StaticDividingLine``
|
||||
----------------------
|
||||
|
||||
``StaticDividingLine`` создаёт разделительную линию **фиксированной** длины. Этот тип линии полезен для создания предсказуемого и унифицированного интерфейса.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
def __init__(self, unit_part: str = "-", *,
|
||||
length: int = 25) -> None
|
||||
|
||||
Создаёт экземпляр статической разделительной линии.
|
||||
|
||||
* ``unit_part``: Символ для построения линии (учитывается только первый символ). По умолчанию: ``-``.
|
||||
* ``length``: Фиксированная длина линии. По умолчанию: ``25``.
|
||||
|
||||
-----
|
||||
|
||||
``DynamicDividingLine``
|
||||
-----------------------
|
||||
|
||||
``DynamicDividingLine`` создаёт линию, длина которой **динамически** подстраивается под самую длинную строку в выводе команды. Это требует перехвата ``stdout``, в результате чего разделители идеально обрамляют выводимый контент.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(self, unit_part: str = "-") -> None
|
||||
|
||||
Создаёт экземпляр динамической разделительной линии.
|
||||
|
||||
* ``unit_part``: Символ для построения линии. По умолчанию: ``-``.
|
||||
|
||||
Длина вычисляется автоматически и не задаётся при инициализации.
|
||||
|
||||
.. warning::
|
||||
Обязательно почитайте про нюансы использования динамических линий и перехвата ``stdout`` в :ref:`этом разделе<root_redirect_stdout>`.
|
||||
|
||||
-----
|
||||
|
||||
Назначение и использование
|
||||
---------------------------
|
||||
|
||||
Выбор между статической и динамической линией зависит от ваших задач.
|
||||
|
||||
* **StaticDividingLine** идеально подходит, если:
|
||||
|
||||
* Вам нужен строгий и консистентный дизайн.
|
||||
* Вы используете роутеры с отключённым перехватом ``stdout`` (``disable_redirect_stdout=True``), где динамическое вычисление длины невозможно.
|
||||
|
||||
* **DynamicDividingLine** (поведение по умолчанию) — предпочтительный выбор, если:
|
||||
|
||||
* Вы хотите, чтобы интерфейс был адаптивным.
|
||||
* Вывод ваших команд имеет разную длину.
|
||||
* В ваших обработчиках нет интерактивных операций ввода (например, ``input()``).
|
||||
|
||||
Тип разделителя для всего приложения задаётся при инициализации ``App`` через параметр ``dividing_line``.
|
||||
@@ -0,0 +1,192 @@
|
||||
.. _root_api_app_index:
|
||||
|
||||
App
|
||||
===
|
||||
|
||||
Объект ``App`` — это ядро вашего консольного приложения. Он отвечает за конфигурацию, управление жизненным циклом, обработку команд и взаимодействие с пользователем, координируя работу всех компонентов: роутеров, обработчиков и системных сообщений.
|
||||
|
||||
------
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
AVAILABLE_DIVIDING_LINES: TypeAlias = StaticDividingLine | DynamicDividingLine
|
||||
DEFAULT_DIVIDING_LINE: StaticDividingLine = StaticDividingLine()
|
||||
|
||||
DEFAULT_PRINT_FUNC: Printer = Console().print
|
||||
DEFAULT_AUTOCOMPLETER: AutoCompleter = AutoCompleter()
|
||||
DEFAULT_EXIT_COMMAND: Command = Command("Q", description="Exit command")
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
def __init__(self, *, prompt: str = "What do you want to do?\n\n",
|
||||
initial_message: str = "Argenta\n",
|
||||
farewell_message: str = "\nSee you\n",
|
||||
exit_command: Command = DEFAULT_EXIT_COMMAND,
|
||||
system_router_title: str | None = "System points:",
|
||||
ignore_command_register: bool = True,
|
||||
dividing_line: AVAILABLE_DIVIDING_LINES = DEFAULT_DIVIDING_LINE,
|
||||
repeat_command_groups_printing: bool = True,
|
||||
override_system_messages: bool = False,
|
||||
autocompleter: AutoCompleter = DEFAULT_AUTOCOMPLETER,
|
||||
print_func: Printer = DEFAULT_PRINT_FUNC) -> None
|
||||
|
||||
Создаёт и настраивает экземпляр приложения.
|
||||
|
||||
* ``prompt``: Приглашение к вводу, отображаемое перед каждой командой.
|
||||
* ``initial_message``: Сообщение, выводимое при запуске приложения.
|
||||
* ``farewell_message``: Сообщение, выводимое при выходе из приложения.
|
||||
* ``exit_command``: Команда, которая маркируется как триггер для выхода из приложения.
|
||||
* ``system_router_title``: Заголовок для системного роутера (содержит команду выхода).
|
||||
* ``ignore_command_register``: Если ``True``, регистр вводимых команд игнорируется при поиске обработчика.
|
||||
* ``dividing_line``: Тип разделительной линии (``StaticDividingLine`` или ``DynamicDividingLine``).
|
||||
* ``repeat_command_groups_printing``: Если ``True``, список доступных команд выводится перед каждым вводом.
|
||||
* ``override_system_messages``: Если ``True``, стандартное форматирование (цвета, ASCII-арт) отключается.
|
||||
* ``autocompleter``: Экземпляр класса :ref:`AutoCompleter <root_api_app_autocompleter>`, отвечающий за автодополнение команд.
|
||||
* ``print_func``: Функция для вывода всех системных сообщений (по умолчанию ``rich.Console().print``).
|
||||
|
||||
-----
|
||||
|
||||
Основные методы
|
||||
---------------
|
||||
|
||||
- .. py:method:: include_router(self, router: Router) -> None
|
||||
|
||||
Регистрирует роутер в приложении. Все команды из этого роутера становятся доступными для вызова.
|
||||
|
||||
:param router: Экземпляр ``Router`` для регистрации.
|
||||
|
||||
- .. py:method:: include_routers(self, *routers: Router) -> None
|
||||
|
||||
Регистрирует несколько роутеров одновременно.
|
||||
|
||||
:param routers: Последовательность экземпляров ``Router`` для регистрации.
|
||||
|
||||
- .. py:method:: add_message_on_startup(self, message: str) -> None
|
||||
|
||||
Добавляет текстовое сообщение, которое выводится при запуске приложения после ``initial_message``.
|
||||
|
||||
:param message: Строка с сообщением.
|
||||
|
||||
.. seealso::
|
||||
Для вывода стандартных сообщений можно использовать готовые шаблоны из :ref:`PredefinedMessages <root_api_predefined_messages>`.
|
||||
|
||||
-----
|
||||
|
||||
Методы установки обработчиков
|
||||
-------------------------------
|
||||
|
||||
``App`` позволяет настраивать реакцию на различные события, такие как ошибки ввода или неизвестные команды.
|
||||
|
||||
.. hint::
|
||||
Подробнее об исключениях и их обработке в соответствующем :ref:`разделе документации <root_error_handling>`.
|
||||
|
||||
-----
|
||||
|
||||
.. py:method:: set_description_message_pattern(self, handler: Callable[[str, str], str]) -> None
|
||||
|
||||
Устанавливает шаблон для форматирования описания команды.
|
||||
|
||||
Обработчик принимает триггер команды (``str``) и её описание (``str``).
|
||||
|
||||
------
|
||||
|
||||
.. py:method:: set_incorrect_input_syntax_handler(self, handler: Callable[[str], None]) -> None
|
||||
|
||||
Устанавливает обработчик при некорректном введённом синтаксисе флагов.
|
||||
|
||||
Обработчик принимает строку, введённую пользователем.
|
||||
|
||||
------
|
||||
|
||||
.. py:method:: set_repeated_input_flags_handler(self, handler: Callable[[str], None]) -> None
|
||||
|
||||
Устанавливает обработчик при повторяющихся флагах в введённой команде.
|
||||
|
||||
Обработчик принимает строку, введённую пользователем.
|
||||
|
||||
------
|
||||
|
||||
.. py:method:: set_unknown_command_handler(self, handler: Callable[[InputCommand], None]) -> None
|
||||
|
||||
Устанавливает обработчик при вводе неизвестной команды.
|
||||
|
||||
Обработчик принимает объект ``InputCommand`` - объект введённой команды.
|
||||
|
||||
-----
|
||||
|
||||
.. py:method:: set_empty_command_handler(self, handler: Callable[[], None]) -> None
|
||||
|
||||
Устанавливает обработчик при вводе пустой строки.
|
||||
|
||||
Обработчик не принимает аргументов.
|
||||
|
||||
-----
|
||||
|
||||
.. py:method:: set_exit_command_handler(self, handler: Callable[[Response], None]) -> None
|
||||
|
||||
Переопределяет стандартное поведение при вызове команды выхода.
|
||||
|
||||
Обработчик принимает объект ``Response``.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
autocompleter
|
||||
dividing_lines
|
||||
|
||||
-----
|
||||
|
||||
.. _root_api_predefined_messages:
|
||||
|
||||
PredefinedMessages
|
||||
------------------
|
||||
|
||||
``PredefinedMessages`` — это контейнер, содержащий набор готовых к использованию сообщений. Они отформатированы с использованием синтаксиса ``rich`` и предназначены для вывода стандартной информации, такой как подсказки по использованию.
|
||||
|
||||
Рекомендуется использовать их при старте приложения.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
from argenta import App, Orchestrator
|
||||
from argenta.app import PredefinedMessages
|
||||
|
||||
app: App = App()
|
||||
orchestrator: Orchestrator = Orchestrator()
|
||||
|
||||
def main():
|
||||
app.add_message_on_startup(PredefinedMessages.USAGE)
|
||||
app.add_message_on_startup(PredefinedMessages.AUTOCOMPLETE)
|
||||
app.add_message_on_startup(PredefinedMessages.HELP)
|
||||
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
.. py:class:: PredefinedMessages
|
||||
:no-index:
|
||||
|
||||
.. py:attribute:: USAGE
|
||||
|
||||
Строка: ``[b dim]Usage[/b dim]: [i]<command> <[green]flags[/green]>[/i]``
|
||||
|
||||
Отображается как: ``Usage: <command> <flags>``
|
||||
|
||||
.. py:attribute:: HELP
|
||||
|
||||
Строка: ``[b dim]Help[/b dim]: [i]<command>[/i] [b red]--help[/b red]``
|
||||
|
||||
Отображается как: ``Help: <command> --help``
|
||||
|
||||
.. py:attribute:: AUTOCOMPLETE
|
||||
|
||||
Строка: ``[b dim]Autocomplete[/b dim]: [i]<part>[/i] [bold]<tab>``
|
||||
|
||||
Отображается как: ``Autocomplete: <part> <tab>``
|
||||
@@ -0,0 +1,62 @@
|
||||
.. _root_api_bridge:
|
||||
|
||||
DataBridge
|
||||
==========
|
||||
|
||||
``DataBridge`` — это сущность, предоставляющая временное хранилище данных, которое существует в рамках одной сессии приложения (от запуска до выхода). Она предназначена для обмена данными между обработчиками.
|
||||
|
||||
Основной способ получения доступа к ``DataBridge`` — через DI.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
from argenta.di import FromDishka
|
||||
from argenta import DataBridge, Response
|
||||
|
||||
# ... setting up router and other
|
||||
|
||||
def my_handler(response: Response, data_bridge: FromDishka[DataBridge]):
|
||||
# ... your code
|
||||
|
||||
**Практический пример: Аутентификация**
|
||||
|
||||
Рассмотрим пример, где команда `login` сохраняет токен аутентификации, а команда `get-profile` использует его.
|
||||
|
||||
.. literalinclude:: ../../code_snippets/response/data_sharing.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
**Как это работает:**
|
||||
|
||||
1. При вызове обработчика ``dishka`` автоматически внедряет экземпляр ``DataBridge``.
|
||||
2. Команда ``login --username <имя>`` вызывает ``login_handler``, который через внедрённый ``data_bridge`` сохраняет токен.
|
||||
3. Команда ``get-profile`` вызывает ``get_profile_handler``, который так же получает ``data_bridge`` и извлекает из него токен.
|
||||
|
||||
-----------
|
||||
|
||||
.. py:class:: DataBridge
|
||||
|
||||
.. py:method:: __init__(self, initial_data: dict | None = None)
|
||||
:no-index:
|
||||
|
||||
Инициализирует хранилище. При использовании через DI вызывается автоматически.
|
||||
|
||||
.. py:method:: update(self, data: dict) -> None
|
||||
|
||||
Обновляет хранилище данными из словаря.
|
||||
|
||||
.. py:method:: get_all(self) -> dict
|
||||
|
||||
Возвращает все данные из хранилища.
|
||||
|
||||
.. py:method:: get_by_key(self, key: str) -> Any
|
||||
|
||||
Возвращает значение по ключу или ``None``, если ключ не найден.
|
||||
|
||||
.. py:method:: delete_by_key(self, key: str) -> None
|
||||
|
||||
Удаляет значение по ключу. Вызывает ``KeyError``, если ключ не найден.
|
||||
|
||||
.. py:method:: clear_all(self) -> None
|
||||
|
||||
Полностью очищает хранилище.
|
||||
@@ -0,0 +1,257 @@
|
||||
.. _root_api_command_flag:
|
||||
|
||||
Flag
|
||||
=====
|
||||
|
||||
``Flag`` — это сущность, описывающая флаг команды. Её основная задача — определить параметры флага, включая его имя, префикс и правила валидации.
|
||||
|
||||
.. seealso::
|
||||
|
||||
Документация по :ref:`PossibleValues <root_api_command_possible_values>` — перечисление, определяющее типы допустимых значений.
|
||||
|
||||
Документация по :ref:`InputFlag <root_api_command_input_flag>` — объект обработанного флага, введённого пользователем.
|
||||
|
||||
:ref:`Общая информация <root_flags>` о флагах и их использовании в ``Argenta``
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(
|
||||
self, name: str, *,
|
||||
prefix: Literal["-", "--", "---"] = "--",
|
||||
possible_values: list[str] | Pattern[str] | PossibleValues = PossibleValues.ALL,
|
||||
) -> None
|
||||
|
||||
Создаёт новый флаг для регистрации в команде.
|
||||
|
||||
* ``name``: Имя флага (обязательный параметр).
|
||||
* ``prefix``: Префикс флага (``-``, ``--``, ``---``). По умолчанию ``--``.
|
||||
* ``possible_values``: Правила валидации значения. Может быть списком строк, регулярным выражением или значением из ``PossibleValues``. По умолчанию ``PossibleValues.ALL``, то есть любое значение допустимо.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: name
|
||||
|
||||
Имя флага в виде строки.
|
||||
|
||||
.. py:attribute:: prefix
|
||||
|
||||
Префикс флага. Один из: ``"-"``, ``"--"``, ``"---"``.
|
||||
|
||||
.. py:attribute:: possible_values
|
||||
|
||||
Допустимые значения для флага.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flag/snippet.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
Свойства
|
||||
--------
|
||||
|
||||
string_entity
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
@property
|
||||
string_entity(self) -> str
|
||||
|
||||
Возвращает строковое представление флага в формате ``prefix + name``.
|
||||
|
||||
:return: Строковое представление флага
|
||||
|
||||
Это свойство объединяет префикс и имя в единую строку, которая представляет флаг так, как он выглядел бы в командной строке.
|
||||
|
||||
-----
|
||||
|
||||
Магические методы
|
||||
-----------------
|
||||
|
||||
__str__
|
||||
~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__str__(self) -> str
|
||||
|
||||
Возвращает строковое представление флага (аналогично ``string_entity``).
|
||||
|
||||
:return: Строковое представление флага
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flag/snippet4.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
__repr__
|
||||
~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__repr__(self) -> str
|
||||
|
||||
Возвращает отладочное представление объекта.
|
||||
|
||||
:return: Строка в формате ``Flag<prefix=..., name=...>``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flag/snippet5.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
__eq__
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__eq__(self, other: object) -> bool
|
||||
|
||||
Сравнивает два флага на равенство по их строковому представлению (``string_entity``).
|
||||
|
||||
:param other: Объект для сравнения
|
||||
:return: **True**, если флаги равны, иначе **False**
|
||||
|
||||
Два флага считаются равными, если их ``string_entity`` идентичны.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flag/snippet6.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
.. _root_api_command_flag_predefined_flags:
|
||||
|
||||
PredefinedFlags
|
||||
---------------
|
||||
|
||||
``argenta.command.PredefinedFlags``
|
||||
|
||||
Класс ``PredefinedFlags`` предоставляет набор готовых флагов для использования в приложениях без их ручного создания. Эти флаги покрывают распространённые сценарии.
|
||||
|
||||
Все предопределённые флаги являются атрибутами класса и представляют собой готовые экземпляры ``Flag``.
|
||||
|
||||
-----
|
||||
|
||||
Информационные флаги
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
.. py:attribute:: PredefinedFlags.HELP
|
||||
|
||||
Флаг для отображения справки: ``--help``
|
||||
|
||||
* ``name``: ``"help"``
|
||||
* ``prefix``: ``"--"`` (по умолчанию)
|
||||
* ``possible_values``: ``PossibleValues.NEITHER``
|
||||
|
||||
.. py:attribute:: PredefinedFlags.SHORT_HELP
|
||||
|
||||
Короткая версия флага справки: ``-H``
|
||||
|
||||
* ``name``: ``"H"``
|
||||
* ``prefix``: ``"-"``
|
||||
* ``possible_values``: ``PossibleValues.NEITHER``
|
||||
|
||||
.. py:attribute:: PredefinedFlags.INFO
|
||||
|
||||
Флаг для отображения информации: ``--info``
|
||||
|
||||
* ``name``: ``"info"``
|
||||
* ``prefix``: ``"--"`` (по умолчанию)
|
||||
* ``possible_values``: ``PossibleValues.NEITHER``
|
||||
|
||||
.. py:attribute:: PredefinedFlags.SHORT_INFO
|
||||
|
||||
Короткая версия флага информации: ``-I``
|
||||
|
||||
* ``name``: ``"I"``
|
||||
* ``prefix``: ``"-"``
|
||||
* ``possible_values``: ``PossibleValues.NEITHER``
|
||||
|
||||
-----
|
||||
|
||||
Флаги выбора
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. py:attribute:: PredefinedFlags.ALL
|
||||
|
||||
Флаг для выбора всех элементов: ``--all``
|
||||
|
||||
* ``name``: ``"all"``
|
||||
* ``prefix``: ``"--"``
|
||||
* ``possible_values``: ``PossibleValues.NEITHER``
|
||||
|
||||
.. py:attribute:: PredefinedFlags.SHORT_ALL
|
||||
|
||||
Короткая версия флага выбора всех элементов: ``-A``
|
||||
|
||||
* ``name``: ``"A"``
|
||||
* ``prefix``: ``"-"``
|
||||
* ``possible_values``: ``PossibleValues.NEITHER``
|
||||
|
||||
-----
|
||||
|
||||
Сетевые флаги
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. py:attribute:: PredefinedFlags.HOST
|
||||
|
||||
Флаг для указания IP-адреса хоста: ``--host``
|
||||
|
||||
* ``name``: ``"host"``
|
||||
* ``prefix``: ``"--"`` (по умолчанию)
|
||||
* ``possible_values``: Регулярное выражение для валидации IPv4: ``r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"``
|
||||
|
||||
.. py:attribute:: PredefinedFlags.SHORT_HOST
|
||||
|
||||
Короткая версия флага хоста: ``-H``
|
||||
|
||||
* ``name``: ``"H"``
|
||||
* ``prefix``: ``"-"``
|
||||
* ``possible_values``: Регулярное выражение для валидации IPv4: ``r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"``
|
||||
|
||||
.. py:attribute:: PredefinedFlags.PORT
|
||||
|
||||
Флаг для указания порта: ``--port``
|
||||
|
||||
* ``name``: ``"port"``
|
||||
* ``prefix``: ``"--"`` (по умолчанию)
|
||||
* ``possible_values``: Регулярное выражение для валидации порта: ``r"^\d{1,5}$"``
|
||||
|
||||
.. py:attribute:: PredefinedFlags.SHORT_PORT
|
||||
|
||||
Короткая версия флага порта: ``-P``
|
||||
|
||||
* ``name``: ``"P"``
|
||||
* ``prefix``: ``"-"``
|
||||
* ``possible_values``: Регулярное выражение для валидации порта: ``r"^\d{1,5}$"``
|
||||
|
||||
-----
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flag/predefined_flags.py
|
||||
:linenos:
|
||||
:language: python
|
||||
@@ -0,0 +1,113 @@
|
||||
.. _root_api_command_flags:
|
||||
|
||||
Flags
|
||||
======
|
||||
|
||||
``Flags`` — это коллекция флагов команды. Её основная задача — группировать и управлять набором флагов, зарегистрированных для конкретной команды. ``Flags`` служит контейнером, который позволяет удобно добавлять, извлекать, итерировать флаги и проверять их наличие.
|
||||
|
||||
.. seealso::
|
||||
|
||||
Документация по отдельным флагам (:ref:`Flag <root_api_command_flag>`, :ref:`InputFlag <root_api_command_input_flag>`)
|
||||
|
||||
Документация по :ref:`InputFlags <root_api_command_input_flags>` — коллекция обработанных флагов, введённых пользователем.
|
||||
|
||||
:ref:`Общая информация <root_flags>` о флагах и их использовании в приложении ``Argenta``
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(self, flags: list[Flag] | None = None) -> None
|
||||
|
||||
Создаёт новую коллекцию флагов.
|
||||
|
||||
* ``flags``: Необязательный список флагов типа ``Flag`` для инициализации коллекции. Если не указан, создаётся пустая коллекция.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: flags
|
||||
:no-index:
|
||||
|
||||
Список всех зарегистрированных флагов типа ``Flag``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flags/snippet.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
Методы
|
||||
------
|
||||
|
||||
add_flag
|
||||
~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
add_flag(self, flag: Flag) -> None
|
||||
|
||||
Добавляет флаг в коллекцию.
|
||||
|
||||
:param flag: Флаг типа ``Flag`` для добавления.
|
||||
:return: None.
|
||||
|
||||
Используется для динамического расширения набора флагов.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flags/snippet2.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
add_flags
|
||||
~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
add_flags(self, flags: list[Flag]) -> None
|
||||
|
||||
Добавляет в коллекцию список флагов.
|
||||
|
||||
:param flags: Список флагов типа ``Flag`` для добавления.
|
||||
:return: None.
|
||||
|
||||
Метод расширяет коллекцию, добавляя в неё все флаги из переданного списка. Эффективен для пакетного добавления.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flags/snippet3.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
get_flag_by_name
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
get_flag_by_name(self, name: str) -> Flag | None
|
||||
|
||||
Возвращает флаг по имени.
|
||||
|
||||
:param name: Имя искомого флага.
|
||||
:return: Объект ``Flag`` или ``None``, если флаг не найден.
|
||||
|
||||
Метод возвращает флаг с соответствующим именем. Если флаг не найден, возвращается ``None``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/flags/snippet4.py
|
||||
:linenos:
|
||||
:language: python
|
||||
@@ -0,0 +1,128 @@
|
||||
.. _root_api_command_index:
|
||||
|
||||
Command
|
||||
=======
|
||||
|
||||
``Command`` — это основная единица функциональности в приложении. Каждая команда связывает хэндлер с триггером, введя который он будет вызван для обработки.
|
||||
|
||||
``Command`` инкапсулирует всю информацию о команде: её триггер (ключевое слово для вызова), описание, набор флагов и список псевдонимов.
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(self, trigger: str, *,
|
||||
description: str | None = None,
|
||||
flags: Flag | Flags = DEFAULT_WITHOUT_FLAGS,
|
||||
aliases: list[str] | list[Never] = DEFAULT_WITHOUT_ALIASES) -> None
|
||||
|
||||
Создаёт новую команду для регистрации в роутере.
|
||||
|
||||
* ``trigger``: Строковый триггер, который пользователь вводит для вызова команды. Является основным идентификатором.
|
||||
* ``description``: Необязательное описание, объясняющее назначение команды. Отображается в справке.
|
||||
* ``flags``: Набор флагов для настройки поведения. Может быть одиночным объектом ``Flag`` или коллекцией ``Flags``.
|
||||
* ``aliases``: Список строковых псевдонимов для основного триггера.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: trigger
|
||||
|
||||
Основной триггер команды. Используется для её идентификации при обработке пользовательского ввода.
|
||||
|
||||
.. py:attribute:: description
|
||||
|
||||
Текстовое описание команды. Если не передано, используется значение по умолчанию.
|
||||
|
||||
.. py:attribute:: registered_flags
|
||||
|
||||
Объект ``Flags``, содержащий все зарегистрированные флаги. Если был передан ``Flag``, то автоматически конвертируется из одиночного в коллекцию при инициализации.
|
||||
|
||||
.. py:attribute:: aliases
|
||||
|
||||
Список строковых псевдонимов. Пуст, если псевдонимы не заданы.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/command/snippet.py
|
||||
:linenos:
|
||||
|
||||
.. seealso ::
|
||||
Подробнее про флаги: :ref:`Flags <root_api_command_flags>` и :ref:`Флаги команд <root_flags>`.
|
||||
|
||||
-----
|
||||
|
||||
Регистрация команд
|
||||
------------------
|
||||
|
||||
Команды передаются в качестве аргумента в декоратор ``@router.command()``.
|
||||
|
||||
**Базовый пример:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/command/snippet2.py
|
||||
:linenos:
|
||||
|
||||
**Команды с флагами:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/command/snippet3.py
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
Работа с псевдонимами
|
||||
---------------------
|
||||
|
||||
Псевдонимы позволяют вызывать один и тот же обработчик разными триггерами, сохраняя флаги и описание команды.
|
||||
|
||||
**Пример с псевдонимами:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/command/snippet5.py
|
||||
:linenos:
|
||||
|
||||
Теперь пользователь может вызвать команду любым из способов:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
shutdown
|
||||
poweroff
|
||||
halt
|
||||
stop
|
||||
|
||||
Все эти варианты вызовут один и тот же хэндлер ``handle_shutdown``.
|
||||
|
||||
-----
|
||||
|
||||
.. _root_api_command_input_command:
|
||||
|
||||
InputCommand
|
||||
------------
|
||||
|
||||
``InputCommand`` представляет собой обработанную команду, введённую пользователем. Этот внутренний класс создаётся автоматически при обработке пользовательского ввода. Прямая работа с ним возможна при создании пользовательского обработчика для неизвестных команд.
|
||||
|
||||
.. seealso ::
|
||||
Подробнее о пользовательских обработчиках исключений см. :ref:`здесь <root_error_handling_unknown_command>`.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: trigger
|
||||
:no-index:
|
||||
|
||||
Строковый триггер, введённый пользователем.
|
||||
|
||||
.. py:attribute:: input_flags
|
||||
:no-index:
|
||||
|
||||
Объект ``InputFlags``, содержащий все введённые и распаршенные флаги.
|
||||
|
||||
.. toctree ::
|
||||
:hidden:
|
||||
|
||||
flag
|
||||
possible_values
|
||||
input_flag
|
||||
validation_status
|
||||
flags
|
||||
input_flags
|
||||
@@ -0,0 +1,116 @@
|
||||
.. _root_api_command_input_flag:
|
||||
|
||||
InputFlag
|
||||
=========
|
||||
|
||||
Объект ``InputFlag`` представляет собой флаг, введённый пользователем. Он создаётся в результате обработки пользовательского ввода и содержит информацию о распознанном флаге: его имя, префикс, значение и статус валидации.
|
||||
|
||||
.. seealso::
|
||||
|
||||
Документация по :ref:`Flag <root_api_command_flag>` — класс для регистрации флага.
|
||||
|
||||
Документация по :ref:`ValidationStatus <root_api_command_validation_status>` — статусы валидации флагов.
|
||||
|
||||
-----
|
||||
|
||||
.. warning ::
|
||||
Экземпляры этого класса не предназначены для прямого создания. Они содержатся в объекте :ref:`Response <root_api_response>`.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: name
|
||||
:no-index:
|
||||
|
||||
Имя введённого флага.
|
||||
|
||||
.. py:attribute:: prefix
|
||||
:no-index:
|
||||
|
||||
Префикс флага: ``-``, ``--`` или ``---``.
|
||||
|
||||
.. py:attribute:: input_value
|
||||
|
||||
Значение, переданное с флагом. Может быть ``''`` (пустой строкой) для флагов без значений.
|
||||
|
||||
.. py:attribute:: status
|
||||
:no-index:
|
||||
|
||||
Статус валидации флага: ``ValidationStatus.VALID``, ``ValidationStatus.INVALID`` или ``ValidationStatus.UNDEFINED``.
|
||||
|
||||
-----
|
||||
|
||||
Свойства
|
||||
--------
|
||||
|
||||
string_entity
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
@property
|
||||
string_entity(self) -> str
|
||||
|
||||
Возвращает строковое представление флага в формате ``prefix + name``.
|
||||
|
||||
:return: Строковое представление флага
|
||||
|
||||
-----
|
||||
|
||||
Магические методы
|
||||
-----------------
|
||||
|
||||
__str__
|
||||
~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__str__(self) -> str
|
||||
|
||||
Возвращает строковое представление флага вместе с его значением.
|
||||
|
||||
:return: Строка в формате ``флаг значение``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/input_flag/snippet3.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
__repr__
|
||||
~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__repr__(self) -> str
|
||||
|
||||
Возвращает отладочное представление объекта.
|
||||
|
||||
:return: Строка в формате ``InputFlag<prefix=..., name=..., value=..., status=...>``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/input_flag/snippet4.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
__eq__
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__eq__(self, other: object) -> bool
|
||||
|
||||
Сравнивает два введённых флага на равенство по имени.
|
||||
|
||||
:param other: Объект для сравнения.
|
||||
:return: **True**, если имена флагов совпадают, иначе **False**.
|
||||
|
||||
Два введённых флага считаются равными, если их имена совпадают.
|
||||
@@ -0,0 +1,135 @@
|
||||
.. _root_api_command_input_flags:
|
||||
|
||||
InputFlags
|
||||
==========
|
||||
|
||||
``InputFlags`` — это коллекция флагов, введённых пользователем. Её основная задача — группировать и управлять набором флагов, переданных вместе с командой. ``InputFlags`` служит контейнером, который позволяет удобно извлекать, итерировать и проверять наличие флагов, а также работать с их значениями и статусами валидации.
|
||||
|
||||
.. seealso::
|
||||
|
||||
Документация по отдельным флагам (:ref:`Flag <root_api_command_flag>`, :ref:`InputFlag <root_api_command_input_flag>`)
|
||||
|
||||
Документация по :ref:`InputFlags <root_api_command_input_flags>` — коллекция обработанных флагов, введённых пользователем.
|
||||
|
||||
Документация по :ref:`Response <root_api_response>` — объект ответа, содержащий ``InputFlags``
|
||||
|
||||
:ref:`Общая информация <root_flags>` о флагах и их использовании в приложении ``Argenta``
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(self, flags: list[InputFlag] | None = None) -> None
|
||||
|
||||
Создаёт новую коллекцию введённых флагов.
|
||||
|
||||
* ``flags``: Необязательный список флагов типа ``InputFlag`` для инициализации коллекции. Если не указан, создаётся пустая коллекция.
|
||||
|
||||
.. warning ::
|
||||
Экземпляры этого класса обычно не создаются напрямую. Они автоматически формируются системой при обработке пользовательского ввода и доступны через атрибут ``input_flags`` объекта ``Response``.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: flags
|
||||
:no-index:
|
||||
|
||||
Список всех введённых флагов типа ``InputFlag``. Пуст, если флаги не были переданы при инициализации или пользователь не ввёл их с командой.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/input_flags/snippet1.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
Методы
|
||||
------
|
||||
|
||||
get_flag_by_name
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
get_flag_by_name(self, name: str) -> InputFlag | None
|
||||
|
||||
Возвращает флаг по имени.
|
||||
|
||||
:param name: Имя искомого флага (без префикса).
|
||||
:return: Объект ``InputFlag`` или ``None``, если флаг не найден.
|
||||
|
||||
Метод возвращает первый флаг с соответствующим именем (без учёта префикса).
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/input_flags/snippet2.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
add_flag
|
||||
~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
add_flag(self, flag: InputFlag) -> None
|
||||
|
||||
Добавляет введённый флаг в коллекцию.
|
||||
|
||||
:param flag: Флаг типа ``InputFlag`` для добавления.
|
||||
:return: None.
|
||||
|
||||
Метод добавляет флаг в конец списка ``flags``. Используется для динамического расширения коллекции.
|
||||
|
||||
.. note::
|
||||
Этот метод используется редко, так как `InputFlags` обычно создаётся автоматически. Однако он может быть полезен для тестирования или ручного создания коллекций.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/input_flags/snippet3.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
add_flags
|
||||
~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
add_flags(self, flags: list[InputFlag]) -> None
|
||||
|
||||
Добавляет в коллекцию список введённых флагов.
|
||||
|
||||
:param flags: Список флагов типа ``InputFlag`` для добавления.
|
||||
:return: None.
|
||||
|
||||
Метод расширяет коллекцию, добавляя в неё все флаги из переданного списка. Эффективен для пакетного добавления.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/input_flags/snippet4.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
Практические примеры
|
||||
--------------------
|
||||
|
||||
Обработка всех флагов с проверкой статусов
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/input_flags/snippet10.py
|
||||
:linenos:
|
||||
:language: python
|
||||
@@ -0,0 +1,92 @@
|
||||
.. _root_api_command_possible_values:
|
||||
|
||||
|
||||
PossibleValues
|
||||
==============
|
||||
|
||||
``PossibleValues`` — это перечисление, которое определяет специальные режимы валидации для значений флагов. ``PossibleValues`` используется в параметре ``possible_values`` класса ``Flag``, чтобы указать, может ли флаг принимать значения и какие ограничения на них накладываются.
|
||||
|
||||
``PossibleValues`` содержит два основных значения: ``NEITHER`` (для флагов, которые не могут принимать значения) и ``ALL`` (для флагов, принимающих любые значения). Это перечисление используется вместе со списками строк и регулярными выражениями для создания гибкой системы валидации.
|
||||
|
||||
.. note::
|
||||
Результат валидации доступен через атрибут ``status`` у экземпляра ``InputFlag``. Подробнее см. :ref:`здесь <root_api_command_input_flag>`.
|
||||
|
||||
.. seealso::
|
||||
|
||||
Документация по :ref:`Flag <root_api_command_flag>` — класс флага, использующий ``PossibleValues``.
|
||||
|
||||
Документация по :ref:`ValidationStatus <root_api_command_validation_status>` — результат валидации ввёденного флага.
|
||||
|
||||
:ref:`Общая информация <root_flags>` о флагах и их использовании в приложении ``Argenta``
|
||||
|
||||
-----
|
||||
|
||||
NEITHER
|
||||
~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
PossibleValues.NEITHER = 'NEITHER'
|
||||
|
||||
Указывает, что флаг **не должен** иметь значения.
|
||||
|
||||
Флаги с этим значением работают как булевы переключатели: их наличие в командной строке само по себе является информацией. Попытка передать такому флагу значение приведёт к ошибке валидации.
|
||||
|
||||
**Примеры флагов с** ``NEITHER``:
|
||||
|
||||
* ``--help`` — флаг справки
|
||||
* ``--verbose`` — флаг подробного вывода
|
||||
* ``--force`` — флаг принудительного выполнения
|
||||
* ``-A`` / ``--all`` — флаг выбора всех элементов
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/possible_values/neither.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
ALL
|
||||
~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
PossibleValues.ALL = 'ALL'
|
||||
|
||||
Указывает, что флаг может принимать **любое** значение.
|
||||
|
||||
Флаги с этим значением универсальны и не накладывают ограничений на передаваемые данные. Валидация всегда будет успешной.
|
||||
|
||||
**Примеры флагов с** ``ALL``:
|
||||
|
||||
* ``--message`` — произвольное текстовое сообщение
|
||||
* ``--name`` — произвольное имя
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/possible_values/all.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
Параметр possible_values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``PossibleValues`` используется как один из возможных типов для параметра ``possible_values`` при создании экземпляра ``Flag``.
|
||||
|
||||
**Доступные типы для** ``possible_values``:
|
||||
|
||||
1. ``PossibleValues.NEITHER``: флаг без значения.
|
||||
2. ``PossibleValues.ALL``: флаг с любым значением (по умолчанию).
|
||||
3. ``list[str]``: флаг с ограниченным набором значений.
|
||||
4. ``Pattern[str]``: флаг со значением, проверяемым по регулярному выражению.
|
||||
|
||||
**Пример комбинированного использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/possible_values/combined.py
|
||||
:linenos:
|
||||
:language: python
|
||||
@@ -0,0 +1,78 @@
|
||||
.. _root_api_command_validation_status:
|
||||
|
||||
ValidationStatus
|
||||
================
|
||||
|
||||
``ValidationStatus`` — это перечисление, которое определяет состояние валидации флага. Его задача — предоставить стандартные константы для отображения результата проверки. ``ValidationStatus`` используется в атрибуте ``status`` класса ``InputFlag``.
|
||||
|
||||
``ValidationStatus`` содержит три значения: **VALID** (корректный флаг), **INVALID** (некорректный) и **UNDEFINED** (незарегистрированный).
|
||||
|
||||
.. note::
|
||||
|
||||
Статус валидации устанавливается автоматически при создании экземпляра ``InputFlag`` на основе правил, заданных в соответствующем ``Flag``.
|
||||
|
||||
.. seealso::
|
||||
|
||||
Документация по :ref:`InputFlag <root_api_command_input_flag>` — класс введённого флага, использующий ``ValidationStatus``.
|
||||
|
||||
Документация по :ref:`Flag <root_api_command_flag>` — класс флага с правилами валидации.
|
||||
|
||||
Документация по :ref:`PossibleValues <root_api_command_possible_values>` — типы допустимых значений.
|
||||
|
||||
-----
|
||||
|
||||
VALID
|
||||
~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
ValidationStatus.VALID = 'VALID'
|
||||
|
||||
Указывает, что флаг и его значение **прошли** валидацию.
|
||||
|
||||
Флаги с этим статусом соответствуют правилам, заданным в ``possible_values`` соответствующего ``Flag``. Их можно безопасно использовать в логике приложения без дополнительных проверок.
|
||||
|
||||
**Условия получения статуса** ``VALID``:
|
||||
|
||||
* Флаг с ``PossibleValues.NEITHER`` передан без значения.
|
||||
* Флаг с ``PossibleValues.ALL`` передан с любым значением или без него.
|
||||
* Значение флага входит в список разрешённых.
|
||||
* Значение флага соответствует регулярному выражению.
|
||||
|
||||
-----
|
||||
|
||||
INVALID
|
||||
~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
ValidationStatus.INVALID = 'INVALID'
|
||||
|
||||
Указывает, что флаг или его значение **не прошли** валидацию.
|
||||
|
||||
Флаги с этим статусом нарушают правила, заданные в ``possible_values`` соответствующего ``Flag``. Их следует обрабатывать как ошибочные.
|
||||
|
||||
**Условия получения статуса** ``INVALID``:
|
||||
|
||||
* Флаг с ``PossibleValues.NEITHER`` передан со значением.
|
||||
* Значение флага не входит в список разрешённых.
|
||||
* Значение флага не соответствует регулярному выражению.
|
||||
* Флаг требует значение, но передан без него.
|
||||
|
||||
-----
|
||||
|
||||
UNDEFINED
|
||||
~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
ValidationStatus.UNDEFINED = 'UNDEFINED'
|
||||
|
||||
Указывает, что введённый флаг не был зарегистрирован в команде.
|
||||
|
||||
**Условия получения статуса** ``UNDEFINED``:
|
||||
|
||||
* Введённый флаг не найден среди зарегистрированных для данной команды.
|
||||
@@ -0,0 +1,97 @@
|
||||
.. _root_api_index:
|
||||
|
||||
|
||||
Публичное API
|
||||
=============
|
||||
|
||||
Описание раздела
|
||||
----------------
|
||||
|
||||
В этом разделе описан публичный API библиотеки. Он включает:
|
||||
|
||||
- Классы и функции для интеграции в ваши приложения.
|
||||
- Рекомендации по использованию и поддерживаемые сценарии.
|
||||
- Примеры кода, подробные сигнатуры и описание возвращаемых значений.
|
||||
- Гарантии стабильности и обратной совместимости.
|
||||
|
||||
Интерфейсы, не описанные в этом разделе, считаются внутренними. Их использование может привести к ошибкам при обновлении библиотеки. При разработке собственных решений используйте только компоненты, описанные здесь. Это обеспечит стабильность и совместимость ваших продуктов с будущими версиями ``Argenta``.
|
||||
|
||||
-----
|
||||
|
||||
Публичные импорты
|
||||
-----------------
|
||||
|
||||
Все основные компоненты библиотеки доступны для прямого импорта из корневого пакета ``argenta`` или его подмодулей.
|
||||
|
||||
.. rubric:: Основные компоненты
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from argenta import App, Orchestrator, Router, Command, Response
|
||||
|
||||
* :ref:`App <root_api_app_index>` — Объект приложения, который отвечает за логику роутинга, настройки, валидации и т.д.
|
||||
* :ref:`Orchestrator <root_api_orchestrator_index>` — Класс для конфигурирования и запуска всего приложения.
|
||||
* :ref:`Router <root_api_router>` — Класс для группировки и регистрации команд.
|
||||
* :ref:`Command <root_api_command_index>` — Класс для создания команд при инициализации хэндлеров.
|
||||
* :ref:`Response <root_api_response>` — Объект ответа, передаваемый в обработчики.
|
||||
|
||||
.. rubric:: Команды и флаги
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from argenta.command import (
|
||||
Flag,
|
||||
Flags,
|
||||
InputFlag,
|
||||
InputFlags,
|
||||
PossibleValues,
|
||||
ValidationStatus,
|
||||
PredefinedFlags
|
||||
)
|
||||
|
||||
* :ref:`Flag <root_api_command_flag>` — Класс для описания флага.
|
||||
* :ref:`Flags <root_api_command_flags>` — Коллекция для регистрации флагов.
|
||||
* :ref:`InputFlag <root_api_command_input_flag>` — Класс для введённого пользователем флага.
|
||||
* :ref:`InputFlags <root_api_command_input_flags>` — Коллекция введённых флагов.
|
||||
* :ref:`PossibleValues <root_api_command_possible_values>` — Правила валидации значений флага.
|
||||
* :ref:`ValidationStatus <root_api_command_validation_status>` — Статусы валидации флагов.
|
||||
* :ref:`PredefinedFlags <root_api_command_flag_predefined_flags>` — Коллекция предопределённых флагов.
|
||||
|
||||
.. rubric:: Настройка приложения
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from argenta.app import (
|
||||
AutoCompleter,
|
||||
StaticDividingLine,
|
||||
DynamicDividingLine,
|
||||
PredefinedMessages
|
||||
)
|
||||
|
||||
* :ref:`AutoCompleter <root_api_app_autocompleter>` - Класс для настройки автодополнения.
|
||||
* :ref:`StaticDividingLine <root_api_app_dividing_lines>` — Статическая разделительная линия для оформления вывода.
|
||||
* :ref:`DynamicDividingLine <root_api_app_dividing_lines>` — Динамическая разделительная линия для оформления вывода.
|
||||
* :ref:`PredefinedMessages <root_api_predefined_messages>` — Готовые сообщения для вывода при старте приложения.
|
||||
|
||||
.. rubric:: Внедрение зависимостей
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from argenta.di import (
|
||||
FromDishka,
|
||||
inject
|
||||
)
|
||||
|
||||
* :ref:`FromDishka <root_dependency_injection>` — Маркер аргумента функции как зависимости, которая должна быть инжектирована.
|
||||
* :ref:`inject <root_dependency_injection>` — Декоратор для инжектирования зависимостей, указанных в сигнатуре.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
app/index
|
||||
router
|
||||
orchestrator/index
|
||||
command/index
|
||||
response
|
||||
bridge
|
||||
@@ -0,0 +1,86 @@
|
||||
.. _root_api_orchestrator_argparser:
|
||||
|
||||
ArgParser
|
||||
==========
|
||||
|
||||
``ArgParser`` предназначен для обработки **аргументов командной строки**, передаваемых приложению при запуске. Важно не путать их с флагами, которые пользователь вводит в интерактивном режиме. ``ArgParser`` позволяет получать внешнюю конфигурацию в момент старта (например, путь к файлу настроек, флаги отладки или режим запуска).
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
def __init__(self, processed_args: list[ValueArgument | BooleanArgument], *,
|
||||
name: str = "Argenta",
|
||||
description: str = "Argenta available arguments",
|
||||
epilog: str = "github.com/koloideal/Argenta | made by kolo")
|
||||
|
||||
Создаёт экземпляр парсера аргументов командной строки.
|
||||
|
||||
* ``processed_args``: Список аргументов для обработки при запуске приложения. Подробнее см. :ref:`здесь <root_api_orchestrator_arguments>`.
|
||||
* ``name``: Имя приложения для отображения в справке.
|
||||
* ``description``: Описание приложения для отображения в справке.
|
||||
* ``epilog``: Дополнительная информация для отображения в конце справки.
|
||||
|
||||
-----
|
||||
|
||||
Атрибуты
|
||||
--------
|
||||
|
||||
.. py:attribute:: parsed_argspace: ArgSpace
|
||||
|
||||
Экземпляр ``ArgSpace``, содержащий все обработанные аргументы командной строки. Подробнее см. :ref:`здесь <root_api_orchestrator_argspace>`.
|
||||
|
||||
.. caution::
|
||||
До инициализации ``Orchestrator``, в конструктор которого был передан экземпляр ``ArgParser``, атрибут ``parsed_argspace`` будет содержать пустой ``ArgSpace``.
|
||||
|
||||
Парсинг и валидация аргументов происходят при инициализации ``Orchestrator``, поэтому использовать ``parsed_argspace`` **целесообразно только после** этого.
|
||||
|
||||
-----
|
||||
|
||||
Лучшие практики
|
||||
---------------
|
||||
|
||||
Использовать атрибут ``parsed_argspace`` рекомендуется только на этапе настройки приложения. В обработчиках лучшей практикой является получение ``ArgSpace`` через DI. Подробнее см. :ref:`здесь <root_dependency_injection>`.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/argparser/snippet.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
Обработка ошибок
|
||||
----------------
|
||||
|
||||
.. seealso::
|
||||
Про типы аргументов подробнее в :ref:`Arguments <root_api_orchestrator_arguments>`
|
||||
|
||||
При работе с аргументами командной строки стандартный ``ArgumentParser`` автоматически обрабатывает следующие ситуации:
|
||||
|
||||
**Отсутствие обязательного аргумента:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python app.py
|
||||
usage: Argenta [-h] --config CONFIG
|
||||
Argenta: error: the following arguments are required: --config
|
||||
|
||||
**Недопустимое значение из списка possible_values:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python app.py --config app.yaml --log-level TRACE
|
||||
usage: Argenta [-h] --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
|
||||
Argenta: error: argument --log-level: invalid choice: 'TRACE'
|
||||
|
||||
**Использование устаревшего аргумента:**
|
||||
|
||||
При использовании аргумента с ``is_deprecated=True`` выводится предупреждение, но выполнение продолжается:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python app.py --old-param value
|
||||
Warning: argument --old-param is deprecated
|
||||
@@ -0,0 +1,103 @@
|
||||
.. _root_api_orchestrator_argspace:
|
||||
|
||||
ArgSpace
|
||||
==========
|
||||
|
||||
``ArgSpace`` — это контейнер для хранения и управления обработанными аргументами командной строки. Его основная задача — предоставить удобный интерфейс для доступа к значениям, переданным при запуске приложения.
|
||||
|
||||
``ArgSpace`` создаётся автоматически после обработки аргументов с помощью ``ArgParser`` и содержит коллекцию объектов ``InputArgument``.
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
Создание экземпляров класса ``ArgSpace`` происходит под `капотом`, вам не нужно создавать их вручную.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: all_arguments
|
||||
|
||||
Список всех обработанных аргументов типа ``InputArgument``.
|
||||
|
||||
-----
|
||||
|
||||
Методы
|
||||
------
|
||||
|
||||
get_by_name
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
get_by_name(self, name: str) -> InputArgument | None
|
||||
|
||||
Возвращает аргумент по имени.
|
||||
|
||||
:param name: Имя искомого аргумента.
|
||||
:return: Объект ``InputArgument`` или ``None``, если аргумент не найден.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/argspace/snippet4.py
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
get_by_type
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
get_by_type(self, arg_type: type[BaseArgument]) -> list[InputArgument] | list[Never]
|
||||
|
||||
Возвращает все аргументы определённого типа.
|
||||
|
||||
:param arg_type: Тип аргумента (``BooleanArgument`` или ``ValueArgument``).
|
||||
:return: Список аргументов указанного типа или пустой список.
|
||||
|
||||
Метод фильтрует ``all_arguments`` по атрибуту ``founder_class`` и возвращает аргументы, созданные из указанного типа.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/argspace/snippet3.py
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
InputArgument
|
||||
-------------
|
||||
|
||||
.. seealso ::
|
||||
Документация по ``InputArgument`` находится :ref:`здесь <root_api_orchestrator_arguments_inputargument>`.
|
||||
|
||||
-----
|
||||
|
||||
Примеры использования
|
||||
---------------------
|
||||
|
||||
``ArgSpace`` используется для доступа к значениям аргументов после запуска приложения. Типичный сценарий включает обработку аргументов через ``ArgParser`` и последующее извлечение значений из ``ArgSpace``.
|
||||
|
||||
**Полный пример:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/argspace/snippet.py
|
||||
:linenos:
|
||||
|
||||
Доступ к аргументам из обработчиков осуществляется с помощью DI. Подробнее см. :ref:`здесь <root_dependency_injection>`.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/argspace/snippet2.py
|
||||
:linenos:
|
||||
|
||||
**Запуск приложения:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python server.py --host 0.0.0.0 --port 9000
|
||||
# Output:
|
||||
# Server configuration:
|
||||
# Host: 0.0.0.0
|
||||
# Port: 9000
|
||||
@@ -0,0 +1,137 @@
|
||||
.. _root_api_orchestrator_arguments:
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
Модуль ``Arguments`` предоставляет классы для работы с аргументами командной строки. Они позволяют настраивать поведение приложения в момент его запуска, передавая различные параметры конфигурации.
|
||||
|
||||
Аргументы регистрируются в ``ArgParser`` и после обработки становятся доступными в объекте ``ArgSpace``.
|
||||
|
||||
-----
|
||||
|
||||
ValueArgument
|
||||
-------------
|
||||
|
||||
Класс для аргументов, требующих передачи значения.
|
||||
|
||||
.. py:class:: ValueArgument(BaseArgument)
|
||||
:no-index:
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__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) -> None
|
||||
|
||||
Создаёт аргумент командной строки, требующий значения.
|
||||
|
||||
:param name: Имя аргумента
|
||||
:param prefix: Префикс (по умолчанию ``--``)
|
||||
:param help: Сообщение для справки (``--help``)
|
||||
:param possible_values: Список допустимых значений
|
||||
:param default: Значение по умолчанию, если аргумент не передан
|
||||
:param is_required: Если ``True``, аргумент становится обязательным. Если не передать при запуске, приложение не запустится
|
||||
:param is_deprecated: Если ``True``, помечает аргумент как устаревший. Если передать при запуске, будет выведено предупреждение в консоль
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/arguments/snippet.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
**Запуск приложения:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python app.py --host 127.0.0.1
|
||||
python app.py --host 127.0.0.1 --config custom.yaml --log-level DEBUG
|
||||
|
||||
-----
|
||||
|
||||
BooleanArgument
|
||||
---------------
|
||||
|
||||
Класс для булевых аргументов, не требующих значения. Их наличие при запуске устанавливает значение в **True**, отсутствие — в **False**.
|
||||
|
||||
.. py:class:: BooleanArgument(BaseArgument)
|
||||
:no-index:
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(self, name: str, *,
|
||||
prefix: Literal["-", "--", "---"] = "--",
|
||||
help: str = "Help message for the boolean argument",
|
||||
is_deprecated: bool = False) -> None
|
||||
|
||||
Создаёт булев аргумент командной строки без значения.
|
||||
|
||||
:param name: Имя аргумента
|
||||
:param prefix: Префикс (по умолчанию ``--``)
|
||||
:param help: Сообщение для справки (``--help``)
|
||||
:param is_deprecated: Если ``True``, помечает аргумент как устаревший
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/arguments/snippet2.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
**Запуск приложения:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python app.py --verbose
|
||||
python app.py --debug --no-cache
|
||||
python app.py # without arguments
|
||||
|
||||
-----
|
||||
|
||||
.. _root_api_orchestrator_arguments_inputargument:
|
||||
|
||||
InputArgument
|
||||
-------------
|
||||
|
||||
.. seealso::
|
||||
``InputArgument`` напрямую связан с контейнером ``ArgSpace`` и является его наполнителем. Подробнее о нём см. :ref:`здесь <root_api_orchestrator_argspace>`.
|
||||
|
||||
Представляет собой обработанный аргумент командной строки. Этот класс используется внутри ``ArgSpace`` для хранения значений, полученных после парсинга.
|
||||
|
||||
.. py:class:: InputArgument
|
||||
:no-index:
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(self, name: str,
|
||||
value: str | Literal[True],
|
||||
founder_class: type[BaseArgument]) -> None
|
||||
|
||||
Создаёт экземпляр обработанного входного аргумента.
|
||||
|
||||
:param name: Имя аргумента
|
||||
:param value: Значение аргумента. Для ``BooleanArgument`` — **True**, если аргумент передан, и **False**, если нет; для ``ValueArgument`` — введённая строка
|
||||
:param founder_class: Класс-родитель, из которого был создан аргумент (``BooleanArgument`` или ``ValueArgument``)
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: name
|
||||
:no-index:
|
||||
|
||||
Имя аргумента, указанное при создании ``ValueArgument`` или ``BooleanArgument``.
|
||||
|
||||
.. py:attribute:: value
|
||||
|
||||
Значение аргумента. Тип зависит от исходного класса:
|
||||
|
||||
* Для ``BooleanArgument``: **True**, если аргумент был передан
|
||||
* Для ``ValueArgument``: строка с переданным значением или значением по умолчанию
|
||||
|
||||
.. py:attribute:: founder_class
|
||||
|
||||
Ссылка на класс-родитель. Используется для определения типа и фильтрации.
|
||||
@@ -0,0 +1,64 @@
|
||||
.. _root_api_orchestrator_index:
|
||||
|
||||
Orchestrator
|
||||
====================
|
||||
|
||||
``Orchestrator`` — это высокоуровневый компонент, который конфигурирует и оркестрирует приложение, парсер командной строки, DI и остальные компоненты, находящиеся по иерархии на уровне с ``App``.
|
||||
|
||||
В то время как ``App`` отвечает за логику интерактивной сессии (ввод команд, маршрутизация), ``Orchestrator`` подготавливает окружение для его работы и служит точкой входа в приложение.
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
DEFAULT_ARGPARSER: ArgParser = ArgParser(processed_args=[])
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
def __init__(self, arg_parser: ArgParser = DEFAULT_ARGPARSER,
|
||||
custom_providers: list[Provider] = [],
|
||||
auto_inject_handlers: bool = True) -> None
|
||||
|
||||
Создаёт и конфигурирует экземпляр ``Orchestrator``.
|
||||
|
||||
* ``arg_parser``: Экземпляр ``ArgParser``, отвечающий за парсинг аргументов командной строки при запуске скрипта (не путать с командами в интерактивном режиме).
|
||||
* ``custom_providers``: Список пользовательских провайдеров ``dishka.Provider`` для добавления ваших сервисов (например, подключений к БД или API-клиентов) в di-контейнер.
|
||||
* ``auto_inject_handlers``: Если **True** (по умолчанию), ``dishka`` автоматически внедрит зависимости в обработчики команд, инспектируя их сигнатуры.
|
||||
|
||||
-----
|
||||
|
||||
Основные методы
|
||||
----------------
|
||||
|
||||
.. py:method:: start_polling(self, app: App) -> None
|
||||
|
||||
Это главный метод, который запускает приложение. Он запускает бесконечный цикл ввода -> вывода.
|
||||
|
||||
:param app: Экземпляр ``App``, который будет запущен.
|
||||
|
||||
-----
|
||||
|
||||
Назначение и использование
|
||||
----------------------------
|
||||
|
||||
``Orchestrator`` абстрагирует сложность, связанную с настройкой DI и парсингом стартовых аргументов.
|
||||
|
||||
Такой подход разделяет ответственности: ``App`` отвечает за логику интерактивной сессии, а ``Orchestrator`` — за подготовку окружения и запуск приложения.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../../code_snippets/orchestrator/snippet.py
|
||||
:language: python
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
argparser
|
||||
arguments
|
||||
argspace
|
||||
@@ -0,0 +1,116 @@
|
||||
.. _root_api_response:
|
||||
|
||||
Response
|
||||
========
|
||||
|
||||
``Response`` — это объект, который передаётся в обработчик команды. Он создаётся автоматически при обработке пользовательского ввода и содержит статус валидации, введённые флаги.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
Документация по :ref:`InputFlags <root_api_command_input_flags>` — коллекция введённых флагов команды.
|
||||
|
||||
Документация по :ref:`ResponseStatus <root_api_response_status>` — статусы валидации флагов команды.
|
||||
|
||||
Документация по :ref:`InputFlag <root_api_command_input_flag>` — отдельный введённый флаг.
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(
|
||||
self, status: ResponseStatus,
|
||||
input_flags: InputFlags = EMPTY_INPUT_FLAGS,
|
||||
)
|
||||
|
||||
Создаёт новый объект ответа.
|
||||
|
||||
* ``status``: Общий статус валидации флагов из перечисления ``ResponseStatus``.
|
||||
* ``input_flags``: Коллекция введённых флагов (``InputFlags``). По умолчанию — пустая.
|
||||
|
||||
.. warning::
|
||||
Экземпляры этого класса не предназначены для прямого создания. Они автоматически формируются системой и передаются в обработчик команды в качестве первого обязательного аргумента.
|
||||
|
||||
**Атрибуты:**
|
||||
|
||||
.. py:attribute:: status
|
||||
:no-index:
|
||||
|
||||
Общий статус валидации всех флагов команды (``ResponseStatus``). Указывает, были ли среди введённых флагов некорректные или незарегистрированные.
|
||||
|
||||
.. py:attribute:: input_flags
|
||||
:no-index:
|
||||
|
||||
Коллекция всех флагов, переданных с командой (``InputFlags``). Содержит все обработанные флаги с их значениями и статусами валидации.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../code_snippets/response/snippet1.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
Работа с флагами
|
||||
----------------
|
||||
|
||||
``Response`` предоставляет доступ к введённым флагам через атрибут ``input_flags``. Вы можете проверять их наличие, получать значения и статусы валидации.
|
||||
|
||||
**Пример работы с флагами:**
|
||||
|
||||
.. literalinclude:: ../../code_snippets/response/snippet6.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
.. _root_api_response_status:
|
||||
|
||||
ResponseStatus
|
||||
--------------
|
||||
|
||||
``ResponseStatus`` — это перечисление, которое определяет общий статус валидации всех флагов команды. Используется в атрибуте ``status`` объекта ``Response``.
|
||||
|
||||
ALL_FLAGS_VALID
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
ResponseStatus.ALL_FLAGS_VALID = 'ALL_FLAGS_VALID'
|
||||
|
||||
Все введённые флаги прошли валидацию. Нет ни некорректных, ни незарегистрированных флагов.
|
||||
|
||||
UNDEFINED_FLAGS
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
ResponseStatus.UNDEFINED_FLAGS = 'UNDEFINED_FLAGS'
|
||||
|
||||
Среди введённых флагов есть незарегистрированные, но нет флагов с некорректными значениями.
|
||||
|
||||
INVALID_VALUE_FLAGS
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
ResponseStatus.INVALID_VALUE_FLAGS = 'INVALID_VALUE_FLAGS'
|
||||
|
||||
Среди введённых флагов есть флаги с некорректными значениями, но нет незарегистрированных.
|
||||
|
||||
UNDEFINED_AND_INVALID_FLAGS
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
ResponseStatus.UNDEFINED_AND_INVALID_FLAGS = 'UNDEFINED_AND_INVALID_FLAGS'
|
||||
|
||||
Среди введённых флагов есть как незарегистрированные, так и флаги с некорректными значениями.
|
||||
@@ -0,0 +1,91 @@
|
||||
.. _root_api_router:
|
||||
|
||||
Router
|
||||
=============
|
||||
|
||||
``Router`` — это основной строительный блок для организации логики в приложении. Его задача — группировать связанные команды и их обработчики. Каждый роутер представляет собой логический контейнер для определённого набора функций.
|
||||
|
||||
Например, в приложении для управления пользователями один роутер может отвечать за аутентификацию (``login``, ``logout``), а другой — за операции с профилем (``profile-show``, ``profile-edit``).
|
||||
|
||||
-----
|
||||
|
||||
Инициализация
|
||||
-------------
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
__init__(self, title: str | None = None,
|
||||
disable_redirect_stdout: bool = False) -> None
|
||||
|
||||
Создаёт новый экземпляр роутера.
|
||||
|
||||
* ``title``: Необязательный заголовок для группы команд. Отображается в списке доступных команд, помогая пользователю ориентироваться.
|
||||
* ``disable_redirect_stdout``: Если ``True``, отключает перехват ``stdout`` для всех команд этого роутера. Это необходимо для интерактивных команд (например, с ``input()``). При отключении перехвата автоматически используется статическая разделительная линия. Подробнее см. в разделе :ref:`Переопределение стандартного вывода <root_redirect_stdout>`.
|
||||
|
||||
-----
|
||||
|
||||
Регистрация команд
|
||||
------------------
|
||||
|
||||
Для регистрации команды и привязки к ней обработчика используется декоратор ``@command``.
|
||||
|
||||
.. py:method:: @command(self, command: Command | str)
|
||||
|
||||
Декоратор для регистрации функции как обработчика команды.
|
||||
|
||||
:param command: Экземпляр ``Command``, описывающий триггер, флаги и описание команды. Может быть строкой, которая станет триггером (без возможности настройки флагов и описания).
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../../code_snippets/router/snippet.py
|
||||
:linenos:
|
||||
:language: python
|
||||
|
||||
-----
|
||||
|
||||
Системный роутер
|
||||
-----------------------------
|
||||
|
||||
``Argenta`` поставляется со встроенным системным роутером, который автоматически подключается к каждому приложению.
|
||||
|
||||
.. py:data:: system_router
|
||||
:no-index:
|
||||
|
||||
Предопределённый экземпляр ``Router`` с базовыми системными командами (по умолчанию — команда выхода). Имеет заголовок **«System points:»**, который можно переопределить в ``App``.
|
||||
|
||||
Вы можете добавлять свои команды в этот роутер. Для этого импортируйте ``argenta.router.defaults.system_router`` и используйте его декоратор ``@command``.
|
||||
|
||||
-----
|
||||
|
||||
Возможные исключения
|
||||
--------------------
|
||||
|
||||
При регистрации команд и флагов в ``Router`` могут возникнуть следующие исключения:
|
||||
|
||||
.. py:exception:: TriggerContainSpacesException
|
||||
|
||||
Выбрасывается, если триггер команды в ``Command`` содержит пробелы. Триггеры должны быть одним словом.
|
||||
|
||||
**Неправильно:** ``Command("add user")``
|
||||
|
||||
**Правильно:** ``Command("add-user")``
|
||||
|
||||
.. py:exception:: RepeatedFlagNameException
|
||||
|
||||
Возникает, если при определении флагов для команды были использованы дублирующиеся имена. Имена флагов в рамках одной команды должны быть уникальны.
|
||||
|
||||
**Пример, вызывающий исключение:**
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
Command("send", flags=[
|
||||
Flag("recipient"),
|
||||
Flag("recipient") # Duplicate!
|
||||
])
|
||||
|
||||
.. py:exception:: RequiredArgumentNotPassedException
|
||||
|
||||
Возникает, если обработчик команды не принимает обязательный аргумент ``Response``.
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
.. _root_code_of_conduct:
|
||||
|
||||
Правила сообщества
|
||||
==========================
|
||||
|
||||
Наше обязательство
|
||||
------------------
|
||||
|
||||
В целях создания открытой и гостеприимной атмосферы мы, как участники и мейнтейнеры, обязуемся сделать участие в нашем проекте и сообществе свободным от преследований для всех, независимо от возраста, телосложения, инвалидности, этнической принадлежности, уровня опыта, образования, социально-экономического статуса, национальности, внешности, расы или религии.
|
||||
|
||||
-----
|
||||
|
||||
Наши стандарты
|
||||
--------------
|
||||
|
||||
Примеры поведения, которые способствуют созданию позитивной среды:
|
||||
|
||||
* Проявление эмпатии и доброты по отношению к другим.
|
||||
* Уважение к различным мнениям, точкам зрения и опыту.
|
||||
* Предоставление и тактичное принятие конструктивной обратной связи.
|
||||
* Принятие ответственности и извинения перед теми, кого затронули наши ошибки, а также извлечение уроков из этого опыта.
|
||||
* Фокус на том, что лучше для всего сообщества.
|
||||
|
||||
Примеры недопустимого поведения включают:
|
||||
|
||||
* Троллинг, оскорбительные или уничижительные комментарии, а также личные или политические нападки.
|
||||
* Публичное или частное преследование.
|
||||
* Публикация личной информации других лиц (например, физического или электронного адреса) без их явного разрешения.
|
||||
* Любое другое поведение, которое можно обоснованно считать неуместным в профессиональной среде.
|
||||
|
||||
-----
|
||||
|
||||
Наши обязанности
|
||||
----------------
|
||||
|
||||
Мейнтейнеры проекта несут ответственность за разъяснение и обеспечение соблюдения стандартов приемлемого поведения и предпримут справедливые корректирующие действия в ответ на любые случаи неприемлемого поведения.
|
||||
|
||||
Мейнтейнеры проекта имеют право и обязанность удалять, редактировать или отклонять комментарии, коммиты, код, правки в вики, задачи и другие вклады, которые не соответствуют настоящему Кодексу поведения, а также временно или навсегда блокировать любого участника за поведение, которое они сочтут неуместным, угрожающим, оскорбительным или вредным.
|
||||
|
||||
-----
|
||||
|
||||
Сфера применения
|
||||
----------------
|
||||
|
||||
Настоящий Кодекс поведения применяется как в рамках проекта, так и в публичных пространствах, когда человек официально представляет сообщество. Примеры такого представительства включают использование официального адреса электронной почты, публикации через официальный аккаунт в социальных сетях или выступление в качестве назначенного представителя на онлайн- или офлайн-мероприятии.
|
||||
|
||||
-----
|
||||
|
||||
Обеспечение соблюдения
|
||||
----------------------
|
||||
|
||||
О случаях оскорбительного, преследовательского или иного неприемлемого поведения можно сообщить команде проекта по адресу kolo.is.main@gmail.com. Все жалобы будут рассмотрены и расследованы оперативно и справедливо.
|
||||
|
||||
Команда проекта обязуется уважать частную жизнь и безопасность заявителя.
|
||||
|
||||
-----
|
||||
|
||||
Атрибуция
|
||||
----------
|
||||
|
||||
Настоящий Кодекс поведения адаптирован из `Contributor Covenant <https://www.contributor-covenant.org/>`__, версии
|
||||
`1.4 <https://www.contributor-covenant.org/version/1/4/code-of-conduct/code_of_conduct.md>`__ и
|
||||
`2.0 <https://www.contributor-covenant.org/version/2/0/code_of_conduct/code_of_conduct.md>`__.
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
.. _root_contributing:
|
||||
|
||||
Вклад в проект
|
||||
==============
|
||||
|
||||
.. default-role:: code
|
||||
|
||||
Прежде всего, спасибо, что уделили время для внесения своего вклада! ❤️
|
||||
|
||||
Мы приветствуем и ценим любой вклад. Пожалуйста, прочтите соответствующий раздел, прежде чем начать. Это облегчит работу мейнтейнеров и сделает процесс более гладким для всех. Сообщество с нетерпением ждёт ваших идей! 🎉
|
||||
|
||||
.. note::
|
||||
|
||||
Если вам нравится проект, но у вас нет времени на активный вклад, вы можете поддержать нас другими способами:
|
||||
|
||||
* Поставить звезду на GitHub.
|
||||
* Написать о проекте в Twitter или других социальных сетях.
|
||||
* Сослаться на проект в `README` вашего репозитория.
|
||||
* Упомянуть проект на митапах и рассказать о нём друзьям и коллегам.
|
||||
|
||||
.. _contents:
|
||||
|
||||
Содержание
|
||||
----------
|
||||
|
||||
* :ref:`Кодекс поведения <code-of-conduct>`
|
||||
* :ref:`У меня есть вопрос <i-have-a-question>`
|
||||
* :ref:`Я хочу внести вклад <i-want-to-contribute>`
|
||||
* :ref:`Сообщение об ошибках <reporting-bugs>`
|
||||
* :ref:`Предложение улучшений <suggesting-enhancements>`
|
||||
* :ref:`Ваш первый вклад в код <your-first-code-contribution>`
|
||||
* :ref:`Улучшение документации <improving-documentation>`
|
||||
* :ref:`Руководства по стилю <styleguide>`
|
||||
* :ref:`Присоединяйтесь к команде проекта <join-the-project-team>`
|
||||
|
||||
.. _code-of-conduct:
|
||||
|
||||
Кодекс поведения
|
||||
----------------
|
||||
|
||||
Этот проект и все его участники руководствуются :ref:`Кодексом поведения Argenta <root_code_of_conduct>`.
|
||||
Участвуя, вы обязуетесь соблюдать этот кодекс. Пожалуйста, сообщайте о недопустимом поведении.
|
||||
|
||||
-----
|
||||
|
||||
.. _i-have-a-question:
|
||||
|
||||
У меня есть вопрос
|
||||
------------------
|
||||
|
||||
.. note::
|
||||
|
||||
Прежде чем задать вопрос, пожалуйста, ознакомьтесь с `документацией <https://argenta.readthedocs.io>`_.
|
||||
|
||||
Поищите ответ в существующих `Issues <https://github.com/koloideal/Argenta/issues>`_. Если вы нашли похожий вопрос, но всё ещё нуждаетесь в разъяснениях, можете написать в нём. Также рекомендуем поискать ответ в интернете.
|
||||
|
||||
Если ответа не нашлось, создайте новый `Issue <https://github.com/koloideal/Argenta/issues/new>`_ и предоставьте как можно больше контекста, включая версии проекта и платформы.
|
||||
|
||||
Мы займемся вашей задачей как можно скорее.
|
||||
|
||||
-----
|
||||
|
||||
.. _i-want-to-contribute:
|
||||
|
||||
Я хочу внести вклад
|
||||
-------------------
|
||||
|
||||
.. rubric:: Правовое уведомление
|
||||
|
||||
.. note::
|
||||
|
||||
Внося вклад в этот проект, вы подтверждаете, что являетесь автором 100% контента, обладаете необходимыми правами на него и соглашаетесь, что он может распространяться под лицензией проекта.
|
||||
|
||||
.. _reporting-bugs:
|
||||
|
||||
Сообщение об ошибках
|
||||
--------------------
|
||||
|
||||
.. rubric:: Перед отправкой отчета об ошибке
|
||||
|
||||
Хороший отчёт об ошибке не должен заставлять других вытягивать из вас дополнительную информацию. Пожалуйста, тщательно всё изучите, соберите информацию и подробно опишите проблему. Это поможет нам исправить её как можно быстрее.
|
||||
|
||||
* Убедитесь, что вы используете последнюю версию.
|
||||
* Убедитесь, что проблема действительно является ошибкой, а не вызвана, например, использованием несовместимых версий окружения. Прочтите `документацию <https://argenta.readthedocs.io>`_ и, если нужна поддержка, загляните в раздел :ref:`У меня есть вопрос <i-have-a-question>`.
|
||||
* Проверьте, нет ли уже отчёта о вашей ошибке в `трекере <https://github.com/koloideal/Argenta/issues?q=label%3Abug>`_.
|
||||
* Также поищите в интернете (включая `Stack Overflow`), чтобы узнать, обсуждалась ли проблема за пределами `GitHub`.
|
||||
* Соберите информацию об ошибке:
|
||||
* Трассировка стека.
|
||||
* ОС, платформа и версия (Windows, Linux, macOS, x86, ARM).
|
||||
* Версия интерпретатора, компилятора, SDK, среды выполнения, менеджера пакетов и т.д.
|
||||
* Входные данные и полученный результат.
|
||||
* Можете ли вы надёжно воспроизвести проблему? Воспроизводится ли она на старых версиях?
|
||||
|
||||
.. rubric:: Как мне отправить хороший отчет об ошибке?
|
||||
|
||||
.. note::
|
||||
|
||||
Никогда не сообщайте о проблемах безопасности, уязвимостях или ошибках с конфиденциальной информацией в публичном трекере. Для этого используйте электронную почту.
|
||||
|
||||
Мы используем `GitHub Issues` для отслеживания ошибок. Если вы столкнулись с проблемой:
|
||||
|
||||
* Откройте новый `Issue <https://github.com/koloideal/Argenta/issues/new>`_. На этом этапе не нужно присваивать ему метки.
|
||||
* Объясните ожидаемое и фактическое поведение.
|
||||
* Предоставьте как можно больше контекста и опишите **шаги для воспроизведения**, чтобы проблему можно было воссоздать. Лучше всего изолировать её и создать минимальный тестовый пример.
|
||||
* Предоставьте информацию, которую вы собрали в предыдущем разделе.
|
||||
|
||||
После того, как задача будет создана:
|
||||
|
||||
* Команда проекта присвоит задаче соответствующую метку.
|
||||
* Член команды попытается воспроизвести проблему. Если шагов нет или они не приводят к результату, команда попросит вас предоставить их и пометит задачу как `needs-repro`. Такие задачи не будут рассматриваться до тех пор, пока проблема не будет воспроизведена.
|
||||
* Если проблема будет воспроизведена, она будет помечена как `needs-fix` (и, возможно, другими метками, например `critical`), после чего её сможет взять в работу :ref:`любой желающий <your-first-code-contribution>`.
|
||||
|
||||
-----
|
||||
|
||||
.. _suggesting-enhancements:
|
||||
|
||||
Предложение улучшений
|
||||
---------------------
|
||||
|
||||
Этот раздел поможет вам отправить предложение по улучшению `Argenta`, **включая как новые функции, так и незначительные улучшения**. Следование этим рекомендациям поможет мейнтейнерам и сообществу лучше понять вашу идею.
|
||||
|
||||
.. rubric:: Перед отправкой предложения по улучшению
|
||||
|
||||
* Убедитесь, что вы используете последнюю версию.
|
||||
* Внимательно прочтите `документацию <https://argenta.readthedocs.io>`_ и убедитесь, что предлагаемая функциональность ещё не реализована (возможно, через конфигурацию).
|
||||
* Выполните `поиск <https://github.com/koloideal/Argenta/issues>`_, чтобы проверить, не предлагалось ли это улучшение ранее. Если да, добавьте комментарий к существующей задаче.
|
||||
* Определите, соответствует ли ваша идея масштабу и целям проекта. Вам предстоит убедительно доказать её пользу. Мы хотим видеть функции, которые будут полезны большинству пользователей. Если ваша идея ориентирована на узкий круг, рассмотрите возможность создания плагина.
|
||||
|
||||
.. rubric:: Как мне отправить хорошее предложение по улучшению?
|
||||
|
||||
Предложения по улучшению отслеживаются в `GitHub Issues <https://github.com/koloideal/Argenta/issues>`_.
|
||||
|
||||
* Используйте **чёткий и описательный заголовок**, чтобы идентифицировать предложение.
|
||||
* Предоставьте **пошаговое и подробное описание** предлагаемого улучшения.
|
||||
* **Опишите текущее поведение** и **объясните, какое вы ожидали увидеть вместо этого** и почему. Здесь же можно указать, какие альтернативы вам не подходят.
|
||||
* **Приложите скриншоты или видео**, которые помогут продемонстрировать шаги или указать на часть, к которой относится предложение.
|
||||
* **Объясните, почему это улучшение будет полезно** большинству пользователей `Argenta`. Вы также можете указать на другие проекты, которые решили эту проблему и могут послужить источником вдохновения.
|
||||
|
||||
-----
|
||||
|
||||
.. _your-first-code-contribution:
|
||||
|
||||
Ваш первый вклад в код
|
||||
-----------------------
|
||||
|
||||
Не знаете, с чего начать? Посмотрите на задачи с метками `good first issue` и `help wanted` в нашем репозитории на `GitHub`. Они хорошо подходят для новичков.
|
||||
|
||||
Чтобы начать, настройте локальное окружение для разработки, следуя этим шагам.
|
||||
|
||||
#. Сделайте форк репозитория ``Argenta`` на ``GitHub``.
|
||||
#. Клонируйте ваш форк на локальную машину:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/<ВАШ_НИКНЕЙМ>/Argenta.git
|
||||
cd Argenta
|
||||
|
||||
#. Создайте и активируйте виртуальное окружение.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Для macOS/Linux
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
|
||||
# Для Windows
|
||||
python -m venv .venv
|
||||
.venv\Scripts\activate
|
||||
|
||||
#. Установите зависимости проекта, включая инструменты для разработки.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -e .[dev]
|
||||
|
||||
#. Создайте новую ветку для вашей функции или исправления. Используйте описательное имя, например `fix/login-bug` или `feat/new-widget`.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git switch -c your-new-branch-name
|
||||
|
||||
#. Внесите свои изменения. Напишите код и не забудьте добавить или обновить тесты.
|
||||
#. Запустите тесты, чтобы убедиться, что все работает корректно.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python -m pytest tests
|
||||
|
||||
#. Сделайте коммит, следуя :ref:`нашему руководству по стилю <styleguide>`, и отправьте изменения в ваш форк.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git add .
|
||||
git commit -m "feat(widget): add the new super widget"
|
||||
git push origin your-new-branch-name
|
||||
|
||||
#. Откройте `Pull Request` из вашей ветки в ветку `main` официального репозитория. Предоставьте чёткое описание проблемы и вашего решения. Укажите номер связанной задачи, если она есть.
|
||||
|
||||
-----
|
||||
|
||||
.. _improving-documentation:
|
||||
|
||||
Улучшение документации
|
||||
----------------------
|
||||
|
||||
Хорошая документация крайне важна. Мы используем `Sphinx` для её генерации из исходных файлов в директории `docs/`. Мы приветствуем любые улучшения: от исправления опечатки до написания нового раздела.
|
||||
|
||||
.. note::
|
||||
|
||||
Мы поддерживаем документацию на двух языках: русском и английском.
|
||||
|
||||
.. important::
|
||||
|
||||
Для инкапсуляции различных команд, необходимых для настройки и запуска проекта мы используем ``just``, он же фигурирует в различных примерах в документации, поэтому рекомендуем вам `установить его <https://github.com/casey/just#installation>`_
|
||||
|
||||
Для улучшения документации вы можете следовать процессу, похожему на внесение вклада в код:
|
||||
|
||||
#. Убедитесь, что ваше окружение для разработки настроено, как описано в разделе :ref:`Ваш первый вклад в код <your-first-code-contribution>`.
|
||||
#. Перейдите в директорию с документацией.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd docs
|
||||
|
||||
#. Внесите изменения в **русскую** версию документации (`docs/index.rst` и/или `docs/root/*`).
|
||||
#. Чтобы собрать документацию локально в режиме автоматического ребилда и увидеть изменения, выполните:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
just live-ru
|
||||
|
||||
#. Откройте `127.0.0.1:8000` в браузере, чтобы просмотреть сгенерированную документацию.
|
||||
#. После завершения работы над русской версией необходимо создать английский перевод:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
just update-langs
|
||||
|
||||
#. После обновления шаблона обновите файлы перевода, расположенные в `docs/locales/en/LC_MESSAGES/`.
|
||||
#. Когда изменения будут готовы, сделайте коммит и откройте `Pull Request`. Используйте префикс `docs:` в сообщении коммита.
|
||||
|
||||
-----
|
||||
|
||||
.. _styleguide:
|
||||
|
||||
Руководства по стилю
|
||||
--------------------
|
||||
|
||||
.. _commits_messages:
|
||||
|
||||
**Сообщения коммитов**
|
||||
|
||||
Мы следуем спецификации `Conventional Commits <https://www.conventionalcommits.org/en/v1.0.0/>`_. Это делает историю проекта более читаемой и позволяет автоматически генерировать журнал изменений.
|
||||
|
||||
Каждое сообщение коммита состоит из **заголовка**, **тела** и **нижнего колонтитула**.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<тип>(<область>): <тема>
|
||||
|
||||
[опциональное тело]
|
||||
|
||||
[опциональный нижний колонтитул]
|
||||
|
||||
``<тип>`` должен быть одним из следующих:
|
||||
|
||||
* **feat**: Новая функция для пользователя.
|
||||
* **fix**: Исправление ошибки для пользователя.
|
||||
* **docs**: Только изменения в документации.
|
||||
* **style**: Изменения, не влияющие на смысл кода (пробелы, форматирование и т.д.).
|
||||
* **refactor**: Изменение кода, которое не исправляет ошибку и не добавляет новую функцию.
|
||||
* **perf**: Изменение кода, улучшающее производительность.
|
||||
* **test**: Добавление недостающих тестов или исправление существующих.
|
||||
* **chore**: Изменения в процессе сборки или вспомогательных инструментах и библиотеках.
|
||||
|
||||
.. rubric:: Примеры
|
||||
|
||||
Простое исправление:
|
||||
``fix: correct typo in user authentication flow``
|
||||
|
||||
Новая функция с областью видимости:
|
||||
``feat(api): add new endpoint for user profiles``
|
||||
|
||||
-----
|
||||
|
||||
.. _join-the-project-team:
|
||||
|
||||
Присоединяйтесь к команде проекта
|
||||
---------------------------------
|
||||
|
||||
Мы всегда ищем энтузиастов для присоединения к команде. Если вы являетесь постоянным участником и продемонстрировали глубокое понимание целей и архитектуры проекта, вы можете стать хорошим кандидатом на роль мейнтейнера.
|
||||
|
||||
Активные члены сообщества могут стать членами команды. Обычно это включает:
|
||||
|
||||
* Постоянный вклад в виде качественного кода и документации.
|
||||
* Помощь другим пользователям с их вопросами и проблемами.
|
||||
* Проверку `Pull Request`'ов от других участников с конструктивной обратной связью.
|
||||
|
||||
Если вы заинтересованы в том, чтобы стать постоянным членом команды, лучший способ — быть активным и полезным участником сообщества. Существующие мейнтейнеры заметят ваши усилия и могут связаться с вами.
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
.. _root_dependency_injection:
|
||||
|
||||
Внедрение зависимостей
|
||||
=======================
|
||||
|
||||
Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования, который помогает писать слабосвязанный, легко тестируемый и расширяемый код. Вместо того чтобы обработчики сами создавали нужные им объекты (зависимости), они получают их извне.
|
||||
|
||||
``Argenta`` использует библиотеку ``dishka`` для реализации DI, что позволяет декларативно объявлять зависимости прямо в сигнатурах ваших обработчиков.
|
||||
Подробнее о DI, IoC и API для создания провайдеров можно прочитать в `официальной документации dishka <https://dishka.readthedocs.io/en/stable/di_intro.html>`_.
|
||||
|
||||
-----
|
||||
|
||||
Основная идея
|
||||
-------------
|
||||
|
||||
Представьте, что вашему обработчику для работы нужен доступ к базе данных. Вместо импорта и инициализации соединения внутри функции, вы просто объявляете его как аргумент с аннотацией типа:
|
||||
|
||||
.. note::
|
||||
``argenta.di.FromDishka`` является алиасом для ``dishka.FromDishka``, и они полностью взаимозаменяемы.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/dependency_injection/snippet.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
``Argenta`` с помощью ``dishka`` разрешит зависимость по типу ``Connection`` и внедрит её. Но прежде чем использовать зависимость, её необходимо объявить в провайдере:
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/dependency_injection/snippet2.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
После создания провайдера его необходимо зарегистрировать в оркестраторе.
|
||||
|
||||
.. note::
|
||||
Провайдеры регистрируются в ``Orchestrator``, а не в ``App``, так как оркестратор отвечает за настройку DI-контейнера на уровне всего приложения. Вы можете передать список из нескольких провайдеров через параметр ``custom_providers``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/dependency_injection/snippet3.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
Как это работает?
|
||||
-----------------
|
||||
|
||||
В основе DI в Argenta лежат **провайдеры** и **контейнер**.
|
||||
|
||||
* **Провайдер (Provider)** — это "рецепт", который объясняет, как создавать и настраивать ту или иную зависимость (например, подключение к БД, API-клиент или любой другой сервис).
|
||||
* **Контейнер (IoC Container)** — это "фабрика", которая хранит все рецепты (провайдеры) и по запросу создаёт и выдаёт готовые зависимости.
|
||||
|
||||
-----
|
||||
|
||||
Встроенные провайдеры
|
||||
-----------------------
|
||||
|
||||
``Argenta`` поставляется со встроенным провайдером, который даёт доступ к важным системным зависимостям без дополнительной настройки. Например, вы можете получить объект :ref:`ArgSpace <root_api_orchestrator_argspace>`, который содержит аргументы командной строки, переданные при запуске приложения.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/dependency_injection/snippet4.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
Обмен данными между обработчиками
|
||||
----------------------------------
|
||||
|
||||
Помимо DI, обработчики могут обмениваться данными в рамках сессии через **объект контекста**. В ``Argenta`` эту роль выполняет объект ``DataBridge``.
|
||||
|
||||
Каждый обработчик может записывать в него данные, а также читать, обновлять и удалять их.
|
||||
|
||||
.. seealso::
|
||||
Подробнее об этом можно прочитать в разделе :ref:`root_api_bridge`.
|
||||
@@ -0,0 +1,130 @@
|
||||
.. _root_error_handling:
|
||||
|
||||
Обработка ошибок
|
||||
==========================================
|
||||
|
||||
``Argenta`` выбрасывает исключения в пограничных случаях, связанных с пользовательским вводом.
|
||||
По умолчанию они обрабатываются системными обработчиками, но вы можете их переопределить. Это делается с помощью сеттеров экземпляра ``App`` вида ``.set_*_handler()``. Подробнее о каждом из них рассказано :ref:`ниже <possible_errors>`.
|
||||
|
||||
.. note::
|
||||
Ни одно исключение не остаётся необработанным, так как для каждого случая предусмотрен стандартный обработчик. Поэтому переопределение является опциональным.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/error_handling/snippet.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
|
||||
.. _possible_errors:
|
||||
|
||||
Возможные исключения и нестандартное поведение
|
||||
----------------------------------------------
|
||||
|
||||
``UnprocessedInputFlagException``: Некорректный синтаксис флагов
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Это исключение выбрасывается, когда парсер не может обработать команду из-за некорректного синтаксиса. Чаще всего это связано с ошибкой в синтаксисе флагов. Подробнее о них можно прочитать в разделе :ref:`Flags <root_flags>`.
|
||||
|
||||
Стандартный обработчик выводит в консоль:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
Incorrect flag syntax: <raw input command>
|
||||
|
||||
Для переопределения используется сеттер ``.set_incorrect_input_syntax_handler()``. Он принимает на вход обработчик с сигнатурой ``Callable[[str], None]``, где единственный аргумент — это строка с необработанной командой.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/error_handling/snippet2.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
---------------
|
||||
|
||||
``RepeatedInputFlagsException``: Повторяющиеся флаги в команде
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Исключение выбрасывается, если пользователь ввёл команду с повторяющимися флагами. Два флага (:ref:`InputFlag <root_api_command_input_flag>`) считаются одинаковыми, если у них совпадают имена. Подробнее о флагах и их синтаксисе — в разделе :ref:`Flags <root_flags>`.
|
||||
|
||||
.. note::
|
||||
Сравнение на равенство у регистрируемых флагов (``Flag``) происходит иначе, подробнее в :ref:`Flag <root_flags>`.
|
||||
|
||||
Стандартный обработчик выводит в консоль:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
Repeated input flags: <raw input command>
|
||||
|
||||
Для переопределения используется сеттер ``.set_repeated_input_flags_handler()``. Он принимает на вход обработчик с сигнатурой ``Callable[[str], None]``, где единственный аргумент — это строка с необработанной командой.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/error_handling/snippet3.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
---------------
|
||||
|
||||
``EmptyInputCommandException``: Введена пустая команда
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Исключение выбрасывается, если пользователь ввёл пустую строку или строку, состоящую только из пробельных символов (``\n``, ``\t``, пробел и т.д.).
|
||||
|
||||
Стандартный обработчик выводит в консоль:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
Empty input command
|
||||
|
||||
Для переопределения используется сеттер ``.set_empty_command_handler()``. Он принимает на вход обработчик с сигнатурой ``Callable[[], None]`` (без аргументов).
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/error_handling/snippet4.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
---------------
|
||||
|
||||
.. _root_error_handling_unknown_command:
|
||||
|
||||
Обработка неизвестной команды
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Это поведение активируется, когда пользователь вводит команду, которая не зарегистрирована ни в одном из роутеров и не является псевдонимом (alias) для существующей команды.
|
||||
|
||||
Стандартный обработчик выводит в консоль:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
Unknown command: <trigger of the input command>
|
||||
|
||||
Для переопределения используется сеттер ``.set_unknown_command_handler()``. Он принимает на вход обработчик с сигнатурой ``Callable[[InputCommand], None]``, где аргумент — объект :ref:`InputCommand <root_api_command_input_command>`.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/error_handling/snippet5.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
---------------
|
||||
|
||||
Выход из приложения
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Это поведение активируется, когда пользователь вводит команду, помеченную как команда выхода.
|
||||
|
||||
Стандартный обработчик выводит в консоль текст и завершает работу приложения:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
See you
|
||||
|
||||
Для переопределения используется сеттер ``.set_exit_command_handler()``. Он принимает на вход обработчик с сигнатурой ``Callable[[Response], None]``, где аргумент — объект :ref:`Response <root_api_response>`.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/error_handling/snippet6.py
|
||||
:language: python
|
||||
:linenos:
|
||||
@@ -0,0 +1,150 @@
|
||||
.. _root_flags:
|
||||
|
||||
Флаги вводимых команд
|
||||
=====================
|
||||
|
||||
Флаги — это специальные параметры, которые пользователь может добавлять к командам для управления их поведением.
|
||||
|
||||
Зачем нужны флаги в командах
|
||||
----------------------------
|
||||
|
||||
Управление поведением команды
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Основная цель флагов — предоставить способ изменить логику работы команды без её переработки. Команда может работать в нескольких режимах: стандартном, подробном, отладочном или упрощённом. Флаги переключают эти режимы по требованию пользователя, оставляя основную функциональность неизменной.
|
||||
|
||||
Опциональность и удобство
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Флаги решают проблему обязательности параметров. Если все параметры команды сделать обязательными, это затруднит использование команды. Флаги же позволяют задать значения только необходимые в конкретной ситуации, остальные используют значения по умолчанию.
|
||||
|
||||
Когда могут понадобиться флаги
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Переключение режимов работы**
|
||||
Команда выполняет развёртывание приложения обычно, но нужен режим без фактического развёртывания (dry-run) для проверки. Флаг ``--dry-run`` переключит режим работы.
|
||||
|
||||
**Настройка уровня детальности**
|
||||
При отладке или анализе требуется больше информации о процессе выполнения команды. Флаги ``--verbose`` или ``--debug`` предоставляют подробный вывод.
|
||||
|
||||
**Управление поведением при ошибках**
|
||||
По умолчанию команда может прерваться при первой ошибке. Флаг ``--force`` позволит продолжить работу, пропуская некритичные ошибки.
|
||||
|
||||
**Форматирование вывода**
|
||||
Команда выводит данные текстом, но в некоторых сценариях нужен JSON или CSV. Флаг ``--format=json`` переключит формат вывода.
|
||||
|
||||
**Комбинирование опций**
|
||||
Часто нужна комбинация нескольких изменений: подробный вывод, dry-run режим и JSON формат. Несколько флагов решают эту задачу одновременно.
|
||||
|
||||
Практическое значение
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Флаги делают команды более предсказуемыми и контролируемыми. Пользователь может начать с простого использования, а затем добавлять флаги по мере необходимости. Это особенно важно при автоматизации задач в скриптах, где гибкость интерфейса критична.
|
||||
|
||||
Флаги также облегчают интеграцию команд в различные системы, так как дополнительное поведение достигается без изменения структуры команды, а только через передачу опциональных параметров.
|
||||
|
||||
-----
|
||||
|
||||
Синтаксис флагов
|
||||
-----------------
|
||||
|
||||
Общий синтаксис выглядит так:
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
<command_name> <flag_prefix: Literal['-', '--', '---']><flag_name> <flag_value: Optional>
|
||||
|
||||
Флаг состоит из префикса (``-``, ``--`` или ``---``), имени и, опционально, значения, которое указывается через пробел.
|
||||
|
||||
**Примеры:**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
greet --name John
|
||||
deploy --verbose
|
||||
backup -f --compress
|
||||
|
||||
-----
|
||||
|
||||
Работа с флагами в обработчиках
|
||||
--------------------------------
|
||||
|
||||
Чтобы получить значение флага в обработчике, используйте объект ``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>`.
|
||||
|
||||
-----
|
||||
|
||||
Два типа флагов
|
||||
---------------
|
||||
|
||||
Флаги бывают двух основных видов:
|
||||
|
||||
1. **Флаги со значениями** — принимают параметр после имени флага (например, ``--name John``, ``--port 8080``)
|
||||
2. **Флаги-переключатели** — не принимают значения, их наличие само по себе является сигналом (например, ``--verbose``, ``--force``)
|
||||
|
||||
``Argenta`` позволяет регистрировать и вводить флаги обоих типов в любой последовательности для одной команды.
|
||||
|
||||
.. note::
|
||||
Ошибки валидации не выбрасывают исключений. Вместо этого у каждого объекта :ref:`InputFlag <root_api_command_input_flag>` есть атрибут ``status``, по которому можно определить, прошла ли валидация успешно. Подробное описание API для создания флагов находится в разделе :ref:`Flag <root_api_command_flag>`.
|
||||
|
||||
При регистрации флага можно задать правила валидации для его значения. По умолчанию любое значение считается корректным. Валидацию можно настроить несколькими способами:
|
||||
|
||||
-----
|
||||
|
||||
Флаги против аргументов
|
||||
-----------------------
|
||||
|
||||
В контексте Argenta флаги и аргументы относятся к разным уровням взаимодействия с приложением.
|
||||
|
||||
**Аргументы** — это параметры, передаваемые при запуске приложения. Они определяют глобальную конфигурацию на протяжении всей его работы (например, адрес базы данных, уровень логирования).
|
||||
|
||||
.. seealso:: API и более подробное описание в разделах :ref:`ArgParser <root_api_orchestrator_argparser>` и :ref:`Arguments <root_api_orchestrator_arguments>`.
|
||||
|
||||
**Флаги** — это параметры командных операций, доступные в рамках интерактивной сессии при вводе каждой новой команды. Они позволяют модифицировать поведение конкретной команды без перезагрузки приложения.
|
||||
|
||||
.. seealso:: API и более подробное описание в разделе :ref:`Flag <root_api_command_flag>`.
|
||||
|
||||
-----
|
||||
|
||||
Ключевые различия
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Время жизни**
|
||||
Аргументы передаются один раз при запуске и действуют на весь период работы приложения. Флаги локальны и существуют только в рамках выполнения команды.
|
||||
|
||||
**Изменяемость**
|
||||
Для изменения аргументов необходимо перезапустить приложение. Флаги можно менять при каждом вводе команды.
|
||||
|
||||
**Назначение**
|
||||
Аргументы управляют глобальной конфигурацией приложения. Флаги управляют поведением отдельных команд.
|
||||
|
||||
-----
|
||||
|
||||
Практические примеры
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Аргументы при запуске приложения:
|
||||
|
||||
- Адрес подключения к базе данных
|
||||
- Режим работы (production, development, testing)
|
||||
- Уровень логирования
|
||||
|
||||
Флаги в интерактивной сессии:
|
||||
|
||||
- ``deploy --verbose --dry-run`` — для команды развёртывания
|
||||
- ``backup --compress --encrypted`` — для команды резервного копирования
|
||||
- ``test --parallel --coverage`` — для команды тестирования
|
||||
@@ -0,0 +1,38 @@
|
||||
.. _root_overriding_formatting:
|
||||
|
||||
Форматирование вывода
|
||||
=================================
|
||||
|
||||
По умолчанию ``Argenta`` использует библиотеку ``rich`` для вывода текста с расширенным форматированием. Она позволяет применять цвета и стили, создавать таблицы, подсвечивать синтаксис и многое другое, что улучшает визуальное восприятие информации.
|
||||
|
||||
------
|
||||
|
||||
Управление стандартным форматированием
|
||||
--------------------------------------
|
||||
|
||||
При создании экземпляра ``App`` можно использовать параметр ``override_system_messages: bool`` (по умолчанию ``False``), который позволяет отключать стандартное форматирование.
|
||||
|
||||
Если установить его в ``True``, стилизация текста и ASCII-графика будут отключены, а системные сообщения — выводиться в «сыром» виде.
|
||||
|
||||
-----
|
||||
|
||||
Приветственное и прощальное сообщения
|
||||
--------------------------------------
|
||||
|
||||
Приветственное (``initial_message``) и прощальное (``farewell_message``) сообщения по умолчанию выводятся в виде ASCII-графики.
|
||||
|
||||
.. warning::
|
||||
Библиотека ``art`` ориентирована на работу с ASCII-символами и **не поддерживает кириллицу**. Это приводит к искажению символов русского и других кириллических алфавитов. Если ваше сообщение содержит кириллицу, рекомендуется отключить форматирование с помощью ``override_system_messages=True`` или использовать только латинские символы.
|
||||
|
||||
-----
|
||||
|
||||
Кастомизация вывода
|
||||
-------------------
|
||||
|
||||
Для полной замены логики вывода текста в конструкторе ``App`` предусмотрен параметр ``print_func``.
|
||||
|
||||
* **print_func**: ``Callable[[str], None]``
|
||||
Этот параметр позволяет передать любую вызываемую сущность (например, функцию), которая будет использоваться для вывода всех системных сообщений. По умолчанию это ``rich.console.Console().print``. Вы можете передать сюда свою функцию, чтобы, например, логировать вывод в файл или отправлять его по сети.
|
||||
|
||||
.. important::
|
||||
При переопределении функции вывода вам следует убедиться, что она поддерживает разметку ``rich``, иначе системные сообщения будут выводиться в сыром виде, в этом случае рекомендуется переопределить стандартное форматирование с помощью ``override_system_messages=True``.
|
||||
@@ -0,0 +1,117 @@
|
||||
.. _root_quickstart:
|
||||
|
||||
Быстрый старт
|
||||
=============
|
||||
|
||||
В этом руководстве мы рассмотрим два примера создания CLI-приложения с помощью Argenta:
|
||||
|
||||
* **Простой пример**: минимальное приложение для быстрого знакомства с основными компонентами.
|
||||
* **Более сложный пример**: полнофункциональное приложение «Менеджер задач» с внедрением зависимостей и бизнес-логикой.
|
||||
|
||||
Простой пример
|
||||
---------------
|
||||
|
||||
**Установка**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
pip install argenta
|
||||
|
||||
Этот пример демонстрирует абсолютный минимум, необходимый для создания и запуска приложения. Вы можете скопировать этот код, запустить его и сразу увидеть результат.
|
||||
|
||||
.. literalinclude:: ../code_snippets/quickstart/simple_app.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
**Запуск**
|
||||
|
||||
Сохраните код в файл (например, ``main.py``) и запустите:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python main.py
|
||||
|
||||
**Результат**
|
||||
|
||||
.. image:: https://i.ibb.co/35q24Bh8/image.png
|
||||
:alt: Simple App Example
|
||||
|
||||
-----
|
||||
|
||||
Промежуточный пример: Калькулятор с флагами
|
||||
--------------------------------------------
|
||||
|
||||
Прежде чем перейти к сложному примеру с DI, рассмотрим промежуточный вариант — калькулятор, который использует флаги для управления поведением.
|
||||
|
||||
.. literalinclude:: ../code_snippets/quickstart/calculator_app.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
**Запуск:**
|
||||
|
||||
Сохраните код в файл ``calculator.py`` и запустите:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python calculator.py
|
||||
|
||||
**Использование:**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
calc --a 10 --b 5 --operation add
|
||||
calc --a 10 --b 5 --operation mul
|
||||
|
||||
Этот пример показывает, как работать с флагами без использования DI. Теперь перейдём к более сложному примеру.
|
||||
|
||||
-----
|
||||
|
||||
Сложный пример: Менеджер задач с DI
|
||||
------------------------------------
|
||||
|
||||
В этом руководстве мы создадим полнофункциональное CLI-приложение «Менеджер задач», которое продемонстрирует работу с внедрением зависимостей.
|
||||
|
||||
1. **Установка**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
pip install argenta
|
||||
|
||||
2. **Определение моделей данных и репозитория**
|
||||
|
||||
Сначала определим модели данных для задачи и репозиторий для их хранения.
|
||||
|
||||
.. literalinclude:: ../code_snippets/quickstart/task_manager/repository.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
3. **Создание провайдера для DI**
|
||||
|
||||
Чтобы Argenta могла внедрять ``TaskRepository`` в наши обработчики, мы создадим провайдер для ``dishka``.
|
||||
|
||||
.. literalinclude:: ../code_snippets/quickstart/task_manager/provider.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
4. **Создание обработчиков команд**
|
||||
|
||||
Теперь создадим обработчики для команд ``add-task`` и ``list-tasks``. Обратите внимание, как мы используем флаги и внедряем ``TaskRepository``.
|
||||
|
||||
.. literalinclude:: ../code_snippets/quickstart/task_manager/handlers.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
5. **Сборка и запуск приложения**
|
||||
|
||||
Наконец, соберем все вместе: создадим экземпляр ``App``, подключим роутер и провайдер, а затем запустим приложение.
|
||||
|
||||
.. literalinclude:: ../code_snippets/quickstart/task_manager/main.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
6. **Результат**
|
||||
|
||||
Теперь вы можете запустить ``main.py`` и взаимодействовать с вашим новым CLI-приложением.
|
||||
|
||||
.. image:: https://i.ibb.co/bgsCLZhP/image.png
|
||||
:alt: Task Manager Example
|
||||
@@ -0,0 +1,136 @@
|
||||
.. _root_redirect_stdout:
|
||||
|
||||
Переопределение стандартного вывода
|
||||
===================================
|
||||
|
||||
``Argenta`` предоставляет гибкие механизмы для форматирования вывода, включая динамические разделительные линии. Это достигается за счёт перехвата стандартного потока вывода (``stdout``), что накладывает некоторые особенности.
|
||||
|
||||
-----
|
||||
|
||||
Когда нужно отключать перехват stdout
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Отключайте перехват ``stdout`` (``disable_redirect_stdout=True`` в ``Router``), если ваши команды:
|
||||
|
||||
✓ Используют ``input()`` для интерактивного ввода данных от пользователя
|
||||
✓ Используют прогресс-бары (``tqdm``, ``rich.progress``)
|
||||
✓ Выводят данные в реальном времени (streaming, логи)
|
||||
✓ Используют библиотеки, которые напрямую работают с ``stdout``
|
||||
|
||||
Для обычных команд с ``print()`` перехват можно оставить включённым — это не влияет на их работу.
|
||||
|
||||
-----
|
||||
|
||||
Механизм перехвата ``stdout``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
По умолчанию ``Argenta`` перехватывает весь текст, выводимый в ``stdout`` внутри обработчика команды. Это необходимо для реализации **динамических разделителей**: система анализирует вывод, находит самую длинную строку и использует её для отрисовки верхней и нижней границ. Такой подход создаёт аккуратный интерфейс, где вывод команды «обёрнут» в рамку, подогнанную под его содержимое.
|
||||
|
||||
Пример приложения с динамической разделительной линией:
|
||||
|
||||
.. image:: https://i.ibb.co/yn9rWnNC/2025-11-07-180751.png
|
||||
:alt: Example of an application with a dynamic dividing line
|
||||
|
||||
Как вы можете заметить, разделительная линия ровно той же длины, что и самая длинная строка в выводе.
|
||||
|
||||
То же приложение с статической линией:
|
||||
|
||||
.. image:: https://i.ibb.co/P8B4xyp/2025-11-07-180330.png
|
||||
:alt: Example of an application with a static dividing line
|
||||
|
||||
В этом примере разделительная линия имеет фиксированную длину (по умолчанию 25 символов).
|
||||
|
||||
-----
|
||||
|
||||
Побочные эффекты перехвата ``stdout``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Побочный эффект этого механизма проявляется при использовании функций, которые последовательно выводят текст в консоль и ожидают ввод от пользователя. Классический пример — стандартная функция ``input()``.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
user_name = input("Enter your name: ")
|
||||
print(f"Привет, {user_name}!")
|
||||
|
||||
.. warning::
|
||||
При включённом перехвате ``stdout`` текст (например, ``"Введите ваше имя: "``) **не будет выведен в консоль немедленно**. Он попадёт в буфер и отобразится лишь после завершения работы обработчика вместе с остальным выводом. Это может сбить пользователя с толку.
|
||||
|
||||
-----
|
||||
|
||||
Отключение перехвата ``stdout`` с помощью ``disable_redirect_stdout``
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Чтобы решить эту проблему, в конструкторе ``Router`` предусмотрен специальный аргумент:
|
||||
|
||||
* **disable_redirect_stdout** (``bool``, по умолчанию ``False``)
|
||||
|
||||
Если при создании роутера установить ``disable_redirect_stdout=True``, механизм перехвата ``stdout`` будет отключён для всех его обработчиков.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/redirect_stdout/sample.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
В этом случае ``input()`` будет работать как обычно, и пользователь сразу увидит приглашение к вводу.
|
||||
|
||||
-----
|
||||
|
||||
Типы разделительных линий
|
||||
--------------------------
|
||||
|
||||
``Argenta`` поддерживает два типа разделителей, которые настраиваются при инициализации ``App``:
|
||||
|
||||
1. **``DynamicDividingLine()``**
|
||||
* Поведение по умолчанию. Длина линии динамически подстраивается под самый длинный текст в выводе.
|
||||
* Требует включённого перехвата ``stdout`` (``disable_redirect_stdout=False`` в роутере).
|
||||
|
||||
2. **``StaticDividingLine(length: int = 25)``**
|
||||
* Линия имеет фиксированную длину (по умолчанию 25 символов), которую можно задать через аргумент ``length``.
|
||||
* Используется принудительно для роутеров с ``disable_redirect_stdout=True``, так как без перехвата вывода невозможно определить динамическую длину.
|
||||
|
||||
-----
|
||||
|
||||
Настройка разделительной линии в ``App``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Вы можете глобально задать тип разделителя для всего приложения через аргумент ``dividing_line`` в конструкторе ``App``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/redirect_stdout/sample2.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
Итоговое поведение
|
||||
------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 25 25 35 15
|
||||
:header-rows: 1
|
||||
|
||||
* - ``disable_redirect_stdout`` на ``Router``
|
||||
- Тип линии в ``App``
|
||||
- Фактическое поведение
|
||||
- ``input()`` работает корректно?
|
||||
* - ``False`` (по умолчанию)
|
||||
- ``DynamicDividingLine``
|
||||
- Динамическая линия, длина по содержимому
|
||||
- Нет
|
||||
* - ``False`` (по умолчанию)
|
||||
- ``StaticDividingLine``
|
||||
- Статическая линия указанной длины
|
||||
- Нет
|
||||
* - ``True``
|
||||
- ``DynamicDividingLine``
|
||||
- **Принудительно статическая линия** (длина по умолч.)
|
||||
- Да
|
||||
* - ``True``
|
||||
- ``StaticDividingLine``
|
||||
- Статическая линия указанной длины
|
||||
- Да
|
||||
|
||||
Таким образом, для интерактивных команд, требующих ввода от пользователя, отключайте перехват ``stdout`` на уровне роутера. Для всех остальных команд можно оставить поведение по умолчанию.
|
||||
@@ -0,0 +1,70 @@
|
||||
Тестирование
|
||||
============
|
||||
|
||||
В этом разделе описаны практики тестирования приложений на основе ``Argenta``. Примеры основаны на фактическом публичном API.
|
||||
|
||||
Модульное тестирование обработчиков
|
||||
------------------------------------
|
||||
|
||||
Обработчики в ``Argenta`` — обычные функции. Их удобно тестировать как чистые функции, не поднимая весь цикл приложения. Рекомендуются ``unittest`` или ``pytest``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/testing/simple_handler_unittest.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
Тестирование с внедрением зависимостей (DI)
|
||||
-------------------------------------------
|
||||
|
||||
Если обработчику нужны зависимости, используйте ``dishka`` и интеграцию ``Argenta``:
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/testing/di_handler_unittest.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
Интеграционное тестирование приложения
|
||||
--------------------------------------
|
||||
|
||||
Для более высокого уровня тестов собирайте ``App`` и ``Router`` и вызывайте обработчики через парсинг команд, обходя бесконечный цикл ввода. Это даёт близкое к реальности поведение без необходимости симулировать ``stdin``.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/testing/app_integration_unittest.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
E2E-тестирование цикла
|
||||
----------------------
|
||||
|
||||
Полный запуск цикла ``start_polling`` можно покрывать через подпроцесс с передачей строк в ``stdin``. Это тяжелее и обычно не требуется. Если всё же необходимо — пример ниже.
|
||||
|
||||
.. danger::
|
||||
**Важно:** Обязательно передавайте строковый триггер команды выхода последним элементом в списке ``side_effects`` при патче ``input``.
|
||||
|
||||
Иначе тестируемое приложение будет ожидать ввода следующей команды и не сможет корректно завершиться.
|
||||
|
||||
**Пример использования:**
|
||||
|
||||
.. literalinclude:: ../code_snippets/testing/app_e2e_test.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
-----
|
||||
|
||||
Советы по тестированию
|
||||
----------------------
|
||||
|
||||
1. **Изолируйте тесты**: Каждый тест должен быть независимым от других.
|
||||
2. **Моки для внешних интеграций**: БД, HTTP-клиенты и т.п. подменяйте заглушками и провайдерами ``dishka``.
|
||||
3. **Покрывайте ошибочные сценарии**: Некорректные флаги, неизвестные команды, пустой ввод.
|
||||
4. **Минимизируйте зависимость от форматирования**: Сравнивайте ключевые фрагменты вывода, а не весь блок целиком.
|
||||
5. **Измеряйте покрытие**: Используйте ``pytest-cov``.
|
||||
Reference in New Issue
Block a user