cs-progress 20250306__tar.gz → 20250412__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cs-progress
3
- Version: 20250306
3
+ Version: 20250412
4
4
  Summary: A progress tracker with methods for throughput, ETA and update notification; also a compound progress meter composed from other progress meters.
5
5
  Keywords: python2,python3
6
6
  Author-email: Cameron Simpson <cs@cskk.id.au>
@@ -13,10 +13,11 @@ Classifier: Operating System :: OS Independent
13
13
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
14
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
15
15
  Requires-Dist: cs.deco>=20250306
16
- Requires-Dist: cs.logutils>=20250306
16
+ Requires-Dist: cs.logutils>=20250323
17
17
  Requires-Dist: cs.py.func>=20240630
18
+ Requires-Dist: cs.resources>=20250325
18
19
  Requires-Dist: cs.seq>=20250306
19
- Requires-Dist: cs.threads>=20250306
20
+ Requires-Dist: cs.threads>=20250325
20
21
  Requires-Dist: cs.units
21
22
  Requires-Dist: cs.upd>=20240630
22
23
  Requires-Dist: icontract
@@ -29,26 +30,20 @@ Project-URL: Source, https://github.com/cameron-simpson/css/blob/main/lib/python
29
30
  A progress tracker with methods for throughput, ETA and update notification;
30
31
  also a compound progress meter composed from other progress meters.
31
32
 
32
- *Latest release 20250306*:
33
- * Progress: new .qbar() method to make a progress bar and return a queue on which to put items to track.
34
- * progressbar: return the iterable unchanged if upd is None or disabled.
35
- * BaseProgress.iterbar: new optional cancelled parameter for a cancellation test callable, passed through by progressbar etc.
36
-
37
- ## <a name="auto_progressbar"></a>`auto_progressbar(*da, **dkw)`
38
-
39
- Decorator for a function accepting an optional `progress`
40
- keyword parameter.
41
- If `progress` is not `None` and the default `Upd` is not disabled,
42
- run the function with a progress bar.
43
-
44
- ## <a name="BaseProgress"></a>Class `BaseProgress`
33
+ *Latest release 20250412*:
34
+ Bugfix progressbar: fix early return if no active Upd.
45
35
 
46
- The base class for `Progress` and `OverProcess`
47
- with various common methods.
36
+ Module contents:
37
+ - <a name="auto_progressbar"></a>`auto_progressbar(*da, **dkw)`: Decorator for a function accepting an optional `progress`
38
+ keyword parameter.
39
+ If `progress` is not `None` and the default `Upd` is not disabled,
40
+ run the function with a progress bar.
41
+ - <a name="BaseProgress"></a>`Class `BaseProgress`: The base class for `Progress` and `OverProcess`
42
+ with various common methods.
48
43
 
49
- Note that durations are in seconds
50
- and that absolute time is in seconds since the UNIX epoch
51
- (the basis of `time.time()`).
44
+ Note that durations are in seconds
45
+ and that absolute time is in seconds since the UNIX epoch
46
+ (the basis of `time.time()`).
52
47
 
53
48
  *`BaseProgress.__init__(self, name=None, start_time=None, units_scale=None)`*:
54
49
  Initialise a progress instance.
@@ -83,7 +78,7 @@ if its position is less than `int(other)`.
83
78
  Construct a progress arrow representing completion
84
79
  to fit in the specified `width`.
85
80
 
86
- *`BaseProgress.bar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x1057109a0>, **kw)`*:
81
+ *`BaseProgress.bar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10c191da0>, **kw)`*:
87
82
  A context manager to create and withdraw a progress bar.
88
83
  It returns the `UpdProxy` which displays the progress bar.
89
84
 
@@ -130,7 +125,7 @@ If `remaining_time` is `None`, this is also `None`.
130
125
  Format `value` accoridng to `scale` and `max_parts`
131
126
  using `cs.units.transcribe`.
132
127
 
133
- *`BaseProgress.iterbar(self, it, label=None, *, itemlenfunc=None, incfirst=False, update_period=0.3, cancelled=None, **bar_kw)`*:
128
+ *`BaseProgress.iterbar(self, it, label=None, *, itemlenfunc=None, incfirst=False, update_period=0.3, cancelled=None, runstate: Optional[cs.resources.RunState] = <function uses_runstate.<locals>.<lambda> at 0x10c192200>, **bar_kw)`*:
134
129
  An iterable progress bar: a generator yielding values
135
130
  from the iterable `it` while updating a progress bar.
136
131
 
@@ -243,55 +238,52 @@ during `elapsed_time`.
243
238
 
244
239
  *`BaseProgress.throughput_recent(self, time_window)`*:
245
240
  The recent throughput. Implemented by subclasses.
241
+ - <a name="CheckPoint"></a>`Class `CheckPoint(builtins.tuple)`: CheckPoint(time, position)
246
242
 
