Regression testing tool for Python
Project description
Regrest
Regrest is a simple and powerful regression testing tool for Python. It automatically records function outputs on the first run and validates them on subsequent runs.
Features
- 🎯 Simple decorator-based API - Just add
@regrestto your functions - 📝 Automatic recording - First run records outputs, subsequent runs validate
- 🔍 Smart comparison - Handles floats, dicts, lists, nested structures, and custom classes
- 🛠 CLI tools - List, view, delete, and visualize test records
- 📊 Web visualization - Beautiful dashboard with JSONesque display, hierarchical navigation, and hot reload
- ⚙️ Configurable - Custom tolerance, storage location, and more
- 🔧 Auto .gitignore - Automatically creates
.regrest/.gitignoreto exclude test records on first run
Requirements
- Python 3.9 or higher
Installation
pip install regrest
# Optional: Install with Flask for better server performance
pip install regrest[server]
Quick Start
Basic Usage
from regrest import regrest
@regrest
def calculate_price(items, discount=0):
total = sum(item['price'] for item in items)
return total * (1 - discount)
# First run: records the result
items = [{'price': 100}, {'price': 200}]
result = calculate_price(items, discount=0.1) # Returns 270.0, records it
# Output: [regrest] Recorded: __main__.calculate_price (id: abc123...)
# Second run: validates against recorded result
result = calculate_price(items, discount=0.1) # Returns 270.0, compares with record
# Output: [regrest] Passed: __main__.calculate_price (id: abc123...)
Custom Tolerance
@regrest(tolerance=1e-6)
def calculate_pi():
return 3.14159265359
Update Mode
To update existing records instead of testing:
@regrest(update=True)
def my_function():
return "new result"
Or set the environment variable:
REGREST_UPDATE_MODE=1 python your_script.py
Environment Variables
| Variable | Description | Values | Default |
|---|---|---|---|
REGREST_LOG_LEVEL |
Log level | DEBUG, INFO, WARNING, ERROR, CRITICAL | INFO |
REGREST_RAISE_ON_ERROR |
Raise exceptions on test failure | True/False | False |
REGREST_UPDATE_MODE |
Update all records | True/False | False |
REGREST_STORAGE_DIR |
Custom storage directory | Directory path | .regrest |
REGREST_FLOAT_TOLERANCE |
Float comparison tolerance | Numeric value | 1e-9 |
Priority: Constructor arguments > Environment variables > Default values
CLI Commands
List Records
regrest list # List all records
regrest list -k calculate # Filter by keyword
Lists all test records with module, function, arguments, results, and timestamps.
Delete Records
regrest delete abc123def456 # Delete by ID
regrest delete --pattern "test_*" # Delete by pattern
regrest delete --all # Delete all records
Serve Web UI
regrest serve # Start on localhost:8000
regrest serve --port 8080 # Custom port
regrest serve --host 0.0.0.0 # Allow external access
regrest serve --reload # Enable hot reload
Access the web UI at http://localhost:8000 for:
- Hierarchical view - Organized by module → function → record
- Search & filter - Find records by keyword
- JSONesque display - Syntax-highlighted, readable format
- Record management - Delete individual or all records
Architecture
System Overview
graph TB
subgraph "User Code"
A[Decorated Function<br/>@regrest]
end
subgraph "Regrest Core"
B[Decorator<br/>decorator.py]
C[Storage<br/>storage.py]
D[Matcher<br/>matcher.py]
E[Config<br/>config.py]
F[Exceptions<br/>exceptions.py]
end
subgraph "Storage Layer"
G[JSON Files<br/>.regrest/*.json]
H[Pickle Serialization<br/>base64 encoded]
end
subgraph "CLI & Server"
I[CLI<br/>typer-based]
J[Web Server<br/>Flask/HTTP]
K[Web UI<br/>Tailwind CSS]
end
A --> B
B --> C
B --> D
B --> E
B --> F
C --> G
C --> H
I --> C
J --> C
J --> K
style A fill:#e1f5ff
style B fill:#fff4e1
style C fill:#f0e1ff
style D fill:#e1ffe1
style I fill:#ffe1e1
style J fill:#ffe1e1
How It Works
-
First Run: When you call a function decorated with
@regrest, it executes normally and saves:- Module and function name
- Arguments (args and kwargs)
- Return value
- Timestamp
The record is saved to
.regrest/directory as a JSON file. -
Subsequent Runs: On the next call with the same arguments:
- The function executes
- The result is compared with the recorded value
- If they match → Test passes ✅
- If they don't match →
RegressionTestErroris raised ❌
-
Update Mode: When you need to update the expected values:
- Use
@regrest(update=True)orREGREST_UPDATE_MODE=1 - The old record is replaced with the new result
- Use
Configuration
| Level | Usage | Example |
|---|---|---|
| Global | Configure all tests | from regrest import Config, set_configconfig = Config(storage_dir='.my_records', float_tolerance=1e-6)set_config(config) |
| Per-function | Configure specific function | @regrest(tolerance=1e-9)def precise_calculation(): return 3.141592653589793 |
Advanced Features
Comparison Logic
The matcher intelligently compares:
- Primitives: Exact match for strings, booleans
- Numbers: Tolerance-based for floats, exact for integers
- Collections: Deep comparison for lists, dicts, sets
- Nested structures: Recursive comparison with detailed error messages
Storage Format
File Structure
Records are stored as JSON files in the .regrest/ directory:
.regrest/
├── .gitignore # Auto-generated
├── example.calculate_price.a1b2c3d4.json # Record file
└── mymodule.process_data.e5f6g7h8.json # Record file
File Naming Convention
{module}.{function}.{record_id}.json
| Component | Description | Example |
|---|---|---|
module |
Module name where function is defined | example, mymodule |
function |
Function name | calculate_price, process_data |
record_id |
SHA256 hash of arguments (first 16 chars) | a1b2c3d4e5f6g7h8 |
Record ID Generation: Records are uniquely identified by:
- Module name
- Function name
- SHA256 hash of serialized arguments (args + kwargs)
This means different argument combinations create separate records for the same function.
Encoding Strategy
Regrest uses a hybrid encoding approach for maximum compatibility and readability:
| Data Type | Storage Method | Readable | Example |
|---|---|---|---|
| JSON-serializable (int, float, str, bool, list, dict, None) |
JSON | ✅ Yes | {"result": {"type": "json", "data": 270.0}} |
| Non-JSON-serializable (custom classes, complex objects) |
Pickle + Base64 | ❌ No | {"result": {"type": "pickle", "data": "gASV..."}} |
Advantages:
- ✅ Readable: Simple data types are stored as JSON for easy inspection
- ✅ Flexible: Complex objects are automatically pickled
- ✅ Version control friendly: JSON format produces clean diffs
Considerations:
- ⚠️ Pickle compatibility: May have issues across different Python versions
- ⚠️ Custom classes: Must be pickle-serializable and implement
__eq__for comparison
Best Practices
| Practice | Description |
|---|---|
| Deterministic functions | Use @regrest only on functions with consistent outputs (same input → same output) |
| Auto .gitignore | Test records are automatically excluded from git via .regrest/.gitignore |
| Update workflow | When intentionally changing behavior, update records: REGREST_UPDATE_MODE=1 python script.py |
Limitations
| Limitation | Description |
|---|---|
| Python version | Requires Python 3.9+ |
| Non-deterministic functions | Don't use on functions with random outputs, timestamps, or external API calls |
| Serialization | Data must be JSON or pickle-serializable; custom classes need __eq__ for comparison |
| Pickle compatibility | May have issues across different Python versions |
Contributing
Contributions welcome! Run make check before submitting PRs.
License
MIT License
Changelog
0.1.0 (Initial Release)
- Published to PyPI - Install with
pip install regrest - Core decorator functionality (
@regrest) - Hybrid JSON/Pickle storage system
- Smart comparison with floating-point tolerance
- CLI tools (
regrest list,regrest delete) - Custom class support
- Auto
.gitignoregeneration - Environment variable configuration
- Colorful logging output
- Python 3.9+ support
- pyproject.toml-based build system
- ruff + mypy static analysis
- Makefile task automation
- GitHub Actions CI/CD
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 regrest-0.2.0.tar.gz.
File metadata
- Download URL: regrest-0.2.0.tar.gz
- Upload date:
- Size: 26.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.16
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8a449bcb406e8c9c0e6f9a2f80b78da9040f4601ec2520f7713d96e8074e434
|
|
| MD5 |
b1e2f7cf4ffb0a8ba76c591d052118ef
|
|
| BLAKE2b-256 |
6c8abc26fe45923b917bc84a16a39b1919088f50db76640102dcdf1f9a23dbee
|
File details
Details for the file regrest-0.2.0-py3-none-any.whl.
File metadata
- Download URL: regrest-0.2.0-py3-none-any.whl
- Upload date:
- Size: 24.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.16
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77921b1418c6735825b4a5c6ea17577e399eb2daebbf477699df58a3eaf97fe4
|
|
| MD5 |
47ee07069ac8f9752a09dbac1e6f8b4e
|
|
| BLAKE2b-256 |
5999cf2bac8b848abd72a06441cd1b47d05e22f937461d11dd301e43e92247db
|