about-time


Nameabout-time JSON
Version 4.2.1 PyPI version JSON
download
home_pagehttps://github.com/rsalmei/about-time
SummaryEasily measure timing and throughput of code blocks, with beautiful human friendly representations.
upload_time2022-12-21 04:15:54
maintainer
docs_urlNone
authorRogério Sampaio de Almeida
requires_python>=3.7, <4
licenseMIT
keywords python track tracker time code blocks monitor statistics analytics
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [<img align="right" src="https://cdn.buymeacoffee.com/buttons/default-orange.png" width="217px" height="51x">](https://www.buymeacoffee.com/rsalmei)
[<img align="right" alt="Donate with PayPal button" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif">](https://www.paypal.com/donate?business=6SWSHEB5ZNS5N&no_recurring=0&item_name=I%27m+the+author+of+alive-progress%2C+clearly+and+about-time.+Thank+you+for+appreciating+my+work%21&currency_code=USD)

# about-time
### A cool helper for tracking time and throughput of code blocks, with beautiful human friendly renditions.

[![Coverage](https://img.shields.io/badge/coverage-100%25-green.svg)]()
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/rsalmei/about-time/graphs/commit-activity)
[![PyPI version](https://img.shields.io/pypi/v/about-time.svg)](https://pypi.python.org/pypi/about-time/)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/about-time.svg)](https://pypi.python.org/pypi/about-time/)
[![PyPI status](https://img.shields.io/pypi/status/about-time.svg)](https://pypi.python.org/pypi/about-time/)
[![PyPI Downloads](https://pepy.tech/badge/about-time)](https://pepy.tech/project/about-time)

## What does it do?

Did you ever need to measure the duration of an operation? Yeah, this is easy.

But how to:
- measure the duration of two or more blocks at the same time, including the whole duration?
- instrument a code to cleanly retrieve durations in one line, to log or send to time series databases?
- easily see human friendly durations in *s* (seconds), *ms* (milliseconds), *µs* (microseconds) and even *ns* (nanoseconds)?
- easily see human friendly counts with SI prefixes like *k*, *M*, *G*, *T*, etc?
- measure the actual throughput of a block? (this is way harder, since it needs to measure both duration and number of iterations)
- easily see human friendly throughputs in "/second", "/minute", "/hour" or even "/day", including SI prefixes?

Yes, it can get tricky! More interesting details about [duration](https://github.com/rsalmei/about-time#the-human-duration-magic) and [throughput](https://github.com/rsalmei/about-time#the-human-throughput-magic).
<br>If you'd tried to do it without these magic, it would probably get messy and immensely pollute the code being instrumented.

I have the solution, behold!

```python
from about_time import about_time


def some_func():
    import time
    time.sleep(85e-3)
    return True


def main():
    with about_time() as t1:  # <-- use it like a context manager!

        t2 = about_time(some_func)  # <-- use it with any callable!!

        t3 = about_time(x * 2 for x in range(56789))  # <-- use it with any iterable or generator!!!
        data = [x for x in t3]  # then just iterate!

    print(f'total: {t1.duration_human}')
    print(f'  some_func: {t2.duration_human} -> result: {t2.result}')
    print(f'  generator: {t3.duration_human} -> {t3.count_human} elements, throughput: {t3.throughput_human}')
```

This `main()` function prints:
```
total: 95.6ms
  some_func: 89.7ms -> result: True
  generator: 5.79ms -> 56.8k elements, throughput: 9.81M/s
```

How cool is that? 😲👏

You can also get the duration in seconds if needed:
```
In [7]: t1.duration
Out[7]: 0.09556673200064251
```
But `95.6ms` is way better, isn't it? The same with `count` and `throughput`!

So, `about_time` measures code blocks, both time and throughput, and converts them to beautiful human friendly representations! 👏


## Get it

Just install with pip:

```bash
❯ pip install about-time
```


## Use it

There are three modes of operation: context manager, callable and throughput. Let's dive in.


### 1. Use it like a context manager:

```python
from about_time import about_time

with about_time() as t:
    # the code to be measured...
    # any lenghty block.

print(f'The whole block took: {t.duration_human}')
```

This way you can nicely wrap any amount of code.

> In this mode, there are the basic fields `duration` and `duration_human`.


### 2. Use it with any callable:

```python
from about_time import about_time

t = about_time(some_func)

print(f'The whole block took: {t.duration_human}')
print(f'And the result was: {t.result}')

```

This way you have a nice one liner, and do not need to increase the indent of your code.

> In this mode, there is an additional field `result`, with the return of the callable.

If the callable have params, you can use a `lambda` or (📌 new) simply send them:

```python
def add(n, m):
    return n + m

t = about_time(add, 1, 41)
# or:
t = about_time(add, n=1, m=41)
# or even:
t = about_time(lambda: add(1, 41))

```


### 3. Use it with any iterable or generator:

```python
from about_time import about_time

t = about_time(iterable)
for item in t:
    # process item.

print(f'The whole block took: {t.duration_human}')
print(f'It was detected {t.count_human} elements')
print(f'The throughput was: {t.throughput_human}')
```

This way `about_time` also extracts the number of iterations, and with the measured duration it calculates the throughput of the whole loop! It's especially useful with generators, which do not have length.

> In this mode, there are the additional fields `count`, `count_human`, `throughput` and `throughput_human`.

Cool tricks under the hood:
- you can use it even with generator expressions, anything that is iterable to python!
- you can consume it not only in a `for` loop, but also in { list | dict | set } comprehensions, `map()`s, `filter()`s, `sum()`s, `max()`s, `list()`s, etc, thus any function that expects an iterator! 👏
- the timer only starts when the first element is queried, so you can initialize whatever you need before entering the loop! 👏
- the `count`/`count_human` and `throughput`/`throughput_human` fields are updated in **real time**, so you can use them even inside the loop!


## Features:

According to the SI standard, there are 1000 bytes in a `kilobyte`.
<br>There is another standard called IEC that has 1024 bytes in a `kibibyte`, but this is only useful when measuring things that are naturally a power of two, e.g. a stick of RAM.

Be careful to not render IEC quantities with SI scaling, which would be incorrect. But I still support it, if you really want to ;)

By default, this will use SI, `1000` divisor, and `no space` between values and scales/units. SI uses prefixes: `k`, `M`, `G`, `T`, `P`, `E`, `Z`, and `Y`.

These are the optional features:
- `iec` => use IEC instead of SI: `Ki`, `Mi`, `Gi`, `Ti`, `Pi`, `Ei`, `Zi`, `Yi` (implies `1024`);
- `1024` => use `1024` divisor — if `iec` is not enabled, use prefixes: `K`, `M`, `G`, `T`, `P`, `E`, `Z`, and `Y` (note the upper 'K');
- `space` => include a space between values and scales/units everywhere: `48 B` instead of `48B`, `15.6 µs` instead of `15.6µs`, and `12.4 kB/s` instead of `12.4kB/s`.

To change them, just use the properties:

```python
from about_time import FEATURES

FEATURES.feature_1024
FEATURES.feature_iec
FEATURES.feature_space
```

For example, to enable spaces between scales/units:
```python
from about_time import FEATURES
FEATURES.feature_space = True
```

## The human duration magic

I've used just one key concept in designing the human duration features: cleanliness.
> `3.44s` is more meaningful than `3.43584783784s`, and `14.1us` is much nicer than `.0000141233333s`.

So what I do is: round values to at most two decimal places (three significant digits), and find the best scale unit to represent them, minimizing resulting values smaller than `1`. The search for the best unit considers even the rounding been applied!
> `0.000999999` does not end up as `999.99us` (truncate) nor `1000.0us` (bad unit), but is auto-upgraded to the next unit `1.0ms`!

The `duration_human` units change seamlessly from nanoseconds to hours.
  - values smaller than 60 seconds are always rendered as "num.D[D]unit", with one or two decimals;
  - from 1 minute onward it changes to "H:MM:SS".

It feels much more humane, humm? ;)

Some examples:

| duration (float seconds) | duration_human |
|:------------------------:|:--------------:|
|       .00000000185       |    '1.85ns'    |
|      .000000999996       |    '1.00µs'    |
|          .00001          |    '10.0µs'    |
|         .0000156         |    '15.6µs'    |
|           .01            |    '10.0ms'    |
|      .0141233333333      |    '14.1ms'    |
|         .1099999         |    '110ms'     |
|         .1599999         |    '160ms'     |
|          .8015           |    '802ms'     |
|         3.434999         |    '3.43s'     |
|          59.999          |   '0:01:00'    |
|           68.5           |   '0:01:08'    |
|         125.825          |   '0:02:05'    |
|         4488.395         |   '1:14:48'    |


## The human throughput magic

I've made the `throughput_human` with a similar logic. It is funny how much trickier "throughput" is to the human brain!
> If something took `1165263 seconds` to handle `123 items`, how fast did it go? It's not obvious...

It doesn't help even if we divide the duration by the number of items, `9473 seconds/item`, which still does not mean much. How fast was that? We can't say.
<br>How many items did we do per time unit?
> Oh, we just need to invert it, so `0,000105555569858 items/second`, there it is! 😂

To make some sense of it we need to multiply that by 3600 (seconds in an hour) to get `0.38/h`, which is much better, and again by 24 (hours in a day) to finally get `9.12/d`!! Now we know how fast that process was! \o/ As you see, it's not easy at all.

The `throughput_human` unit changes seamlessly from per-second, per-minute, per-hour, and per-day.
<br>It also automatically inserts SI-prefixes, like k, M, and G. 👍

| duration (float seconds) | number of elements | throughput_human |
|:------------------------:|:------------------:|:----------------:|
|           1\.            |         10         |     '10.0/s'     |
|           1\.            |        2500        |    '2.50k/s'     |
|           1\.            |      1825000       |    '1.82M/s'     |
|           2\.            |         1          |     '30.0/m'     |
|           2\.            |         10         |     '5.00/s'     |
|    1.981981981981982     |         11         |     '5.55/s'     |
|          100\.           |         10         |     '6.00/m'     |
|          1600\.          |         3          |     '6.75/h'     |
|           .99            |         1          |     '1.01/s'     |
|        1165263\.         |        123         |     '9.12/d'     |


## Accuracy

`about_time` supports all versions of python, but in pythons >= `3.3` it performs even better, with much higher resolution and smaller propagation of errors, thanks to the new `time.perf_counter`. In older versions, it uses `time.time` as usual.


## Changelog highlights:
- 4.2.1: makes fixed precision actually gain more resolution, when going from a default 1 to 2 decimals
- 4.2.0: support for fixed precision, useful when one needs output without varying lengths; official Python 3.11 support
- 4.1.0: enable to cache features within closures, to improve performance for https://github.com/rsalmei/alive-progress
- 4.0.0: new version, modeled after my Rust implementation in https://crates.io/crates/human-repr; includes new global features, new objects for each operation, and especially, new simpler human friendly representations; supports Python 3.7+
- 3.3.0: new interfaces for count_human and throughput_human; support more common Kbyte for base 2 (1024), leaving IEC one as an alternate
- 3.2.2: support IEC kibibyte standard for base 2 (1024)
- 3.2.1: support divisor in throughput_human
- 3.2.0: both durations and throughputs now use 3 significant digits; throughputs now include SI-prefixes
- 3.1.1: make `duration_human()` and `throughput_human()` available for external use
- 3.1.0: include support for parameters in callable mode; official support for python 3.8, 3.9 and 3.10
- 3.0.0: greatly improved the counter/throughput mode, with a single argument and working in real time
- 2.0.0: feature complete, addition of callable and throughput modes
- 1.0.0: first public release, context manager mode


## License
This software is licensed under the MIT License. See the LICENSE file in the top distribution directory for the full license text.


---
Maintaining an open source project is hard and time-consuming, and I've put much ❤️ and effort into this.

If you've appreciated my work, you can back me up with a donation! Thank you 😊

[<img align="right" src="https://cdn.buymeacoffee.com/buttons/default-orange.png" width="217px" height="51x">](https://www.buymeacoffee.com/rsalmei)
[<img align="right" alt="Donate with PayPal button" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif">](https://www.paypal.com/donate?business=6SWSHEB5ZNS5N&no_recurring=0&item_name=I%27m+the+author+of+alive-progress%2C+clearly+and+about-time.+Thank+you+for+appreciating+my+work%21&currency_code=USD)

---



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/rsalmei/about-time",
    "name": "about-time",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7, <4",
    "maintainer_email": "",
    "keywords": "python,track,tracker,time,code,blocks,monitor,statistics,analytics",
    "author": "Rog\u00e9rio Sampaio de Almeida",
    "author_email": "rsalmei@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/1c/3f/ccb16bdc53ebb81c1bf837c1ee4b5b0b69584fd2e4a802a2a79936691c0a/about-time-4.2.1.tar.gz",
    "platform": null,
    "description": "[<img align=\"right\" src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" width=\"217px\" height=\"51x\">](https://www.buymeacoffee.com/rsalmei)\n[<img align=\"right\" alt=\"Donate with PayPal button\" src=\"https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif\">](https://www.paypal.com/donate?business=6SWSHEB5ZNS5N&no_recurring=0&item_name=I%27m+the+author+of+alive-progress%2C+clearly+and+about-time.+Thank+you+for+appreciating+my+work%21&currency_code=USD)\n\n# about-time\n### A cool helper for tracking time and throughput of code blocks, with beautiful human friendly renditions.\n\n[![Coverage](https://img.shields.io/badge/coverage-100%25-green.svg)]()\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/rsalmei/about-time/graphs/commit-activity)\n[![PyPI version](https://img.shields.io/pypi/v/about-time.svg)](https://pypi.python.org/pypi/about-time/)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/about-time.svg)](https://pypi.python.org/pypi/about-time/)\n[![PyPI status](https://img.shields.io/pypi/status/about-time.svg)](https://pypi.python.org/pypi/about-time/)\n[![PyPI Downloads](https://pepy.tech/badge/about-time)](https://pepy.tech/project/about-time)\n\n## What does it do?\n\nDid you ever need to measure the duration of an operation? Yeah, this is easy.\n\nBut how to:\n- measure the duration of two or more blocks at the same time, including the whole duration?\n- instrument a code to cleanly retrieve durations in one line, to log or send to time series databases?\n- easily see human friendly durations in *s* (seconds), *ms* (milliseconds), *\u00b5s* (microseconds) and even *ns* (nanoseconds)?\n- easily see human friendly counts with SI prefixes like *k*, *M*, *G*, *T*, etc?\n- measure the actual throughput of a block? (this is way harder, since it needs to measure both duration and number of iterations)\n- easily see human friendly throughputs in \"/second\", \"/minute\", \"/hour\" or even \"/day\", including SI prefixes?\n\nYes, it can get tricky! More interesting details about [duration](https://github.com/rsalmei/about-time#the-human-duration-magic) and [throughput](https://github.com/rsalmei/about-time#the-human-throughput-magic).\n<br>If you'd tried to do it without these magic, it would probably get messy and immensely pollute the code being instrumented.\n\nI have the solution, behold!\n\n```python\nfrom about_time import about_time\n\n\ndef some_func():\n    import time\n    time.sleep(85e-3)\n    return True\n\n\ndef main():\n    with about_time() as t1:  # <-- use it like a context manager!\n\n        t2 = about_time(some_func)  # <-- use it with any callable!!\n\n        t3 = about_time(x * 2 for x in range(56789))  # <-- use it with any iterable or generator!!!\n        data = [x for x in t3]  # then just iterate!\n\n    print(f'total: {t1.duration_human}')\n    print(f'  some_func: {t2.duration_human} -> result: {t2.result}')\n    print(f'  generator: {t3.duration_human} -> {t3.count_human} elements, throughput: {t3.throughput_human}')\n```\n\nThis `main()` function prints:\n```\ntotal: 95.6ms\n  some_func: 89.7ms -> result: True\n  generator: 5.79ms -> 56.8k elements, throughput: 9.81M/s\n```\n\nHow cool is that? \ud83d\ude32\ud83d\udc4f\n\nYou can also get the duration in seconds if needed:\n```\nIn [7]: t1.duration\nOut[7]: 0.09556673200064251\n```\nBut `95.6ms` is way better, isn't it? The same with `count` and `throughput`!\n\nSo, `about_time` measures code blocks, both time and throughput, and converts them to beautiful human friendly representations! \ud83d\udc4f\n\n\n## Get it\n\nJust install with pip:\n\n```bash\n\u276f pip install about-time\n```\n\n\n## Use it\n\nThere are three modes of operation: context manager, callable and throughput. Let's dive in.\n\n\n### 1. Use it like a context manager:\n\n```python\nfrom about_time import about_time\n\nwith about_time() as t:\n    # the code to be measured...\n    # any lenghty block.\n\nprint(f'The whole block took: {t.duration_human}')\n```\n\nThis way you can nicely wrap any amount of code.\n\n> In this mode, there are the basic fields `duration` and `duration_human`.\n\n\n### 2. Use it with any callable:\n\n```python\nfrom about_time import about_time\n\nt = about_time(some_func)\n\nprint(f'The whole block took: {t.duration_human}')\nprint(f'And the result was: {t.result}')\n\n```\n\nThis way you have a nice one liner, and do not need to increase the indent of your code.\n\n> In this mode, there is an additional field `result`, with the return of the callable.\n\nIf the callable have params, you can use a `lambda` or (\ud83d\udccc new) simply send them:\n\n```python\ndef add(n, m):\n    return n + m\n\nt = about_time(add, 1, 41)\n# or:\nt = about_time(add, n=1, m=41)\n# or even:\nt = about_time(lambda: add(1, 41))\n\n```\n\n\n### 3. Use it with any iterable or generator:\n\n```python\nfrom about_time import about_time\n\nt = about_time(iterable)\nfor item in t:\n    # process item.\n\nprint(f'The whole block took: {t.duration_human}')\nprint(f'It was detected {t.count_human} elements')\nprint(f'The throughput was: {t.throughput_human}')\n```\n\nThis way `about_time` also extracts the number of iterations, and with the measured duration it calculates the throughput of the whole loop! It's especially useful with generators, which do not have length.\n\n> In this mode, there are the additional fields `count`, `count_human`, `throughput` and `throughput_human`.\n\nCool tricks under the hood:\n- you can use it even with generator expressions, anything that is iterable to python!\n- you can consume it not only in a `for` loop, but also in { list | dict | set } comprehensions, `map()`s, `filter()`s, `sum()`s, `max()`s, `list()`s, etc, thus any function that expects an iterator! \ud83d\udc4f\n- the timer only starts when the first element is queried, so you can initialize whatever you need before entering the loop! \ud83d\udc4f\n- the `count`/`count_human` and `throughput`/`throughput_human` fields are updated in **real time**, so you can use them even inside the loop!\n\n\n## Features:\n\nAccording to the SI standard, there are 1000 bytes in a `kilobyte`.\n<br>There is another standard called IEC that has 1024 bytes in a `kibibyte`, but this is only useful when measuring things that are naturally a power of two, e.g. a stick of RAM.\n\nBe careful to not render IEC quantities with SI scaling, which would be incorrect. But I still support it, if you really want to ;)\n\nBy default, this will use SI, `1000` divisor, and `no space` between values and scales/units. SI uses prefixes: `k`, `M`, `G`, `T`, `P`, `E`, `Z`, and `Y`.\n\nThese are the optional features:\n- `iec` => use IEC instead of SI: `Ki`, `Mi`, `Gi`, `Ti`, `Pi`, `Ei`, `Zi`, `Yi` (implies `1024`);\n- `1024` => use `1024` divisor \u2014 if `iec` is not enabled, use prefixes: `K`, `M`, `G`, `T`, `P`, `E`, `Z`, and `Y` (note the upper 'K');\n- `space` => include a space between values and scales/units everywhere: `48 B` instead of `48B`, `15.6 \u00b5s` instead of `15.6\u00b5s`, and `12.4 kB/s` instead of `12.4kB/s`.\n\nTo change them, just use the properties:\n\n```python\nfrom about_time import FEATURES\n\nFEATURES.feature_1024\nFEATURES.feature_iec\nFEATURES.feature_space\n```\n\nFor example, to enable spaces between scales/units:\n```python\nfrom about_time import FEATURES\nFEATURES.feature_space = True\n```\n\n## The human duration magic\n\nI've used just one key concept in designing the human duration features: cleanliness.\n> `3.44s` is more meaningful than `3.43584783784s`, and `14.1us` is much nicer than `.0000141233333s`.\n\nSo what I do is: round values to at most two decimal places (three significant digits), and find the best scale unit to represent them, minimizing resulting values smaller than `1`. The search for the best unit considers even the rounding been applied!\n> `0.000999999` does not end up as `999.99us` (truncate) nor `1000.0us` (bad unit), but is auto-upgraded to the next unit `1.0ms`!\n\nThe `duration_human` units change seamlessly from nanoseconds to hours.\n  - values smaller than 60 seconds are always rendered as \"num.D[D]unit\", with one or two decimals;\n  - from 1 minute onward it changes to \"H:MM:SS\".\n\nIt feels much more humane, humm? ;)\n\nSome examples:\n\n| duration (float seconds) | duration_human |\n|:------------------------:|:--------------:|\n|       .00000000185       |    '1.85ns'    |\n|      .000000999996       |    '1.00\u00b5s'    |\n|          .00001          |    '10.0\u00b5s'    |\n|         .0000156         |    '15.6\u00b5s'    |\n|           .01            |    '10.0ms'    |\n|      .0141233333333      |    '14.1ms'    |\n|         .1099999         |    '110ms'     |\n|         .1599999         |    '160ms'     |\n|          .8015           |    '802ms'     |\n|         3.434999         |    '3.43s'     |\n|          59.999          |   '0:01:00'    |\n|           68.5           |   '0:01:08'    |\n|         125.825          |   '0:02:05'    |\n|         4488.395         |   '1:14:48'    |\n\n\n## The human throughput magic\n\nI've made the `throughput_human` with a similar logic. It is funny how much trickier \"throughput\" is to the human brain!\n> If something took `1165263 seconds` to handle `123 items`, how fast did it go? It's not obvious...\n\nIt doesn't help even if we divide the duration by the number of items, `9473 seconds/item`, which still does not mean much. How fast was that? We can't say.\n<br>How many items did we do per time unit?\n> Oh, we just need to invert it, so `0,000105555569858 items/second`, there it is! \ud83d\ude02\n\nTo make some sense of it we need to multiply that by 3600 (seconds in an hour) to get `0.38/h`, which is much better, and again by 24 (hours in a day) to finally get `9.12/d`!! Now we know how fast that process was! \\o/ As you see, it's not easy at all.\n\nThe `throughput_human` unit changes seamlessly from per-second, per-minute, per-hour, and per-day.\n<br>It also automatically inserts SI-prefixes, like k, M, and G. \ud83d\udc4d\n\n| duration (float seconds) | number of elements | throughput_human |\n|:------------------------:|:------------------:|:----------------:|\n|           1\\.            |         10         |     '10.0/s'     |\n|           1\\.            |        2500        |    '2.50k/s'     |\n|           1\\.            |      1825000       |    '1.82M/s'     |\n|           2\\.            |         1          |     '30.0/m'     |\n|           2\\.            |         10         |     '5.00/s'     |\n|    1.981981981981982     |         11         |     '5.55/s'     |\n|          100\\.           |         10         |     '6.00/m'     |\n|          1600\\.          |         3          |     '6.75/h'     |\n|           .99            |         1          |     '1.01/s'     |\n|        1165263\\.         |        123         |     '9.12/d'     |\n\n\n## Accuracy\n\n`about_time` supports all versions of python, but in pythons >= `3.3` it performs even better, with much higher resolution and smaller propagation of errors, thanks to the new `time.perf_counter`. In older versions, it uses `time.time` as usual.\n\n\n## Changelog highlights:\n- 4.2.1: makes fixed precision actually gain more resolution, when going from a default 1 to 2 decimals\n- 4.2.0: support for fixed precision, useful when one needs output without varying lengths; official Python 3.11 support\n- 4.1.0: enable to cache features within closures, to improve performance for https://github.com/rsalmei/alive-progress\n- 4.0.0: new version, modeled after my Rust implementation in https://crates.io/crates/human-repr; includes new global features, new objects for each operation, and especially, new simpler human friendly representations; supports Python 3.7+\n- 3.3.0: new interfaces for count_human and throughput_human; support more common Kbyte for base 2 (1024), leaving IEC one as an alternate\n- 3.2.2: support IEC kibibyte standard for base 2 (1024)\n- 3.2.1: support divisor in throughput_human\n- 3.2.0: both durations and throughputs now use 3 significant digits; throughputs now include SI-prefixes\n- 3.1.1: make `duration_human()` and `throughput_human()` available for external use\n- 3.1.0: include support for parameters in callable mode; official support for python 3.8, 3.9 and 3.10\n- 3.0.0: greatly improved the counter/throughput mode, with a single argument and working in real time\n- 2.0.0: feature complete, addition of callable and throughput modes\n- 1.0.0: first public release, context manager mode\n\n\n## License\nThis software is licensed under the MIT License. See the LICENSE file in the top distribution directory for the full license text.\n\n\n---\nMaintaining an open source project is hard and time-consuming, and I've put much \u2764\ufe0f and effort into this.\n\nIf you've appreciated my work, you can back me up with a donation! Thank you \ud83d\ude0a\n\n[<img align=\"right\" src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" width=\"217px\" height=\"51x\">](https://www.buymeacoffee.com/rsalmei)\n[<img align=\"right\" alt=\"Donate with PayPal button\" src=\"https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif\">](https://www.paypal.com/donate?business=6SWSHEB5ZNS5N&no_recurring=0&item_name=I%27m+the+author+of+alive-progress%2C+clearly+and+about-time.+Thank+you+for+appreciating+my+work%21&currency_code=USD)\n\n---\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Easily measure timing and throughput of code blocks, with beautiful human friendly representations.",
    "version": "4.2.1",
    "split_keywords": [
        "python",
        "track",
        "tracker",
        "time",
        "code",
        "blocks",
        "monitor",
        "statistics",
        "analytics"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "10e3fd17d47ce5a095e341d96d5da064",
                "sha256": "8bbf4c75fe13cbd3d72f49a03b02c5c7dca32169b6d49117c257e7eb3eaee341"
            },
            "downloads": -1,
            "filename": "about_time-4.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "10e3fd17d47ce5a095e341d96d5da064",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7, <4",
            "size": 13295,
            "upload_time": "2022-12-21T04:15:53",
            "upload_time_iso_8601": "2022-12-21T04:15:53.613734Z",
            "url": "https://files.pythonhosted.org/packages/fb/cd/7ee00d6aa023b1d0551da0da5fee3bc23c3eeea632fbfc5126d1fec52b7e/about_time-4.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "a27e20534af8e06b9a3caed289a60884",
                "sha256": "6a538862d33ce67d997429d14998310e1dbfda6cb7d9bbfbf799c4709847fece"
            },
            "downloads": -1,
            "filename": "about-time-4.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "a27e20534af8e06b9a3caed289a60884",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7, <4",
            "size": 15380,
            "upload_time": "2022-12-21T04:15:54",
            "upload_time_iso_8601": "2022-12-21T04:15:54.991078Z",
            "url": "https://files.pythonhosted.org/packages/1c/3f/ccb16bdc53ebb81c1bf837c1ee4b5b0b69584fd2e4a802a2a79936691c0a/about-time-4.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-12-21 04:15:54",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "rsalmei",
    "github_project": "about-time",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "about-time"
}
        
Elapsed time: 0.02652s