247
- ## <a name="CheckPoint"></a>Class `CheckPoint(builtins.tuple)`
248
-
249
- CheckPoint(time, position)
243
+ *`CheckPoint.__replace__(self, /, **kwds)`*:
244
+ Return a new CheckPoint object replacing specified fields with new values
250
245
 
251
246
  *`CheckPoint.position`*:
252
247
  Alias for field number 1
253
248
 
254
249
  *`CheckPoint.time`*:
255
250
  Alias for field number 0
256
-
257
- ## <a name="OverProgress"></a>Class `OverProgress(BaseProgress)`
258
-
259
- A `Progress`-like class computed from a set of subsidiary `Progress`es.
260
-
261
- AN OverProgress instance has an attribute ``notify_update`` which
262
- is a set of callables.
263
- Whenever the position of a subsidiary `Progress` is updated,
264
- each of these will be called with the `Progress` instance and `None`.
265
-
266
- Example:
267
-
268
- >>> P = OverProgress(name="over")
269
- >>> P1 = Progress(name="progress1", position=12)
270
- >>> P1.total = 100
271
- >>> P1.advance(7)
272
- >>> P2 = Progress(name="progress2", position=20)
273
- >>> P2.total = 50
274
- >>> P2.advance(9)
275
- >>> P.add(P1)
276
- >>> P.add(P2)
277
- >>> P1.total
278
- 100
279
- >>> P2.total
280
- 50
281
- >>> P.total
282
- 150
283
- >>> P1.start
284
- 12
285
- >>> P2.start
286
- 20
287
- >>> P.start
288
- 0
289
- >>> P1.position
290
- 19
291
- >>> P2.position
292
- 29
293
- >>> P.position
294
- 16
251
+ - <a name="OverProgress"></a>`Class `OverProgress(BaseProgress)`: A `Progress`-like class computed from a set of subsidiary `Progress`es.
252
+
253
+ AN OverProgress instance has an attribute ``notify_update`` which
254
+ is a set of callables.
255
+ Whenever the position of a subsidiary `Progress` is updated,
256
+ each of these will be called with the `Progress` instance and `None`.
257
+
258
+ Example:
259
+
260
+ >>> P = OverProgress(name="over")
261
+ >>> P1 = Progress(name="progress1", position=12)
262
+ >>> P1.total = 100
263
+ >>> P1.advance(7)
264
+ >>> P2 = Progress(name="progress2", position=20)
265
+ >>> P2.total = 50
266
+ >>> P2.advance(9)
267
+ >>> P.add(P1)
268
+ >>> P.add(P2)
269
+ >>> P1.total
270
+ 100
271
+ >>> P2.total
272
+ 50
273
+ >>> P.total
274
+ 150
275
+ >>> P1.start
276
+ 12
277
+ >>> P2.start
278
+ 20
279
+ >>> P.start
280
+ 0
281
+ >>> P1.position
282
+ 19
283
+ >>> P2.position
284
+ 29
285
+ >>> P.position
286
+ 16
295
287
 
296
288
  *`OverProgress.add(self, subprogress)`*:
297
289
  Add a subsidairy `Progress` to the contributing set.
@@ -317,46 +309,43 @@ The `throughput_recent` is the sum of the subsidiary throughput_recentss.
317
309
 
318
310
  *`OverProgress.total`*:
319
311
  The `total` is the sum of the subsidiary totals.
320
-
321
- ## <a name="Progress"></a>Class `Progress(BaseProgress)`
322
-
323
- A progress counter to track task completion with various utility methods.
324
-
325
- Example:
326
-
327
- >>> P = Progress(name="example")
328
- >>> P #doctest: +ELLIPSIS
329
- Progress(name='example',start=0,position=0,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0)]
330
- >>> P.advance(5)
331
- >>> P #doctest: +ELLIPSIS
332
- Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
333
- >>> P.total = 100
334
- >>> P #doctest: +ELLIPSIS
335
- Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=100):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
336
-
337
- A Progress instance has an attribute ``notify_update`` which
338
- is a set of callables. Whenever the position is updated, each
339
- of these will be called with the `Progress` instance and the
340
- latest `CheckPoint`.
341
-
342
- `Progress` objects also make a small pretense of being an integer.
343
- The expression `int(progress)` returns the current position,
344
- and `+=` and `-=` adjust the position.
345
-
346
- This is convenient for coding, but importantly it is also
347
- useful for discretionary use of a Progress with some other
348
- object.
349
- If you want to make a lightweight `Progress` capable class
350
- you can set a position attribute to an `int`
351
- and manipulate it carefully using `+=` and `-=` entirely.
352
- If you decide to incur the cost of maintaining a `Progress` object
353
- you can slot it in:
354
-
355
- # initial setup with just an int
356
- my_thing.amount = 0
357
-
358
- # later, or on some option, use a Progress instance
359
- my_thing.amount = Progress(my_thing.amount)
312
+ - <a name="Progress"></a>`Class `Progress(BaseProgress)`: A progress counter to track task completion with various utility methods.
313
+
314
+ Example:
315
+
316
+ >>> P = Progress(name="example")
317
+ >>> P #doctest: +ELLIPSIS
318
+ Progress(name='example',start=0,position=0,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0)]
319
+ >>> P.advance(5)
320
+ >>> P #doctest: +ELLIPSIS
321
+ Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
322
+ >>> P.total = 100
323
+ >>> P #doctest: +ELLIPSIS
324
+ Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=100):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
325
+
326
+ A Progress instance has an attribute ``notify_update`` which
327
+ is a set of callables. Whenever the position is updated, each
328
+ of these will be called with the `Progress` instance and the
329
+ latest `CheckPoint`.
330
+
331
+ `Progress` objects also make a small pretense of being an integer.
332
+ The expression `int(progress)` returns the current position,
333
+ and `+=` and `-=` adjust the position.
334
+
335
+ This is convenient for coding, but importantly it is also
336
+ useful for discretionary use of a Progress with some other
337
+ object.
338
+ If you want to make a lightweight `Progress` capable class
339
+ you can set a position attribute to an `int`
340
+ and manipulate it carefully using `+=` and `-=` entirely.
341
+ If you decide to incur the cost of maintaining a `Progress` object
342
+ you can slot it in:
343
+
344
+ # initial setup with just an int
345
+ my_thing.amount = 0
346
+
347
+ # later, or on some option, use a Progress instance
348
+ my_thing.amount = Progress(my_thing.amount)
360
349
 
