logbar 0.2.3__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {logbar-0.2.3 → logbar-0.2.4}/LogBar.egg-info/PKG-INFO +12 -1
- {logbar-0.2.3 → logbar-0.2.4}/PKG-INFO +12 -1
- {logbar-0.2.3 → logbar-0.2.4}/README.md +11 -0
- {logbar-0.2.3 → logbar-0.2.4}/logbar/logbar.py +13 -3
- {logbar-0.2.3 → logbar-0.2.4}/logbar/progress.py +94 -4
- {logbar-0.2.3 → logbar-0.2.4}/pyproject.toml +1 -1
- {logbar-0.2.3 → logbar-0.2.4}/tests/test_progress.py +75 -0
- {logbar-0.2.3 → logbar-0.2.4}/LICENSE +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/LogBar.egg-info/SOURCES.txt +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/LogBar.egg-info/dependency_links.txt +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/LogBar.egg-info/top_level.txt +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/logbar/__init__.py +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/logbar/buffer.py +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/logbar/columns.py +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/logbar/terminal.py +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/logbar/util.py +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/setup.cfg +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/tests/test_columns.py +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/tests/test_example.py +0 -0
- {logbar-0.2.3 → logbar-0.2.4}/tests/test_log.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: LogBar
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: A unified Logger and ProgressBar util with zero dependencies.
|
|
5
5
|
Author-email: ModelCloud <qubitium@modelcloud.ai>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -39,6 +39,8 @@ Dynamic: license-file
|
|
|
39
39
|
- Built-in styling for progress bar fills, colors, gradients, and head glyphs.
|
|
40
40
|
- Animated progress titles with a subtle sweeping highlight.
|
|
41
41
|
Set `LOGBAR_ANIMATION=0` to disable the highlight animation.
|
|
42
|
+
- Progress output throttling for reducing redraw churn in batch-heavy jobs.
|
|
43
|
+
Set `LOGBAR_PROGRESS_OUTPUT_INTERVAL=10` to render every 10 logical updates instead of every update.
|
|
42
44
|
- Column-aware table printer with spans, width hints, and `fit` sizing.
|
|
43
45
|
- Zero dependencies; works anywhere Python runs.
|
|
44
46
|
|
|
@@ -114,6 +116,15 @@ for _ in log.pb(500).title("Downloading"):
|
|
|
114
116
|
time.sleep(0.05)
|
|
115
117
|
```
|
|
116
118
|
|
|
119
|
+
When a workload updates progress very frequently, throttle redraw churn globally or per bar:
|
|
120
|
+
|
|
121
|
+
```py
|
|
122
|
+
for _ in log.pb(500, output_interval=10).title("Quantizing"):
|
|
123
|
+
time.sleep(0.01)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`output_interval=10` means LogBar will emit a fresh snapshot after roughly every 10 logical progress steps, while still forcing the last pending step to render before the bar closes. Set `LOGBAR_PROGRESS_OUTPUT_INTERVAL=10` to apply the same default process-wide.
|
|
127
|
+
|
|
117
128
|
Manual mode gives full control when you need to interleave logging and redraws:
|
|
118
129
|
|
|
119
130
|
```py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: LogBar
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: A unified Logger and ProgressBar util with zero dependencies.
|
|
5
5
|
Author-email: ModelCloud <qubitium@modelcloud.ai>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -39,6 +39,8 @@ Dynamic: license-file
|
|
|
39
39
|
- Built-in styling for progress bar fills, colors, gradients, and head glyphs.
|
|
40
40
|
- Animated progress titles with a subtle sweeping highlight.
|
|
41
41
|
Set `LOGBAR_ANIMATION=0` to disable the highlight animation.
|
|
42
|
+
- Progress output throttling for reducing redraw churn in batch-heavy jobs.
|
|
43
|
+
Set `LOGBAR_PROGRESS_OUTPUT_INTERVAL=10` to render every 10 logical updates instead of every update.
|
|
42
44
|
- Column-aware table printer with spans, width hints, and `fit` sizing.
|
|
43
45
|
- Zero dependencies; works anywhere Python runs.
|
|
44
46
|
|
|
@@ -114,6 +116,15 @@ for _ in log.pb(500).title("Downloading"):
|
|
|
114
116
|
time.sleep(0.05)
|
|
115
117
|
```
|
|
116
118
|
|
|
119
|
+
When a workload updates progress very frequently, throttle redraw churn globally or per bar:
|
|
120
|
+
|
|
121
|
+
```py
|
|
122
|
+
for _ in log.pb(500, output_interval=10).title("Quantizing"):
|
|
123
|
+
time.sleep(0.01)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`output_interval=10` means LogBar will emit a fresh snapshot after roughly every 10 logical progress steps, while still forcing the last pending step to render before the bar closes. Set `LOGBAR_PROGRESS_OUTPUT_INTERVAL=10` to apply the same default process-wide.
|
|
127
|
+
|
|
117
128
|
Manual mode gives full control when you need to interleave logging and redraws:
|
|
118
129
|
|
|
119
130
|
```py
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
- Built-in styling for progress bar fills, colors, gradients, and head glyphs.
|
|
25
25
|
- Animated progress titles with a subtle sweeping highlight.
|
|
26
26
|
Set `LOGBAR_ANIMATION=0` to disable the highlight animation.
|
|
27
|
+
- Progress output throttling for reducing redraw churn in batch-heavy jobs.
|
|
28
|
+
Set `LOGBAR_PROGRESS_OUTPUT_INTERVAL=10` to render every 10 logical updates instead of every update.
|
|
27
29
|
- Column-aware table printer with spans, width hints, and `fit` sizing.
|
|
28
30
|
- Zero dependencies; works anywhere Python runs.
|
|
29
31
|
|
|
@@ -99,6 +101,15 @@ for _ in log.pb(500).title("Downloading"):
|
|
|
99
101
|
time.sleep(0.05)
|
|
100
102
|
```
|
|
101
103
|
|
|
104
|
+
When a workload updates progress very frequently, throttle redraw churn globally or per bar:
|
|
105
|
+
|
|
106
|
+
```py
|
|
107
|
+
for _ in log.pb(500, output_interval=10).title("Quantizing"):
|
|
108
|
+
time.sleep(0.01)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`output_interval=10` means LogBar will emit a fresh snapshot after roughly every 10 logical progress steps, while still forcing the last pending step to render before the bar closes. Set `LOGBAR_PROGRESS_OUTPUT_INTERVAL=10` to apply the same default process-wide.
|
|
112
|
+
|
|
102
113
|
Manual mode gives full control when you need to interleave logging and redraws:
|
|
103
114
|
|
|
104
115
|
```py
|
|
@@ -319,7 +319,17 @@ def _render_progress_stack_locked(precomputed: Optional[dict] = None, columns_hi
|
|
|
319
319
|
|
|
320
320
|
if rendered is None:
|
|
321
321
|
try:
|
|
322
|
-
|
|
322
|
+
# Progress bars may throttle redraws. When a bar is not due for
|
|
323
|
+
# a fresh snapshot, keep its last rendered line in the stack
|
|
324
|
+
# instead of recomputing it opportunistically on another bar's
|
|
325
|
+
# redraw.
|
|
326
|
+
resolve_rendered = getattr(pb, "_resolve_rendered_line", None)
|
|
327
|
+
if callable(resolve_rendered):
|
|
328
|
+
rendered = resolve_rendered(columns)
|
|
329
|
+
if rendered is None:
|
|
330
|
+
rendered = pb._last_rendered_line or ""
|
|
331
|
+
else:
|
|
332
|
+
rendered = pb._render_snapshot(columns)
|
|
323
333
|
except Exception: # pragma: no cover - avoid breaking logging on render issues
|
|
324
334
|
rendered = pb._last_rendered_line or ""
|
|
325
335
|
else:
|
|
@@ -565,10 +575,10 @@ class LogBar(logging.Logger):
|
|
|
565
575
|
return shared_logger
|
|
566
576
|
|
|
567
577
|
|
|
568
|
-
def pb(self, iterable: Iterable):
|
|
578
|
+
def pb(self, iterable: Iterable, *, output_interval: Optional[int] = None):
|
|
569
579
|
from logbar.progress import ProgressBar
|
|
570
580
|
|
|
571
|
-
return ProgressBar(iterable, owner=self).attach(self)
|
|
581
|
+
return ProgressBar(iterable, owner=self, output_interval=output_interval).attach(self)
|
|
572
582
|
|
|
573
583
|
def spinner(self, title: str = "", *, interval: float = 0.5, tail_length: int = 4):
|
|
574
584
|
from logbar.progress import RollingProgressBar
|
|
@@ -82,6 +82,27 @@ def _env_animation_enabled() -> bool:
|
|
|
82
82
|
return str(value).strip().lower() not in {"0", "false", "off", "no"}
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
def _normalize_output_interval(value: Optional[Union[str, int]]) -> int:
|
|
86
|
+
"""Normalize logical progress render intervals to a safe integer >= 1."""
|
|
87
|
+
|
|
88
|
+
if value is None:
|
|
89
|
+
return 1
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
normalized = int(str(value).strip())
|
|
93
|
+
except (TypeError, ValueError):
|
|
94
|
+
return 1
|
|
95
|
+
|
|
96
|
+
return max(1, normalized)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@lru_cache(maxsize=1)
|
|
100
|
+
def _env_progress_output_interval() -> int:
|
|
101
|
+
"""Global default for how many logical progress updates occur per render."""
|
|
102
|
+
|
|
103
|
+
return _normalize_output_interval(os.environ.get("LOGBAR_PROGRESS_OUTPUT_INTERVAL", "1"))
|
|
104
|
+
|
|
105
|
+
|
|
85
106
|
def _fg_256(code: int) -> str:
|
|
86
107
|
return f"\033[38;5;{code}m"
|
|
87
108
|
|
|
@@ -374,7 +395,13 @@ class ProgressBar:
|
|
|
374
395
|
def default_style(cls) -> ProgressStyle:
|
|
375
396
|
return get_progress_style(_DEFAULT_STYLE_NAME)
|
|
376
397
|
|
|
377
|
-
def __init__(
|
|
398
|
+
def __init__(
|
|
399
|
+
self,
|
|
400
|
+
iterable: Union[Iterable, int, dict, set],
|
|
401
|
+
owner: Optional["LogBarType"] = None,
|
|
402
|
+
*,
|
|
403
|
+
output_interval: Optional[int] = None,
|
|
404
|
+
):
|
|
378
405
|
self._iterating = False # state: in init or active iteration
|
|
379
406
|
|
|
380
407
|
self._render_mode = RenderMode.AUTO
|
|
@@ -398,6 +425,10 @@ class ProgressBar:
|
|
|
398
425
|
self.time = time.time()
|
|
399
426
|
self._title_animation_start = self.time
|
|
400
427
|
self._title_animation_period = 0.1
|
|
428
|
+
self._output_interval = _normalize_output_interval(
|
|
429
|
+
_env_progress_output_interval() if output_interval is None else output_interval
|
|
430
|
+
)
|
|
431
|
+
self._last_output_step: Optional[int] = None
|
|
401
432
|
|
|
402
433
|
self.ui_show_left_steps = True # show [1 of 100] on left side
|
|
403
434
|
self.ui_show_left_steps_offset = 0
|
|
@@ -424,6 +455,12 @@ class ProgressBar:
|
|
|
424
455
|
self._style_name = resolved.name
|
|
425
456
|
return self
|
|
426
457
|
|
|
458
|
+
def output_interval(self, interval: int):
|
|
459
|
+
"""Render after at least `interval` logical progress updates."""
|
|
460
|
+
|
|
461
|
+
self._output_interval = _normalize_output_interval(interval)
|
|
462
|
+
return self
|
|
463
|
+
|
|
427
464
|
def fill(self, fill: Union[str, ProgressStyle] = "█", empty: Optional[str] = None):
|
|
428
465
|
if isinstance(fill, ProgressStyle) or (isinstance(fill, str) and fill in _PROGRESS_STYLES):
|
|
429
466
|
return self.style(fill)
|
|
@@ -672,10 +709,50 @@ class ProgressBar:
|
|
|
672
709
|
|
|
673
710
|
return self
|
|
674
711
|
|
|
675
|
-
def
|
|
712
|
+
def _render_position(self) -> int:
|
|
713
|
+
"""Progress coordinate used for render throttling."""
|
|
714
|
+
|
|
715
|
+
return self.step()
|
|
716
|
+
|
|
717
|
+
def _should_render(self, force: bool = False, allow_repeat: bool = False) -> bool:
|
|
718
|
+
if force:
|
|
719
|
+
return True
|
|
720
|
+
|
|
721
|
+
if not self._last_rendered_line:
|
|
722
|
+
return True
|
|
723
|
+
|
|
724
|
+
last_output_step = self._last_output_step
|
|
725
|
+
if last_output_step is None:
|
|
726
|
+
return True
|
|
727
|
+
|
|
728
|
+
current_step = self._render_position()
|
|
729
|
+
if allow_repeat and current_step <= last_output_step:
|
|
730
|
+
return True
|
|
731
|
+
|
|
732
|
+
return (current_step - last_output_step) >= self._output_interval
|
|
733
|
+
|
|
734
|
+
def _resolve_rendered_line(
|
|
735
|
+
self,
|
|
736
|
+
columns: int,
|
|
737
|
+
force: bool = False,
|
|
738
|
+
allow_repeat: bool = False,
|
|
739
|
+
) -> Optional[str]:
|
|
740
|
+
if not self._should_render(force=force, allow_repeat=allow_repeat):
|
|
741
|
+
return None
|
|
742
|
+
|
|
743
|
+
rendered_line = self._render_snapshot(columns)
|
|
744
|
+
self._last_output_step = self._render_position()
|
|
745
|
+
return rendered_line
|
|
746
|
+
|
|
747
|
+
def draw(self, force: bool = False):
|
|
748
|
+
# Even skipped draws count as activity. This prevents the background
|
|
749
|
+
# refresher from redrawing the same bar immediately and undoing the
|
|
750
|
+
# throttle when progress is advancing quickly.
|
|
676
751
|
_record_progress_activity()
|
|
677
752
|
columns, _ = terminal_size()
|
|
678
|
-
rendered_line = self.
|
|
753
|
+
rendered_line = self._resolve_rendered_line(columns, force=force, allow_repeat=True)
|
|
754
|
+
if rendered_line is None:
|
|
755
|
+
return
|
|
679
756
|
|
|
680
757
|
render_fn = render_progress_stack if callable(render_progress_stack) else None
|
|
681
758
|
context, lock_held = self._render_lock_context()
|
|
@@ -976,6 +1053,13 @@ class ProgressBar:
|
|
|
976
1053
|
if self.closed:
|
|
977
1054
|
return
|
|
978
1055
|
|
|
1056
|
+
# Force the last observed progress state to render even when the final
|
|
1057
|
+
# step does not land on the configured output interval, e.g. 15 with an
|
|
1058
|
+
# interval of 10. Without this, the closing detach would erase the bar
|
|
1059
|
+
# before a 100% snapshot is ever emitted.
|
|
1060
|
+
if self.step() > 0 and (self._last_output_step is None or self.step() != self._last_output_step):
|
|
1061
|
+
self.draw(force=True)
|
|
1062
|
+
|
|
979
1063
|
self.closed = True
|
|
980
1064
|
self.detach()
|
|
981
1065
|
|
|
@@ -984,7 +1068,10 @@ class RollingProgressBar(ProgressBar):
|
|
|
984
1068
|
"""Indeterminate progress indicator with a rolling highlight."""
|
|
985
1069
|
|
|
986
1070
|
def __init__(self, owner: Optional["LogBarType"] = None, interval: float = 0.5, tail_length: int = 4):
|
|
987
|
-
|
|
1071
|
+
# Spinner animation already has its own wall-clock interval. Keep
|
|
1072
|
+
# output throttling at 1 so the phase animation stays smooth unless a
|
|
1073
|
+
# caller explicitly changes it later.
|
|
1074
|
+
super().__init__(iterable=1, owner=owner, output_interval=1)
|
|
988
1075
|
self._interval = max(0.05, float(interval))
|
|
989
1076
|
self._tail_length = max(1, int(tail_length))
|
|
990
1077
|
self._phase = 0
|
|
@@ -1050,6 +1137,9 @@ class RollingProgressBar(ProgressBar):
|
|
|
1050
1137
|
def _advance_phase(self) -> None:
|
|
1051
1138
|
self._phase = (self._phase + 1) % 1_000_000
|
|
1052
1139
|
|
|
1140
|
+
def _render_position(self) -> int:
|
|
1141
|
+
return self._phase
|
|
1142
|
+
|
|
1053
1143
|
def _render_snapshot(self, columns: Optional[int] = None) -> str:
|
|
1054
1144
|
if columns is None:
|
|
1055
1145
|
columns, _ = terminal_size()
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
# Contact: qubitium@modelcloud.ai, x.com/qubitium
|
|
5
5
|
|
|
6
|
+
import os
|
|
6
7
|
import subprocess
|
|
7
8
|
import random
|
|
8
9
|
import re
|
|
@@ -15,6 +16,7 @@ from time import sleep
|
|
|
15
16
|
from unittest.mock import patch
|
|
16
17
|
|
|
17
18
|
from logbar import LogBar
|
|
19
|
+
from logbar import progress as progress_module
|
|
18
20
|
from logbar.progress import ProgressBar, TITLE_HIGHLIGHT_COLOR, ANSI_BOLD_RESET
|
|
19
21
|
from logbar.logbar import _active_progress_bars
|
|
20
22
|
|
|
@@ -68,6 +70,33 @@ SAMPLES = generate_expanding_str_a_to_z()
|
|
|
68
70
|
REVERSED_SAMPLES = reversed(SAMPLES)
|
|
69
71
|
|
|
70
72
|
class TestProgress(unittest.TestCase):
|
|
73
|
+
def setUp(self):
|
|
74
|
+
self._saved_env = {
|
|
75
|
+
"LOGBAR_ANIMATION": os.environ.get("LOGBAR_ANIMATION"),
|
|
76
|
+
"LOGBAR_PROGRESS_OUTPUT_INTERVAL": os.environ.get("LOGBAR_PROGRESS_OUTPUT_INTERVAL"),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for key in self._saved_env:
|
|
80
|
+
os.environ.pop(key, None)
|
|
81
|
+
|
|
82
|
+
self._clear_progress_env_caches()
|
|
83
|
+
|
|
84
|
+
def tearDown(self):
|
|
85
|
+
for key, value in self._saved_env.items():
|
|
86
|
+
if value is None:
|
|
87
|
+
os.environ.pop(key, None)
|
|
88
|
+
else:
|
|
89
|
+
os.environ[key] = value
|
|
90
|
+
|
|
91
|
+
self._clear_progress_env_caches()
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def _clear_progress_env_caches():
|
|
95
|
+
for helper_name in ("_env_animation_enabled", "_env_progress_output_interval"):
|
|
96
|
+
helper = getattr(progress_module, helper_name, None)
|
|
97
|
+
cache_clear = getattr(helper, "cache_clear", None)
|
|
98
|
+
if callable(cache_clear):
|
|
99
|
+
cache_clear()
|
|
71
100
|
|
|
72
101
|
def test_title_fixed_subtitle_dynamic(self):
|
|
73
102
|
pb = log.pb(SAMPLES).title("TITLE:").manual()
|
|
@@ -170,6 +199,52 @@ class TestProgress(unittest.TestCase):
|
|
|
170
199
|
)
|
|
171
200
|
self.assertEqual(disabled.stdout.strip(), "0")
|
|
172
201
|
|
|
202
|
+
def test_progress_output_interval_respects_env(self):
|
|
203
|
+
cache_clear = progress_module._env_progress_output_interval.cache_clear
|
|
204
|
+
|
|
205
|
+
with patch.dict(os.environ, {"LOGBAR_PROGRESS_OUTPUT_INTERVAL": "10"}):
|
|
206
|
+
cache_clear()
|
|
207
|
+
pb = ProgressBar(range(5))
|
|
208
|
+
self.assertEqual(pb._output_interval, 10)
|
|
209
|
+
with redirect_stdout(StringIO()):
|
|
210
|
+
pb.close()
|
|
211
|
+
|
|
212
|
+
cache_clear()
|
|
213
|
+
|
|
214
|
+
def test_progress_output_interval_defaults_to_one(self):
|
|
215
|
+
cache_clear = progress_module._env_progress_output_interval.cache_clear
|
|
216
|
+
|
|
217
|
+
with patch.dict(os.environ, {}, clear=True):
|
|
218
|
+
cache_clear()
|
|
219
|
+
pb = ProgressBar(range(5))
|
|
220
|
+
self.assertEqual(pb._output_interval, 1)
|
|
221
|
+
with redirect_stdout(StringIO()):
|
|
222
|
+
pb.close()
|
|
223
|
+
|
|
224
|
+
cache_clear()
|
|
225
|
+
|
|
226
|
+
def test_progress_output_interval_skips_intermediate_draws_but_flushes_final_step(self):
|
|
227
|
+
columns = 96
|
|
228
|
+
|
|
229
|
+
with patch('logbar.progress.terminal_size', return_value=(columns, 24)), \
|
|
230
|
+
patch('logbar.logbar.terminal_size', return_value=(columns, 24)):
|
|
231
|
+
buffer = StringIO()
|
|
232
|
+
with redirect_stdout(buffer):
|
|
233
|
+
pb = log.pb(15, output_interval=10).manual()
|
|
234
|
+
for step in range(1, 16):
|
|
235
|
+
pb.current_iter_step = step
|
|
236
|
+
pb.draw()
|
|
237
|
+
pb.close()
|
|
238
|
+
|
|
239
|
+
lines = extract_rendered_lines(buffer.getvalue())
|
|
240
|
+
progress_lines = [line for line in lines if "/15]" in line]
|
|
241
|
+
|
|
242
|
+
self.assertTrue(any("[0/15]" in line for line in progress_lines))
|
|
243
|
+
self.assertTrue(any("[10/15]" in line for line in progress_lines))
|
|
244
|
+
self.assertTrue(any("[15/15]" in line and "100.0%" in line for line in progress_lines))
|
|
245
|
+
self.assertFalse(any("[9/15]" in line for line in progress_lines))
|
|
246
|
+
self.assertFalse(any("[14/15]" in line for line in progress_lines))
|
|
247
|
+
|
|
173
248
|
def test_draw_respects_terminal_width(self):
|
|
174
249
|
pb = log.pb(100).title("TITLE").subtitle("SUBTITLE").manual()
|
|
175
250
|
pb.current_iter_step = 50
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|