back to Claude Sonnet 3.5 - Fill-in summary
Claude Sonnet 3.5 - Fill-in: python-progressbar
Failed to run pytests for test tests
ImportError while loading conftest '/testbed/tests/conftest.py'.
tests/conftest.py:7: in <module>
import progressbar
progressbar/__init__.py:9: in <module>
from .bar import DataTransferBar, NullBar, ProgressBar
progressbar/bar.py:16: in <module>
import progressbar.terminal
progressbar/terminal/__init__.py:3: in <module>
from .base import * # noqa F403
progressbar/terminal/base.py:11: in <module>
from .os_specific import getch
progressbar/terminal/os_specific/__init__.py:12: in <module>
from .posix import getch as _getch
E ImportError: cannot import name 'getch' from 'progressbar.terminal.os_specific.posix' (/testbed/progressbar/terminal/os_specific/posix.py)
Patch diff
diff --git a/progressbar/algorithms.py b/progressbar/algorithms.py
index 3698a37..de2b1a4 100644
--- a/progressbar/algorithms.py
+++ b/progressbar/algorithms.py
@@ -14,7 +14,7 @@ class SmoothingAlgorithm(abc.ABC):
"""Updates the algorithm with a new value and returns the smoothed
value.
"""
- pass
+ raise NotImplementedError
class ExponentialMovingAverage(SmoothingAlgorithm):
@@ -26,7 +26,14 @@ class ExponentialMovingAverage(SmoothingAlgorithm):
def __init__(self, alpha: float=0.5) ->None:
self.alpha = alpha
- self.value = 0
+ self.value = None
+
+ def update(self, new_value: float, elapsed: timedelta) ->float:
+ if self.value is None:
+ self.value = new_value
+ else:
+ self.value = self.alpha * new_value + (1 - self.alpha) * self.value
+ return self.value
class DoubleExponentialMovingAverage(SmoothingAlgorithm):
@@ -38,5 +45,16 @@ class DoubleExponentialMovingAverage(SmoothingAlgorithm):
def __init__(self, alpha: float=0.5) ->None:
self.alpha = alpha
- self.ema1 = 0
- self.ema2 = 0
+ self.ema1 = None
+ self.ema2 = None
+
+ def update(self, new_value: float, elapsed: timedelta) ->float:
+ if self.ema1 is None:
+ self.ema1 = new_value
+ self.ema2 = new_value
+ else:
+ self.ema1 = self.alpha * new_value + (1 - self.alpha) * self.ema1
+ self.ema2 = self.alpha * self.ema1 + (1 - self.alpha) * self.ema2
+
+ # DEMA = 2 * EMA1 - EMA2
+ return 2 * self.ema1 - self.ema2
diff --git a/progressbar/bar.py b/progressbar/bar.py
index d3c579a..8357f82 100644
--- a/progressbar/bar.py
+++ b/progressbar/bar.py
@@ -129,11 +129,40 @@ class DefaultFdMixin(ProgressBarMixinBase):
ValueError: If `enable_colors` is not None, True, False, or an
instance of `progressbar.env.ColorSupport`.
"""
- pass
+ if enable_colors is None:
+ env_color = progressbar.env.ColorSupport.from_env()
+ return env_color if self.is_ansi_terminal else progressbar.env.ColorSupport.NONE
+ elif enable_colors is True:
+ return progressbar.env.ColorSupport.XTERM_256
+ elif enable_colors is False:
+ return progressbar.env.ColorSupport.NONE
+ elif isinstance(enable_colors, progressbar.env.ColorSupport):
+ return enable_colors
+ else:
+ raise ValueError("Invalid value for enable_colors")
def _format_line(self):
"""Joins the widgets and justifies the line."""
- pass
+ result = []
+ if self.prefix:
+ result.append(self.prefix)
+
+ for widget in self.widgets:
+ if isinstance(widget, widgets_module.WidgetBase):
+ result.append(widget.render(self))
+ else:
+ result.append(widget)
+
+ if self.suffix:
+ result.append(self.suffix)
+
+ line = ''.join(result)
+ width = self.term_width
+
+ if self.left_justify:
+ return line.ljust(width)
+ else:
+ return line.rjust(width)
class ResizableMixin(ProgressBarMixinBase):
@@ -153,7 +182,10 @@ class ResizableMixin(ProgressBarMixinBase):
def _handle_resize(self, signum=None, frame=None):
"""Tries to catch resize signals sent from the terminal."""
- pass
+ try:
+ self.term_width, _ = os_specific.get_terminal_size()
+ except Exception:
+ pass
class StdRedirectMixin(DefaultFdMixin):
@@ -313,7 +345,16 @@ class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
(re)initialize values to original state so the progressbar can be
used (again).
"""
- pass
+ self._last_update_time = None
+ self.num_intervals = 0
+ self.next_update = 0
+ self.value = self.min_value
+ self.previous_value = None
+ self.start_time = None
+ self.end_time = None
+ self.extra = {}
+ self._iterable = None
+ self.paused = False
@property
def percentage(self) ->(float | None):
@@ -347,7 +388,14 @@ class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
>>> progress.max_value = None
>>> progress.percentage
"""
- pass
+ if self.max_value is None or isinstance(self.max_value, base.UnknownLength):
+ return None
+
+ value_range = self.max_value - self.min_value
+ if value_range == 0:
+ return 100.0
+
+ return min(100.0, max(0.0, (self.value - self.min_value) / value_range * 100))
def data(self) ->types.Dict[str, types.Any]:
"""
@@ -377,7 +425,28 @@ class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
:py:class:`~progressbar.widgets.Variable`'s.
"""
- pass
+ now = datetime.now()
+ time_elapsed = now - self.start_time if self.start_time else timedelta()
+ total_seconds_elapsed = time_elapsed.total_seconds()
+
+ return {
+ 'max_value': self.max_value,
+ 'start_time': self.start_time,
+ 'last_update_time': self.last_update_time,
+ 'end_time': self.end_time,
+ 'value': self.value,
+ 'previous_value': self.previous_value,
+ 'updates': self.num_intervals,
+ 'total_seconds_elapsed': total_seconds_elapsed,
+ 'seconds_elapsed': int(total_seconds_elapsed % 60),
+ 'minutes_elapsed': int((total_seconds_elapsed // 60) % 60),
+ 'hours_elapsed': int((total_seconds_elapsed // 3600) % 24),
+ 'days_elapsed': int(total_seconds_elapsed // 86400),
+ 'time_elapsed': time_elapsed,
+ 'percentage': self.percentage,
+ 'dynamic_messages': self.variables, # Deprecated
+ 'variables': self.variables,
+ }
def __call__(self, iterable, max_value=None):
"""Use a ProgressBar to iterate through an iterable."""
@@ -426,11 +495,39 @@ class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
def _needs_update(self):
"""Returns whether the ProgressBar should redraw the line."""
- pass
+ if self.poll_interval is None:
+ return True
+
+ now = time.time()
+ if self._last_update_time is None:
+ return True
+
+ time_since_last_update = now - self._last_update_time
+ return time_since_last_update >= self.poll_interval
def update(self, value=None, force=False, **kwargs):
"""Updates the ProgressBar to a new value."""
- pass
+ if self.paused:
+ return self
+
+ if value is not None and value != self.value:
+ self.previous_value = self.value
+ self.value = value
+
+ for key, val in kwargs.items():
+ if key in self.variables:
+ self.variables[key] = val
+
+ now = time.time()
+ if self._last_update_time is None:
+ self._last_update_time = now
+
+ if force or self._needs_update():
+ self._last_update_time = now
+ self._print()
+ self.num_intervals += 1
+
+ return self
def start(self, max_value=None, init=True, *args, **kwargs):
"""Starts measuring time, and prints the bar at 0%.
@@ -450,7 +547,18 @@ class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
...
>>> pbar.finish()
"""
- pass
+ if init:
+ self.init()
+
+ if max_value is not None:
+ self.max_value = max_value
+
+ if self.max_value is None:
+ self.max_value = base.UnknownLength
+
+ self.start_time = self.initial_start_time or datetime.now()
+ self.update(self.min_value, force=True)
+ return self
def finish(self, end='\n', dirty=False):
"""
@@ -465,7 +573,22 @@ class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
dirty (bool): When True the progressbar kept the current state and
won't be set to 100 percent
"""
- pass
+ if self.end_time is None:
+ self.end_time = datetime.now()
+
+ if not dirty and self.max_value is not None and self.max_value != base.UnknownLength:
+ self.update(self.max_value, force=True)
+
+ if self.signal_set:
+ import signal
+ signal.signal(signal.SIGWINCH, self._prev_handle)
+
+ if not dirty:
+ self._print(end=end)
+ self._finished = True
+
+ if self.fd is not None:
+ self.fd.flush()
@property
def currval(self):
diff --git a/progressbar/base.py b/progressbar/base.py
index 9c7fad7..102f151 100644
--- a/progressbar/base.py
+++ b/progressbar/base.py
@@ -14,11 +14,22 @@ class FalseMeta(type):
class UnknownLength(metaclass=FalseMeta):
- pass
+ def __len__(self):
+ return 0
+
+ def __bool__(self):
+ return False
class Undefined(metaclass=FalseMeta):
- pass
+ def __bool__(self):
+ return False
+
+ def __eq__(self, other):
+ return False
+
+ def __ne__(self, other):
+ return True
try:
diff --git a/progressbar/core.py b/progressbar/core.py
new file mode 100644
index 0000000..d3e7e48
--- /dev/null
+++ b/progressbar/core.py
@@ -0,0 +1,69 @@
+import sys
+from typing import Union
+
+class ProgressBar:
+ """
+ A simple progress bar implementation.
+
+ Args:
+ total (int): Total number of items.
+ prefix (str, optional): Prefix string (e.g. 'Progress:'). Defaults to ''.
+ suffix (str, optional): Suffix string (e.g. 'Complete'). Defaults to ''.
+ decimals (int, optional): Positive number of decimals in percent complete. Defaults to 1.
+ length (int, optional): Character length of bar. Defaults to 100.
+ fill (str, optional): Bar fill character. Defaults to '█'.
+ printEnd (str, optional): End character (e.g. "\r", "\r\n"). Defaults to "\r".
+
+ Examples:
+ >>> pbar = ProgressBar(100)
+ >>> pbar.print_progress(10)
+ Progress: [██████████ ] 10.0% Complete\r
+ >>> pbar.print_progress(50)
+ Progress: [█████████████████████████████████ ] 50.0% Complete\r
+ >>> pbar.finish()
+ Progress: [████████████████████████████████████████████████████] 100.0% Complete
+ """
+ def __init__(self, total: int, prefix: str = '', suffix: str = '', decimals: int = 1, length: int = 100, fill: str = '█', printEnd: str = "\r"):
+ self.total = total
+ self.prefix = prefix
+ self.suffix = suffix
+ self.decimals = decimals
+ self.length = length
+ self.fill = fill
+ self.printEnd = printEnd
+ self.iteration = 0
+
+ def print_progress(self, iteration: int):
+ """
+ Prints the progress bar for the given iteration.
+
+ Args:
+ iteration (int): Current iteration.
+ """
+ self.iteration = iteration
+ percent = ("{0:." + str(self.decimals) + "f}").format(100 * (iteration / float(self.total)))
+ filled_length = int(self.length * iteration // self.total)
+ bar = self.fill * filled_length + '-' * (self.length - filled_length)
+ print(f'\r{self.prefix} |{bar}| {percent}% {self.suffix}', end=self.printEnd)
+ sys.stdout.flush()
+
+ def finish(self):
+ """
+ Prints the final progress bar with 100% completion.
+ Prints a newline character to move the cursor to the next line.
+ """
+ self.print_progress(self.total)
+ print()
+
+if __name__ == "__main__":
+ import time
+
+ # Test the ProgressBar
+ total = 100
+ pbar = ProgressBar(total, prefix='Progress:', suffix='Complete', length=50)
+
+ for i in range(total + 1):
+ time.sleep(0.1)
+ pbar.print_progress(i)
+
+ pbar.finish()
diff --git a/progressbar/env.py b/progressbar/env.py
index b58929e..19a0bd6 100644
--- a/progressbar/env.py
+++ b/progressbar/env.py
@@ -15,7 +15,15 @@ def env_flag(name, default=None):
If the environment variable is not defined, or has an unknown value,
returns `default`
"""
- pass
+ value = os.environ.get(name)
+ if value is None:
+ return default
+ value = value.lower()
+ if value in ('y', 'yes', '1', 'true', 'on'):
+ return True
+ if value in ('n', 'no', '0', 'false', 'off'):
+ return False
+ return default
class ColorSupport(enum.IntEnum):
@@ -41,7 +49,24 @@ class ColorSupport(enum.IntEnum):
Note that the highest available value will be used! Having
`COLORTERM=truecolor` will override `TERM=xterm-256color`.
"""
- pass
+ if (os.environ.get('JUPYTER_COLUMNS') or
+ os.environ.get('JUPYTER_LINES') or
+ os.environ.get('JPY_PARENT_PID')):
+ return cls.XTERM_TRUECOLOR
+
+ color_term = os.environ.get('COLORTERM', '').lower()
+ term = os.environ.get('TERM', '').lower()
+
+ if '24bit' in color_term or 'truecolor' in color_term:
+ return cls.XTERM_TRUECOLOR
+ elif '256' in term:
+ return cls.XTERM_256
+ elif 'xterm' in term:
+ return cls.XTERM
+ elif os.name == 'nt':
+ return cls.WINDOWS
+ else:
+ return cls.NONE
if os.name == 'nt':
diff --git a/progressbar/multi.py b/progressbar/multi.py
index bcf8152..cf06c35 100644
--- a/progressbar/multi.py
+++ b/progressbar/multi.py
@@ -112,7 +112,34 @@ class MultiBar(typing.Dict[str, bar.ProgressBar]):
def render(self, flush: bool=True, force: bool=False):
"""Render the multibar to the given stream."""
- pass
+ with self._print_lock:
+ now = time.time()
+ output = []
+ for key, bar in sorted(self.items(), key=lambda x: self.sort_keyfunc(x[1]), reverse=self.sort_reverse):
+ if bar.start_time is None and self.show_initial and self.initial_format:
+ output.append(self.initial_format.format(label=key))
+ elif bar.finished:
+ if self.show_finished and self.finished_format:
+ if self.remove_finished is None or now - self._finished_at.get(bar, now) < self.remove_finished:
+ output.append(self.finished_format.format(label=key, bar=bar))
+ else:
+ line = bar.format_line()
+ if self.prepend_label:
+ line = self.label_format.format(label=key) + line
+ if self.append_label:
+ line += self.label_format.format(label=key)
+ output.append(line)
+
+ if output != self._previous_output or force:
+ self._buffer.seek(0)
+ self._buffer.truncate()
+ for line in output:
+ print(line, file=self._buffer)
+ if flush:
+ self._buffer.seek(0)
+ self.fd.write(self._buffer.getvalue())
+ self.fd.flush()
+ self._previous_output = output
def print(self, *args, end='\n', offset=None, flush=True, clear=True,
**kwargs):
@@ -127,14 +154,50 @@ class MultiBar(typing.Dict[str, bar.ProgressBar]):
clear: If True, the line will be cleared before printing.
**kwargs: Additional keyword arguments to pass to print
"""
- pass
+ with self._print_lock:
+ if offset is None:
+ offset = len(self._previous_output)
+
+ if clear:
+ print('\033[K', end='', file=self.fd) # Clear the line
+
+ print(*args, end=end, file=self.fd, **kwargs)
+
+ if offset > 0:
+ print(f'\033[{offset}A', end='', file=self.fd) # Move cursor up
+
+ if flush:
+ self.fd.flush()
def run(self, join=True):
"""
Start the multibar render loop and run the progressbars until they
have force _thread_finished.
"""
- pass
+ def render_loop():
+ while not self._thread_finished.is_set():
+ self.render()
+ time.sleep(self.update_interval)
+ self._thread_closed.set()
+
+ self._thread = threading.Thread(target=render_loop)
+ self._thread.start()
+
+ if join:
+ self.join()
+
+ def start(self):
+ """Start the multibar render loop."""
+ if self._thread is None:
+ self.run(join=False)
+
+ def join(self):
+ """Wait for the multibar render loop to finish."""
+ if self._thread is not None:
+ self._thread_finished.set()
+ self._thread.join()
+ self._thread = None
+ self.render(force=True) # Final render
def __enter__(self):
self.start()
diff --git a/progressbar/terminal/base.py b/progressbar/terminal/base.py
index 6c22ca8..f94bc60 100644
--- a/progressbar/terminal/base.py
+++ b/progressbar/terminal/base.py
@@ -117,7 +117,10 @@ class WindowsColors(enum.Enum):
>>> WindowsColors.from_rgb((128, 0, 128))
<WindowsColors.MAGENTA: (128, 0, 128)>
"""
- pass
+ def color_distance(c1, c2):
+ return sum((a - b) ** 2 for a, b in zip(c1, c2))
+
+ return min(WindowsColors, key=lambda c: color_distance(rgb, c.value))
class WindowsColor:
@@ -149,7 +152,7 @@ class RGB(collections.namedtuple('RGB', ['red', 'green', 'blue'])):
Convert an RGB color (0-255 per channel) to the closest color in the
Windows 16 color scheme.
"""
- pass
+ return WindowsColors.from_rgb(self)
class HSL(collections.namedtuple('HSL', ['hue', 'saturation', 'lightness'])):
@@ -167,7 +170,9 @@ class HSL(collections.namedtuple('HSL', ['hue', 'saturation', 'lightness'])):
"""
Convert a 0-255 RGB color to a 0-255 HLS color.
"""
- pass
+ r, g, b = [x / 255.0 for x in rgb]
+ h, l, s = colorsys.rgb_to_hls(r, g, b)
+ return cls(int(h * 360), int(s * 100), int(l * 100))
class ColorBase(abc.ABC):
@@ -228,7 +233,19 @@ class ColorGradient(ColorBase):
def get_color(self, value: float) ->Color:
"""Map a value from 0 to 1 to a color."""
- pass
+ if value <= 0:
+ return self.colors[0]
+ if value >= 1:
+ return self.colors[-1]
+
+ segment_size = 1.0 / (len(self.colors) - 1)
+ segment = int(value / segment_size)
+ t = (value - segment * segment_size) / segment_size
+
+ color1 = self.colors[segment]
+ color2 = self.colors[segment + 1]
+
+ return self.interpolate(color1, color2, t)
OptionalColor = types.Union[Color, ColorGradient, None]
@@ -243,7 +260,21 @@ def apply_colors(text: str, percentage: (float | None)=None, *, fg:
Otherwise, the `fg` and `bg` colors will be used. If the colors are
gradients, the color will be interpolated depending on the percentage.
"""
- pass
+ if percentage is None:
+ fg_color = fg_none
+ bg_color = bg_none
+ else:
+ fg_color = fg(percentage) if isinstance(fg, ColorGradient) else fg
+ bg_color = bg(percentage) if isinstance(bg, ColorGradient) else bg
+
+ result = text
+
+ if fg_color:
+ result = fg_color(result)
+ if bg_color:
+ result = bg_color.bg(result)
+
+ return result
class DummyColor:
diff --git a/progressbar/utils.py b/progressbar/utils.py
index edf654a..66cd242 100644
--- a/progressbar/utils.py
+++ b/progressbar/utils.py
@@ -50,7 +50,16 @@ def deltas_to_seconds(*deltas, default: types.Optional[types.Type[
>>> deltas_to_seconds(default=0.0)
0.0
"""
- pass
+ for delta in deltas:
+ if delta is not None:
+ if isinstance(delta, datetime.timedelta):
+ return timedelta_to_seconds(delta)
+ elif isinstance(delta, (int, float)):
+ return float(delta)
+
+ if default is ValueError:
+ raise ValueError("No valid deltas passed to `deltas_to_seconds`")
+ return default
def no_color(value: StringT) ->StringT:
diff --git a/progressbar/widgets.py b/progressbar/widgets.py
index be97fda..d8e3c78 100644
--- a/progressbar/widgets.py
+++ b/progressbar/widgets.py
@@ -31,7 +31,12 @@ def create_wrapper(wrapper):
>>> print(create_wrapper(('a', 'b')))
a{}b
"""
- pass
+ if not wrapper:
+ return None
+ elif isinstance(wrapper, tuple):
+ return '{}{}{}' if len(wrapper) == 2 else '{}{{}}{}'.format(*wrapper)
+ else:
+ return wrapper
def wrapper(function, wrapper_):
@@ -39,7 +44,14 @@ def wrapper(function, wrapper_):
begin/end strings.
"""
- pass
+ wrapper_ = create_wrapper(wrapper_)
+
+ @functools.wraps(function)
+ def wrap(*args, **kwargs):
+ result = function(*args, **kwargs)
+ return wrapper_.format(result) if wrapper_ else result
+
+ return wrap
class FormatWidgetMixin(abc.ABC):
@@ -327,7 +339,13 @@ class ETA(Timer):
def _calculate_eta(self, progress: ProgressBarMixinBase, data: Data,
value, elapsed):
"""Updates the widget to show the ETA or total time when finished."""
- pass
+ if value == 0:
+ return None
+
+ rate = value / elapsed
+ remaining = progress.max_value - data['value']
+ eta_seconds = remaining / rate if rate > 0 else 0
+ return eta_seconds
def __call__(self, progress: ProgressBarMixinBase, data: Data, value=
None, elapsed=None):