Skip to main content

TrafficMorph Python SDK — typed client for the /api/v1 API.

Project description

TrafficMorph Python SDK

████████╗██████╗  █████╗ ███████╗███████╗██╗ ██████╗
╚══██╔══╝██╔══██╗██╔══██╗██╔════╝██╔════╝██║██╔════╝
   ██║   ██████╔╝███████║█████╗  █████╗  ██║██║
   ██║   ██╔══██╗██╔══██║██╔══╝  ██╔══╝  ██║██║
   ██║   ██║  ██║██║  ██║██║     ██║     ██║╚██████╗
   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝     ╚═╝     ╚═╝ ╚═════╝
        ███╗   ███╗ ██████╗ ██████╗ ██████╗ ██╗  ██╗
        ████╗ ████║██╔═══██╗██╔══██╗██╔══██╗██║  ██║
        ██╔████╔██║██║   ██║██████╔╝██████╔╝███████║
        ██║╚██╔╝██║██║   ██║██╔══██╗██╔═══╝ ██╔══██║
        ██║ ╚═╝ ██║╚██████╔╝██║  ██║██║     ██║  ██║
        ╚═╝     ╚═╝ ╚═════╝ ╚═╝  ╚═╝╚═╝     ╚═╝  ╚═╝

PyPI Python versions License

Typed Python client for the TrafficMorph /api/v1 API. Request and response shapes are typed attrs classes; endpoint methods expose both sync and async call styles.

Install

# Quick start — always picks up the latest release.
pip install trafficmorph

# Reproducible builds (CI / production) — pin to an exact version.
pip install 'trafficmorph==0.3.3'

Prerequisites

  • Python 3.10 or newer — declared minimum in pyproject.toml. Required for PEP 604 union syntax (str | None).
  • A TrafficMorph API key in the form tm_…. Provision one from the in-app Settings → API keys page.
  • A reachable TrafficMorph install. The examples below assume http://localhost:8080 for local development; swap for your hosted URL otherwise. There is no built-in default — the SDK requires the base URL to be set explicitly.

Quickstart

Export the two required values before running the program, so the snippet works as a single copy-paste:

export TM_API_KEY="tm_your_key_here"
export TM_BASE_URL="http://localhost:8080"   # or your hosted TrafficMorph URL

Then:

import json
import os

from trafficmorph import Client
from trafficmorph.api.profiles import list_profiles

c = Client(
    api_key=os.environ["TM_API_KEY"],
    base_url=os.environ["TM_BASE_URL"],
    timeout=15.0,
)

resp = list_profiles.sync_detailed(client=c.api)
print(f"status: {resp.status_code}, {len(resp.content)} bytes")

