diff --git a/CHANGES b/CHANGES index 0b444fd06..cb2d35ae8 100644 --- a/CHANGES +++ b/CHANGES @@ -23,10 +23,10 @@ Version 7.0 - ``launch`` now works properly under Cygwin. See #650. - `CliRunner.invoke` now may receive `args` as a string representing a Unix shell command. See #664. -- Fix bug that caused bashcompletion to give improper completions on +- Fix bug that caused bashcompletion to give improper completions on chained commands. See #774. - Add support for bright colors. -- 't' and 'f' are now converted to True and False. +- 't' and 'f' are now converted to True and False. - Fix bug that caused bashcompletion to give improper completions on chained commands when a required option/argument was being completed. See #790. diff --git a/click/_termui_impl.py b/click/_termui_impl.py index 5cb942db5..a4e421ecb 100644 --- a/click/_termui_impl.py +++ b/click/_termui_impl.py @@ -90,6 +90,7 @@ def __init__(self, iterable, length=None, fill_char='#', empty_char=' ', self.current_item = None self.is_hidden = not isatty(self.file) self._last_line = None + self.short_limit = 0.5 def __enter__(self): self.entered = True @@ -105,8 +106,11 @@ def __iter__(self): self.render_progress() return self.generator() + def is_fast(self): + return time.time() - self.start <= self.short_limit + def render_finish(self): - if self.is_hidden: + if self.is_hidden or self.is_fast(): return self.file.write(AFTER_BAR) self.file.flush() @@ -224,7 +228,8 @@ def render_progress(self): buf.append(' ' * (clear_width - line_len)) line = ''.join(buf) # Render the line only if it changed. - if line != self._last_line: + + if line != self._last_line and not self.is_fast(): self._last_line = line echo(line, file=self.file, color=self.color, nl=True) self.file.flush() diff --git a/tests/test_termui.py b/tests/test_termui.py index 23f064f9c..9e855d303 100644 --- a/tests/test_termui.py +++ b/tests/test_termui.py @@ -2,15 +2,28 @@ import time +class FakeClock(object): + def __init__(self): + self.now = time.time() + + def advance_time(self, seconds=1): + self.now += seconds + + def time(self): + return self.now + + def test_progressbar_strip_regression(runner, monkeypatch): + fake_clock = FakeClock() label = ' padded line' @click.command() def cli(): with click.progressbar(tuple(range(10)), label=label) as progress: for thing in progress: - pass + fake_clock.advance_time() + monkeypatch.setattr(time, 'time', fake_clock.time) monkeypatch.setattr(click._termui_impl, 'isatty', lambda _: True) assert label in runner.invoke(cli, []).output @@ -34,26 +47,31 @@ def __next__(self): next = __next__ + fake_clock = FakeClock() + @click.command() def cli(): with click.progressbar(Hinted(10), label='test') as progress: for thing in progress: - pass + fake_clock.advance_time() + monkeypatch.setattr(time, 'time', fake_clock.time) monkeypatch.setattr(click._termui_impl, 'isatty', lambda _: True) result = runner.invoke(cli, []) assert result.exception is None def test_progressbar_hidden(runner, monkeypatch): + fake_clock = FakeClock() label = 'whatever' @click.command() def cli(): with click.progressbar(tuple(range(10)), label=label) as progress: for thing in progress: - pass + fake_clock.advance_time() + monkeypatch.setattr(time, 'time', fake_clock.time) monkeypatch.setattr(click._termui_impl, 'isatty', lambda _: False) assert runner.invoke(cli, []).output == '' @@ -91,16 +109,6 @@ def test_progressbar_yields_all_items(runner): def test_progressbar_update(runner, monkeypatch): - class FakeClock(object): - def __init__(self): - self.now = time.time() - - def advance_time(self, seconds=1): - self.now += seconds - - def time(self): - return self.now - fake_clock = FakeClock() @click.command() @@ -116,8 +124,7 @@ def cli(): lines = [line for line in output.split('\n') if '[' in line] - assert ' 0%' in lines[0] - assert ' 25% 00:00:03' in lines[1] - assert ' 50% 00:00:02' in lines[2] - assert ' 75% 00:00:01' in lines[3] - assert '100% ' in lines[4] + assert ' 25% 00:00:03' in lines[0] + assert ' 50% 00:00:02' in lines[1] + assert ' 75% 00:00:01' in lines[2] + assert '100% ' in lines[3]