diff --git a/docs/code_snippets/redirect_stdout_example_sample.py b/docs/code_snippets/redirect_stdout_example_sample.py new file mode 100644 index 0000000..c571941 --- /dev/null +++ b/docs/code_snippets/redirect_stdout_example_sample.py @@ -0,0 +1,9 @@ +from argenta.router import Router + +# Для этого роутера перехват stdout будет отключен +interactive_router = Router(disable_redirect_stdout=True) + +@interactive_router.command("ask") +def ask_name(response): + name = input("Как вас зовут? ") + print(f"Приятно познакомиться, {name}!") \ No newline at end of file diff --git a/docs/code_snippets/redirect_stdout_example_sample2.py b/docs/code_snippets/redirect_stdout_example_sample2.py new file mode 100644 index 0000000..1229a7d --- /dev/null +++ b/docs/code_snippets/redirect_stdout_example_sample2.py @@ -0,0 +1,6 @@ +from argenta.app import App +from argenta.app.dividing_line import StaticDividingLine + +# Все роутеры по умолчанию будут использовать статическую линию длиной 50 символов +# (если для них не отключен перехват stdout) +app = App(dividing_line=StaticDividingLine(length=50)) \ No newline at end of file diff --git a/docs/root/redirect_stdout.rst b/docs/root/redirect_stdout.rst index 3585bea..80fc041 100644 --- a/docs/root/redirect_stdout.rst +++ b/docs/root/redirect_stdout.rst @@ -1,6 +1,98 @@ .. _root_redirect_stdout: - Переопределение стандартного вывода -*********************************** +=================================== +``Argenta`` предоставляет гибкие механизмы для управления форматированием вывода, включая использование динамических разделительных линий. Это достигается за счет перехвата стандартного потока вывода (``stdout``), что имеет свои особенности. + +----- + +Механизм перехвата ``stdout`` +----------------------------- + +По умолчанию ``Argenta`` перехватывает весь текст, который выводится в ``stdout`` внутри обработчика команды (``handler``). Это делается для реализации **динамической длины разделителя**. Система анализирует весь выведенный текст, находит самую длинную строку и использует её длину для отрисовки верхней и нижней разделительных линий. Это создает аккуратный и визуально согласованный интерфейс, где вывод команды "обернут" в рамку, идеально подогнанную под его содержимое. + +Побочные эффекты перехвата ``stdout`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Главный побочный эффект этого механизма проявляется при использовании функций, которые одновременно ожидают ввод от пользователя и выводят текст-приглашение. Классический пример — стандартная функция ``input()``. + +.. code-block:: python + + # Внутри обработчика команды + user_name = input("Введите ваше имя: ") + print(f"Привет, {user_name}!") + +.. warning:: + При включенном перехвате ``stdout`` текст-приглашение ``"Введите ваше имя: "`` **не будет выведен в консоль немедленно**. Он попадет в буфер, и пользователь увидит только мигающий курсор, ожидающий ввода. Текст приглашения будет выведен только после того, как выполнение всего обработчика завершится, вместе с остальным буферизованным выводом. Это может сбить пользователя с толку и является пограничным случаем, требующим внимания при разработке. + +----- + +Отключение перехвата ``stdout`` с помощью ``disable_redirect_stdout`` +--------------------------------------------------------------------- + +Чтобы решить проблему с ``input()`` и другими подобными функциями, в конструкторе класса ``Router`` предусмотрен специальный аргумент: + +* **disable_redirect_stdout** (``bool``, по умолчанию ``False``) + +Если при создании роутера установить ``disable_redirect_stdout=True``, то для всех команд этого роутера механизм перехвата ``stdout`` будет отключен. + +.. literalinclude:: ../code_snippets/redirect_stdout_example_sample.py + :language: python + +В этом случае ``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_example_sample2.py + :language: python + +----- + +Итоговое поведение +------------------ + +.. 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`` на соответствующем роутере. Для всех остальных команд можно оставить поведение по умолчанию.