.. _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`` на уровне роутера. Для всех остальных команд можно оставить поведение по умолчанию.