API reference¶
Everything public is importable from the package root:
from action0.openapi import load_documents, bundle_documents, RefResolver, SchemaError
from action0.openapi import Api, Model, EnumModel, Field, OperationIR, Param, Body
from action0.openapi import SecurityScheme
Schema loading¶
Loading OpenAPI schema documents from disk or via http(s).
load_schema() reads a JSON or YAML file into the plain
dict the rest of the pipeline works on and verifies it actually is
an OpenAPI 3.x document. load_documents() additionally follows
file references (./components/geo.yaml#/...) and loads every
referenced file too, for bundle_documents()
to merge; its schema source may also be an http(s) URL, and referenced
files download — each one gated by the caller’s allow_download
consent callback. JSON needs nothing beyond the stdlib; YAML needs
PyYAML, installable as the yaml extra of
this package — the import happens lazily, so JSON-only users never
touch it.
- class action0.openapi.loader.Documents(root, files)[source]¶
An OpenAPI document plus every file it references, loaded.
Keys are canonical file paths (absolute, symlinks and
..resolved) or http(s) URLs, so the same file referenced from two places is loaded — and later bundled — only once.
- action0.openapi.loader.load_schema(path)[source]¶
Read an OpenAPI 3.x document from a JSON or YAML file.
.yaml/.ymlfiles are parsed as YAML, everything else is parsed as JSON first and — since JSON is a subset of YAML — as YAML if that fails.
- action0.openapi.loader.load_documents(source, *, allow_download=None)[source]¶
Load a schema and, recursively, every file its
$refs point at.The source may be a file path or an http(s) URL; naming a URL as the source is the consent to fetch it. Relative reference paths resolve against the file containing them — against its URL, for a downloaded document, which can therefore only ever reference further URLs, never local files. Referenced URLs were not named by the caller, so each one downloads only after
allow_downloadapproves it; without the callback, any referenced URL is an error. Referenced files are decoded like schemas but not validated as OpenAPI documents — component-only fragment files have noopenapiversion field. The loaded set is merged into a single document bybundle_documents().- Parameters:
- Return type:
- Returns:
the loaded document set
- Raises:
SchemaError – if any file cannot be read, downloaded or decoded, a download is not approved, the root is not an OpenAPI 3.0/3.1 schema, or a reference has an unsupported scheme
Multi-file bundling¶
Bundling multi-file OpenAPI documents into a single document.
OpenAPI schemas may reference sibling files, as in
$ref: './components/geo.yaml#/components/schemas/Point'. The rest
of the pipeline works on one document with local #/... pointers
only, so bundle_documents() merges a loaded file set (see
load_documents()) up front: referenced
components are imported into the root document’s components
sections — renamed on a name collision, with a warning — and references
to anything that is not a component are inlined. The result parses
exactly like a hand-bundled single file.
- action0.openapi.bundle.bundle_documents(documents)[source]¶
Merge a loaded multi-file schema into one single-file document.
Every reference into another file is either imported — the target sits under a
#/components/<section>/<Name>pointer, so it moves into the root document’s matching section, keeping its name unless that name is already taken — or inlined in place, when the target is not a component (a deep pointer, or a whole-file reference). A single-file document without file references is returned unchanged.>>> from action0.openapi.loader import Documents >>> documents = Documents( ... root="/specs/zoo.json", ... files={ ... "/specs/zoo.json": { ... "openapi": "3.0.3", ... "components": {"schemas": {"Cage": {"$ref": "./geo.json#/components/schemas/Point"}}}, ... }, ... "/specs/geo.json": {"components": {"schemas": {"Point": {"type": "object"}}}}, ... }, ... ) >>> document, warnings = bundle_documents(documents) >>> document["components"]["schemas"]["Cage"] {'$ref': '#/components/schemas/Point'} >>> document["components"]["schemas"]["Point"] {'type': 'object'} >>> warnings []
- Parameters:
documents (
Documents) – the loaded document set- Return type:
- Returns:
the merged document and the bundling warnings (component renames)
- Raises:
SchemaError – on broken pointers, references to files missing from the set, or circular references that cannot be represented locally
- action0.openapi.bundle.referenced_files(document, *, base)[source]¶
List the canonical paths of the files a document references.
>>> referenced_files( ... {"$ref": "./components/geo.yaml#/components/schemas/Point"}, ... base="/specs/zoo.yaml", ... ) ['/specs/components/geo.yaml']
- Parameters:
- Return type:
- Returns:
the referenced files (paths or URLs), in document order, without duplicates and without
baseitself- Raises:
SchemaError – on references with an unsupported scheme
Reference resolution¶
Resolution of local $ref pointers inside an OpenAPI document.
OpenAPI schemas reference shared definitions as JSON pointers like
#/components/schemas/Pet. RefResolver looks such
pointers up in the loaded document and follows chains of them, so the
translation stage can work with plain schema objects. Only local
references (into the same document) are supported — remote and file
references raise SchemaError.
- class action0.openapi.resolve.RefResolver(document)[source]¶
Looks up local
$refJSON pointers in one OpenAPI document.- lookup(ref)[source]¶
Return the node a local JSON pointer refers to.
>>> resolver = RefResolver({"components": {"schemas": {"Pet": {"type": "object"}}}}) >>> resolver.lookup("#/components/schemas/Pet") {'type': 'object'}
- Parameters:
ref (
str) – the pointer, e.g.#/components/schemas/Pet- Return type:
- Returns:
the referenced node
- Raises:
SchemaError – if the pointer is not local or does not resolve
- deref(node)[source]¶
Follow a (chain of)
$refto the actual schema object.A node without
$refis returned as-is, so this is safe to call on every schema-shaped node.>>> resolver = RefResolver({"components": {"schemas": {"Pet": {"type": "object"}}}}) >>> resolver.deref({"$ref": "#/components/schemas/Pet"}) {'type': 'object'} >>> resolver.deref({"type": "string"}) {'type': 'string'}
Translation¶
Translating an OpenAPI 3.x document into the intermediate representation.
parse_api() walks a loaded schema document and produces the
Api the emitter renders: the
components/schemas become models and enums (inline schemas are
synthesized into named models on the way), the paths become
operations with parameters, body and response type, and the referenced
securitySchemes become client credentials. Everything outside the
supported subset raises SchemaError
naming the offending schema location; lesser omissions (an unsupported
security scheme, several request media types) are collected as
warnings.
- action0.openapi.parse.parse_api(document)[source]¶
Translate a loaded OpenAPI 3.x document into an
Api.- Parameters:
document (
Mapping[str,Any]) – the document, as returned byload_schema()- Return type:
- Returns:
the intermediate representation
- Raises:
SchemaError – for constructs outside the supported subset
Intermediate representation¶
The intermediate representation (IR) between OpenAPI and generated code.
The translation stage turns a loaded OpenAPI document into one
Api value — plain, frozen dataclasses that carry everything
the code emitter needs and nothing else: models with their fields,
enums, operations with parameters and body, and the security schemes.
All names in the IR are the final Python names (classes PascalCase,
fields snake_case, path templates rewritten to match the field names);
the original schema spellings survive as the wire_name.
Keeping this layer independent of both the OpenAPI document shape and
the emitted source text is deliberate: a future dynamic mode (building
operation classes at import time instead of writing files) would
consume the very same Api.
- class action0.openapi.ir.Scalar(*values)[source]¶
The scalar types generated code distinguishes.
- ANY = 'any'¶
free-form values that stay whatever the JSON decoder produced
- class action0.openapi.ir.MapType(value)[source]¶
A JSON object with
additionalPropertiesonly —dict[str, value]in generated code.
- class action0.openapi.ir.ModelType(name)[source]¶
A reference to a generated model dataclass, by Python class name.
- Parameters:
name (
str)
- class action0.openapi.ir.EnumType(name)[source]¶
A reference to a generated enum class, by Python class name.
- Parameters:
name (
str)
- class action0.openapi.ir.UnionType(name, members)[source]¶
A reference to a generated union alias, by Python name.
The members ride along so the type logic (annotations, whether a conversion is needed at all) works without looking the union up.
- action0.openapi.ir.TypeExpr: TypeAlias = 'ScalarType | ArrayType | MapType | ModelType | EnumType | UnionType'¶
any type generated code can express
- class action0.openapi.ir.Field(name, wire_name, type, required, nullable=False, default=None, description=None)[source]¶
One property of a model, or one field of a request body.
- Parameters:
name (
str) – the Python field namewire_name (
str) – the property name in the JSON/form payloadtype (
ScalarType|ArrayType|MapType|ModelType|EnumType|UnionType) – the field’s typerequired (
bool) – whether the payload must contain the propertynullable (
bool, default:False) – whethernullis a legal payload valuedefault (
object|None, default:None) – the schema’s default value (scalars only), orNonewhen the schema declares nonedescription (
str|None, default:None) – the schema’s description, for docstrings
- class action0.openapi.ir.Model(name, fields, additional_field=None, description=None)[source]¶
One generated dataclass model.
- Parameters:
name (
str) – the Python class namefields (
tuple[Field,...]) – the model’s fields; the ones rendered without a dataclass default (required and not nullable) come firstadditional_field (
Field|None, default:None) – the catch-all field collecting the payload keys not declared underproperties(schemas combiningpropertieswithadditionalProperties), orNonewhen the schema declares no additional properties; its type is always aMapType, and itswire_nameis empty — the catch-all has no single wire spellingdescription (
str|None, default:None) – the schema’s description, for the docstring
- class action0.openapi.ir.EnumModel(name, base, members, description=None)[source]¶
One generated
enum.Enumclass.
- class action0.openapi.ir.UnionCheck(*values)[source]¶
How one union member is recognized in a decoded payload.
- JSON_TYPE = 'json-type'¶
an
isinstancecheck against a JSON-level Python type
- TAG = 'tag'¶
the discriminator property equals a tag value
- KEY = 'key'¶
a required key only this member has is present
- class action0.openapi.ir.UnionCase(member, check, value)[source]¶
One branch of a union’s dispatching converter.
- Parameters:
member (
ScalarType|ArrayType|MapType|ModelType|EnumType|UnionType) – the member built when the check matchescheck (
UnionCheck) – how the member is recognizedvalue (
str) – the check’s argument — the Python type name (e.g.str,(int, float)) forUnionCheck.JSON_TYPE, the tag value forUnionCheck.TAG, the property name forUnionCheck.KEY
- class action0.openapi.ir.UnionModel(name, members, cases, discriminator=None, description=None)[source]¶
One generated union: a type alias plus a dispatching converter.
- Parameters:
name (
str) – the Python alias namemembers (
tuple[ScalarType|ArrayType|MapType|ModelType|EnumType|UnionType,...]) – the member types, in schema ordercases (
tuple[UnionCase,...]) – the dispatch branches, in the order they are emitteddiscriminator (
str|None, default:None) – the wire property carrying the tag (forUnionCheck.TAGcases)description (
str|None, default:None) – the schema’s description, for the docstring
- class action0.openapi.ir.Param(name, wire_name, location, type, required, nullable=False, default=None, join_with=None, description=None)[source]¶
One path, query or header parameter of an operation.
- Parameters:
name (
str) – the Python field namewire_name (
str) – the parameter name on the wirelocation (
ParamLocation) – where the parameter goestype (
ScalarType|ArrayType|MapType|ModelType|EnumType|UnionType) – the parameter’s typerequired (
bool) – whether the parameter must be sentnullable (
bool, default:False) – whether the schema allowsnulldefault (
object|None, default:None) – the schema’s default value (scalars only), orNonewhen the schema declares nonejoin_with (
str|None, default:None) – the separator joining an array parameter’s items into onekey=valuepair (a non-explodedstyle), orNonefor the default one-pair-per-item serializationdescription (
str|None, default:None) – the parameter’s description, for docstrings
- class action0.openapi.ir.BodyKind(*values)[source]¶
How an operation’s request body is expressed as fields.
- JSON_FIELDS = 'json-fields'¶
an inline JSON object schema, one
json_field()per property
- JSON_BODY = 'json-body'¶
a referenced/array/scalar JSON schema, one
json_body()field
- FORM_FIELDS = 'form-fields'¶
application/x-www-form-urlencoded, oneform_field()per property
- RAW_BODY = 'raw-body'¶
any other media type, one raw-bytes
body()field
- class action0.openapi.ir.Body(kind, fields=(), type=None, required=True, media_type=None)[source]¶
An operation’s request body.
- Parameters:
kind (BodyKind) – how the body maps to operation fields
fields (tuple[Field, …], default:
()) – the properties (forBodyKind.JSON_FIELDSandBodyKind.FORM_FIELDS), or the single payload field (BodyKind.JSON_BODYandBodyKind.RAW_BODY)type (TypeExpr | None, default:
None) – the whole-body type (forBodyKind.JSON_BODY;Noneotherwise)required (bool, default:
True) – whether the request must carry the bodymedia_type (str | None, default:
None) – the media type sent asContent-Type(forBodyKind.RAW_BODY;Noneotherwise)
- class action0.openapi.ir.ErrorCase(status, exception, model, description=None)[source]¶
One documented non-2xx response, raised as a typed exception.
- Parameters:
status (
str) – the response key — a concrete status ("400"), a range ("4XX"/"5XX") or"default"exception (
str) – the generated exception class name; operations documenting the same status with the same model share itmodel (
str) – the class name of the model the error payload parses intodescription (
str|None, default:None) – the response’s description, for thecheckdocstring
- class action0.openapi.ir.ResponseKind(*values)[source]¶
What an operation’s success response parses into.
- MODEL = 'model'¶
a JSON payload loaded into a typed value
- NONE = 'none'¶
no content (e.g. 204) — the operation returns
None
- BYTES = 'bytes'¶
non-JSON content returned as raw
bytes
- class action0.openapi.ir.OperationIR(class_name, method, path_template, wire_path, params=(), body=None, response_kind=ResponseKind.NONE, response_type=None, errors=(), summary=None, description=None, tag=None)[source]¶
One generated operation class.
- Parameters:
class_name (str) – the Python class name
method (str) – the HTTP method, uppercase
path_template (str) – the path with
{placeholder}names already rewritten to the Python parameter nameswire_path (str) – the original path as spelled in the schema
params (tuple[Param, …], default:
()) – the path/query/header parametersbody (Body | None, default:
None) – the request body, if anyresponse_kind (ResponseKind, default:
<ResponseKind.NONE: 'none'>) – what the success response parses intoresponse_type (TypeExpr | None, default:
None) – the parsed type (forResponseKind.MODEL;Noneotherwise)errors (tuple[ErrorCase, …], default:
()) – the documented non-2xx responses raised as typed exceptions (concrete statuses first, then ranges, thendefault— the order the generatedchecktests them in)summary (str | None, default:
None) – the schema’s summary, for the docstringdescription (str | None, default:
None) – the schema’s description, for the docstringtag (str | None, default:
None) – the operation’s firsttagsentry, if any — the grouping key when the generated package splits operations into per-tag modules
- class action0.openapi.ir.SecurityKind(*values)[source]¶
The supported OpenAPI security scheme kinds.
- class action0.openapi.ir.SecurityScheme(kind, param_name, wire_name=None)[source]¶
One security scheme, turned into client credentials.
- Parameters:
kind (
SecurityKind) – the scheme kindparam_name (
str) – the Python name of the credential parameter on the generated client’s__init__(e.g.token,api_key)wire_name (
str|None, default:None) – the header or query parameter carrying the credential (Nonefor HTTP bearer/basic, which fix theAuthorizationheader)
- class action0.openapi.ir.Api(title, version, base_url=None, models=(), operations=(), security=(), warnings=())[source]¶
Everything the emitter needs to generate one client package.
- Parameters:
title (
str) – the schema’sinfo.titleversion (
str) – the schema’sinfo.versionbase_url (
str|None, default:None) – the default base URL fromservers, if anymodels (
tuple[Model|EnumModel|UnionModel,...], default:()) – the models and enums, in schema orderoperations (
tuple[OperationIR,...], default:()) – the operations, in path ordersecurity (
tuple[SecurityScheme,...], default:()) – the security schemes becoming client credentialswarnings (
tuple[str,...], default:()) – notes about constructs the translation flattened or skipped (printed by the CLI, documented in the generated code where possible)
Name mangling¶
Turning OpenAPI spellings into the Python names of the generated code.
OpenAPI documents name things in whatever style the API grew up with —
camelCase properties, kebab-case headers, PascalCase or
dotted component names. Generated code follows PEP 8: classes are
PascalCase, fields snake_case, enum members UPPER_SNAKE.
The functions here perform that conversion and keep the results valid:
Python keywords and context-reserved names get a trailing underscore
(the original spelling survives as the field’s wire name), identifiers
that would start with a digit get a V/v_ prefix, and
NameRegistry de-duplicates within one scope.
- action0.openapi.names.RESERVED_OPERATION_FIELDS = frozenset({'accept', 'body', 'default_location', 'form_field', 'header', 'json_body', 'json_field', 'method', 'path', 'path_param', 'query'})¶
names an operation dataclass field must not use: the Operation ClassVars (reserved by action0-client) and the field specifiers the generated operations module imports at module level (a field binding one of these in the class body would shadow the specifier for every later field of the same class)
- action0.openapi.names.class_name(raw)[source]¶
Turn a schema name into a
PascalCaseclass name.>>> class_name("pet-store") 'PetStore' >>> class_name("petStatus") 'PetStatus' >>> class_name("HTTPValidationError") 'HttpValidationError' >>> class_name("APIs.guru") # pluralized acronyms stay one word 'ApisGuru' >>> class_name("get /v1/forecast") # digits stay with their word 'GetV1Forecast' >>> class_name("PokéAPI") # accents are dropped, not word breaks 'PokeApi' >>> class_name("1password") # leading digit: prefixed 'V1password'
- action0.openapi.names.field_name(raw, *, reserved=())[source]¶
Turn a schema name into a
snake_casefield name.>>> field_name("petId") 'pet_id' >>> field_name("X-Request-Id") 'x_request_id' >>> field_name("numAPIs") # pluralized acronyms stay one word 'num_apis' >>> field_name("GetV1ForecastResponse") # digits stay with their word 'get_v1_forecast_response' >>> field_name("SHA256Sum") 'sha256_sum' >>> field_name("class") # Python keyword 'class_' >>> field_name("path", reserved=RESERVED_OPERATION_FIELDS) 'path_' >>> field_name("1st") # leading digit: prefixed 'v_1st'
- Parameters:
raw (
str) – the name as spelled in the schemareserved (
Collection[str], default:()) – additional names to avoid (e.g.RESERVED_OPERATION_FIELDSfor operation fields)
- Return type:
- Returns:
a valid, non-reserved Python field name
- action0.openapi.names.constant_name(raw)[source]¶
Turn an enum value into an
UPPER_SNAKEmember name.>>> constant_name("on-sale") 'ON_SALE' >>> constant_name("notAvailable") 'NOT_AVAILABLE' >>> constant_name("1st") # digit-led: enum members must not start with "_" 'V_1ST'
- action0.openapi.names.operation_class_name(operation_id, method, path)[source]¶
Name the operation class after the
operationId, if there is one, and after method and path otherwise.>>> operation_class_name("listPets", "get", "/pets") 'ListPets' >>> operation_class_name(None, "get", "/pets/{petId}") 'GetPetsPetId'
- action0.openapi.names.converter_name(model_class)[source]¶
Name the JSON-to-model converter function for a model class.
>>> converter_name("Pet") 'pet_from_json' >>> converter_name("HttpError") 'http_error_from_json'
- action0.openapi.names.properties_constant_name(model_class)[source]¶
Name the declared-properties set constant of a model with a catch-all
additionalPropertiesfield.The constant holds the wire names of the declared properties; the model’s converter fills the catch-all field with every payload key outside the set.
>>> properties_constant_name("Pet") '_PET_PROPERTIES' >>> properties_constant_name("HttpError") '_HTTP_ERROR_PROPERTIES'
- action0.openapi.names.path_placeholders(path)[source]¶
Return the
{placeholder}names of a path template, in order.>>> path_placeholders("/stores/{storeId}/pets/{petId}") ('storeId', 'petId')
- Parameters:
path (
str) – the path template- Return type:
- Returns:
the placeholder names
- Raises:
ValueError – if the template’s braces are malformed
- action0.openapi.names.rewrite_path(path, renames)[source]¶
Rename the
{placeholder}s of a path template.Placeholder names must equal the Python names of the operation’s
path_param()fields (action0-client validates that, and the specifier deliberately has no wire-name parameter), so the template is rewritten to the renamed fields.>>> rewrite_path("/pets/{petId}", {"petId": "pet_id"}) '/pets/{pet_id}'
- class action0.openapi.names.NameRegistry[source]¶
De-duplicates names within one scope (module, enum, class).
The first claim of a name gets it as-is, later claims of the same name get a numeric suffix:
>>> registry = NameRegistry() >>> registry.claim("Pet") 'Pet' >>> registry.claim("Pet") 'Pet2' >>> registry.claim("Pet") 'Pet3'
Type mapping¶
Mapping between schema scalar types and the Python of the generated code.
Three views of one TypeExpr:
scalar_type() builds the IR leaf from a schema’s
type/format pair, annotation() renders the type
annotation the generated code spells, converter_expr() renders
the expression that turns a decoded JSON value into the typed value
(with imports_for() supplying the imports the rendered text
needs). The request direction needs no counterpart: action0-client
serializes enums, dates and nested dataclasses on its own — only
UUID request fields need a
serialize=str argument, which the emitter adds.
- action0.openapi.types.scalar_type(type_name, format_name)[source]¶
Build the scalar for a schema’s
type/formatpair.>>> scalar_type("string", None) ScalarType(kind=<Scalar.STR: 'str'>) >>> scalar_type("string", "date-time") ScalarType(kind=<Scalar.DATETIME: 'datetime'>) >>> scalar_type(None, None) # no type: any JSON value is fine ScalarType(kind=<Scalar.ANY: 'any'>)
- Parameters:
- Return type:
- Returns:
the scalar
- Raises:
ValueError – if the type is not a scalar type
- action0.openapi.types.annotation(t, *, optional=False)[source]¶
Render the type annotation generated code uses for a type.
>>> annotation(ArrayType(ModelType("Pet"))) 'list[Pet]' >>> annotation(MapType(ScalarType(Scalar.DATE)), optional=True) 'dict[str, datetime.date] | None'
- action0.openapi.types.imports_for(t)[source]¶
Return the import statements a type’s annotation and converter need.
Imports of generated models and enums are not included — where they live relative to the rendered module is the emitter’s business.
>>> sorted(imports_for(MapType(ScalarType(Scalar.UUID)))) ['import uuid']
- action0.openapi.types.needs_conversion(t)[source]¶
Whether a decoded JSON value of this type needs converting at all.
Plain scalars come out of the JSON decoder ready to use; dates, UUIDs, enums and models need an expression around them.
>>> needs_conversion(ArrayType(ScalarType(Scalar.STR))) False >>> needs_conversion(ArrayType(EnumType("Status"))) True
- Parameters:
t (
ScalarType|ArrayType|MapType|ModelType|EnumType|UnionType) – the type- Return type:
- Returns:
whether
converter_expr()is more than a pass-through
- action0.openapi.types.converter_expr(t, source, *, _depth=0)[source]¶
Render the expression converting a decoded JSON value to a type.
>>> converter_expr(ScalarType(Scalar.STR), 'data["name"]') 'data["name"]' >>> converter_expr(EnumType("Status"), 'data["status"]') 'Status(data["status"])' >>> converter_expr(ArrayType(ModelType("Pet")), 'data["items"]') '[pet_from_json(item) for item in data["items"]]'
- Parameters:
- Return type:
- Returns:
the converting expression (
sourceitself when nothing needs converting)
Command line interface¶
The action0-openapi command line interface.
One command: read an OpenAPI 3.x schema — a file or an http(s) URL,
following references to other files, where each referenced download
needs an interactive yes or --download — generate the client
package, write it into the output directory. Expected input problems
(SchemaError, an existing output
without --force) are printed as one-line errors without a
traceback; translation warnings go to stderr, the written files to
stdout.
Package generation¶
Assembling and writing one generated client package.
generate_package() renders the whole package —
__init__.py, models.py, operations.py, client.py,
errors.py (when the schema documents error responses) and the
py.typed marker — as a mapping of file names to file contents;
write_package() puts it on disk. The default package and
client class names are derived from the schema’s info.title by
default_package_name() and default_client_name().
- action0.openapi.generate.default_package_name(title)[source]¶
The default generated-package name for a schema title.
>>> default_package_name("Petstore") 'petstore_client'
- action0.openapi.generate.default_client_name(title)[source]¶
The default client class name for a schema title.
>>> default_client_name("Petstore") 'PetstoreClient'
- action0.openapi.generate.generate_package(api, *, client_name, schema_name, split_by_tag=False)[source]¶
Render one generated client package.
- Parameters:
api (
Api) – the intermediate representationclient_name (
str) – the client class nameschema_name (
str) – the schema file’s name, quoted in the header of every generated filesplit_by_tag (
bool, default:False) – put each OpenAPI tag’s operations into a module of its own (operations_<tag>.py; untagged operations stay inoperations.py) instead of one sharedoperations.py
- Return type:
- Returns:
file name to file content
- action0.openapi.generate.write_package(files, package_dir, *, force=False)[source]¶
Write a generated package to disk.
- Parameters:
- Return type:
- Returns:
the written paths, in file-name order
- Raises:
FileExistsError – if a file exists and
forceis not set (nothing is written then)
Code emission¶
Rendering the intermediate representation as Python source text.
The emitter builds the generated modules with plain string assembly —
no template engine — so the exact output is controlled in one place.
The produced text is already in the shape ruff format and
ruff check (with this repository’s isort settings) accept: import
blocks in isort order with one import per line, two blank lines between
top-level definitions, double quotes, magic trailing commas on
multi-line calls, and lines within the 99-column limit (over-long field
conversions are wrapped the way ruff format wraps them).
- class action0.openapi.render.Lines[source]¶
An indentation-aware builder for one module’s source text.
- comment(text)[source]¶
Append a
#:documentation comment at the current indentation.Sphinx autodoc reads consecutive
#:lines above an attribute as its documentation. Each line of the text is wrapped to the line-length limit; blank lines are dropped (they would render as stray empty comments between fields).
- class action0.openapi.render.Imports[source]¶
Collects import statements and renders them in isort order.
The order replicates this repository’s ruff isort settings (one import per line,
action0first-party): the__future__block, the stdlib block, theaction0block, and relative imports last — within each block all plainimport Xlines first, then thefrom X import ...lines, each alphabetically.
- action0.openapi.render.render_models(api, header)[source]¶
Render the
models.pymodule: enums, dataclass models, and the JSON-to-model converter functions.
- action0.openapi.render.render_operations(api, header, operations=None)[source]¶
Render one operations module: one operation class per endpoint.
- Parameters:
api (
Api) – the intermediate representationheader (
str) – the generated-by header comment line (without#)operations (
Sequence[OperationIR] |None, default:None) – the operations to render into this module (all of the API’s whenNone— per-tag splitting passes subsets)
- Return type:
- Returns:
the module’s source text
- action0.openapi.render.render_errors(api, header)[source]¶
Render the
errors.pymodule: the JSON decoding helper and oneAPIErrorsubclass per documented (status, error model) pair.
- action0.openapi.render.render_client(api, header, client_name)[source]¶
Render the
client.pymodule: the API client subclass with the base URL and the security schemes baked in.
- action0.openapi.render.render_init(api, header, client_name, operation_modules=None)[source]¶
Render the generated package’s
__init__.py: docstring and re-exports of the client, the models and the operations.- Parameters:
api (
Api) – the intermediate representationheader (
str) – the generated-by header comment line (without#)client_name (
str) – the client class nameoperation_modules (
Mapping[str,str] |None, default:None) – operation class name to the module it lives in (every class inoperationswhenNone— per-tag splitting passes the actual layout)
- Return type:
- Returns:
the module’s source text
Errors¶
The exception raised for OpenAPI documents this library cannot process.
Everything that goes wrong with the input — an unreadable schema file,
an unsupported OpenAPI version, a broken or unsupported $ref, a
construct outside the supported subset — raises SchemaError
with a message meant for the person running the generator. Bugs in this
library keep raising their natural exceptions.