361
350
  *`Progress.__init__(self, name: Optional[str] = None, *, position: Optional[float] = None, start: Optional[float] = None, start_time: Optional[float] = None, throughput_window: Optional[int] = None, total: Optional[float] = None, units_scale=None)`*:
362
351
  Initialise the Progesss object.
@@ -444,39 +433,39 @@ Record more progress.
444
433
  >>> P.update(12)
445
434
  >>> P.position
446
435
  12
436
+ - <a name="progressbar"></a>`progressbar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10c193c40>, **kw)`: Convenience function to construct and run a `Progress.iterbar`
437
+ wrapping the iterable `it`,
438
+ issuing and withdrawing a progress bar during the iteration.
447
439
 
448
- ## <a name="progressbar"></a>`progressbar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x105712660>, **kw)`
440
+ Parameters:
441
+ * `it`: the iterable to consume
442
+ * `label`: optional label, doubles as the `Progress.name`
443
+ * `position`: optional starting position
444
+ * `total`: optional value for `Progress.total`,
445
+ default from `len(it)` if supported.
446
+ * `units_scale`: optional units scale for `Progress`,
447
+ default `UNSCALED_SCALE`
449
448
 
450
- Convenience function to construct and run a `Progress.iterbar`
451
- wrapping the iterable `it`,
452
- issuing and withdrawing a progress bar during the iteration.
449
+ If `total` is `None` and `it` supports `len()`
450
+ then the `Progress.total` is set from it.
453
451
 
