Dependency-free Python failure capture, fingerprinting and assisted replay
Project description
TraceSeed
Turn Python failures into verifiable, reproducible diagnostic packages.
TraceSeed is a modular library with zero runtime dependencies. It captures an exception, collects useful context, removes sensitive information, generates a stable fingerprint, and saves a .tseed package with integrity hashes.
Status: initial release
0.1.0, ready for study, controlled use, and further development. Replay is assisted and should only be used with trusted packages.
Features
- Small API:
@capture,guard(), andcapture_exception(). - Synchronous and asynchronous support.
- Chained exceptions, notes, and
ExceptionGroup. - Arguments, locals, traceback, runtime info, threads, and breadcrumbs.
- Deep sanitization by field name, regex, and custom function.
- Stable fingerprinting that normalizes IDs, numbers, UUIDs, long tokens, and hex addresses.
.tseedpackages in ZIP format with a manifest and SHA-256 hashes.- Atomic writes to prevent incomplete packages.
- File, directory, and in-memory storage backends.
- Extensible collectors and serializers.
- CLI for viewing, verifying, listing, comparing, and replaying packages.
- Global hooks for
sys,threading, andasyncio. - Over 330 regression tests, with lint and static type checking.
Requirements
- Python 3.11 or higher.
- No external runtime dependencies.
Quick start (no install)
From the project root:
PYTHONPATH=src python examples/basic.py
PYTHONPATH=src python -m traceseed --version
On Windows PowerShell:
$env:PYTHONPATH = "src"
python examples/basic.py
Installation
python -m pip install .
No runtime dependencies are declared.
Basic example
from traceseed import capture
@capture(operation="process-payment")
def process_payment(order_id: int, token: str) -> None:
raise ValueError(f"payment rejected for order {order_id}")
process_payment(123, token="secret-token")
The original exception is re-raised. A package is created under .traceseeds/:
.traceseeds/
└── process-payment-traceseed-9c41...-2ac39f10.tseed
The token is redacted before persistence.
Context manager
from traceseed import guard
with guard("import-customers", metadata={"file": "customers.csv"}):
import_customers()
Manual capture
from traceseed import capture_exception
try:
execute_job()
except Exception as error:
result = capture_exception(
error,
operation="background-job",
metadata={"job_id": 42},
)
raise
By default, an internal TraceSeed failure never replaces the original exception. Use strict=True in tests or admin tools to surface capture errors explicitly.
Configuration
from pathlib import Path
from traceseed import TraceSeedConfig, configure
configure(
TraceSeedConfig(
output_directory=Path("var/traceseeds"),
capture_arguments=True,
capture_locals=True,
capture_argv=False, # disabled by default — argv may contain secrets
capture_threads=False,
max_depth=6,
max_collection_items=80,
max_operation_length=256,
max_exception_depth=20,
max_exception_children=32,
).with_redact_fields({"cpf", "session_id"})
)
Security-relevant defaults
| Field | Default | Notes |
|---|---|---|
capture_argv |
False |
sys.argv may contain secrets; opt in explicitly |
capture_cwd |
True |
working directory is low-risk; disable if needed |
max_exception_depth |
20 |
limits chained-exception recursion |
max_exception_children |
32 |
limits ExceptionGroup children |
max_operation_length |
256 |
operation name is truncated to this length |
max_replay_payload_size |
1 MB |
replay payloads larger than this are rejected |
Context and breadcrumbs
from traceseed import breadcrumb, context
with context(request_id="req-123", tenant="company-a"):
breadcrumb("database", "customer loaded", customer_id=42)
breadcrumb("payment", "gateway request sent")
process_payment()
Context uses contextvars and stays isolated across async tasks.
Logs as breadcrumbs
import logging
from traceseed import BreadcrumbHandler
handler = BreadcrumbHandler()
logging.getLogger().addHandler(handler)
Storage backends
from traceseed import TraceSeedConfig
from traceseed.serialization import SafeSerializer
from traceseed.storage import ArchiveStorage, DirectoryStorage, MemoryStorage
config = TraceSeedConfig()
serializer = SafeSerializer(config)
archive = ArchiveStorage(config, serializer) # .tseed ZIP files
directory = DirectoryStorage(config, serializer) # unpacked directory
memory = MemoryStorage() # in-memory, useful in tests
Pass a storage per capture:
@capture(storage=memory)
def operation():
...
A custom storage only needs to implement:
class MyStorage:
name = "my-storage"
def save(self, record, extra=None):
...
Custom collectors
from traceseed import register_collector
class TenantCollector:
name = "tenant"
def collect(self, exception, context, config):
return {"tenant_runtime": read_current_tenant()}
register_collector(TenantCollector())
A failing collector is recorded in collector_errors and does not block the others.
Assisted replay
@capture(operation="calculate-tax", replayable=True)
def calculate_tax(amount, rate):
return amount * rate
Replay is generated only when the callable is importable and all arguments are reconstructable. If any argument was redacted or could not be serialized, replay.json contains {"replayable": false} and the runner refuses to execute.
traceseed replay failure.tseed --allow-code-execution
Warning: replay imports modules and executes application code. Never replay a package received from an untrusted source.
CLI
traceseed show error.tseed
traceseed show error.tseed --json
traceseed verify error.tseed
traceseed list .traceseeds
traceseed compare first.tseed second.tseed
traceseed replay error.tseed --allow-code-execution
Without installation:
PYTHONPATH=src python -m traceseed show error.tseed
Development
TraceSeed has zero runtime dependencies. Development, testing, linting, and type checking use pytest, Ruff, and mypy.
python -m ruff format --check .
python -m ruff check .
python -m mypy src
python -m pytest
The test suite covers over 330 scenarios, including package corruption, ZIP bomb protection, exception cycles, broken repr(), async concurrency, global hooks, collector failures, and replay.
Project layout
src/traceseed/
├── api.py public API and hooks
├── engine.py capture orchestration
├── config.py immutable configuration
├── context.py context and breadcrumbs
├── fingerprint.py stable failure grouping
├── redaction.py secret removal
├── serialization.py safe JSON codec
├── collectors/ independent data collectors
├── storage/ file, directory, and memory backends
├── replay/ assisted reproduction
└── cli.py administrative commands
See also:
Known limitations
- Replay does not automatically recreate databases, network, external files, or global state.
- Arbitrary objects are represented for diagnostic purposes but are not automatically reconstructed.
- Replay isolation is not a security sandbox.
- Capturing locals may record sensitive data — maintain proper sanitization and limits.
License
MIT.
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 traceseed-0.1.0.tar.gz.
File metadata
- Download URL: traceseed-0.1.0.tar.gz
- Upload date:
- Size: 64.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc30be5f252bc0fe0ff34ca9b3074b38792cb67ab918592f821ad256b5d2d6f4
|
|
| MD5 |
58c329cb2b9c47fe1b122cb59c36f9eb
|
|
| BLAKE2b-256 |
17b0cd804820e2bd277865e1e38dcef690b4ffd87e1c5f8ced6704d63cd4c6b0
|
Provenance
The following attestation bundles were made for traceseed-0.1.0.tar.gz:
Publisher:
publish.yml on igors93/traceseed
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
traceseed-0.1.0.tar.gz -
Subject digest:
dc30be5f252bc0fe0ff34ca9b3074b38792cb67ab918592f821ad256b5d2d6f4 - Sigstore transparency entry: 1740069274
- Sigstore integration time:
-
Permalink:
igors93/traceseed@9026505c31516c4884eae8a2ba9799bb6afbfbb7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/igors93
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9026505c31516c4884eae8a2ba9799bb6afbfbb7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file traceseed-0.1.0-py3-none-any.whl.
File metadata
- Download URL: traceseed-0.1.0-py3-none-any.whl
- Upload date:
- Size: 40.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87ce9aa4c1a81674f3298b058cca6de6bc04739c97194cfad0a6ddfc63f313f3
|
|
| MD5 |
69655812c6aebf52bb9bba25e4dc6bef
|
|
| BLAKE2b-256 |
c2b207ed0589751cd05bcac234c3463d35d427fb714838dc748be679609fcd28
|
Provenance
The following attestation bundles were made for traceseed-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on igors93/traceseed
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
traceseed-0.1.0-py3-none-any.whl -
Subject digest:
87ce9aa4c1a81674f3298b058cca6de6bc04739c97194cfad0a6ddfc63f313f3 - Sigstore transparency entry: 1740069287
- Sigstore integration time:
-
Permalink:
igors93/traceseed@9026505c31516c4884eae8a2ba9799bb6afbfbb7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/igors93
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9026505c31516c4884eae8a2ba9799bb6afbfbb7 -
Trigger Event:
release
-
Statement type: