Строка выполнения текста в консоли с заголовком выше

Я использую этот ответ, чтобы напечатать индикатор выполнения но хотите, чтобы он печатал то, что именно он делает, пока он прогрессирует. Я добавил параметр print_progress() с параметром "current_task", и теперь он хотел бы выполнить следующее. Как это сделать?

FYI: я включен в систему Unix: macOS Sierra

print_progress(7,10,...remaining params..., "downloading contacts")

должен напечатать это

В настоящее время загрузка контактов
Прогресс | ████████████████████████████████ ---------------- ----- | 70% Полная

последующий вызов

print_progress(8,10,...remaining params..., "downloading companies")

должно привести к тому, что индикатор выполнения изменится, чтобы теперь выглядеть следующим образом

В настоящее время загрузка компаний
Прогресс | ████████████████████████████████████ ------------ - | 80% Полная

Ответ 1

Здесь приведена измененная версия кода Greenstick, которая поддерживает строку заголовка. Он использует ANSI control sequence '\x1b[3A', чтобы переместить курсор терминала на 3 строки после того, как он напечатал заголовок и индикатор выполнения.

Эта обновленная версия работает правильно на Python 2 (проверена на 2.6.6) и Python 3 (проверена на 3.6.0). Он также стирает предыдущее содержимое строки заголовка, поэтому вы не получаете бродячих символов, если текущий заголовок короче предыдущего.

from __future__ import print_function
from time import sleep

# Print iterations progress
#Originally written by Greensticks, modified by PM 2Ring
def printProgressBar (iteration, total, prefix='', suffix='', decimals=1, 
    length=100, fill=u'\u2588', header=''):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        header      - Optional  : header string (Str)
    """
    # Clear the current line and print the header
    print('\x1b[2K', header, '\n')
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    # Generate and print the bar
    bar = fill * filledLength + u'-' * (length - filledLength)
    print('%s |%s| %s%% %s\x1b[3A' % (prefix, bar, percent, suffix))
    # Print New Lines on Complete
    if iteration == total: 
        print('\n' * 2)

# Test

maxi = 10
delay = 0.5

# Initial call to print 0% progress
header = 'Currently downloading contacts now'
printProgressBar(0, maxi, prefix='Progress:', suffix='Complete', length=50, header=header)
for i in range(1, 8):
    # Do stuff...
    sleep(delay)
    # Update Progress Bar
    printProgressBar(i, maxi, prefix='Progress:', suffix='Complete', length=50, header=header)

header = 'Currently downloading companies'
for i in range(8, maxi + 1):
    # Do stuff...
    sleep(delay)
    # Update Progress Bar
    printProgressBar(i, maxi, prefix='Progress:', suffix='Complete', length=50, header=header)

print('Finished')

Обратите внимание: если вы не укажете строку заголовка, вы получите пустую строку заголовка. Пожалуйста, убедитесь, что строка заголовка будет действительно соответствовать одной строке вашего терминала и определенно не помещает в нее символы '\n'!


Вы можете сделать этот индикатор выполнения более универсальным, используя threading, как показано на рисунке Таймер прокрутки Я написал несколько месяцев назад.


Здесь версия printProgressBar, которая отключает курсор, поэтому нам не нужен дополнительный темп в начале курсора.

def printProgressBar (iteration, total, prefix='', suffix='', decimals=1, 
    length=100, fill=u'\u2588', header=''):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        header      - Optional  : header string (Str)
    """
    if iteration == 0:
        # Turn off the cursor
        print("\x1b[?25l", end='')
    # Clear the current line & print the header
    print('\x1b[2K', header, sep= '', end='\n\n')
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    # Generate and print the bar
    bar = fill * filledLength + u'-' * (length - filledLength)
    print('%s |%s| %s%% %s\x1b[3A' % (prefix, bar, percent, suffix))
    # Print New Lines on Complete
    if iteration == total: 
        # Turn on the cursor, and skip a few lines
        print("\x1b[?25h", end='\n\n')

Одна из проблем заключается в том, что если мы рано завершаем программу (например, нажав Ctrl C), в то время как курсор отключен, он по-прежнему будет отключен после изменения программы. В Linux вы можете просто отправить последовательность ANSI, чтобы снова включить курсор с помощью простой команды Bash:

echo -e "\e[?25h"

хотя проще reset терминал:

echo -e "\ec"

Конечно, мы могли бы также захватить signal.SIGINT и добавить функцию обработчика, чтобы повернуть курсор до выхода программы, но это добавляет дополнительную сложность в код.