First successful call checklist

  • tm_… API key exported as TM_API_KEY (or passed as the api_key= kwarg).
  • TM_BASE_URL points at a reachable TrafficMorph server (http://localhost:8080 for local dev).
  • Program prints status: 200, N bytes — an empty profile list is [], so N is typically ≥ 2.
  • resp.content holds the JSON payload (bytes). Decode it per Decoding responses below.

If the program errored before reaching the first line, jump to Common errors.

Decoding responses

resp.content is the raw HTTP response body as bytes. Decode with json and the typed classes from trafficmorph.models — replace the print(...) line in the Quickstart with:

from trafficmorph.models import TrafficProfileSummaryResponse

if resp.status_code == 200:
    profiles = [
        TrafficProfileSummaryResponse.from_dict(p)
        for p in json.loads(resp.content)
    ]
    for p in profiles:
        print(p.id, p.name)
elif resp.status_code in (400, 401, 403, 404):
    err = json.loads(resp.content)
    raise SystemExit(f"server returned {resp.status_code}: {err.get('error')}")
else:
    raise SystemExit(f"unexpected status {resp.status_code}: {resp.content!r}")

The *.from_dict classmethod on every model handles the OpenAPI optional-field semantics — missing fields become attrs.NOTHING so you don't get surprise KeyErrors.

For status-code branching alone (without decoding), use resp.status_code. resp.content is the raw bytes; resp.headers is the response headers.

Next steps

Three common flows after list_profiles:

Create a profile

from trafficmorph.api.profiles import create_profile
from trafficmorph.models import ApiProfileRequest, TrafficProfilePointRequest

body = ApiProfileRequest(
    name="smoke-test",
    target_url="https://api.example.com/health",
    http_method="GET",
    duration=60,
    points=[
        TrafficProfilePointRequest(x=0, y=10),
        TrafficProfilePointRequest(x=60, y=10),
    ],
)
resp = create_profile.sync_detailed(client=c.api, body=body)

Start a run

from trafficmorph.api.runs import start

# profile_id from list_profiles or create_profile
resp = start.sync_detailed(client=c.api, id=profile_id)
# resp.status_code == 200 → run started; poll get_profile for status.

View recent history

from trafficmorph.api.history import list_history

resp = list_history.sync_detailed(
    client=c.api,
    size=20,
    # Other optional filters: profile_id, triggered_by, region, auto_verdict, tag.
)

Every endpoint function exposes four call styles:

Form Returns
endpoint.sync(client=…) Parsed body (currently None — see Decoding responses)
endpoint.sync_detailed(client=…) Response with .status_code, .content, .headers
endpoint.asyncio(client=…) Awaitable form of sync
endpoint.asyncio_detailed(client=…) Awaitable form of sync_detailed

For most cases, prefer sync_detailed / asyncio_detailed — they give you status code branching and the raw bytes for decoding.

Common errors

All errors below come from Client(...) — they surface at construction time, before any network call, so you don't need to set up the rest of your app to hit them.

Error fragment Cause Fix
api_key must not be empty First arg to Client is "" — usually a missing TM_API_KEY env var. Pass the literal key or export TM_API_KEY=... before running.
api_key: value contains a carriage return … (or newline, NUL, DEL, other control byte) API key has stray whitespace / control chars (a common copy-paste artifact). Only the literal tm_… characters belong in the value; strip surrounding whitespace.
base_url is required: pass base_url='http://…' No base_url= kwarg AND no $TM_BASE_URL env var. Pass base_url="http://..." or export TM_BASE_URL.
base URL "…" must include http:// or https:// scheme Base URL is missing the protocol (e.g. localhost:8080). Add the scheme: http://localhost:8080.
base URL "…" has scheme "…"; must be http or https Non-http/https scheme (e.g. ftp://…). Use http:// or https://.
base URL "…" must not contain a query string Base URL has ?key=value appended. Strip the query — attach per-request params at the endpoint call site instead.
base URL "…" must not contain a fragment Base URL has #foo appended. Strip the fragment — fragments are client-side only and meaningless to the server.
$TM_BASE_URL: … (any of the above) Env-supplied base URL fails the same checks. Same fixes; the prefix names the source so you know whether the kwarg or the env var was at fault.

Configuration

Source Precedence
Constructor kwargs (base_url=, timeout=, …) Highest
Environment variables (TM_BASE_URL) Middle
Built-in defaults Lowest
Kwarg Env var Default Notes
api_key (required) Full tm_… value. Empty string and header-invalid characters rejected upfront.
base_url TM_BASE_URL none — required Points at your TrafficMorph install. See Base URL rules for accepted/rejected shapes.
timeout 30.0 Per-call timeout in seconds. Applied via httpx.Timeout on every request.
user_agent tm-python-sdk/<spec-version> Override to tag app traffic in HTTP logs (e.g. "my-app/1.2.3 (tm-python-sdk/v1)").
httpx_args {} Extra kwargs forwarded to the underlying httpx.Client (proxies, mTLS, custom transports).

Base URL rules

Kwarg and env values are validated and normalized the same way, so they produce identical results for the same logical input. The kwarg wins on conflict.

Accepted shapes — any absolute http:// or https:// URL with a non-empty host:

  • http://localhost:8080 — typical local dev.
  • https://app.example.com — hosted deployment.
  • https://host/proxy-prefix — reverse-proxy mount; the prefix is preserved during URL resolution.
  • https://host/a%2Fb — percent-encoded path segments stay verbatim. Per RFC 3986, /a%2Fb (one segment, containing a literal slash) and /a/b (two segments) are semantically different paths — the SDK never collapses one into the other.

The SDK appends a trailing slash if missing, so both spellings (with or without) produce the same final value.

Rejected at construction time — clear error from Client(...), not a late transport failure:

Bad input Error fragment
"" or whitespace-only must not be empty
localhost:8080 (no scheme) must include … scheme
ftp://x (wrong scheme) must be http or https
https:// (no host) must include a host
https://x/?q=1 (query) must not contain a query string
https://x/#frag (fragment) must not contain a fragment

Query strings and fragments are refused because they belong on per-request URLs, not the deployment root.

Authentication

The SDK sends every request with X-Api-Key: tm_…. The API also accepts Authorization: Bearer tm_…, but the SDK uses X-Api-Key.

What's in the box

trafficmorph                 ← public package (Client, env names, constants)
trafficmorph.api.<tag>       ← endpoint modules, one per OpenAPI tag
trafficmorph.models          ← typed request/response attrs classes
trafficmorph.errors          ← UnexpectedStatus exception

Endpoint coverage matches the server's /api/v1 endpoints 1:1:

Module Endpoints
trafficmorph.api.profiles list_profiles, create_profile, get_profile, update_profile, delete_profile
trafficmorph.api.runs start, stop, pause, resume
trafficmorph.api.history list_history, get_history_item
trafficmorph.api.domains list_, add, verify_dns, verify_http, remove
trafficmorph.api.captures analyse, import_capture
trafficmorph.api.variables_sets list_variables_sets, create, get, rename, change_mode, delete

Versioning

Symbol Meaning
SDK release PyPI version (pip install trafficmorph==X.Y.Z) Pin in your requirements.txt or pyproject.toml
API version trafficmorph.SPEC_VERSION (currently "v1") The /api/v1 revision this SDK targets

Each SDK release targets one specific server /api/v1 revision. The server preserves backwards compatibility within /api/v1, so SDK and server versions move independently — any released SDK version works against any TrafficMorph server still exposing /api/v1.

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

trafficmorph-0.3.3.tar.gz (35.3 kB view details)

Uploaded Source

Built Distribution

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

trafficmorph-0.3.3-py3-none-any.whl (79.1 kB view details)

Uploaded Python 3

File details

Details for the file trafficmorph-0.3.3.tar.gz.

File metadata

  • Download URL: trafficmorph-0.3.3.tar.gz
  • Upload date:
  • Size: 35.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for trafficmorph-0.3.3.tar.gz
Algorithm Hash digest
SHA256 e8b7e8d16b77fc1ed154773628b632c08aac56dcad5ab418df883b2cbb7d7e4f
MD5 4755891cc16c1b964f27e967cf7347a5
BLAKE2b-256 f8a07f033bf2cb8662a303d91c6eed5c0e318f4c209962e9de002aed37c353a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for trafficmorph-0.3.3.tar.gz:

Publisher: publish-trafficmorph.yml on trafficmorph-gif/tm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file trafficmorph-0.3.3-py3-none-any.whl.

File metadata

  • Download URL: trafficmorph-0.3.3-py3-none-any.whl
  • Upload date:
  • Size: 79.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for trafficmorph-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 aac539a833dc0ffd5f58bba94ba33a4bd33e1fe877613a891b9e48f2985a765a
MD5 fec9a92220c901ac2cb6b7ef87218e7a
BLAKE2b-256 0560fb699a7ee7626cb677aeb2f9893b9a667965539f764548e361d585e2ec19

See more details on using hashes here.

Provenance

The following attestation bundles were made for trafficmorph-0.3.3-py3-none-any.whl:

Publisher: publish-trafficmorph.yml on trafficmorph-gif/tm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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