Skip to content

Python Integration

Installation

TraceCov is available as a Python package:

$ uv pip install tracecov

Basic Usage

The core workflow with TraceCov involves three steps: creating a coverage map, tracking API calls, and generating a report.

Step 1: Create a CoverageMap Instance

First, create a coverage map by providing your OpenAPI schema:

import tracecov

coverage = tracecov.CoverageMap.from_path("openapi.json")

# Alternatively, from an already parsed schema
# coverage = tracecov.CoverageMap.from_dict(schema)

Step 2: Track API calls

TraceCov offers multiple ways to track API calls, depending on your testing approach and existing code structure:

import requests

# Option A: Create and configure a session
session = coverage.requests.track_session(requests.Session())
session.headers.update({"Authorization": "Bearer token"})

# Use the session as normal - all requests will be tracked
response = session.get("https://api.example.com/users/1")
response = session.post("https://api.example.com/users", json={"name": "Alice"})

# Option B: Record individual requests manually
response = requests.get("https://api.example.com/users/1")
coverage.requests.record(request=response.request, response=response)

# Option C: Pass a response hook to each call
hook = coverage.requests.response_hook()
response = requests.get(
    "https://api.example.com/users/1", hooks={"response": [hook]}
)

Step 3: Generate a Coverage Report

Once you've tracked your API interactions, generate an HTML report to visualize your coverage:

# Store an HTML report to a file
# Default filename is coverage.html
coverage.save_report(output_file="my-api-coverage.html")
# Or get it as a string
html = coverage.generate_report()

Open my-api-coverage.html in a browser. For a quick check in the terminal, print the text report:

print(coverage.generate_text_report(width=80, colored=False))

For an openapi.json with GET /users, POST /users, and GET /users/{id}, the calls above give:

Operation                                      Params   Missed   Partial   Cover
--------------------------------------------------------------------------------
GET /users                                          1        1         0   0.00%
POST /users                                         1        0         1   0.00%
GET /users/{id}                                     1        0         1   0.00%
--------------------------------------------------------------------------------
TOTAL                                               3        1         2   0.00%

Using with other HTTP clients

TraceCov also supports httpx2 (the maintained successor of httpx) and legacy httpx:

import httpx2

client = coverage.httpx.track_client(httpx2.Client())
# Use the client as normal - all requests will be tracked
# `track_client` also accepts `AsyncClient`
client = coverage.httpx.track_client(httpx2.AsyncClient())

The same calls accept httpx.Client / httpx.AsyncClient.

FastAPI / Starlette

FastAPI's TestClient inherits from httpx.Client, so it works with the httpx integration:

import tracecov
from fastapi import FastAPI
from fastapi.testclient import TestClient

app = FastAPI()


@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"id": user_id}


coverage = tracecov.CoverageMap.from_dict(app.openapi())
client = coverage.httpx.track_client(TestClient(app))

response = client.get("/users/1")

Django / Django REST Framework

TraceCov integrates with Django's test Client, AsyncClient, and Django REST Framework's APIClient. The examples need configured Django settings: run them under pytest-django or with DJANGO_SETTINGS_MODULE set.

from django.test import Client
import tracecov

coverage = tracecov.CoverageMap.from_path("openapi.json")

# Wrap the test client
client = coverage.django.track_client(Client())

# All requests are automatically tracked
response = client.get("/api/users/")
response = client.post("/api/users/", {"name": "John"}, content_type="application/json")

Async tests work with AsyncClient. This test uses the tracecov_map fixture from the pytest plugin:

from django.test import AsyncClient
import pytest

@pytest.mark.anyio
async def test_coverage(tracecov_map):
    client = tracecov_map.django.track_client(AsyncClient())
    response = await client.get("/api/users/")
    assert response.status_code == 200

For Django REST Framework's APIClient:

from rest_framework.test import APIClient

client = coverage.django.track_client(APIClient())
client.credentials(HTTP_AUTHORIZATION="Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b")
response = client.get("/api/protected/")

Manual recording is also supported:

from django.test import Client

client = Client()
response = client.get("/api/users/")

# Elapsed time is measured automatically with track_client,
# but can be passed manually when using record directly
coverage.django.record(response.wsgi_request, response, elapsed=0.5)

You can also use RequestFactory or APIRequestFactory to build requests directly without making HTTP calls:

from django.http import JsonResponse
from django.test import RequestFactory
from rest_framework.test import APIRequestFactory


def create_user(request):
    return JsonResponse({"name": "John"}, status=201)


# Django's RequestFactory
factory = RequestFactory()
request = factory.post("/api/users/", {"name": "John"}, content_type="application/json")

# DRF's APIRequestFactory (supports format parameter)
factory = APIRequestFactory()
request = factory.post("/api/users/", {"name": "John"}, format="json")

# Call your view directly
response = create_user(request)

# Record for coverage
coverage.django.record(request, response)

Flask

TraceCov integrates with Flask's test client:

from flask import Flask
import tracecov

app = Flask("myapp")

@app.route("/api/users/", methods=["GET", "POST"])
def users():
    return {"status": "ok"}

