Переопределение стандартного вывода

Argenta предоставляет гибкие механизмы для форматирования вывода, включая динамические разделительные линии. Это достигается за счёт перехвата стандартного потока вывода (stdout), что накладывает некоторые особенности.


Когда нужно отключать перехват stdout

Отключайте перехват stdout (disable_redirect_stdout=True в Router), если ваши команды:

✓ Используют input() для интерактивного ввода данных от пользователя

✓ Используют прогресс-бары (tqdm, rich.progress)

✓ Выводят данные в реальном времени (streaming, логи)

✓ Используют библиотеки, которые напрямую работают с stdout

Для обычных команд с print() перехват можно оставить включённым — это не влияет на их работу.


Механизм перехвата stdout

По умолчанию Argenta перехватывает весь текст, выводимый в stdout внутри обработчика команды. Это необходимо для реализации динамических разделителей: система анализирует вывод, находит самую длинную строку и использует её для отрисовки верхней и нижней границ. Такой подход создаёт аккуратный интерфейс, где вывод команды «обёрнут» в рамку, подогнанную под его содержимое.

Пример приложения с динамической разделительной линией:

Example of an application with a dynamic dividing line

Как вы можете заметить, разделительная линия ровно той же длины, что и самая длинная строка в выводе.

То же приложение с статической линией:

Example of an application with a static dividing line

В этом примере разделительная линия имеет фиксированную длину (по умолчанию 25 символов).


Побочные эффекты перехвата stdout

Побочный эффект этого механизма проявляется при использовании функций, которые последовательно выводят текст в консоль и ожидают ввод от пользователя. Классический пример — стандартная функция input().

1user_name = input("Enter your name: ")
2print(f"Привет, {user_name}!")

Предупреждение

При включённом перехвате stdout текст (например, "Введите ваше имя: ") не будет выведен в консоль немедленно. Он попадёт в буфер и отобразится лишь после завершения работы обработчика вместе с остальным выводом. Это может сбить пользователя с толку.


Отключение перехвата stdout с помощью disable_redirect_stdout

Чтобы решить эту проблему, в конструкторе Router предусмотрен специальный аргумент:

  • disable_redirect_stdout (bool, по умолчанию False)

Если при создании роутера установить disable_redirect_stdout=True, механизм перехвата stdout будет отключён для всех его обработчиков.

Пример использования:

 1from argenta import Response, Router
 2
 3# For this router stdout redirect will be disabled
 4interactive_router = Router(disable_redirect_stdout=True)
 5
 6
 7@interactive_router.command("ask")
 8def ask_name(response: Response):
 9    name = input("What is your name? ")
10    print(f"Nice to meet you, {name}!")

В этом случае 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.

Пример использования:

1from argenta import App
2from argenta.app import StaticDividingLine
3
4# All routers will use static line with length 50 by default
5app = App(dividing_line=StaticDividingLine(length=50))

Итоговое поведение

disable_redirect_stdout на Router

Тип линии в App

Фактическое поведение

input() работает корректно?

False (по умолчанию)

DynamicDividingLine

Динамическая линия, длина по содержимому

Нет

False (по умолчанию)

StaticDividingLine

Статическая линия указанной длины

Нет

True

DynamicDividingLine

Принудительно статическая линия (длина по умолч.)

Да

True

StaticDividingLine

Статическая линия указанной длины

Да

Таким образом, для интерактивных команд, требующих ввода от пользователя, отключайте перехват stdout на уровне роутера. Для всех остальных команд можно оставить поведение по умолчанию.