454
- Parameters:
455
- * `it`: the iterable to consume
456
- * `label`: optional label, doubles as the `Progress.name`
457
- * `position`: optional starting position
458
- * `total`: optional value for `Progress.total`,
459
- default from `len(it)` if supported.
460
- * `units_scale`: optional units scale for `Progress`,
461
- default `UNSCALED_SCALE`
462
-
463
- If `total` is `None` and `it` supports `len()`
464
- then the `Progress.total` is set from it.
465
-
466
- All arguments are passed through to `Progress.iterbar`.
452
+ All arguments are passed through to `Progress.iterbar`.
467
453
 
468
- Example use:
454
+ Example use:
469
455
 
470
- for row in progressbar(rows):
471
- ... do something with row ...
456
+ for row in progressbar(rows):
457
+ ... do something with row ...
458
+ - <a name="selftest"></a>`selftest(argv)`: Exercise some of the functionality.
472
459
 
473
- ## <a name="selftest"></a>`selftest(argv)`
460
+ # Release Log
474
461
 
475
- Exercise some of the functionality.
476
462
 
477
- # Release Log
478
463
 
464
+ *Release 20250412*:
465
+ Bugfix progressbar: fix early return if no active Upd.
479
466
 
467
+ *Release 20250325*:
468
+ BaseProgress.iterbar: use @uses_runstate, accept a runstate parameter overridable by the cancelled param.
480
469
 
481
470
  *Release 20250306*:
482
471
  * Progress: new .qbar() method to make a progress bar and return a queue on which to put items to track.
@@ -10,10 +10,11 @@ keywords = [
10
10
  ]