coverage = tracecov.CoverageMap.from_path("openapi.json")

# Wrap the test client
client = coverage.flask.track_client(app.test_client())

# All requests are automatically tracked
response = client.get("/api/users/")
response = client.post("/api/users/", json={"name": "John"})

Manual recording is also supported:

from flask import Flask
import tracecov

app = Flask("myapp")

@app.route("/api/users/")
def users():
    return {"status": "ok"}

coverage = tracecov.CoverageMap.from_path("openapi.json")
client = app.test_client()
response = client.get("/api/users/")

# Access the request from the response
coverage.flask.record(response.request, response, elapsed=0.5)

Using with pytest

TraceCov includes a built-in pytest plugin that prints a coverage summary after your run and saves HTML or Markdown reports.

See the pytest Plugin guide for setup and all available options.

For cases where you need full control over the coverage map inside tests — for example, to share a tracked HTTP client across fixtures — create a session fixture manually. A fixture named tracecov_map replaces the plugin's own, so the plugin reports on this map:

import pytest
import requests
import tracecov


@pytest.fixture(scope="session")
def tracecov_map():
    return tracecov.CoverageMap.from_path("openapi.json")


@pytest.fixture(scope="session")
def api_client(tracecov_map):
    return tracecov_map.requests.track_session(requests.Session())


def test_get_user(api_client):
    response = api_client.get("https://api.example.com/users/1")
    assert response.status_code == 200

Using with Schemathesis

Schemathesis is a property-based testing tool for APIs. TraceCov can track all API calls made during Schemathesis test runs:

Step 1: Create a Python file, for example hooks.py

import tracecov

tracecov.schemathesis.install()

Step 2: Set the SCHEMATHESIS_HOOKS environment variable

$ export SCHEMATHESIS_HOOKS=hooks

Step 3: Run Schemathesis

$ schemathesis run https://example.schemathesis.io/openapi.json

...
_______________________________ Schema Coverage ________________________________

Operations          10/10  100.0%
Parameters           0/7     0.0%  (7 partial)
Keywords             2/21    9.5%  (19 partial)
Examples             2/2   100.0%
Responses           16/18   88.8%
Response Keywords   43/65   66.1%

HTML report         ./schema-coverage.html

"Partial" counts items exercised with only valid or only invalid values. Add text to --coverage-format (e.g. --coverage-format=html,text) for a per-operation table below the summary; --coverage-no-report turns the section off.

Note

TraceCov is tested with Schemathesis 4.18.4 and above.

Low-Level API

For advanced use cases or integration with custom HTTP clients, TraceCov provides a low-level API that accepts generic request and response objects:

from tracecov import HttpRequest, HttpResponse

coverage.record(
    request=HttpRequest(
        method="GET",
        url="https://api.example.com/users/1",
        body=None,
        headers={},
    ),
    response=HttpResponse(
        status_code=200,
        elapsed=1.3,
        body=b'{"id": 1, "name": "Alice"}',
        headers={"Content-Type": "application/json"},
    ),
)

Pass the response body and headers; without them, response schema coverage is not measured.

Third-Party Format Integrations

Professional Edition

HAR, Postman, and VCR import features require TraceCov Professional.

TraceCov has built-in support for common API traffic formats.

Postman Collections

If you use Postman for API testing, TraceCov can analyze your collections to measure coverage:

import json

# Load and analyze a Postman Collection from a file
coverage.postman.record_from_path("path/to/collection.json")

# Analyze a collection from a dictionary
with open("path/to/collection.json") as fd:
  collection = json.load(fd)
coverage.postman.record_from_dict(collection)

Note

TraceCov supports Postman Collection formats v1.0, v2.0, and v2.1.

HTTP Archive (HAR) Files

TraceCov can analyze HAR files exported from browser dev tools or API tools:

import json

# Load and analyze a HAR file
coverage.har.record_from_path("path/to/traffic.har")

# Analyze HAR data from a dictionary
with open("path/to/traffic.har") as fd:
  har = json.load(fd)
coverage.har.record_from_dict(har)

Note

TraceCov supports HAR formats v1.2 and v1.3 from Chrome, Firefox, Edge, Postman, and other tools that export standard HAR format.

VCR Cassettes

TraceCov can analyze VCR cassette files:

import json

# Load and analyze a VCR cassette from a file
coverage.vcr.record_from_path("path/to/cassette.json")

# Analyze a cassette from a dictionary
with open("path/to/cassette.json") as fd:
  cassette = json.load(fd)
coverage.vcr.record_from_dict(cassette)

Note

Cassettes from Ruby's VCR library and Schemathesis are supported.

Troubleshooting

Nothing is recorded, or coverage stays at 0%

Request paths must match the specification's paths plus the base path. The base path comes from servers[0].url (OpenAPI 3) or basePath (Swagger 2.0). When the API is served under a different prefix, pass it explicitly:

coverage = tracecov.CoverageMap.from_path("openapi.json", base_path="/api/v1")

coverage.unmatched_requests() lists requests that matched no operation, and coverage.dropped_requests() counts requests with an unparsable URL or an unknown HTTP method. See the Python API reference.