A framework-agnostic, process-safe, local performance timer for Python applications.
Project description
Performance Timing Module (tmng)
A developer-first, framework-agnostic performance timer for Python.
Designed for targeted, insightful profiling of application segments, not just line-by-line noise.
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.
- Fork the repository.
- Create a new branch (
git checkout -b feature/my-new-feature). - Install development dependencies:
pip install -e .[dev]. - Make your changes.
- Run tests:
pytest. - Submit a pull request.
📜 License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ad2607c3a3509e0c9a3416e81c5a396b0ce1393a83f33e56560701e2f78188d
|
|
| MD5 |
381456f7dacf4beae82a9a9dacdc09cd
|
|
| BLAKE2b-256 |
2a4908d30498c894e47096c401db5c10cb1fe4d1819945eccdec1c69aa6f7970
|
Provenance
The following attestation bundles were made for tmng-1.2.1.tar.gz:
Publisher:
python-publish.yml on lguibr/timing
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tmng-1.2.1.tar.gz -
Subject digest:
0ad2607c3a3509e0c9a3416e81c5a396b0ce1393a83f33e56560701e2f78188d - Sigstore transparency entry: 321432156
- Sigstore integration time:
-
Permalink:
lguibr/timing@fed2815fe6c833860cd8dc60b66f8ed86c44faf4 -
Branch / Tag:
refs/tags/v1.2.1 - Owner: https://github.com/lguibr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@fed2815fe6c833860cd8dc60b66f8ed86c44faf4 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
efacf71507b15803bff6e7940f144c762ec89aaadaa9a0578c5c438e7b850ad5
|
|
| MD5 |
b451c6451d8c0e58ac73a88ce4b2028e
|
|
| BLAKE2b-256 |
92690bfa09f1f352943dc44265fc2cb345d741e52f1e995e900941d381d3fcf3
|
Provenance
The following attestation bundles were made for tmng-1.2.1-py3-none-any.whl:
Publisher:
python-publish.yml on lguibr/timing
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tmng-1.2.1-py3-none-any.whl -
Subject digest:
efacf71507b15803bff6e7940f144c762ec89aaadaa9a0578c5c438e7b850ad5 - Sigstore transparency entry: 321432234
- Sigstore integration time:
-
Permalink:
lguibr/timing@fed2815fe6c833860cd8dc60b66f8ed86c44faf4 -
Branch / Tag:
refs/tags/v1.2.1 - Owner: https://github.com/lguibr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@fed2815fe6c833860cd8dc60b66f8ed86c44faf4 -
Trigger Event:
push
-
Statement type: