Skip to main content

tempit

PyPI

tempit is a Python package designed to simplify the process of measuring the execution time of your functions through a straightforward decorator.

Overview

tempit offers a user-friendly decorator for measuring the execution time of Python functions. It simplifies benchmarking with customizable parameters and detailed output for multiple runs and concurrent executions. Supporting various function types, tempit includes features like human-readable time formatting and automatic recursion detection, ensuring precise and efficient timing measurements.

Installation

tempit requires Python 3.11 or newer.

You can install tempit using pip:

pip install tempit

Usage

Utilizing the tempit decorator is simple and intuitive. Follow this section to learn how to make the most of its capabilities.

Basic Usage

Below are some examples demonstrating tempit's usage:

from tempit import tempit

@tempit
def my_function():
    # Normal code of your function
    pass

my_function()

This will output something like:

Function my_function took 10.5908ms.

Advanced Usage

It is possible to use Parameters to customize the behavior of the tempit decorator, allowing you to tailor its functionality to better suit your specific benchmarking needs. Here is an example of how to use them:

from tempit import tempit
@tempit(run_times=20, verbose=True)
def my_function_with_args(a:int = 1, b:int = 2):
    return a + b

result = my_function_with_args(1, b=2)

This will provide detailed output:

***** tempit data for function my_function_with_args: *****
Function name: my_function_with_args
        Function object: <function my_function_with_args at 0x0000000000000000>
        Args: (1,)
        Kwargs: {'b': 2}
        Run times: 20
        Mean: 0.3500µs
        Median: 0.3000µs
        Min: 0.2000µs
        Max: 0.8999µs
        Standard deviation: 0.1792µs
        Sum time: 6.9999µs
        Real time: 14.4000µs
***** End of tempit data. *****

More examples can be found in the examples.py script.

To accurately measure the performance of your functions using the tempit tool, follow these guidelines:

  • Run Functions Multiple Times: Set the run_times parameter to a value greater than 1 to obtain precise measurements. This is especially important for quick functions, as a single execution can be inaccurate due to measurement overhead. For very small functions, using 5 runs is a good rule of thumb. By default, run_times is set to 1, which is generally sufficient for time-consuming functions because their longer execution times are less prone to inaccuracies.
  • Sequential Execution: Leave concurrent_execution at its default of False for the most accurate measurements. This ensures each run is measured independently, without runs competing for CPU resources (which distorts timings).

tempit in Production Environments

The tempit decorator is designed exclusively for benchmarking and is not suitable for use in production code. You can globally deactivate the tempit feature by setting the TempitConfig.ACTIVE flag to false at the top of your imports. While this will skip the decoration of callables, there may still be a minimal CPU overhead. For production-grade applications, it's recommended to manually remove the decorators and tempit imports to maintain optimal performance.

from tempit import TempitConfig, tempit
TempitConfig.ACTIVE = False  # Deactivates the decorator

Features

  • Simplified usage.
  • Accurate measurement of function execution time.
  • Support for functions, methods, classmethod and staticmethod.
  • Human-readable time formatting.
  • Optional verbose mode for detailed information.
  • Ability to globally deactivate the tempit decorator.
  • Parallel execution mode for performance measurement.
  • Automatic recursion detection.
  • Fully type-hinted (PEP 561 py.typed) for static analysis and editor support.

Parameters

Using the decorator @tempit without any parameters executes the function once and displays the execution time. However, you can enhance the experience using the following arguments:

  • run_times (int, optional): Specifies the number of function executions. Defaults to 1.
  • concurrent_execution (bool, optional): Determines whether the function is executed concurrently. It uses joblib for parallel computing. Defaults to False.
  • verbose (bool, optional): Controls whether detailed information is printed after execution. Defaults to False.

Best Practices

The ideal way to use this package is by applying the decorator to the functions you want to measure and running them side by side to compare the results more easily.

  • If you want to measure several times to get an average, you can use the run_times parameter.

  • For more precise time execution, it is recommended to keep concurrent_execution set to False. Please see the Concurrency section to understand the limitations of concurrency.

  • Recursive functions should be encapsulated for better benchmarking. Please refer to the Recursive functions section to learn more about recursion and tempit.

  • Decorating classes will return the class unmodified and will not be decorated. For more information about this decision, please see the Why is class decoration bypassed in the Other Limitations section.

Recursive Functions

Measuring the execution time of recursive functions using decorators can be challenging due to potential verbosity in the output. This package offers an automatic recursion detection feature, but it is strongly recommended to use the encapsulating the recursive function solution for cleaner, more precise, and safer results.

Using the Auto-Recursion Feature

The auto-recursion feature detects recursion in the decorated function by checking the parent call function. If recursion is found, it will only output the time taken to run the appropriate function, plus an overhead. It is not recommended to rely on this feature intentionally since the collected time data will not be accurate and the process will take longer.

This feature is intended for passive use in case the user forgets to encapsulate the recursive function or for non-accurate comparisons.

@tempit(run_times=3, concurrent_execution=True, verbose=False)
def recursive_func(n):
    if n == 0:
        return 0
    else:
        return n + recursive_func(n - 1)


# This will trigger the auto-recursion feature
result = recursive_func(3)

Encapsulating the Recursive Function

The recommended option is to encapsulate the recursive function within another function and then, decorate and call the parent function. Here's an example:

@tempit
def encapsulated_recursive_function(n):
    """A non-verbose wrapper for the recursive function."""
    def recursive_func(n):
        if n == 0:
            return 0
        else:
            return n + recursive_func(n - 1)

    return recursive_func(n)

# Encapsulating the recursive function
result = encapsulated_recursive_function(3)

This approach enhances readability without incurring any performance penalties. However, its main drawback is that users must modify their code to measure this type of function.

Concurrency

How Concurrency Works in tempit

tempit uses joblib for parallel computing. By default, the execution backend is "loky". If a PicklingError occurs while trying to execute the decorated function, tempit switches the backend to "threading" and retries the execution. If any other error occurs with "loky" or "threading", tempit falls back to sequential execution, discarding the joblib option.

The "threading" backend is chosen if tempit is detected to be running outside the MainProcess or MainThread.

The number of workers for any parallel execution is num_processors - 1. While this may not always be the optimal approach (especially for multithreading with large I/O operations), simplicity of use has been prioritized over complexity for this decorator.

Additionally, if the run_times parameter exceeds num_processors - 1, it will be downsized to match the number of available processors minus one to maximize parallelization. Finally, if tempit detects that it is running in concurrency mode and finds that the downsized run_times is equal to 1, tempit falls back to sequential execution, discarding the joblib option.

Concurrency Caveats

There are some caveats when using parallel computing. Creating a process or thread incurs overhead, so it's normal to find that for very low CPU-intensive functions, the concurrent mode may be slower than the sequential one. However, as the functions become more CPU-intensive, concurrency usually results in faster execution times.

That being said, timings measured when using concurrent executions may not be as accurate as those in sequential mode.

Other Limitations

While this package generally delivers excellent performance and reliability, it's essential to be aware of certain scenarios where using the tempit decorator could lead to unexpected behavior.

Why is Class Decoration Bypassed?

When a class is decorated using tempit, it remains unmodified and is not decorated. If the user intends to measure the time of __init__ or any other constructor, it can be done directly on those methods.

This design decision was made due to a potential issue that arises when a decorated class is used in conjunction with spawning a new process. Specifically, if a class decorated with tempit is pickled for use in a separate process and then a method is called within that new process, it may result in a PicklingError.

Zero Values

In some rare cases where multiple recursively decorated functions are called nested within each other, tempit may return some zero values for the measurements of the inner functions.

Error Management and Warnings

Errors

If an error occurs while executing the decorated function in sequential mode, in concurrent mode (which then falls back to sequential execution), or within a recursively decorated function, the error will be propagated to the caller.

Warnings

  • Deprecation warnings will be added before removing a feature.

  • If the run_times parameter exceeds num_processors - 1, it will be downsized to match the number of available processors minus one to maximize parallelization.

  • If recursion has been detected, a warning will be prompted. If so, please, go to Recursive functions.

Contributing

Contributions are welcome! Please follow these guidelines when contributing:

  1. Fork the repository.
  2. Install uv and run make install to install all dependencies (backed by uv sync).
  3. Create a new branch for your changes.
  4. Implement your changes and commit them.
  5. Push your changes to your forked repository.
  6. Submit a pull request.

You can also open an issue if you find a bug or have a suggestion.

You can test your code using make test (current interpreter) or make test-all (all supported Python versions), and make example to trigger the examples. Please, check the Makefile to know more about commands.

Testing

The package has been thoroughly tested using unittesting. Test cases can be found in the tests folder.

CI runs the suite across Python 3.11–3.14 on Linux, macOS and Windows, and reports code coverage.

License

This project is licensed under the MIT License.

Contributors

Metadata

Release files for tempit 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tempit 1.0.0
File Size Uploaded
tempit-1.0.0.tar.gz 73.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tempit 1.0.0
File Interpreter ABI Platform
tempit-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 88.6 kB

Release files / tempit-1.0.0.tar.gz

Download URL tempit-1.0.0.tar.gz
Size 73.8 kB
Tags Source
SHA-256 checksum
How to use checksums
7babe3576db8ff15f407b6754c62841c840caa0efdcd57c02d33876c87672f92
BLAKE2b-256 checksum
How to use checksums
d541a59840bb21ce0fdf36347b97da05888fe722446ed220133dff72da2c3925
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / tempit-1.0.0-py3-none-any.whl

Download URL tempit-1.0.0-py3-none-any.whl
Size 14.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
614cda6e97caeb76d9628c04a2970b5b4f4f61f8c009e432698e5f9b7c214edb
BLAKE2b-256 checksum
How to use checksums
29e19859d36b193df61ace191f42858ab02a88225b51accfd4fa8a2a1bea3612
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.11

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.5

2 release files

0.1.3

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page