progress-table 1.3.0__tar.gz → 1.3.2__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.
- {progress-table-1.3.0 → progress-table-1.3.2}/PKG-INFO +1 -1
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table/__init__.py +1 -1
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table/v0/progress_table.py +8 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table/v1/progress_table.py +33 -15
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table.egg-info/PKG-INFO +1 -1
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table.egg-info/SOURCES.txt +3 -1
- progress-table-1.3.2/tests/test_docs_automated.py +61 -0
- progress-table-1.3.2/tests/test_examples_automated.py +63 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/LICENSE.txt +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/README.md +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table/v0/__init__.py +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table/v0/symbols.py +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table/v1/__init__.py +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table/v1/styles.py +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table.egg-info/PKG-INFO.sync-conflict-20240314-015933-NXTV2IO +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table.egg-info/dependency_links.txt +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table.egg-info/requires.txt +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/progress_table.egg-info/top_level.txt +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/pyproject.toml +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/setup.cfg +0 -0
- {progress-table-1.3.0 → progress-table-1.3.2}/setup.py +0 -0
|
@@ -27,6 +27,8 @@ ALL_COLORS_STYLES = ALL_COLORS + ALL_STYLES
|
|
|
27
27
|
ITERATOR_LENGTH_UNKNOWN_WARNED_ONCE = False
|
|
28
28
|
ITERATOR_LENGTH_CACHE: Dict[int, int] = {}
|
|
29
29
|
|
|
30
|
+
DEPRECATION_PRINTED = False
|
|
31
|
+
|
|
30
32
|
|
|
31
33
|
class ProgressTableV0:
|
|
32
34
|
def __init__(
|
|
@@ -82,6 +84,12 @@ class ProgressTableV0:
|
|
|
82
84
|
file: Redirect the output to another stream. There can be multiple streams at once passed as
|
|
83
85
|
a list or a tuple. Defaults to sys.stdout.
|
|
84
86
|
"""
|
|
87
|
+
global DEPRECATION_PRINTED
|
|
88
|
+
|
|
89
|
+
if not DEPRECATION_PRINTED:
|
|
90
|
+
logging.warning("ProgressTableV0 is deprecated, use ProgressTableV1 instead")
|
|
91
|
+
DEPRECATION_PRINTED = True
|
|
92
|
+
|
|
85
93
|
self.refresh_rate = refresh_rate
|
|
86
94
|
self.default_width = default_column_width
|
|
87
95
|
self.default_alignment = default_column_alignment
|
|
@@ -219,7 +219,7 @@ class ProgressTableV1:
|
|
|
219
219
|
self.finished_rows: list[dict[str, Any]] = []
|
|
220
220
|
|
|
221
221
|
self._new_row: dict[str, Any] = {}
|
|
222
|
-
self.
|
|
222
|
+
self._new_row_cumulated_weight: dict[str, int] = {}
|
|
223
223
|
self.files = (file,) if not isinstance(file, (list, tuple)) else file
|
|
224
224
|
|
|
225
225
|
self.previous_header_counter = 0
|
|
@@ -288,27 +288,35 @@ class ProgressTableV1:
|
|
|
288
288
|
# Initialize color for the column in the new row
|
|
289
289
|
self._prepare_row_color_dict()
|
|
290
290
|
|
|
291
|
-
def add_columns(self,
|
|
291
|
+
def add_columns(self, *columns, **kwds):
|
|
292
292
|
"""Add multiple columns to the table."""
|
|
293
|
-
for column in
|
|
293
|
+
for column in columns:
|
|
294
294
|
self.add_column(column, **kwds)
|
|
295
295
|
|
|
296
|
-
def update(self, key, value, *, weight=1):
|
|
297
|
-
"""Update value in the current row.
|
|
296
|
+
def update(self, key, value, *, weight=1, **column_kwds):
|
|
297
|
+
"""Update value in the current row. This is extends capabilities of __setitem__.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
key: Name of the column.
|
|
301
|
+
value: Value to be set.
|
|
302
|
+
weight: Weight of the value. This is used for aggregation.
|
|
303
|
+
column_kwds: Additional arguments for the column. They will be only used for column creation.
|
|
304
|
+
If column already exists, they will have no effect.
|
|
305
|
+
"""
|
|
298
306
|
if key not in self.column_names:
|
|
299
307
|
if self._is_table_opened:
|
|
300
308
|
logging.info("Closing table (new column added to opened table)")
|
|
301
|
-
self.close(close_pbars=False)
|
|
309
|
+
self.close(close_pbars=False, close_row=False)
|
|
302
310
|
|
|
303
|
-
self.add_column(key)
|
|
311
|
+
self.add_column(key, **column_kwds)
|
|
304
312
|
|
|
305
313
|
# Set default values for new rows
|
|
306
314
|
self._new_row.setdefault(key, 0)
|
|
307
|
-
self.
|
|
315
|
+
self._new_row_cumulated_weight.setdefault(key, 0)
|
|
308
316
|
|
|
309
317
|
fn = self.column_aggregates[key]
|
|
310
|
-
self._new_row[key] = fn(value, self._new_row[key], self.
|
|
311
|
-
self.
|
|
318
|
+
self._new_row[key] = fn(value, self._new_row[key], self._new_row_cumulated_weight[key])
|
|
319
|
+
self._new_row_cumulated_weight[key] += weight
|
|
312
320
|
|
|
313
321
|
t0 = time.time()
|
|
314
322
|
td = t0 - self._last_time_row_printed
|
|
@@ -335,7 +343,7 @@ class ProgressTableV1:
|
|
|
335
343
|
return
|
|
336
344
|
|
|
337
345
|
logging.info("Closing table (reordering columns)")
|
|
338
|
-
self.close(close_pbars=False)
|
|
346
|
+
self.close(close_pbars=False, close_row=False)
|
|
339
347
|
|
|
340
348
|
assert isinstance(column_names, (List, Tuple))
|
|
341
349
|
assert all([x in self.column_names for x in column_names]), f"Columns {column_names} not in {self.column_names}"
|
|
@@ -444,7 +452,8 @@ class ProgressTableV1:
|
|
|
444
452
|
|
|
445
453
|
def _display_new_row_or_pbar(self):
|
|
446
454
|
if self._active_pbars.get(0, None) is not None:
|
|
447
|
-
|
|
455
|
+
# Level 0 pbar is embedded into the row, if it exists we want to display it instead of a row
|
|
456
|
+
self._active_pbars[0].display()
|
|
448
457
|
else:
|
|
449
458
|
self._display_new_row()
|
|
450
459
|
|
|
@@ -466,6 +475,9 @@ class ProgressTableV1:
|
|
|
466
475
|
if split or self._request_splitter:
|
|
467
476
|
self._print_splitter()
|
|
468
477
|
|
|
478
|
+
# Reset aggregated values!
|
|
479
|
+
self._new_row_cumulated_weight = {}
|
|
480
|
+
|
|
469
481
|
self._prepare_row_color_dict(color)
|
|
470
482
|
self._display_new_row()
|
|
471
483
|
self._print() # Insert a newline
|
|
@@ -548,6 +560,7 @@ class ProgressTableV1:
|
|
|
548
560
|
level=None,
|
|
549
561
|
total=None,
|
|
550
562
|
refresh_rate=None,
|
|
563
|
+
description="",
|
|
551
564
|
show_throughput=None,
|
|
552
565
|
show_progress=None,
|
|
553
566
|
):
|
|
@@ -559,6 +572,7 @@ class ProgressTableV1:
|
|
|
559
572
|
level: Level of the progress bar. If not provided, it will be set automatically.
|
|
560
573
|
total: Total number of iterations. If not provided, it will be calculated from the length of the iterable.
|
|
561
574
|
refresh_rate: The maximal number of times per second the progress bar will be refreshed.
|
|
575
|
+
description: Custom description of the progress bar that will be shown as prefix.
|
|
562
576
|
show_throughput: If True, the throughput will be displayed.
|
|
563
577
|
show_progress: If True, the progress will be displayed.
|
|
564
578
|
"""
|
|
@@ -574,6 +588,7 @@ class ProgressTableV1:
|
|
|
574
588
|
total=total,
|
|
575
589
|
level=level,
|
|
576
590
|
refresh_rate=refresh_rate if refresh_rate is not None else self.refresh_rate,
|
|
591
|
+
description=description,
|
|
577
592
|
show_throughput=show_throughput if show_throughput is not None else self.pbar_show_throughput,
|
|
578
593
|
show_progress=show_progress if show_progress is not None else self.pbar_show_progress,
|
|
579
594
|
)
|
|
@@ -589,7 +604,7 @@ class ProgressTableV1:
|
|
|
589
604
|
|
|
590
605
|
|
|
591
606
|
class TableProgressBar:
|
|
592
|
-
def __init__(self, iterable, *, table, total, level, refresh_rate, show_throughput, show_progress):
|
|
607
|
+
def __init__(self, iterable, *, table, total, level, refresh_rate, description, show_throughput, show_progress):
|
|
593
608
|
self.iterable: Iterable | None = iterable
|
|
594
609
|
|
|
595
610
|
self._step: int = 0
|
|
@@ -600,6 +615,7 @@ class TableProgressBar:
|
|
|
600
615
|
self.level: int = level
|
|
601
616
|
self.table: ProgressTableV1 = table
|
|
602
617
|
self.refresh_rate: int = refresh_rate
|
|
618
|
+
self.description: str = description
|
|
603
619
|
self.show_progress: bool = show_progress
|
|
604
620
|
self.show_throughput: bool = show_throughput
|
|
605
621
|
self._is_active: bool = True
|
|
@@ -618,13 +634,15 @@ class TableProgressBar:
|
|
|
618
634
|
throughput = self._step / time_passed if time_passed > 0 else 0.0
|
|
619
635
|
|
|
620
636
|
inside_infobar = []
|
|
621
|
-
if self.
|
|
622
|
-
inside_infobar.append(
|
|
637
|
+
if self.description:
|
|
638
|
+
inside_infobar.append(self.description)
|
|
623
639
|
if self.show_progress:
|
|
624
640
|
if self._total:
|
|
625
641
|
inside_infobar.append(f"{self._step}/{self._total}")
|
|
626
642
|
else:
|
|
627
643
|
inside_infobar.append(f"{self._step}")
|
|
644
|
+
if self.show_throughput:
|
|
645
|
+
inside_infobar.append(f"{throughput: <.2f} it/s")
|
|
628
646
|
infobar = "[" + ", ".join(inside_infobar) + "] " if inside_infobar else ""
|
|
629
647
|
|
|
630
648
|
pbar = ["\n" * self.level]
|
|
@@ -15,4 +15,6 @@ progress_table/v0/progress_table.py
|
|
|
15
15
|
progress_table/v0/symbols.py
|
|
16
16
|
progress_table/v1/__init__.py
|
|
17
17
|
progress_table/v1/progress_table.py
|
|
18
|
-
progress_table/v1/styles.py
|
|
18
|
+
progress_table/v1/styles.py
|
|
19
|
+
tests/test_docs_automated.py
|
|
20
|
+
tests/test_examples_automated.py
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Copyright (c) 2022-2024 Szymon Mikler
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import pathlib
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_header(msg):
|
|
10
|
+
msg_len = len(msg)
|
|
11
|
+
header = [
|
|
12
|
+
"#" * (msg_len + 6),
|
|
13
|
+
"## " + msg + " ##",
|
|
14
|
+
"#" * (msg_len + 6),
|
|
15
|
+
]
|
|
16
|
+
return "\n".join(header) + "\n"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def scan_for_code_blobs(text):
|
|
20
|
+
# Capture code blocks starting with py or python
|
|
21
|
+
blobs = re.findall(r"```(py|python)\n([\s\S]+?)\n```", text)
|
|
22
|
+
|
|
23
|
+
new_blobs = []
|
|
24
|
+
for mode, blob in blobs:
|
|
25
|
+
if "..." in blob:
|
|
26
|
+
continue
|
|
27
|
+
header = get_header(f"Generated ({mode})")
|
|
28
|
+
blob = header + blob
|
|
29
|
+
|
|
30
|
+
# For `py` code blocks, we append them to previous existing block
|
|
31
|
+
# But `python` block starts a new scope and finishes the previous block
|
|
32
|
+
# They usually need to include imports
|
|
33
|
+
if mode == "py" and new_blobs:
|
|
34
|
+
new_blobs[-1] = new_blobs[-1] + "\n" + blob
|
|
35
|
+
else:
|
|
36
|
+
new_blobs.append(blob)
|
|
37
|
+
return new_blobs
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_all_code_blobs():
|
|
41
|
+
# Testing whether code blobs from the documentation run without errors
|
|
42
|
+
all_code_blobs = []
|
|
43
|
+
|
|
44
|
+
for root, dirs, files in os.walk(""):
|
|
45
|
+
for file in files:
|
|
46
|
+
path = pathlib.Path(os.path.join(root, file))
|
|
47
|
+
if path.suffix == ".md":
|
|
48
|
+
code_blobs = scan_for_code_blobs(path.open("r").read())
|
|
49
|
+
for blob in code_blobs:
|
|
50
|
+
all_code_blobs.append(blob)
|
|
51
|
+
|
|
52
|
+
logging.warning(f"Detected {len(all_code_blobs)} code examples!")
|
|
53
|
+
|
|
54
|
+
for idx, blob in enumerate(all_code_blobs):
|
|
55
|
+
try:
|
|
56
|
+
globals_temp = {}
|
|
57
|
+
exec(blob, globals_temp)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
print(f"Exception during automated documentation testing {idx}/{len(all_code_blobs)}:")
|
|
60
|
+
print(blob)
|
|
61
|
+
raise e
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright (c) 2022-2024 Szymon Mikler
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import importlib
|
|
5
|
+
import random
|
|
6
|
+
import sys
|
|
7
|
+
from glob import glob
|
|
8
|
+
from io import StringIO
|
|
9
|
+
|
|
10
|
+
EXPECTED_OUTPUTS = {
|
|
11
|
+
"examples.nn_training": "7e50cfd539e3e1799ecd5a7e7b7a7e18",
|
|
12
|
+
"examples.cumulating": "b5b7bc9b8232545ebfd5ca777bddacb4",
|
|
13
|
+
"examples.fibonacci": "bae5411af4bf8a4326f1bce59ca9aad9",
|
|
14
|
+
"examples.features": "474d4aff94a3070d2300d78d4159e0a6",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def set_seed():
|
|
19
|
+
random.seed(42)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def capture_example_stdout(main_fn):
|
|
23
|
+
# To eliminate run to run variation of the example outputs we need to be independent from the execution speed
|
|
24
|
+
# This includes removing the influence of:
|
|
25
|
+
# * refresh rate
|
|
26
|
+
# * throughput display
|
|
27
|
+
override_kwds = dict(
|
|
28
|
+
refresh_rate=1000000000,
|
|
29
|
+
pbar_show_throughput=False,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# We will replace stdout with custom StringIO and check whether example stdout is as expected
|
|
33
|
+
out_buffer = StringIO()
|
|
34
|
+
sys.stdout = out_buffer
|
|
35
|
+
set_seed()
|
|
36
|
+
main_fn(**override_kwds)
|
|
37
|
+
sys.stdout = sys.__stdout__
|
|
38
|
+
return out_buffer.getvalue()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_all_examples():
|
|
42
|
+
# Testing whether examples run exactly as intended
|
|
43
|
+
|
|
44
|
+
outputs = {}
|
|
45
|
+
for module in glob("examples/*"):
|
|
46
|
+
module = module.replace(".py", "").replace("/", ".")
|
|
47
|
+
print(f"Running example: {module}")
|
|
48
|
+
main_fn = importlib.import_module(module).main
|
|
49
|
+
out_str = capture_example_stdout(main_fn)
|
|
50
|
+
|
|
51
|
+
md5hash = hashlib.md5(out_str.encode()).hexdigest()
|
|
52
|
+
outputs[module] = md5hash
|
|
53
|
+
|
|
54
|
+
err_msg = []
|
|
55
|
+
for key in EXPECTED_OUTPUTS:
|
|
56
|
+
output = outputs.get(key, None)
|
|
57
|
+
expected = EXPECTED_OUTPUTS[key]
|
|
58
|
+
if output != expected:
|
|
59
|
+
err_msg.append(f" {output} instead of {expected} in {key}")
|
|
60
|
+
err_msg = "\n".join(err_msg)
|
|
61
|
+
|
|
62
|
+
if err_msg:
|
|
63
|
+
assert False, f"Errors in example outputs\n{err_msg}"
|
|
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
|