Smart Debug Print & Variable Inspector - Drop-in replacement for print() with automatic context and change tracking
Project description
guardprint 🚨
Smart Debug Print & Variable Inspector — A drop-in replacement for print() with automatic context, pretty-printing, and change tracking.
🎯 The Problem
Debugging in Python is messy:
- 🔧 People spam
print(x)everywhere - 😕 No context (file, line, function, time)
- 🌀 Hard to track nested structures or changes over time
- 📝 Logging is overkill for quick debugging
✨ The Solution
guardprint is an intelligent print function that automatically adds:
- ✅ Variable names + values
- ✅ File name, line number, function name
- ✅ Timestamps
- ✅ Pretty-printed complex objects
- ✅ Change detection between calls
- ✅ Colorized terminal output
🚀 Quick Start
Installation
pip install guardprint
Basic Usage
from guardprint import gprint
x = 10
y = {"a": 1, "b": [1, 2, 3]}
gprint(x)
gprint(y)
Output:
[example.py:5 | <module>] 12:34:56.789
x = 10
[example.py:6 | <module>] 12:34:57.012
y = {
'a': 1,
'b': [1, 2, 3]
}
🔥 Killer Feature: Change Detection
Track when variables change:
from guardprint import gprint
x = 10
gprint(x)
x = 20
gprint(x)
Output:
✎ CHANGED: 10 → 20
Perfect for debugging loops and state mutations!
📚 API Reference
Core Functions
gprint(*args, **kwargs)
Smart print with automatic context and formatting.
from guardprint import gprint
# Single variable (auto-detects name)
x = 42
gprint(x)
# Multiple variables
a, b, c = 1, 2, 3
gprint(a, b, c)
# Complex objects (pretty-printed)
data = {"name": "Alice", "scores": [95, 87, 92]}
gprint(data)
# Custom label (when name detection fails)
gprint(expensive_calculation(), label="result")
# Standard print options
gprint(x, sep=" | ", end="\n\n")
trace(label="TRACE")
Display the current call stack.
from guardprint import trace
def process_data():
trace("checkpoint_1")
# ... more code ...
trace("checkpoint_2")
Output:
[TRACE] Call Stack:
1. main.py:42 in process_data
process_data()
2. main.py:55 in <module>
process_data()
diff(obj1, obj2, label="DIFF")
Show detailed differences between two objects.
from guardprint import diff
old_config = {"debug": False, "port": 8080, "timeout": 30}
new_config = {"debug": True, "port": 8080, "timeout": 60, "workers": 4}
diff(old_config, new_config, label="Config Changes")
Output:
[Config Changes]
~ debug:
was: False
now: True
~ timeout:
was: 30
now: 60
+ workers: 4
timer(name="timer", action="start|end|lap")
Measure execution time with microsecond precision.
from guardprint import timer
import time
# Start timer
timer("download", "start")
# ... do some work ...
time.sleep(1.5)
# End timer and get elapsed time
elapsed = timer("download", "end")
# Or use lap for split times
timer("process", "start")
timer("process", "lap") # Shows elapsed since start
time.sleep(0.5)
timer("process", "lap") # Shows elapsed since last lap
timer("process", "end")
Output:
⏱ Timer [download] started
⏱ Timer [download]: 1.50s
⏱ Timer [process] lap: 0.00ms
⏱ Timer [process] lap: 500.25ms
⏱ Timer [process]: 500.25ms
config(**kwargs)
Dynamically configure guardprint.
from guardprint import config
# Disable colors
config(use_color=False)
# Disable timestamps
config(use_timestamps=False)
# Disable change tracking
config(track_changes=False)
# Multiple options
config(use_color=False, use_timestamps=False, use_context=False)
clear_history()
Clear the change tracking history.
from guardprint import gprint, clear_history
x = 1
gprint(x)
clear_history() # Forget previous values
x = 2
gprint(x) # Will NOT show as changed
Advanced Usage: Custom Instance
Create custom instances with different configurations:
from guardprint import GuardPrint
import sys
# Create instance with specific settings
logger = GuardPrint(
use_color=True, # Enable colors
use_timestamps=True, # Show timestamps
use_context=True, # Show file:line:function
pretty_print=True, # Pretty-print objects
track_changes=True, # Track value changes
max_depth=5, # Max nesting depth
width=80, # Line width
output=sys.stderr # Output stream
)
# Use like normal
x = 42
logger.gprint(x)
# Each instance has its own change history
logger.clear_history()
🎨 Configuration Options
All options can be set during initialization or via config():
| Option | Type | Default | Description |
|---|---|---|---|
use_color |
bool | True |
Enable ANSI color output (auto-detects terminal support) |
use_timestamps |
bool | True |
Show timestamps in HH:MM:SS.mmm format |
use_context |
bool | True |
Show file:line:function context |
pretty_print |
bool | True |
Pretty-print dicts, lists, and complex objects |
track_changes |
bool | True |
Enable change detection between calls |
max_depth |
int | 5 |
Maximum nesting depth for object traversal |
width |
int | 80 |
Line width for pretty-printing |
output |
file | sys.stdout |
Output stream (stdout, stderr, file, etc.) |
🎯 Use Cases
1. Data Pipeline Debugging
from guardprint import gprint, timer
def process_batch(data):
timer("batch", "start")
cleaned = clean_data(data)
gprint(cleaned)
validated = validate_data(cleaned)
gprint(validated)
timer("batch", "end")
2. Configuration Management
from guardprint import gprint, diff
old_config = load_config("config.old.json")
new_config = load_config("config.json")
diff(old_config, new_config, label="Config Migration")
gprint(new_config)
3. State Tracking in Loops
from guardprint import gprint
for i, item in enumerate(items):
processed = process(item)
gprint(processed) # Easily see when values change
4. API Response Inspection
from guardprint import gprint
import requests
response = requests.get("https://api.example.com/data")
data = response.json()
gprint(data) # Beautifully formatted JSON
5. Performance Profiling
from guardprint import timer
for algorithm in ["quick", "merge", "bubble"]:
timer(algorithm, "start")
run_sort(algorithm)
elapsed = timer(algorithm, "end")
# Compare across algorithms
🌈 Color Support
guardprint automatically detects terminal support and uses colors when available:
- File/Line Info: Blue
- Variable Names: Yellow
- Values: Cyan (numbers), Green (strings), Yellow (None), Red (False)
- Changes: Magenta with arrows
- Traces: Red
- Diffs: Green (+), Red (-), Yellow (~)
Colors can be disabled:
from guardprint import config
config(use_color=False) # Disable colors
⚡ Performance Considerations
- Minimal Overhead: Only extracts caller info when needed
- Efficient Change Tracking: Uses shallow copies for comparison
- Stream-Based: Writes directly to output, no buffering
- No External Dependencies: Pure Python (uses only stdlib)
🔧 Troubleshooting
Variable Name Not Detected
If gprint(x) shows = value without the variable name:
- This can happen with complex expressions:
gprint(obj.get("key")) - Solution: Use the
labelparameter:gprint(obj.get("key"), label="key")
Colors Not Showing
Colors are auto-detected based on terminal support:
- On non-TTY outputs (redirected to file), colors are disabled automatically
- To force disable:
config(use_color=False) - To force enable:
GuardPrint(use_color=True)
Change Detection Not Working
Change tracking only works for variables with detected names:
- Ensure gprint is called directly:
gprint(x)✅ - Avoid expressions:
gprint(x + 1)❌ - Use label for complex cases:
gprint(x + 1, label="result")
📦 Installation & Distribution
From PyPI (Recommended)
pip install guardprint
From Source
git clone https://github.com/yourusername/guardprint.git
cd guardprint
pip install -e .
Requirements
- Python 3.6+
- No external dependencies (uses only Python stdlib)
🧪 Testing
Run the test suite:
pytest test_guardprint.py -v
Test coverage:
pytest test_guardprint.py --cov=guardprint --cov-report=html
📖 Examples
Example 1: Web Scraping Debugging
from guardprint import gprint, timer
import requests
from bs4 import BeautifulSoup
timer("scrape", "start")
url = "https://example.com"
response = requests.get(url)
gprint(response.status_code)
soup = BeautifulSoup(response.content, "html.parser")
articles = soup.find_all("article")
gprint(len(articles))
data = [
{
"title": a.h2.text,
"link": a.a["href"],
"published": a.find("time")["datetime"]
}
for a in articles
]
gprint(data)
timer("scrape", "end")
Example 2: Data Processing Pipeline
from guardprint import gprint, diff, trace
def transform_user_data(raw_users):
trace("start_transform")
# Step 1: Parse
users = [parse_user(u) for u in raw_users]
gprint(users)
# Step 2: Validate
valid_users = [u for u in users if validate_user(u)]
gprint(len(valid_users))
# Step 3: Enrich
enriched = [enrich_user(u) for u in valid_users]
gprint(enriched)
trace("end_transform")
return enriched
Example 3: Configuration Migration
from guardprint import gprint, diff, config
# Load configs
old_config = load_yaml("config.v1.yaml")
new_config = load_yaml("config.v2.yaml")
# Show what changed
diff(old_config, new_config, label="Breaking Changes")
# Disable timestamps for cleaner output
config(use_timestamps=False)
# Validate each section
for section in ["database", "cache", "logging"]:
gprint(new_config[section])
🤝 Contributing
Contributions welcome! Areas for enhancement:
- JSON/YAML output mode
- Export to file functionality
- Remote logging integration
- Custom formatters
- Jupyter notebook support
- Rich library integration
- Performance metrics collection
📄 License
MIT License - see LICENSE.txt for details
🙌 Acknowledgments
Inspired by debugging tools in Ruby, JavaScript, and other languages that make development more enjoyable.
💭 Why guardprint?
The name comes from the concept of "guarding" your code with smart print statements. It's a pun on:
- guard: protecting/watching your code
- print: the core Python debugging tool
- guardprint: the combination - intelligent debugging
📞 Support
Happy debugging! 🚀
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 guardprint-1.0.0.tar.gz.
File metadata
- Download URL: guardprint-1.0.0.tar.gz
- Upload date:
- Size: 14.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
613d70c94524c2eb32d87322dcd9e19ad8633b68b9ad6790bf4dcd781f5b727f
|
|
| MD5 |
caf05fcaaf5b5ffd6e2d512dcef0804a
|
|
| BLAKE2b-256 |
c4a47f46f0e1a7ce4a5f40a734890a7b16728d406f034215146fdf3b68d12aad
|
File details
Details for the file guardprint-1.0.0-py3-none-any.whl.
File metadata
- Download URL: guardprint-1.0.0-py3-none-any.whl
- Upload date:
- Size: 11.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a6ecd56005bf68dc3ac200aed9c9886723e739b0bac3da3ee9cdd7c8d8475272
|
|
| MD5 |
1d97f7ac68df71ec44952e7104bc21d8
|
|
| BLAKE2b-256 |
3283c0afb468e46d4e85402a93b9eeea6f9a1dc85b73a455ce70873912ac1db6
|