progress-table 1.2.5__tar.gz → 1.3.1__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.
Files changed (22) hide show
  1. {progress-table-1.2.5 → progress-table-1.3.1}/PKG-INFO +1 -1
  2. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table/__init__.py +2 -2
  3. progress-table-1.3.1/progress_table/v0/__init__.py +1 -0
  4. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table/v0/progress_table.py +9 -1
  5. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table/v0/symbols.py +2 -0
  6. progress-table-1.3.1/progress_table/v1/__init__.py +1 -0
  7. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table/v1/progress_table.py +44 -22
  8. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table/v1/styles.py +3 -0
  9. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table.egg-info/PKG-INFO +1 -1
  10. progress-table-1.3.1/progress_table.egg-info/PKG-INFO.sync-conflict-20240314-015933-NXTV2IO +151 -0
  11. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table.egg-info/SOURCES.txt +1 -1
  12. {progress-table-1.2.5 → progress-table-1.3.1}/setup.py +2 -2
  13. progress-table-1.2.5/progress_table/test_docs_automated.py +0 -60
  14. progress-table-1.2.5/progress_table/v0/__init__.py +0 -0
  15. progress-table-1.2.5/progress_table/v1/__init__.py +0 -0
  16. {progress-table-1.2.5 → progress-table-1.3.1}/LICENSE.txt +0 -0
  17. {progress-table-1.2.5 → progress-table-1.3.1}/README.md +0 -0
  18. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table.egg-info/dependency_links.txt +0 -0
  19. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table.egg-info/requires.txt +0 -0
  20. {progress-table-1.2.5 → progress-table-1.3.1}/progress_table.egg-info/top_level.txt +0 -0
  21. {progress-table-1.2.5 → progress-table-1.3.1}/pyproject.toml +0 -0
  22. {progress-table-1.2.5 → progress-table-1.3.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: progress-table
3
- Version: 1.2.5
3
+ Version: 1.3.1
4
4
  Summary: Display progress as a pretty table in the command line.
5
5
  Home-page: https://github.com/gahaalt/progress-table.git
6
6
  Author: Szymon Mikler
@@ -1,6 +1,6 @@
1
- # Copyright (c) 2022 Szymon Mikler
1
+ # Copyright (c) 2022-2024 Szymon Mikler
2
2
 
3
- __version__ = "1.2.5"
3
+ __version__ = "1.3.1"
4
4
 
5
5
  from progress_table.v0.progress_table import ProgressTableV0
6
6
  from progress_table.v1.progress_table import ProgressTableV1
@@ -0,0 +1 @@
1
+ # Copyright (c) 2022-2024 Szymon Mikler
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2022 Szymon Mikler
1
+ # Copyright (c) 2022-2024 Szymon Mikler
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -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
@@ -1,3 +1,5 @@
1
+ # Copyright (c) 2022-2024 Szymon Mikler
2
+
1
3
  from dataclasses import dataclass
2
4
 
3
5
 
@@ -0,0 +1 @@
1
+ # Copyright (c) 2022-2024 Szymon Mikler
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2022 Szymon Mikler
1
+ # Copyright (c) 2022-2024 Szymon Mikler
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -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.new_row_cumulated_weight: dict[str, int] = {}
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, iterable, **kwds):
291
+ def add_columns(self, *columns, **kwds):
292
292
  """Add multiple columns to the table."""
293
- for column in iterable:
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.new_row_cumulated_weight.setdefault(key, 0)
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.new_row_cumulated_weight[key])
311
- self.new_row_cumulated_weight[key] += weight
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
- self._active_pbars[0].display() # Level 0 pbar is embedded into the row, if it exists we want to display it instead of a row
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.show_throughput:
622
- inside_infobar.append(f"{throughput: <.2f} it/s")
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]
@@ -659,13 +677,17 @@ class TableProgressBar:
659
677
  total = len(row)
660
678
  step = self._step % total
661
679
 
662
- new_row = []
680
+ new_row = [Style.BRIGHT]
663
681
  for letter_idx, letter in enumerate(row):
