First PyPI Project
This tutorial starts from an empty directory and installs ReplayLab from PyPI.
It captures one real requests call against a local loopback service, replays the app with that
service stopped, exports the local React viewer, and generates a pytest provider replay guard.
Use this when you want the shortest public-alpha check that behaves like a normal user project but does not require API keys.
1. Create A Project
mkdir replaylab-first-project
cd replaylab-first-project
python -m venv .venv
source .venv/bin/activate
python -m pip install replaylab==0.1.0a4 requests pytest
Check the install:
replaylab version
replaylab doctor --project-name first-project
Expected output includes:
replaylab 0.1.0a4
replaylab-schemas 0.1.0a4
Project: first-project
2. Add A Local Provider
Create provider.py:
from __future__ import annotations
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlparse
class Handler(BaseHTTPRequestHandler):
def do_GET(self) -> None:
parsed = urlparse(self.path)
ticket_id = parsed.path.rstrip("/").split("/")[-1]
body = json.dumps(
{
"ticket_id": ticket_id,
"priority": "high",
"category": "support",
"private_note": "this payload body should stay out of the viewer",
},
sort_keys=True,
).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, _format: str, *_args: object) -> None:
return
if __name__ == "__main__":
ThreadingHTTPServer(("127.0.0.1", 8765), Handler).serve_forever()
Start it in one terminal:
source .venv/bin/activate
python provider.py
Leave that process running for the capture step.
3. Add The App
Create app.py:
from __future__ import annotations
import json
import os
import replaylab
import requests
from replaylab import CapturePayloadPolicy
BASE_URL = os.environ.get("REPLAYLAB_ONBOARDING_BASE_URL", "http://127.0.0.1:8765")
TICKET_ID = "ticket-123"
def classify_ticket(ticket_id: str) -> dict[str, str]:
response = requests.get(
f"{BASE_URL}/tickets/{ticket_id}",
params={"source": "first-pypi-project"},
headers={"X-ReplayLab-Onboarding": "docs"},
timeout=5,
)
response.raise_for_status()
payload = response.json()
return {
"ticket_id": str(payload["ticket_id"]),
"priority": str(payload["priority"]),
"category": str(payload["category"]),
}
def main() -> None:
handle = replaylab.init(
project_name="first-pypi-project",
auto_patch_integrations="auto",
capture_payload_policy=CapturePayloadPolicy.FULL,
)
with handle.capture("classify_ticket", session_id=TICKET_ID) as capture:
result = classify_ticket(TICKET_ID)
print(json.dumps(result, sort_keys=True))
if capture.capsule is not None:
print(f"capsule_path={capture.capsule.capsule_path}")
if __name__ == "__main__":
main()
This is the production-style integration model:
- initialize ReplayLab once near startup
- keep normal provider code
- scope the user workflow with
handle.capture(...)
4. Capture
In a second terminal, run:
source .venv/bin/activate
python app.py
Expected output:
{"category": "support", "priority": "high", "ticket_id": "ticket-123"}
capsule_path=.replaylab/capsules/cap_...
List and inspect the capsule:
replaylab capsule list --local-store-root .replaylab
replaylab capsule inspect <capsule_id> --local-store-root .replaylab
The inspection output should show one requests HTTP boundary and payload refs. It should not print
the provider response body.
5. Replay With The Provider Stopped
Stop provider.py with Ctrl-C, then run:
replaylab replay <capsule_id> \
--local-store-root .replaylab \
--auto-patch-integrations auto \
--report-id replay_first_project \
-- python app.py
Expected output includes:
ReplayLab replay finished
Command exit code: 0
Next steps
- Inspect report: replaylab report inspect .replaylab/replays/replay_first_project/report.json
- Compare against capsule: replaylab report compare <capsule_id> .replaylab/replays/replay_first_project/report.json --local-store-root .replaylab
- Open local viewer: replaylab report view report .replaylab/replays/replay_first_project/report.json --capsule <capsule_id> --output replay-viewer.html --local-store-root .replaylab
- Generate provider replay guard: replaylab generate-test <capsule_id> --output tests/regression/test_replay.py --fixture-root tests/fixtures/replaylab/capsules --app-root . --auto-patch-integrations auto --local-store-root .replaylab -- <app command>
Replay is meaningful here because the local provider is no longer running. If ReplayLab misses the
provider call, the app tries to connect to 127.0.0.1:8765 and fails.
The Next steps block is deliberately safe: it points to the follow-up commands without printing
payload bodies or the original app command arguments.
6. Compare And View
replaylab report inspect .replaylab/replays/replay_first_project/report.json
replaylab report compare \
<capsule_id> \
.replaylab/replays/replay_first_project/report.json \
--local-store-root .replaylab
replaylab report view report \
.replaylab/replays/replay_first_project/report.json \
--capsule <capsule_id> \
--local-store-root .replaylab \
--output replay-viewer.html
The command writes replay-viewer.html and opens it in your browser. It shows the replay status,
boundary count, provider, request hash, payload availability, and next commands without rendering
payload bodies or secrets.
7. Generate A Regression
replaylab generate-test <capsule_id> \
--output tests/regression/test_first_project_replay.py \
--fixture-root tests/fixtures/replaylab/capsules \
--app-root . \
--auto-patch-integrations auto \
-- python app.py
pytest tests/regression/test_first_project_replay.py
The generated pytest should pass with provider.py still stopped. That means your regression test
uses the captured capsule instead of the live local service.
What Happened
ReplayLab installed provider wrappers in the current Python process when replaylab.init(...) ran.
The handle.capture(...) scope opened a run and default step for the app work. The requests.get(...)
call recorded a request/response boundary with full payload refs. During replay, ReplayLab served the
recorded response from the capsule and wrote a replay report.
The next step is to replace the loopback provider with your real provider call, or use the HTTP Capture And Replay and OpenAI Responses tutorials for provider-specific examples.