{ "info": { "author": "Rog\u00e9rio Sampaio de Almeida", "author_email": "rsalmei@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "[![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\n\n# about-time\n## Small tool to track time of Python code blocks.\n\n\n## What does it do?\n\nSometimes I need something to log code execution, or to extract metrics to send to influx, so I've created this tool.\n\nA simple `start = time.time()` and `end = time.time() - start` does not cut it when you need to track two or more lines/blocks at the same time, or simultaneously whole/part relationship of blocks.\n\nThis tool measures the execution time of blocks of code, and can even count iterations and the system throughput, with beautiful \"human\" representations.\n\n\n## How do I install it?\n\nJust do in your python venv:\n\n```bash\n$ pip install about-time\n```\n\n\n## How to use it?\n\nThere's three modes of operation: context manager, callable handler and iterator metrics.\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_whole:\n with about_time() as t_1:\n func_1()\n with about_time() as t_2:\n func_2('params')\n```\n\nThen, get the timings like this:\n\n```python\n# python 3.7 example, using f strings.\nprint(f'func_1 time: {t_1.duration_human}')\nprint(f'func_2 time: {t_2.duration_human}')\nprint(f'total time: {t_whole.duration_human}')\n```\n\nThere's also the `duration` property, which returns the actual float time in seconds.\n\n```python\nsecs = t_whole.duration\n```\n\n\n### 2. Use it like a callable handler:\n\n```python\nt_1 = about_time(func_1)\nt_2 = about_time(lambda: func_2('params'))\n```\n\nIf you use the callable handler syntax, there will be a new field called `result` to get the outcome of the function!\n\n```python\nresults = t_1.result, t_2.result\n```\n\nOr you can mix and match both:\n\n```python\nwith about_time() as t_whole:\n t_1 = about_time(func_1)\n t_2 = about_time(lambda: func_2('params'))\n```\n\n\n### 3. Use it to count iterations and measure throughput:\n\nWrap your iterable and just iterate it! Since we internally have duration information, it can calculate the throughput of the whole block. Specially useful in generators, which do not have length (but you can use it with any iterables):\n\nThis mode requires a small callback function (which can be an inner function or a lambda) to allow you to use a `for` loop any way you want, and the callback will be called automatically when the iterable is exhausted.\n\n```python\ndef callback(t_func):\n logger.info('func: size=%d throughput=%s', t_func.count,\n t_func.throughput_human)\nitems = filter(...)\nfor item in about_time(callback, items):\n # use item any way you want.\n process(item)\n\n# the callback is already called upon getting here.\n```\n\n\n## Some nice features\n\n### Humans are first class citizens :)\n\nI've considered two key concepts in designing the human friendly functions: `3.44s` is more meaningful than `3.43584783784s`, and `14.12us` is much nicer than `.0000141233333s`. So saying it another way, I round values to two decimal places at most, and finds the smaller unit to represent it, minimizing values smaller than `1`.\n\nNote that it dynamically finds the best unit to represent the value, considering even the rounding been applied. So if a value is for example `0.999999`, it would end up like `1000.0ms` after rounded, but it is auto-upgraded to the next unit `1.0s`.\n\nThe `duration_human` changes seamlessly from nanoseconds to hours. Values smaller than 60 seconds are rendered with two digits precision at most (zeros to the right of the decimal point are not shown), and starting from 1 minute, an \"hours:minutes:seconds.M\" milliseconds (with only one digit precision). Some examples directly from the unit tests:\n\nduration (float seconds) | duration_human\n:---: | :---:\n.00000000185 | '1.85ns'\n.000000999996 | '1.0us'\n.00001 | '10.0us'\n.0000156 | '15.6us'\n.01 | '10.0ms'\n.0141233333333 | '14.12ms'\n.1099999 | '110.0ms'\n.1599999 | '160.0ms'\n.8015 | '801.5ms'\n3.434999 | '3.43s'\n59.999 | '0:01:00'\n68.5 | '0:01:08.5'\n125.825 | '0:02:05.8'\n4488.395 | '1:14:48.4'\n\nThe `throughput_human` has similar logic, and to human brain it is much trickier to figure out: If it took `1165263` seconds to handle `123` items, how fast it did? Even dividing to find out the time per item `9473` seconds don't mean much. Dividing by `3600` we get `2.63` hours per item, and the throughput is returned nicely as `0.38/h`. The tool has per-second, per-minute and per-hour. Some examples:\n\nduration (float seconds) | number of elements | throughput_human\n:---: | :---: | :---:\n1\\. | 10 | '10.0/s'\n1\\. | 2500 | '2500.0/s'\n2\\. | 1 | '30.0/m'\n2\\. | 10 | '5.0/s'\n1.981981981981982 | 11 | '5.55/s'\n100\\. | 10 | '6.0/m'\n1600\\. | 3 | '6.75/h'\n.99 | 1 | '1.01/s'\n1165263\\. | 123 | '0.38/h'\n\n\n### Accuracy\n\nThis tool supports all versions of python, but in pythons >= `3.3`, the code uses the new `time.perf_counter` to gain from the higher resolution and smaller propagating of errors. In older versions, it uses `time.time`.\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## Nice huh?\n\nThanks for your interest!\n\nI wish you have fun using this tool! :)\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/rsalmei/about-time", "keywords": "python,track,tracker,time,code,blocks,statistics,analytics", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "about-time", "package_url": "https://pypi.org/project/about-time/", "platform": "", "project_url": "https://pypi.org/project/about-time/", "project_urls": { "Homepage": "https://github.com/rsalmei/about-time" }, "release_url": "https://pypi.org/project/about-time/2.0.5/", "requires_dist": null, "requires_python": "", "summary": "Small tool to track time of Python code blocks.", "version": "2.0.5" }, "last_serial": 4413441, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "8bbfe9bf7d55f496f874d2df81b3159f", "sha256": "62c89a11a6f95e76a086a2affa1733e063a62c8253a7abf514803dab576bfcb5" }, "downloads": -1, "filename": "about_time-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8bbfe9bf7d55f496f874d2df81b3159f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 3278, "upload_time": "2018-08-21T01:32:06", "url": "https://files.pythonhosted.org/packages/a6/43/7f16965f10fa3c1fc0c9e1b41e68b2b1f22a15c6c7a2c66c7b0af6c7b441/about_time-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7d3c48558ee15abbb2affcd29db4d19f", "sha256": "a753f93acfe67b280e2a074e24528654b262a58d1bf3ff82c00aa23984490725" }, "downloads": -1, "filename": "about-time-1.0.0.tar.gz", "has_sig": false, "md5_digest": "7d3c48558ee15abbb2affcd29db4d19f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3091, "upload_time": "2018-08-21T01:32:07", "url": "https://files.pythonhosted.org/packages/1a/2c/1710aaf95374b9137a0a747bca91d26cfd2c443252820a82f517e65945ec/about-time-1.0.0.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "32feb68c69b1ee249e95b587ac3648cd", "sha256": "c86ff8b3c7fa64ee29c0e0a5cc44b25f1bd75dfd214c7ed8b17d8915cc95fc14" }, "downloads": -1, "filename": "about_time-2.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "32feb68c69b1ee249e95b587ac3648cd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5458, "upload_time": "2018-08-26T22:48:01", "url": "https://files.pythonhosted.org/packages/27/36/240f58d780065f7ad6d410d3adc6207c9a6e18e88f33ecb19311baf59c57/about_time-2.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "acf4026ece5a058da485564647e49f41", "sha256": "256b5c0b6e808ea47a771bc4dde1de42afa967f8441cedba3e4d81f6b8ad0258" }, "downloads": -1, "filename": "about-time-2.0.0.tar.gz", "has_sig": false, "md5_digest": "acf4026ece5a058da485564647e49f41", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5271, "upload_time": "2018-08-26T22:48:03", "url": "https://files.pythonhosted.org/packages/88/5e/ccb7a0de0ced3ba23d4f0888c191ca7fb840385ad575491a2c8f82fba702/about-time-2.0.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "728272e1aab3f111fb6900d752cfacbb", "sha256": "63e0337630950d4f0fd46b5eae72c310f70363ed516ce1824b3e55ca80d47b0d" }, "downloads": -1, "filename": "about_time-2.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "728272e1aab3f111fb6900d752cfacbb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5500, "upload_time": "2018-08-26T23:36:26", "url": "https://files.pythonhosted.org/packages/a5/f0/454cfffc872564c81f385ee4959f7cf6b867e4a25a460cb4ef52a3c7d3cd/about_time-2.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f6d77e5ac21e5d3d9f413c3764159645", "sha256": "08818a4d47e7ffc5a0b1a82f48638a8eafc2c7898df26defaeeac41b61adc497" }, "downloads": -1, "filename": "about-time-2.0.1.tar.gz", "has_sig": false, "md5_digest": "f6d77e5ac21e5d3d9f413c3764159645", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5308, "upload_time": "2018-08-26T23:36:27", "url": "https://files.pythonhosted.org/packages/0c/a5/2bb512eb30aab119b9181ca6d8d44a9ea01eab9029092801ad815e57591c/about-time-2.0.1.tar.gz" } ], "2.0.2": [ { "comment_text": "", "digests": { "md5": "791877e91f694cf1eb54d91ec1eeec30", "sha256": "6ff5d2eaca2fb5070f35503a3fffc396cad49c60bf7b63ffd9af6d54765e5542" }, "downloads": -1, "filename": "about_time-2.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "791877e91f694cf1eb54d91ec1eeec30", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5523, "upload_time": "2018-08-27T00:10:45", "url": "https://files.pythonhosted.org/packages/13/63/165dd8768f4d29d729869bb90372e8459f4023e3addf8f1551b54fda1bef/about_time-2.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "52bc5b6b482c46b496c0d681c273c3d0", "sha256": "9b4cc9caf874ae596493e99e474ba4b348bf8ab937dbca664927d8038e431b42" }, "downloads": -1, "filename": "about-time-2.0.2.tar.gz", "has_sig": false, "md5_digest": "52bc5b6b482c46b496c0d681c273c3d0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5316, "upload_time": "2018-08-27T00:10:46", "url": "https://files.pythonhosted.org/packages/16/b9/f9106f953c594dc0cb82811c3494f9aaa3ec11a154e2266ef3059b642bf8/about-time-2.0.2.tar.gz" } ], "2.0.3": [ { "comment_text": "", "digests": { "md5": "d52d4fd02ad41b838b695e7fb3b373f7", "sha256": "f049148caf6b057c8d6c701598f8206aaf04a82645a2dd7834361b08fa60445a" }, "downloads": -1, "filename": "about_time-2.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "d52d4fd02ad41b838b695e7fb3b373f7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5532, "upload_time": "2018-08-27T00:28:15", "url": "https://files.pythonhosted.org/packages/fe/02/fe9119e09e440ce9752f7a65110b372ba1bdb5a65d87138ae700a5fc50e2/about_time-2.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "bd881fc57c9d650ce276e2f93bce1ba7", "sha256": "711777f958dc1a3dd3be940b758946f2f12787dd0554c0414213165223b0637f" }, "downloads": -1, "filename": "about-time-2.0.3.tar.gz", "has_sig": false, "md5_digest": "bd881fc57c9d650ce276e2f93bce1ba7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5330, "upload_time": "2018-08-27T00:28:16", "url": "https://files.pythonhosted.org/packages/0f/16/999db6adf76a9fb32bec1d7b7bee5695fac98f751351e2c77a6886939d51/about-time-2.0.3.tar.gz" } ], "2.0.4": [ { "comment_text": "", "digests": { "md5": "3a621eb315dfdf839a937e90f9d8b241", "sha256": "f943e04f0cce774eeda0d77280fc346bd4a9a10d0a12d2ba16e4de02484f911a" }, "downloads": -1, "filename": "about_time-2.0.4-py2-none-any.whl", "has_sig": false, "md5_digest": "3a621eb315dfdf839a937e90f9d8b241", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 5532, "upload_time": "2018-08-27T00:55:32", "url": "https://files.pythonhosted.org/packages/a1/2d/455910a45124d6797141648a2e0d37509f13f84fdb4025d56f649848df64/about_time-2.0.4-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1aef99f0b20ee2d8f4817fdf71eaba5c", "sha256": "f667adfa350dff845606a0dad142e55ae267bbdad82f4b73cdc24157cef9408b" }, "downloads": -1, "filename": "about-time-2.0.4.tar.gz", "has_sig": false, "md5_digest": "1aef99f0b20ee2d8f4817fdf71eaba5c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5337, "upload_time": "2018-08-27T00:55:33", "url": "https://files.pythonhosted.org/packages/46/b3/8fc2bb89f23cdeca9e8e3beab65e724cd4d120128c66c1605c0b6e3da2cf/about-time-2.0.4.tar.gz" } ], "2.0.5": [ { "comment_text": "", "digests": { "md5": "ffcb0400d1110423c4340d811c722226", "sha256": "460cb6bded44d0f2c750e446e5b0809334b49d7078c4751ad265633acbc5bffb" }, "downloads": -1, "filename": "about_time-2.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "ffcb0400d1110423c4340d811c722226", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5831, "upload_time": "2018-10-25T03:17:27", "url": "https://files.pythonhosted.org/packages/c7/83/ccbc4bf91dfa5c3e740a59c494ed07a23c8f5165d5cc0600fd74579eecc1/about_time-2.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c07c169566e9a04b49d4e3a26e52afbc", "sha256": "99931c505a9166910b6639a91fd6f90d24ccc87fa82030a05a4e2628ecddac5d" }, "downloads": -1, "filename": "about-time-2.0.5.tar.gz", "has_sig": false, "md5_digest": "c07c169566e9a04b49d4e3a26e52afbc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5699, "upload_time": "2018-10-25T03:17:29", "url": "https://files.pythonhosted.org/packages/0b/51/5b1e954bbc3a27c7e5c5492d775fccba45288d6b781135d039d1882bfee0/about-time-2.0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ffcb0400d1110423c4340d811c722226", "sha256": "460cb6bded44d0f2c750e446e5b0809334b49d7078c4751ad265633acbc5bffb" }, "downloads": -1, "filename": "about_time-2.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "ffcb0400d1110423c4340d811c722226", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5831, "upload_time": "2018-10-25T03:17:27", "url": "https://files.pythonhosted.org/packages/c7/83/ccbc4bf91dfa5c3e740a59c494ed07a23c8f5165d5cc0600fd74579eecc1/about_time-2.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c07c169566e9a04b49d4e3a26e52afbc", "sha256": "99931c505a9166910b6639a91fd6f90d24ccc87fa82030a05a4e2628ecddac5d" }, "downloads": -1, "filename": "about-time-2.0.5.tar.gz", "has_sig": false, "md5_digest": "c07c169566e9a04b49d4e3a26e52afbc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5699, "upload_time": "2018-10-25T03:17:29", "url": "https://files.pythonhosted.org/packages/0b/51/5b1e954bbc3a27c7e5c5492d775fccba45288d6b781135d039d1882bfee0/about-time-2.0.5.tar.gz" } ] }