664
- if letter == " ":
665
- if letter_idx / len(row) <= (step / total) % (1 + EPS):
666
- letter = self.table.table_style.embedded_pbar_filled
667
- elif (letter_idx - 1) / len(row) <= (step / total) % (1 + EPS):
668
- letter = self.table.table_style.embedded_pbar_head
682
+ is_bar = letter_idx / len(row) <= (step / total) % (1 + EPS)
683
+ is_head = (letter_idx - 1) / len(row) <= (step / total) % (1 + EPS)
684
+ if letter == " " and is_bar:
685
+ letter = self.table.table_style.embedded_pbar_filled
686
+ if letter == " " and is_head:
687
+ letter = self.table.table_style.embedded_pbar_head
688
+
689
+ if not is_bar and not is_head:
690
+ new_row.append(Style.RESET_ALL)
669
691
  new_row.append(letter)
670
692
  pbar.extend(new_row)
671
693
  pbar.append(CURSOR_UP * self.level)
@@ -1,3 +1,6 @@
1
+ # Copyright (c) 2022-2024 Szymon Mikler
2
+
3
+
1
4
  class StyleNormal:
2
5
  name = "normal"
3
6
  pbar_filled = "■"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: progress-table
3
- Version: 1.2.5
3
+ Version: 1.3.1
4
4
  Summary: Display progress as a pretty table in the command line.
5
5
  Home-page: https://github.com/gahaalt/progress-table.git
