This is a python rewrite of my ruby tool progressor, so some of the code and examples might not feel pythonic. It may change over time as I use it more.
Basic example
Here's an example long-running task:
for product in fetch_products():
if product.not_something_we_want_to_process():
continue
product.calculate_interesting_stats()
In order to understand how it's progressing, we might add some print statements:
for product in fetch_products():
if product.not_something_we_want_to_process():
print(f"Skipping product: {product.id}")
continue
print(f"Working on product: {product.id}")
product.calculate_interesting_stats()
This gives us some indication of progress, but no idea how much time is left. We could take a count and maintain a manual index, and then eyeball it based on how fast the numbers are adding up. LongTask automates that process:
long_task = LongTask(total_count=Product.count())
for product in fetch_products():
if product.not_something_we_want_to_process():
long_task.skip(1)
continue
with long_task.measure() as progress:
print(f"[{progress} Working on product: {product.id}")
product.calculate_interesting_stats()
Each invocation of measure measures how long its block took and records it. The progress parameter is an object that can be converted to a string to provide progress information.
The output might look like this:
...
[0038/1000, (004%), t/i: 0.5s, ETA: 8m:00s] Product 38
[0039/1000, (004%), t/i: 0.5s, ETA: 7m:58s] Product 39
[0040/1000, (004%), t/i: 0.5s, ETA: 7m:57s] Product 40
...
You can check the documentation for the LongTask class for details on the methods you can call to get the individual pieces of data shown in the report.
Limited and unlimited sequences
Initializing a LongTask with a provided total_count= parameter gives you a limited sequence, which can give you not only a progress report, but an estimation of when it'll be done:
[<current loop>/<total count>, (<progress>%), t/i: <time per iteration>, ETA: <time until it's done>]
The calculation is done by maintaining a list of measurements with a limited size, and a list of averages of those measurements. The average of averages is the "time per iteration" and it's multiplied by the remaining count to produce the estimation.
I can't really say how reliable this is, but it seems to provide smoothly changing estimations that seem more or less correct to me, for similarly-sized chunks of work per iteration.
Not providing a total_count= parameter leads to less available information:
long_task = LongTask()
for _ in range(100):
with long_task.measure() as progress:
print(progress)
time.sleep(random.random())
A sample of output might look like this:
...
11, t: 5.32s, t/i: 442.39ms
12, t: 5.58s, t/i: 446.11ms
...
The format is:
<current>, t: <time from start>, t/i: <time per iteration>
Configuration
Apart from total_count, which is optional and affects the kind of sequence that will be stored, you can provide min_samples and max_samples. You can also provide a custom formatter:
long_task = LongTask(
total_count=1000,
min_samples=5,
max_samples=10,
formatter=lambda p: p.eta()
)
The option min_samples determines how many loops the tool will wait until trying to produce an estimation. A higher number means no information in the beginning, but no wild fluctuations, either. It needs to be at least 1 and the default is 1.
The option max_samples is how many measurements will be retained. Those measurements will be averaged, and then those averages averaged to get a time-per-iteration estimate. A smaller number means giving more weight to later events, while a larger one would average over a larger amount of samples. The default is 100.
The formatter is a callback that gets a progress object as an argument and you can return your own string to output on every loop. Check LimitedSequence and UnlimitedSequence for the available methods and accessors you can use.
Related work
This project is based on my ruby tool progressor. In terms of other python libraries, there seem to be a few:
- ProgressPrinter shows an animated progress bar, which likely means it moves the cursor on top when outputting its progress. This project just gives you a string to print, which could sit in logs, inbetween other output, etc.
- longtask gives you a different interface where you create a separate class to encapsulate your long-running task.
- progressor uses scikit to estimate the remaining time and shows an animated progress bar
Metadata
Release files for long_task_printer 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| long_task_printer-0.1.2.tar.gz | 6.3 kB | Without provenance | Details for long_task_printer-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| long_task_printer-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for long_task_printer-0.1.2-py3-none-any.whl |
Total release size: 15.1 kB
Release files / long_task_printer-0.1.2.tar.gz
| Download URL | long_task_printer-0.1.2.tar.gz |
|---|---|
| Size | 6.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b4fc6a876f58580f2b01bdea2624a03c9bcca9eb90b8bb363eb8bbf635feb27a
|
|
BLAKE2b-256 checksum How to use checksums |
0c91a6d0819be2336dc98cdc8d9be564bd97e7f24e718cad2bcbffcbe3dd40c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.4 CPython/3.12.7 Linux/6.12.1-arch1-1
|
Release files / long_task_printer-0.1.2-py3-none-any.whl
| Download URL | long_task_printer-0.1.2-py3-none-any.whl |
|---|---|
| Size | 8.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5eaa71c9c736aa1fb32cdf0f2bd1abaddc6a612bbfd2c213577c86bdcd293a96
|
|
BLAKE2b-256 checksum How to use checksums |
8644b3768d6f0c91f7ef1d5b727ecab6d2bf94a65102522d8cdd9fd76a6076f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.4 CPython/3.12.7 Linux/6.12.1-arch1-1
|
Security for long_task_printer 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.