Skip to main content

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.

Python 3.6+ License: MIT

🎯 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 label parameter: 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


Download files

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

Source Distribution

guardprint-1.0.0.tar.gz (14.1 kB view details)

Uploaded Source

Built Distribution

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

guardprint-1.0.0-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

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

Hashes for guardprint-1.0.0.tar.gz
Algorithm Hash digest
SHA256 613d70c94524c2eb32d87322dcd9e19ad8633b68b9ad6790bf4dcd781f5b727f
MD5 caf05fcaaf5b5ffd6e2d512dcef0804a
BLAKE2b-256 c4a47f46f0e1a7ce4a5f40a734890a7b16728d406f034215146fdf3b68d12aad

See more details on using hashes here.

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

Hashes for guardprint-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a6ecd56005bf68dc3ac200aed9c9886723e739b0bac3da3ee9cdd7c8d8475272
MD5 1d97f7ac68df71ec44952e7104bc21d8
BLAKE2b-256 3283c0afb468e46d4e85402a93b9eeea6f9a1dc85b73a455ce70873912ac1db6

See more details on using hashes here.

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