6
6
  Author: Szymon Mikler
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.1
2
+ Name: progress-table
3
+ Version: 1.2.3
4
+ Summary: Display progress as a pretty table in the command line.
5
+ Home-page: https://github.com/gahaalt/progress-table.git
6
+ Author: Szymon Mikler
7
+ Author-email: sjmikler@gmail.com
8
+ License: MIT
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.7
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Python: >=3.7
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE.txt
20
+
21
+ > Note: versions 1.X introduced new features and changes of default behaviour.
22
+ >
23
+ > The old version is still available as `progress_table.ProgressTableV0`.
24
+ >
25
+ > New features include:
26
+ > * Nested progress bar support
27
+ > * Custom table styles support
28
+ > * Color customization on row level support
29
+ > * Adding columns automatically, without calling `add_column`
30
+ > * Continuous progress bar when iterator length is unknown
31
+ > * Pandas and numpy being only optional dependencies
32
+ > * Other minor changes
33
+
34
+ # Progress Table
35
+
36
+ [![PyPi version](https://img.shields.io/badge/dynamic/json?label=latest&query=info.version&url=https%3A%2F%2Fpypi.org%2Fpypi%2Fprogress-table%2Fjson)](https://pypi.org/project/progress-table)
37
+ [![PyPI license](https://img.shields.io/badge/dynamic/json?label=license&query=info.license&url=https%3A%2F%2Fpypi.org%2Fpypi%2Fprogress-table%2Fjson)](https://pypi.org/project/progress-table)
38
+
39
+ Lightweight utility to display the progress of your process as a pretty table in the command line.
40
+ Alternative to TQDM whenever you want to track metrics produced by your process.
41
+
42
+ ![example](https://github.com/gahaalt/progress-table/blob/main/images/progress-table-example.png?raw=true)
43
+
44
+ Designed to monitor machine learning experiments, but can be used for any metrics-producing process.
45
+ Allows you to quickly see what's going on with your process.
46
+ Increases readability and simplifies your command line logging.
47
+
48
+ ## Purpose
49
+
50
+ Change this:
51
+
52
+ ![example](https://github.com/gahaalt/progress-table/blob/main/images/progress-before3.gif?raw=true)
53
+
54
+ Into this:
55
+
56
+ ![example](https://github.com/gahaalt/progress-table/blob/main/images/progress-after4.gif?raw=true)
57
+
58
+ ## Example
59
+
60
+ > Click here for examples of integration with deep learning libraries:
61
+ > [integrations.md](https://github.com/gahaalt/progress-table/blob/main/integrations.md).
62
+
63
+ ```python
64
+ import random
65
+ import sys
66
+ import time
67
+
68
+ from progress_table import ProgressTable
69
+
70
+ # Create table object:
71
+ table = ProgressTable()
72
+
73
+ # Or customize its settings:
74
+ table = ProgressTable(
75
+ columns=["step"],
76
+ refresh_rate=20,
77
+ num_decimal_places=4,
78
+ default_column_width=None,
79
+ default_column_color=None,
80
+ default_column_alignment=None,
81
+ default_column_aggregate=None,
82
+ default_row_color=None,
83
+ embedded_progress_bar=True,
84
+ pbar_show_throughput=True,
85
+ pbar_show_progress=False,
86
+ print_row_on_update=True,
87
+ reprint_header_every_n_rows=30,
88
+ custom_format=None,
89
+ table_style="round",
90
+ file=sys.stdout,
91
+ )
92
+
93
+ # You (optionally) define the columns at the beginning
94
+ table.add_column("x", width=3)
95
+ table.add_column("x root", color="red")
96
+ table.add_column("random average", color=["bright", "red"], aggregate="mean")
97
+
98
+ for step in range(10):
99
+ x = random.randint(0, 200)
100
+
101
+ # There are two ways to add new values:
102
+ table["x"] = x
103
+ table["step"] = step
104
+ # Second:
105
+ table.update("x root", x ** 0.5)
106
+ table.update("x squared", x ** 2)
107
+
108
+ # Display the progress bar by wrapping the iterator
109
+ for _ in table(10): # -> Equivalent to `table(range(10))`
110
+ # You can use weights for aggregated values
111
+ table.update("random average", random.random(), weight=1)
112
+ time.sleep(0.1)
113
+
114
+ # Go to the next row when you're ready
115
+ table.next_row()
116
+
117
+ # Close the table when it's ready
118
+ table.close()
119
+
120
+ # Export your data
121
+ data = table.to_list()
122
+ pandas_df = table.to_df() # Requires pandas to be installed
123
+ np_array = table.to_numpy() # Requires numpy to be installed
124
+ ```
125
+
126
+ ![example](https://github.com/gahaalt/progress-table/blob/main/images/example-output4.gif?raw=true)
127
+
128
+ ## Installation
129
+
130
+ Install Progress Table easily with pip:
131
+
132
+ ```
133
+ pip install progress-table
134
+ ```
135
+
136
+ ## Links
137
+
138
+ * [See on GitHub](https://github.com/gahaalt/progress-table)
139
+ * [See on PyPI](https://pypi.org/project/progress-table)
140
+
141
+ ## Alternatives
142
+
143
+ * Progress bars: great for tracking progress, but they don't provide ways to display data in clear and compact way
144
+ * `tqdm`
145
+ * `rich.progress`
146
+ * `keras.utils.Progbar`
147
+
148
+ * Libraries displaying data: great for presenting tabular data, but they lack the progress tracking aspect
149
+ * `rich.table`
150
+ * `tabulate`
151
+ * `texttable`
@@ -4,8 +4,8 @@ pyproject.toml
4
4
  setup.cfg
5
5
  setup.py
6
6
  progress_table/__init__.py
7
- progress_table/test_docs_automated.py
8
7
  progress_table.egg-info/PKG-INFO
8
+ progress_table.egg-info/PKG-INFO.sync-conflict-20240314-015933-NXTV2IO
9
9
  progress_table.egg-info/SOURCES.txt
10
10
  progress_table.egg-info/dependency_links.txt
11
11
  progress_table.egg-info/requires.txt
@@ -1,8 +1,8 @@
1
- # Copyright (c) 2022 Szymon Mikler
1
+ # Copyright (c) 2022-2024 Szymon Mikler
2
2
 
3
3
  from pathlib import Path
4
4
 
5
- from setuptools import setup, find_packages
5
+ from setuptools import find_packages, setup
6
6
 
7
7
 
8
8
  def package_relative_path(path):
@@ -1,60 +0,0 @@
1
- # Copyright (c) 2022 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
- all_code_blobs = []
42
-
43
- for root, dirs, files in os.walk("."):
44
- for file in files:
45
- path = pathlib.Path(os.path.join(root, file))
46
- if path.suffix == ".md":
47
- code_blobs = scan_for_code_blobs(path.open("r").read())
48
- for blob in code_blobs:
49
- all_code_blobs.append(blob)
50
-
51
- logging.warning(f"Detected {len(all_code_blobs)} code examples!")
52
-
53
- for idx, blob in enumerate(all_code_blobs):
54
- try:
55
- globals_temp = {}
56
- exec(blob, globals_temp)
57
- except Exception as e:
58
- print(f"Exception during automated documentation testing {idx}/{len(all_code_blobs)}:")
59
- print(blob)
60
- raise e
File without changes
File without changes
File without changes
File without changes