Merge pull request #9055 from ThomasWaldmann/non-tty-progress-1.4

improved tty-less progress reporting (1.4-maint)
This commit is contained in:
TW 2025-10-12 15:18:09 +02:00 committed by GitHub
commit cb19d62057
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 40 additions and 6 deletions

View file

@ -141,9 +141,12 @@ class Statistics:
def csize_fmt(self):
return format_file_size(self.csize, iec=self.iec)
PROGRESS_FMT = '{0.osize_fmt} O {0.csize_fmt} C {0.usize_fmt} D {0.nfiles} N '
def show_progress(self, item=None, final=False, stream=None, dt=None):
now = time.monotonic()
if dt is None or now - self.last_progress > dt:
stream = stream or sys.stderr
self.last_progress = now
if self.output_json:
if not final:
@ -158,10 +161,18 @@ class Statistics:
})
msg = json.dumps(data)
end = '\n'
elif not stream.isatty():
# if we don't output to a terminal, use normal linefeeds and assume line length is unlimited
if not final:
msg = self.PROGRESS_FMT.format(self)
msg += remove_surrogates(item.path) if item else ''
else:
msg = ''
end = '\n'
else:
columns, lines = get_terminal_size()
if not final:
msg = '{0.osize_fmt} O {0.csize_fmt} C {0.usize_fmt} D {0.nfiles} N '.format(self)
msg = self.PROGRESS_FMT.format(self)
path = remove_surrogates(item.path) if item else ''
space = columns - swidth(msg)
if space < 12:
@ -172,7 +183,7 @@ class Statistics:
else:
msg = ' ' * columns
end = '\r'
print(msg, end=end, file=stream or sys.stderr, flush=True)
print(msg, end=end, file=stream, flush=True)
def is_special(mode):

View file

@ -32,27 +32,50 @@ def test_stats_basic(stats):
assert stats.usize == 10
def tests_stats_progress(stats, monkeypatch, columns=80):
def tests_stats_progress_tty(stats, monkeypatch, columns=80):
class TTYStringIO(StringIO):
def isatty(self):
return True
monkeypatch.setenv('COLUMNS', str(columns))
out = StringIO()
out = TTYStringIO()
stats.show_progress(stream=out)
s = '20 B O 10 B C 10 B D 0 N '
buf = ' ' * (columns - len(s))
assert out.getvalue() == s + buf + "\r"
out = StringIO()
out = TTYStringIO()
stats.update(10**3, 0, unique=False)
stats.show_progress(item=Item(path='foo'), final=False, stream=out)
s = '1.02 kB O 10 B C 10 B D 0 N foo'
buf = ' ' * (columns - len(s))
assert out.getvalue() == s + buf + "\r"
out = StringIO()
out = TTYStringIO()
stats.show_progress(item=Item(path='foo'*40), final=False, stream=out)
s = '1.02 kB O 10 B C 10 B D 0 N foofoofoofoofoofoofoofo...oofoofoofoofoofoofoofoofoo'
buf = ' ' * (columns - len(s))
assert out.getvalue() == s + buf + "\r"
def tests_stats_progress_file(stats, monkeypatch):
out = StringIO()
stats.show_progress(stream=out)
s = '20 B O 10 B C 10 B D 0 N '
assert out.getvalue() == s + "\n"
out = StringIO()
stats.update(10**3, 0, unique=False)
path = 'foo'
stats.show_progress(item=Item(path=path), final=False, stream=out)
s = f'1.02 kB O 10 B C 10 B D 0 N {path}'
assert out.getvalue() == s + "\n"
out = StringIO()
path = 'foo' * 40
stats.show_progress(item=Item(path=path), final=False, stream=out)
s = f'1.02 kB O 10 B C 10 B D 0 N {path}'
assert out.getvalue() == s + "\n"
def test_stats_format(stats):
assert str(stats) == """\
This archive: 20 B 10 B 10 B"""