11
11
  dependencies = [
12
12
  "cs.deco>=20250306",
13
- "cs.logutils>=20250306",
13
+ "cs.logutils>=20250323",
14
14
  "cs.py.func>=20240630",
15
+ "cs.resources>=20250325",
15
16
  "cs.seq>=20250306",
16
- "cs.threads>=20250306",
17
+ "cs.threads>=20250325",
17
18
  "cs.units",
18
19
  "cs.upd>=20240630",
19
20
  "icontract",
@@ -28,7 +29,7 @@ classifiers = [
28
29
  "Topic :: Software Development :: Libraries :: Python Modules",
29
30
  "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
30
31
  ]
31
- version = "20250306"
32
+ version = "20250412"
32
33
 
33
34
  [project.license]
34
35
  text = "GNU General Public License v3 or later (GPLv3+)"
@@ -44,26 +45,20 @@ text = """
44
45
  A progress tracker with methods for throughput, ETA and update notification;
45
46
  also a compound progress meter composed from other progress meters.
46
47
 
47
- *Latest release 20250306*:
48
- * Progress: new .qbar() method to make a progress bar and return a queue on which to put items to track.
49
- * progressbar: return the iterable unchanged if upd is None or disabled.
50
- * BaseProgress.iterbar: new optional cancelled parameter for a cancellation test callable, passed through by progressbar etc.
51
-
52
- ## <a name=\"auto_progressbar\"></a>`auto_progressbar(*da, **dkw)`
53
-
54
- Decorator for a function accepting an optional `progress`
55
- keyword parameter.
56
- If `progress` is not `None` and the default `Upd` is not disabled,
57
- run the function with a progress bar.
58
-
59
- ## <a name=\"BaseProgress\"></a>Class `BaseProgress`
48
+ *Latest release 20250412*:
49
+ Bugfix progressbar: fix early return if no active Upd.
60
50
 
61
- The base class for `Progress` and `OverProcess`
62
- with various common methods.
51
+ Module contents:
52
+ - <a name=\"auto_progressbar\"></a>`auto_progressbar(*da, **dkw)`: Decorator for a function accepting an optional `progress`
53
+ keyword parameter.
54
+ If `progress` is not `None` and the default `Upd` is not disabled,
55
+ run the function with a progress bar.
56
+ - <a name=\"BaseProgress\"></a>`Class `BaseProgress`: The base class for `Progress` and `OverProcess`
57
+ with various common methods.
63
58
 
64
- Note that durations are in seconds
65
- and that absolute time is in seconds since the UNIX epoch
66
- (the basis of `time.time()`).
59
+ Note that durations are in seconds
60
+ and that absolute time is in seconds since the UNIX epoch
61
+ (the basis of `time.time()`).
67
62
 
68
63
  *`BaseProgress.__init__(self, name=None, start_time=None, units_scale=None)`*:
69
64
  Initialise a progress instance.
@@ -98,7 +93,7 @@ if its position is less than `int(other)`.
98
93
  Construct a progress arrow representing completion
99
94
  to fit in the specified `width`.
100
95
 
101
- *`BaseProgress.bar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x1057109a0>, **kw)`*:
96
+ *`BaseProgress.bar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10c191da0>, **kw)`*:
102
97
  A context manager to create and withdraw a progress bar.
103
98
  It returns the `UpdProxy` which displays the progress bar.
104
99
 
@@ -145,7 +140,7 @@ If `remaining_time` is `None`, this is also `None`.
145
140
  Format `value` accoridng to `scale` and `max_parts`
146
141
  using `cs.units.transcribe`.
147
142
 
148
- *`BaseProgress.iterbar(self, it, label=None, *, itemlenfunc=None, incfirst=False, update_period=0.3, cancelled=None, **bar_kw)`*:
143
+ *`BaseProgress.iterbar(self, it, label=None, *, itemlenfunc=None, incfirst=False, update_period=0.3, cancelled=None, runstate: Optional[cs.resources.RunState] = <function uses_runstate.<locals>.<lambda> at 0x10c192200>, **bar_kw)`*:
149
144
  An iterable progress bar: a generator yielding values
150
145
  from the iterable `it` while updating a progress bar.
151
146
 
@@ -258,55 +253,52 @@ during `elapsed_time`.
258
253
 
259
254
  *`BaseProgress.throughput_recent(self, time_window)`*:
260
255
  The recent throughput. Implemented by subclasses.
256
+ - <a name=\"CheckPoint\"></a>`Class `CheckPoint(builtins.tuple)`: CheckPoint(time, position)
261
257
 
262
- ## <a name=\"CheckPoint\"></a>Class `CheckPoint(builtins.tuple)`
263
-
264
- CheckPoint(time, position)
258
+ *`CheckPoint.__replace__(self, /, **kwds)`*:
259
+ Return a new CheckPoint object replacing specified fields with new values
265
260
 
266
261
  *`CheckPoint.position`*:
267
262
  Alias for field number 1
268
263
 
269
264
  *`CheckPoint.time`*:
270
265
  Alias for field number 0
271
-
272
- ## <a name=\"OverProgress\"></a>Class `OverProgress(BaseProgress)`
273
-
274
- A `Progress`-like class computed from a set of subsidiary `Progress`es.
275
-
276
- AN OverProgress instance has an attribute ``notify_update`` which
277
- is a set of callables.
278
- Whenever the position of a subsidiary `Progress` is updated,
279
- each of these will be called with the `Progress` instance and `None`.
280
-
281
- Example:
282
-
283
- >>> P = OverProgress(name=\"over\")
284
- >>> P1 = Progress(name=\"progress1\", position=12)
285
- >>> P1.total = 100
286
- >>> P1.advance(7)
287
- >>> P2 = Progress(name=\"progress2\", position=20)
288
- >>> P2.total = 50
289
- >>> P2.advance(9)
290
- >>> P.add(P1)
291
- >>> P.add(P2)
292
- >>> P1.total
293
- 100
294
- >>> P2.total
295
- 50
296
- >>> P.total
297
- 150
298
- >>> P1.start
299
- 12
300
- >>> P2.start
301
- 20
302
- >>> P.start
303
- 0
304
- >>> P1.position
305
- 19
306
- >>> P2.position
307
- 29
308
- >>> P.position
309
- 16
266
+ - <a name=\"OverProgress\"></a>`Class `OverProgress(BaseProgress)`: A `Progress`-like class computed from a set of subsidiary `Progress`es.
267
+
268
+ AN OverProgress instance has an attribute ``notify_update`` which
269
+ is a set of callables.
270
+ Whenever the position of a subsidiary `Progress` is updated,
271
+ each of these will be called with the `Progress` instance and `None`.
272
+
273
+ Example:
274
+
275
+ >>> P = OverProgress(name=\"over\")
276
+ >>> P1 = Progress(name=\"progress1\", position=12)
277
+ >>> P1.total = 100
278
+ >>> P1.advance(7)
279
+ >>> P2 = Progress(name=\"progress2\", position=20)
280
+ >>> P2.total = 50
281
+ >>> P2.advance(9)
282
+ >>> P.add(P1)
283
+ >>> P.add(P2)
284
+ >>> P1.total
285
+ 100
286
+ >>> P2.total
287
+ 50
288
+ >>> P.total
289
+ 150
290
+ >>> P1.start
291
+ 12
292
+ >>> P2.start
293
+ 20
294
+ >>> P.start
295
+ 0
296
+ >>> P1.position
297
+ 19
298
+ >>> P2.position
299
+ 29
300
+ >>> P.position
301
+ 16
310
302
 
311
303
  *`OverProgress.add(self, subprogress)`*:
312
304
  Add a subsidairy `Progress` to the contributing set.
@@ -332,46 +324,43 @@ The `throughput_recent` is the sum of the subsidiary throughput_recentss.
332
324
 
333
325
  *`OverProgress.total`*:
334
326
  The `total` is the sum of the subsidiary totals.
335
-
336
- ## <a name=\"Progress\"></a>Class `Progress(BaseProgress)`
337
-
338
- A progress counter to track task completion with various utility methods.
339
-
340
- Example:
341
-
342
- >>> P = Progress(name=\"example\")
343
- >>> P #doctest: +ELLIPSIS
344
- Progress(name='example',start=0,position=0,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0)]
345
- >>> P.advance(5)
346
- >>> P #doctest: +ELLIPSIS
347
- Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
348
- >>> P.total = 100
349
- >>> P #doctest: +ELLIPSIS
350
- Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=100):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
351
-
352
- A Progress instance has an attribute ``notify_update`` which
353
- is a set of callables. Whenever the position is updated, each
354
- of these will be called with the `Progress` instance and the
355
- latest `CheckPoint`.
356
-
357
- `Progress` objects also make a small pretense of being an integer.
358
- The expression `int(progress)` returns the current position,
359
- and `+=` and `-=` adjust the position.
360
-
361
- This is convenient for coding, but importantly it is also
362
- useful for discretionary use of a Progress with some other
363
- object.
364
- If you want to make a lightweight `Progress` capable class
365
- you can set a position attribute to an `int`
366
- and manipulate it carefully using `+=` and `-=` entirely.
367
- If you decide to incur the cost of maintaining a `Progress` object
368
- you can slot it in:
369
-
370
- # initial setup with just an int
371
- my_thing.amount = 0
372
-
373
- # later, or on some option, use a Progress instance
374
- my_thing.amount = Progress(my_thing.amount)
327
+ - <a name=\"Progress\"></a>`Class `Progress(BaseProgress)`: A progress counter to track task completion with various utility methods.
328
+
329
+ Example:
330
+
331
+ >>> P = Progress(name=\"example\")
332
+ >>> P #doctest: +ELLIPSIS
333
+ Progress(name='example',start=0,position=0,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0)]
334
+ >>> P.advance(5)
335
+ >>> P #doctest: +ELLIPSIS
336
+ Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=None):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
337
+ >>> P.total = 100
338
+ >>> P #doctest: +ELLIPSIS
339
+ Progress(name='example',start=0,position=5,start_time=...,throughput_window=None,total=100):[CheckPoint(time=..., position=0), CheckPoint(time=..., position=5)]
340
+
341
+ A Progress instance has an attribute ``notify_update`` which
342
+ is a set of callables. Whenever the position is updated, each
343
+ of these will be called with the `Progress` instance and the
344
+ latest `CheckPoint`.
345
+
346
+ `Progress` objects also make a small pretense of being an integer.
347
+ The expression `int(progress)` returns the current position,
348
+ and `+=` and `-=` adjust the position.
349
+
350
+ This is convenient for coding, but importantly it is also
351
+ useful for discretionary use of a Progress with some other
352
+ object.
353
+ If you want to make a lightweight `Progress` capable class
354
+ you can set a position attribute to an `int`
355
+ and manipulate it carefully using `+=` and `-=` entirely.
356
+ If you decide to incur the cost of maintaining a `Progress` object
357
+ you can slot it in:
358
+
359
+ # initial setup with just an int
360
+ my_thing.amount = 0
361
+
362
+ # later, or on some option, use a Progress instance
363
+ my_thing.amount = Progress(my_thing.amount)
375
364
 
376
365
  *`Progress.__init__(self, name: Optional[str] = None, *, position: Optional[float] = None, start: Optional[float] = None, start_time: Optional[float] = None, throughput_window: Optional[int] = None, total: Optional[float] = None, units_scale=None)`*:
377
366
  Initialise the Progesss object.
@@ -459,39 +448,39 @@ Record more progress.
459
448
  >>> P.update(12)
460
449
  >>> P.position
461
450
  12
451
+ - <a name=\"progressbar\"></a>`progressbar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x10c193c40>, **kw)`: Convenience function to construct and run a `Progress.iterbar`
452
+ wrapping the iterable `it`,
453
+ issuing and withdrawing a progress bar during the iteration.
462
454
 
463
- ## <a name=\"progressbar\"></a>`progressbar(*a, upd: Optional[cs.upd.Upd] = <function uses_upd.<locals>.<lambda> at 0x105712660>, **kw)`
455
+ Parameters:
456
+ * `it`: the iterable to consume
457
+ * `label`: optional label, doubles as the `Progress.name`
458
+ * `position`: optional starting position
459
+ * `total`: optional value for `Progress.total`,
460
+ default from `len(it)` if supported.
461
+ * `units_scale`: optional units scale for `Progress`,
462
+ default `UNSCALED_SCALE`
464
463
 
465
- Convenience function to construct and run a `Progress.iterbar`
466
- wrapping the iterable `it`,
467
- issuing and withdrawing a progress bar during the iteration.
464
+ If `total` is `None` and `it` supports `len()`
465
+ then the `Progress.total` is set from it.
468
466
 
469
- Parameters:
470
- * `it`: the iterable to consume
471
- * `label`: optional label, doubles as the `Progress.name`
472
- * `position`: optional starting position
473
- * `total`: optional value for `Progress.total`,
474
- default from `len(it)` if supported.
475
- * `units_scale`: optional units scale for `Progress`,
476
- default `UNSCALED_SCALE`
477
-
478
- If `total` is `None` and `it` supports `len()`
479
- then the `Progress.total` is set from it.
480
-
481
- All arguments are passed through to `Progress.iterbar`.
467
+ All arguments are passed through to `Progress.iterbar`.
482
468
 
483
- Example use:
469
+ Example use:
484
470
 
485
- for row in progressbar(rows):
486
- ... do something with row ...
471
+ for row in progressbar(rows):
472
+ ... do something with row ...
473
+ - <a name=\"selftest\"></a>`selftest(argv)`: Exercise some of the functionality.
487
474
 
488
- ## <a name=\"selftest\"></a>`selftest(argv)`
475
+ # Release Log
489
476
 
490
- Exercise some of the functionality.
491
477
 
492
- # Release Log
493
478
 
479
+ *Release 20250412*:
480
+ Bugfix progressbar: fix early return if no active Upd.
494
481
 
482
+ *Release 20250325*:
483
+ BaseProgress.iterbar: use @uses_runstate, accept a runstate parameter overridable by the cancelled param.
495
484
 
496
485
  *Release 20250306*:
497
486
  * Progress: new .qbar() method to make a progress bar and return a queue on which to put items to track.
@@ -25,6 +25,7 @@ from cs.deco import decorator, uses_quiet
25
25
  from cs.logutils import debug, exception
26
26
  from cs.py.func import funcname
27
27
  from cs.queues import IterableQueue, QueueIterator
28
+ from cs.resources import RunState, uses_runstate
28
29
  from cs.seq import seq
29
30
  from cs.threads import bg
30
31
  from cs.units import (
@@ -37,7 +38,7 @@ from cs.units import (
37
38
  )
38
39
  from cs.upd import Upd, uses_upd, print # pylint: disable=redefined-builtin
39
40
 
40
- __version__ = '20250306'
41
+ __version__ = '20250412'
41
42
 
42
43
  DISTINFO = {
43
44
  'keywords': ["python2", "python3"],
@@ -49,6 +50,7 @@ DISTINFO = {
49
50
  'cs.deco',
50
51
  'cs.logutils',
51
52
  'cs.py.func',
53
+ 'cs.resources',
52
54
  'cs.seq',
53
55
  'cs.threads',
54
56
  'cs.units',
@@ -493,6 +495,7 @@ class BaseProgress(object):
493
495
  )
494
496
 
495
497
  # pylint: disable=too-many-arguments,too-many-branches,too-many-locals
498
+ @uses_runstate
496
499
  def iterbar(
497
500
  self,
498
501
  it,
@@ -502,6 +505,7 @@ class BaseProgress(object):
502
505
  incfirst=False,
503
506
  update_period=DEFAULT_UPDATE_PERIOD,
504
507
  cancelled=None,
508
+ runstate: RunState,
505
509
  **bar_kw,
506
510
  ):
507
511
  ''' An iterable progress bar: a generator yielding values
@@ -547,6 +551,8 @@ class BaseProgress(object):
547
551
  for bs in P.iterbar(readfrom(f), itemlenfunc=len):
548
552
  ... process the file data in bs ...
549
553
  '''
554
+ if cancelled is None:
555
+ cancelled = lambda: runstate.cancelled
550
556
  with self.bar(label, update_period=update_period, **bar_kw) as proxy:
551
557
  for item in it:
552
558
  if cancelled and cancelled():
@@ -1065,15 +1071,16 @@ def progressbar(
1065
1071
  ... do something with row ...
1066
1072
  '''
1067
1073
  if upd is None or upd.disabled:
1068
- return it
1069
- if total is None:
1070
- try:
1071
- total = len(it)
1072
- except TypeError:
1073
- total = None
1074
- yield from Progress(
1075
- name=label, position=position, total=total, units_scale=units_scale
1076
- ).iterbar(it, **iterbar_kw)
1074
+ yield from it
1075
+ else:
1076
+ if total is None:
1077
+ try:
1078
+ total = len(it)
1079
+ except TypeError:
1080
+ total = None
1081
+ yield from Progress(
1082
+ name=label, position=position, total=total, units_scale=units_scale
1083
+ ).iterbar(it, **iterbar_kw)
1077
1084
 
1078
1085
  @decorator
1079
1086
  def auto_progressbar(func, label=None, report_print=False):