Skip to main content

A framework-agnostic, process-safe, local performance timer for Python applications.

Project description

Performance Timing Module (tmng)

tmng logo

A developer-first, framework-agnostic performance timer for Python.
Designed for targeted, insightful profiling of application segments, not just line-by-line noise.

PyPI Version Python Versions CI Status License Code Style: ruff


tmng is a local performance timer designed for clarity and ease of use during development and debugging. It helps you answer questions like, "How long did that specific business logic take for user_id: 123?" or "Which step in my data pipeline is the bottleneck?".

It logs structured timing data to a local SQLite file, avoiding network latency and external dependencies in your application's critical path.

The Philosophy: Timing What Matters

Many profilers measure everything, creating a sea of noise. tmng is different. It's built for explicit, targeted timing of meaningful code blocks:

  • Business rule validations.
  • Third-party API calls.
  • Complex database queries or ORM operations.
  • Steps within a background job or data pipeline.

It's the perfect tool to use during development to add performance instrumentation where it counts.

✨ Key Features

  • 🎯 Targeted & Explicit: No magic. You wrap the code you care about.
  • 📊 Rich Interactive Reports: Generate a self-contained HTML dashboard with interactive Gantt charts, flame graphs, and statistical summaries.
  • 🏷️ Structured Tagging: The killer feature. Add key-value tags (user_id, task_id, source_api) to your events, then group and filter by them in the report.
  • ⚙️ Framework-Agnostic: Seamlessly integrates with Django, Flask, FastAPI, or any standalone Python script.
  • 🔒 Process-Safe: Reliably times operations across multiple processes, making it great for web servers or parallel jobs.
  • 🌍 Global Control: Enable or disable the timer globally via the CLI or an environment variable. No need to hunt down and comment out code.
  • 🚀 Zero Runtime Overhead When Disabled: When switched off, the decorators and context managers are virtually no-ops, making it safe to leave in your code.

📈 The Interactive Dashboard

Go beyond simple print() statements. The generated report is a powerful, interactive dashboard that helps you visualize performance instantly.

*(Image: A dynamic Gantt chart showing event durations, with controls to group events by different tags like `module` or `user_type`)*

# After running your code, this single command builds the report and opens it.
timing report

This generates a timing_dashboard.html file that includes:

  • An interactive Gantt chart to visualize event timelines and overlaps.
  • A Sunburst chart to explore hierarchical relationships.
  • Box plots and scatter plots for statistical analysis.
  • A fully searchable and sortable table of all recorded events.

🚀 Quickstart

1. Install from PyPI

pip install tmng

2. Enable The Timer (One-Time Setup)

This creates a global configuration file in your user directory, enabling the timer for your system.

timing enable

3. Initialize in Your Project

In your project's root directory, create the local database file.

timing init

This will create a timing_log.db file. (Remember to add *.db to your .gitignore!)

4. Instrument Your Code

Use the simple decorators or context managers to time key parts of your application.

from timing import time_block, time_function

# Use a context manager for specific blocks of code
def process_user_data(user_id: int):
    # ... some initial work ...

    with time_block("api_call", tags={"service": "xero", "user": user_id}):
        # Code for the slow API call you want to measure
        ...

    # ... other work ...

# Use a decorator to time an entire function
@time_function(tags={"module": "notifications"})
def send_weekly_emails(user_id: int):
    # Entire function is timed
    ...

5. Generate Your Report

After your script has run, generate the interactive HTML dashboard.

timing report

This command generates timing_dashboard.html and automatically opens it in your browser.


📖 Advanced Usage & Examples

The real power of tmng comes from using tags to create structured, queryable logs.

Scenario: Tracking a Multi-Step Process

Imagine you have a function that processes a file by fetching data, cleaning it, and saving it. Using tags, you can track the entire operation as well as each individual step.

from timing import time_block
import uuid

