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.
Metadata
Release files for tmng 1.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tmng-1.2.1.tar.gz | 23.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tmng-1.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.0 kB
Release files / tmng-1.2.1.tar.gz
| Download URL | tmng-1.2.1.tar.gz |
|---|---|
| Size | 23.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0ad2607c3a3509e0c9a3416e81c5a396b0ce1393a83f33e56560701e2f78188d
|
|
BLAKE2b-256 checksum How to use checksums |
2a4908d30498c894e47096c401db5c10cb1fe4d1819945eccdec1c69aa6f7970
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
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 Jul 28, 2025.
Transparency logRelease files / tmng-1.2.1-py3-none-any.whl
| Download URL | tmng-1.2.1-py3-none-any.whl |
|---|---|
| Size | 23.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
efacf71507b15803bff6e7940f144c762ec89aaadaa9a0578c5c438e7b850ad5
|
|
BLAKE2b-256 checksum How to use checksums |
92690bfa09f1f352943dc44265fc2cb345d741e52f1e995e900941d381d3fcf3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
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 Jul 28, 2025.
Transparency log