Skip to content

Latest commit

 

History

History
73 lines (57 loc) · 3.65 KB

File metadata and controls

73 lines (57 loc) · 3.65 KB

Python SDK codegen (sub-plan 21.3 row C-1)

Per-package codegen tooling decision for @blockchain0x/python (pypi blockchain0x).

What gets generated, what stays handwritten

Layer Source Style
Pydantic models apps/backend/openapi/openapi.yaml codegen
HTTP transport src/blockchain0x/_client.py handwritten
Webhook verifier src/blockchain0x/webhooks.py handwritten
x402 client (Phase C-7, separate package blockchain0x-x402 on pypi) handwritten
Resource methods src/blockchain0x/resources/*.py hybrid (handwritten ergonomics over codegen models)
Errors src/blockchain0x/_errors.py handwritten
Tests tests/ handwritten

Why hybrid

Pure codegen produces transport clients that look great until you need retry, idempotency, structured errors, or the discriminated-union webhook verifier - then the generator gets in the way. Pure handwriting makes every new OpenAPI field a manual port.

The split:

  • Codegen the closed-set DTOs: every request body, response body, and error envelope shape that mirrors components.schemas in the spec. These rarely have ergonomics worth preserving.
  • Handwrite the verbs: every resource method (client.api_keys.list, etc.) is a thin call into the transport with a typed return - small enough that the typing benefit beats the codegen drift cost.
  • Always handwrite the operational pieces: transport, retry, idempotency, error mapping, webhook verifier, x402 client. These are what the SDK ships for; codegen them once and you regret it for the next 18 months.

Tooling: datamodel-code-generator

Pick: datamodel-code-generator configured with --output-model-type pydantic_v2.BaseModel.

Rationale:

  • Pydantic v2 is the de facto Python type framework for HTTP APIs.
  • datamodel-code-generator understands the OpenAPI 3.1 dialect this spec uses (type: [string, 'null'] tuples).
  • Output is editable, type-stable, and round-trippable to JSON.
  • The generated models live under src/blockchain0x/_models/ (single flat namespace) so resources can from .._models import ApiKey without knowing about codegen plumbing.

Regenerate

# from packages/sdk-python/
./codegen/regenerate.sh

The script (lands with C-1 implementation work) reads ../../apps/backend/openapi/openapi.yaml and writes to src/blockchain0x/_models/api.py. The CI workflow in Phase G opens a PR per language whenever openapi.yaml changes.

Why not openapi-python-client / openapi-generator-cli

  • openapi-python-client produces a full Client + Resource scaffold, not just types. The scaffold style does not match this SDK's ergonomics (no structured retry, no Idempotency-Key minting, opaque error handling).
  • openapi-generator-cli with -g python is heavier (Jinja templates in Java; slow CI). Its generated client is the same mismatch.
  • We want types-only, fast, Python-native. datamodel-code-generator is that.