def run_processing_pipeline(file_id: str):
    # A unique ID for this specific run
    pipeline_run_id = str(uuid.uuid4())
    
    # Time the entire pipeline run
    with time_block("full_pipeline", tags={"file_id": file_id, "run_id": pipeline_run_id}):

        print("Step 1: Fetching data...")
        with time_block("fetch_data", tags={"source": "s3", "run_id": pipeline_run_id}):
            # ... code to fetch data ...
            time.sleep(0.5)

        print("Step 2: Cleaning data...")
        with time_block("clean_data", tags={"run_id": pipeline_run_id}):
            # ... code to clean the data ...
            time.sleep(0.8)

        print("Step 3: Saving to database...")
        with time_block("save_to_db", tags={"table": "processed_files", "run_id": pipeline_run_id}):
            # ... code to save results ...
            time.sleep(0.3)

    print("Pipeline finished.")

# In the report, you can now filter for a specific `run_id` 
# to see the full timeline and duration of each step for that run.

Manual Timing for Complex Scopes

For scenarios where the start and end of an event occur in different functions or asynchronous callbacks, you can use manual controls.

from timing import time_start, time_stop

def on_request_start(request_id: str):
    # Start the timer and store the event_id in the request state
    event_id = time_start("http_request", tags={"request_id": request_id, "method": "GET"})
    return event_id

def on_request_end(event_id):
    # When the request is finished, use the stored ID to stop the timer
    if event_id:
        time_stop(event_id)

# --- Usage ---
event_id = on_request_start("xyz-123")
# ... application does work ...
on_request_end(event_id)

⚙️ Configuration

tmng can be configured via environment variables (ideal for servers and CI/CD) or a global config file (ideal for local development). Environment variables always take precedence.

Environment Variable CLI Command Description Default
TIMING_TOOL_ENABLED timing enable Set to true or 1 to enable timing. false
- timing disable Sets the global config to false. -
TIMING_DB_PATH timing init Defines the full path to the database file. init creates it in the CWD. ./timing_log.db

Example for CI/CD or Docker: You can enable timing without a config file by setting an environment variable.

export TIMING_TOOL_ENABLED="true"
export TIMING_DB_PATH="/app/data/performance.db"
python my_script.py

🎛️ Command-Line Interface (CLI)

The timing command is your primary tool for managing the system.

Command Description
timing status Checks if the tool is enabled, shows the DB path, and reports the event count.
timing enable Globally enables the timing tool by writing to the user config file.
timing disable Globally disables the timing tool.
timing init Creates the SQLite database file (timing_log.db) in the current directory.
timing report Generates and opens the interactive HTML report.
timing report -o "perf.html" --no-open Customizes report generation: sets output file and prevents auto-opening.

🤝 Contributing

Contributions are welcome! This project uses ruff for linting and formatting. Please ensure your code conforms to the style by running ruff check . and ruff format . before submitting a pull request.

  1. Fork the repository.
  2. Create a new branch (git checkout -b feature/my-new-feature).
  3. Install development dependencies: pip install -e .[dev].
  4. Make your changes.
  5. Run tests: pytest.
  6. Submit a pull request.

📜 License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tmng-1.2.1.tar.gz (23.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tmng-1.2.1-py3-none-any.whl (23.0 kB view details)

Uploaded Python 3

File details

Details for the file tmng-1.2.1.tar.gz.

File metadata

  • Download URL: tmng-1.2.1.tar.gz
  • Upload date:
  • Size: 23.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for tmng-1.2.1.tar.gz
Algorithm Hash digest
SHA256 0ad2607c3a3509e0c9a3416e81c5a396b0ce1393a83f33e56560701e2f78188d
MD5 381456f7dacf4beae82a9a9dacdc09cd
BLAKE2b-256 2a4908d30498c894e47096c401db5c10cb1fe4d1819945eccdec1c69aa6f7970

See more details on using hashes here.

Provenance

The following attestation bundles were made for tmng-1.2.1.tar.gz:

Publisher: python-publish.yml on lguibr/timing

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tmng-1.2.1-py3-none-any.whl.

File metadata

  • Download URL: tmng-1.2.1-py3-none-any.whl
  • Upload date:
  • Size: 23.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for tmng-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 efacf71507b15803bff6e7940f144c762ec89aaadaa9a0578c5c438e7b850ad5
MD5 b451c6451d8c0e58ac73a88ce4b2028e
BLAKE2b-256 92690bfa09f1f352943dc44265fc2cb345d741e52f1e995e900941d381d3fcf3

See more details on using hashes here.

Provenance

The following attestation bundles were made for tmng-1.2.1-py3-none-any.whl:

Publisher: python-publish.yml on lguibr/timing

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page