{"id":44583637,"url":"https://github.com/jubnl/timeit_decorator","last_synced_at":"2026-02-14T05:57:36.914Z","repository":{"id":208730386,"uuid":"722363124","full_name":"jubnl/timeit_decorator","owner":"jubnl","description":"A versatile timing decorator","archived":false,"fork":false,"pushed_at":"2025-07-14T11:44:50.000Z","size":80,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-18T07:35:26.552Z","etag":null,"topics":["decorators","decorators-python","performance","performance-analysis","profiling","profiling-library"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/timeit-decorator/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jubnl.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-11-23T01:38:00.000Z","updated_at":"2025-07-14T11:39:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"8697415e-fae5-4d22-8058-b52424a24e44","html_url":"https://github.com/jubnl/timeit_decorator","commit_stats":null,"previous_names":["jubnl/timeit_decorator"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/jubnl/timeit_decorator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jubnl%2Ftimeit_decorator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jubnl%2Ftimeit_decorator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jubnl%2Ftimeit_decorator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jubnl%2Ftimeit_decorator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jubnl","download_url":"https://codeload.github.com/jubnl/timeit_decorator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jubnl%2Ftimeit_decorator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29438641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T05:24:35.651Z","status":"ssl_error","status_checked_at":"2026-02-14T05:24:34.830Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decorators","decorators-python","performance","performance-analysis","profiling","profiling-library"],"created_at":"2026-02-14T05:57:36.694Z","updated_at":"2026-02-14T05:57:36.906Z","avatar_url":"https://github.com/jubnl.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Timeit Decorator\n\n[![PyPI - License](https://img.shields.io/pypi/l/timeit_decorator)](./LICENSE)\n[![PyPI Downloads](https://static.pepy.tech/badge/timeit-decorator)](https://pepy.tech/projects/timeit-decorator)\n[![PyPI Downloads](https://static.pepy.tech/badge/timeit-decorator/month)](https://pepy.tech/projects/timeit-decorator)\n[![PyPI version](https://badge.fury.io/py/timeit-decorator.svg)](https://pypi.org/project/timeit-decorator/)\n[![Python versions](https://img.shields.io/pypi/pyversions/timeit-decorator.svg)](https://pypi.org/project/timeit-decorator/)\n[![Build](https://img.shields.io/github/actions/workflow/status/jubnl/timeit_decorator/.github%2Fworkflows%2Fpython-publish.yml)](https://github.com/jubnl/timeit_decorator/actions/workflows/python-publish.yml)\n[![codecov](https://codecov.io/gh/jubnl/timeit_decorator/graph/badge.svg?token=7KGVJM29YP)](https://codecov.io/gh/jubnl/timeit_decorator)\n[![GitHub Issues](https://img.shields.io/github/issues/jubnl/timeit_decorator)](https://github.com/jubnl/timeit_decorator/issues)\n![GitHub Repo stars](https://img.shields.io/github/stars/jubnl/timeit_decorator)\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Features](#features)\n- [Flexible Logging](#flexible-logging)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basic Usage](#basic-usage)\n  - [Efficient Execution for Single Run/Worker](#efficient-execution-for-single-runworker)\n  - [Using Multiprocessing](#using-multiprocessing)\n  - [Using Threading (Default)](#using-threading-default)\n  - [Detailed Output Option](#detailed-output-option)\n  - [Timeout Handling](#timeout-handling)\n  - [Async Support](#async-support)\n- [Limitations](#limitations)\n  - [Incompatibility with Static Methods and Multiprocessing](#incompatibility-with-static-methods-and-multiprocessing)\n- [Requirements](#requirements)\n- [Contributing](#contributing)\n- [License](#license)\n- [Changelog](#changelog)\n\n\n## Overview\n\n`timeit_decorator` is a flexible Python library for benchmarking function execution. It supports repeated runs, parallel\nexecution with threads or processes, detailed timing statistics, and native support for both sync and async functions.\n\n## Features\n\n- **Multiple Runs and Workers**: Run functions multiple times with configurable concurrency.\n- **Sync and Async Support**: Use @timeit_sync or @timeit_async for full feature parity across sync and async code.\n- **Per-Task Timeout Handling**: Enforce or log timeouts individually for each execution.\n- **Multiprocessing and Threading**: Choose concurrency model for CPU- or I/O-bound workloads.\n- **Detailed Statistics**: Enable detailed=True to log timing metrics like average, median, min/max, stddev.\n- **Instance, Class, and Static Method Support**: Fully supports method decorators (with limitations for\n  multiprocessing).\n- **Structured Logging Only**: All output is logged using Python’s logging module.\n\n##### Use Cases\n\n- **Performance Analysis**: Use the `detailed` parameter to get a comprehensive overview of the function's performance\n  across multiple runs.\n- **Debugging**: The detailed statistics can help identify inconsistencies or anomalies in function execution, aiding in\n  debugging efforts.\n\nRemember that enabling detailed output can increase the verbosity of the output, especially for functions executed\nmultiple times. It is recommended to use this feature judiciously based on the specific needs of performance analysis or\ndebugging.\n\n## Flexible Logging\n\nAll output is handled exclusively through Python’s `logging` module. The `timeit_decorator` automatically configures a\ndefault logger if none exists. You can customize verbosity using the `log_level` parameter (default: `logging.INFO`).\n\n## Installation\n\nTo install `timeit_decorator`, run the following command:\n\n```bash\npip install timeit-decorator\n```\n\n## Usage\n\n#### Example Available\n\nYou can find a runnable example in [examples/main.py](examples/main.py).\\\nThe corresponding output is written to [examples/example_output.log](examples/example_output.log).\n\n### Basic Usage\n\nHere's how to use the timeit decorator:\n\n```py\nimport logging\nfrom timeit_decorator import timeit_sync\n\n# Configure logging\nlogging.basicConfig(\n    level=logging.INFO,\n    format=\"%(asctime)s [%(levelname)s] (%(name)s) %(message)s\",\n    datefmt=\"%Y-%m-%d %H:%M:%S\"\n)\n\n\n@timeit_sync(runs=5, workers=2, log_level=logging.INFO)\ndef sample_function():\n    # Function implementation\n    pass\n\n\n# Call the decorated function\nsample_function()\n```\n\n### Efficient Execution for Single Run/Worker\n\nFor single executions, the decorator directly runs the function:\n\n```py\nimport logging\nfrom timeit_decorator import timeit_sync\n\n# Configure logging\nlogging.basicConfig(level=logging.INFO)\n\n\n# Default parameters\n# @timeit_sync(\n#       runs=1,\n#       workers=1,\n#       log_level=logging.INFO,\n#       use_multiprocessing=False,\n#       detailed=False,\n#       timeout=None,\n#       enforce_timeout=False\n# )\n@timeit_sync()\ndef quick_function():\n    # Function implementation for a quick task\n    pass\n\n\n# Call the decorated function\nquick_function()\n```\n\n### Using Multiprocessing\n\nFor CPU-bound tasks, you can enable multiprocessing:\n\n```py\nimport logging\nfrom timeit_decorator import timeit_sync\n\n# Configure logging\nlogging.basicConfig(level=logging.DEBUG)\n\n\n@timeit_sync(runs=10, workers=4, use_multiprocessing=True, log_level=logging.DEBUG)\ndef cpu_intensive_function():\n    # CPU-bound function implementation\n    pass\n\n\n# Call the decorated function\ncpu_intensive_function()\n```\n\n### Using Threading (Default)\n\nFor I/O-bound tasks, the default threading is more efficient:\n\n```py\nimport logging\nfrom timeit_decorator import timeit_sync\n\n# Configure logging\nlogging.basicConfig(level=logging.INFO)\n\n\n@timeit_sync(runs=5, workers=2)\ndef io_bound_function():\n    # I/O-bound function implementation\n    pass\n\n\n# Call the decorated function\nio_bound_function()\n```\n\n### Detailed Output Option\n\nThe `timeit` decorator includes an optional detailed parameter that provides more extensive statistics about the\nfunction\nexecution time when set to True. This feature is particularly useful for in-depth performance analysis and debugging, as\nit gives users a broader view of how the function behaves under different conditions.\n\n#### Usage of the `detailed` Parameter\n\n**Purpose**: When set to True, the timeit decorator provides a detailed tabulated output including average, median,\nminimum,\nand maximum execution times, standard deviation, and total execution time for all runs.\n\n##### Example\n\n```py\n@timeit_sync(runs=5, workers=2, detailed=True)\ndef sample_function(a, b, c=\"some value\"):\n    # Function implementation\n    pass\n\n\nsample_function(\"arg1\", \"arg2\", c=\"value overwrite\")\n```\n\nThis will output a detailed tabulated summary after the function execution, similar to the following:\n\n```\nFunction       \u003cfunction sample_function at 0x000002612FFD9E40\u003e\nArgs           ('arg1', 'arg2')\nKwargs         {'c': 'value overwrite'}\nRuns           5\nWorkers        2\nAverage Time   0.2s\nMedian Time    0.19s\nMin Time       0.18s\nMax Time       0.22s\nStd Deviation  0.015s\nTotal Time     1.0s\n```\n\n### Timeout Handling\n\nYou can specify a `timeout` (in seconds) to monitor execution duration for each run. The `enforce_timeout` parameter\ncontrols how timeouts are handled:\n\n- `enforce_timeout=False` (default): Logs a warning if a run exceeds the timeout but allows it to complete.\n- `enforce_timeout=True`: Cancels the execution if the timeout is reached (only supported with threading and async).\n\n#### Example (Non-Enforced Timeout)\n\n```python\nimport logging\nfrom timeit_decorator import timeit_sync\n\nlogging.basicConfig(level=logging.INFO)\n\n\n@timeit_sync(timeout=0.1)\ndef slow_function():\n    import time\n    time.sleep(0.2)\n\n\nslow_function()\n```\n\nExample (Enforced Timeout with Cancellation)\n\n```python\n@timeit_sync(timeout=0.1, enforce_timeout=True)\ndef fast_abort():\n    import time\n    time.sleep(0.2)\n\n\nfast_abort()\n```\n\n#### Behavior Summary\n\n- If execution completes before timeout -\u003e normal result\n- If enforce_timeout=False and timeout is exceeded -\u003e logs warning, allows completion\n- If enforce_timeout=True and timeout is exceeded -\u003e run is cancelled and marked as timed out\n\n\u003e Note: Enforced timeout is not supported with use_multiprocessing=True due to Python’s process model.\n\n### Async Support\n\n`timeit_decorator` fully supports asynchronous functions via the `@timeit_async` decorator.\n\nYou can configure it with the same options as the sync version, including:\n\n- `runs`, `workers`\n- `timeout`, `enforce_timeout`\n- `detailed`, `log_level`\n\nAsync execution uses an internal `asyncio.Semaphore` to manage concurrency and supports both enforced and non-enforced\ntimeouts via `asyncio.wait_for()` and `asyncio.shield()`.\n\n```python\nimport asyncio\nfrom timeit_decorator import timeit_async\n\n\n@timeit_async(runs=3, workers=2, timeout=0.1, enforce_timeout=False)\nasync def async_task():\n    await asyncio.sleep(0.2)\n    return \"done\"\n\n\nasyncio.run(async_task())\n```\n\n\u003e If `enforce_timeout=False`, timeouts are logged but the coroutine is allowed to finish using `asyncio.shield()`.\n\u003e If `enforce_timeout=True`, the task is cancelled if it exceeds the timeout limit.\n\n## Limitations\n\nWhile `timeit_decorator` is designed to be highly flexible, a few constraints exist due to Python's concurrency model:\n\n### Incompatibility with Static Methods and Multiprocessing\n\n- **Static Methods and Multiprocessing**: The `timeit` decorator currently does not support the use of multiprocessing (\n  `use_multiprocessing=True`) with `@staticmethod`. Attempting to use the `timeit` decorator with multiprocessing on\n  static\n  methods can lead to unexpected behavior or errors, specifically a `PicklingError`.\n\n**Reason for the Limitation**: This issue arises because Python's multiprocessing module requires objects to be\nserialized (pickled) for transfer between processes. However, static methods pose a challenge for Python's pickling\nmechanism due to the way they are referenced internally. This can result in a `PicklingError` stating that the static\nmethod is not the same object as expected.\n\n**Example of the issue**:\n\n```py\n# This will raise a PicklingError when executed\nclass ExampleClass:\n    @staticmethod\n    @timeit(use_multiprocessing=True, runs=2)\n    def example_static_method():\n        # method implementation\n        pass\n```\n\nExample of exception :\n\n```\n_pickle.PicklingError: Can't pickle \u003cfunction ExampleClass.example_static_method at 0x...\u003e: it's not the same object as __main__.ExampleClass.example_static_method\n```\n\n**Recommended Workaround**: To avoid this issue, consider using instance methods or regular functions, which are not\nsubject to the same serialization constraints as static methods. Alternatively, refrain from using\n`use_multiprocessing=True` with static methods.\n\nThis limitation stems from inherent characteristics of Python's multiprocessing and pickling mechanisms. Users are\nencouraged to structure their code accordingly to prevent encountering this issue. We are continuously working to\nenhance the `timeit` decorator and mitigate such limitations wherever possible. If you encounter any other issues or\nlimitations, please feel free to report them in the project's issue tracker.\n\n## Requirements\n\n`timeit_decorator` requires Python 3.7+\n\n## Contributing\n\nContributions to `timeit_decorator` are welcome! Please read our [contributing guidelines](./CONTRIBUTING.md) for more\ndetails.\n\n## License\n\n`timeit_decorator` is released under the [MIT License](./LICENSE).\n\n## Changelog\n\nSee [CHANGELOG.md](./CHANGELOG.md) for a full list of changes, fixes, and new features introduced in each release.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjubnl%2Ftimeit_decorator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjubnl%2Ftimeit_decorator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjubnl%2Ftimeit_decorator/lists"}