OpenAPI to Python mapping rules
Names
| Input | Rule | Example |
|---|---|---|
| Tag | first tag, snake-cased, becomes the resource attribute; <Tag>Resource / Async<Tag>Resource classes; no tag means default |
Things Admin -> client.things_admin |
| operationId | tokenised (camelCase, snake_case, kebab-case, acronyms) then joined with _; tokens equal to the tag or its singular are dropped when something remains |
listPets on pets -> list; getPetById -> get_by_id; uploadPetPhoto -> upload_photo |
| Missing operationId | <method>_<path segments>, path params become by_<name>; check warns |
derived id get_pets_by_id, then tag-stripped like any other (get_by_id on pets) |
| Method collision inside a resource | second tries the full snake-cased operationId, then _2, _3; check warns |
list_things and listThings -> list, list_things |
| Schema name | PascalCase; collisions get a numeric suffix; names clashing with generated helpers (Any, Field, Client, ...) get Model appended |
new_pet -> NewPet, Any -> AnyModel |
| Inline schema | parent + property (PetOwner), array items add Item, request bodies <OperationId>Request, responses <OperationId>Response (<OperationId><status>Response for non-2xx) |
|
| Property / parameter | snake_case; Python keywords, BaseModel attributes and builtin type names get a trailing _ with the original kept as alias |
class -> class_ alias "class"; petType -> pet_type alias "petType" |
| Enum member | UPPER_SNAKE of the value, VALUE_ prefix if it starts with a digit, EMPTY for "", numeric suffix on collision |
in-review -> IN_REVIEW |
Types
| Schema | Python |
|---|---|
string / integer / number / boolean |
str / int / float / bool |
string + format: date-time / date / time / uuid |
datetime / date / time / UUID (imported as _dt.*, _uuid.UUID so fields named date cannot shadow them) |
format: binary |
bytes in models, FileInput for upload parameters |
enum (strings, more than one value) |
class X(str, Enum) |
enum with one value, const, integer enums |
Literal[...] |
object with properties |
class X(BaseModel); additionalProperties other than false sets extra="allow" |
object with only additionalProperties |
dict[str, V] (dict[str, Any] for true/absent) |
array |
list[T] |
allOf |
merged into one model (properties and required unioned); a lone $ref becomes an alias |
oneOf / anyOf + discriminator, all members objects |
Annotated[A | B, Field(discriminator="field")]; each member's discriminator field becomes Literal["value"] |
oneOf / anyOf otherwise |
A | B |
{} / true |
Any |
Optionality
| required | nullable | default | Annotation |
|---|---|---|---|
| yes | no | - | x: T |
| yes | yes | - | x: T | None (still must be provided) |
| no | no | none | x: T | None = None |
| no | yes | none | x: T | None = None |
| any | no | scalar / enum | x: T = <default> |
| any | no | list / dict | x: T = Field(default_factory=...) |
3.0 nullable: true, 3.1 type: [T, "null"] and oneOf: [..., {type: "null"}] are all treated as nullable.
Request bodies are dumped with by_alias=True, exclude_unset=True, so optional fields you did not set are not sent.
Constraints
minimum/maximum -> ge/le; exclusiveMinimum/exclusiveMaximum (3.0 boolean or 3.1 number) -> gt/lt;
multipleOf -> multiple_of; minLength/maxLength/pattern -> min_length/max_length/pattern;
minItems/maxItems -> min_length/max_length. A constrained top-level primitive becomes
Name = Annotated[str, Field(max_length=8)].
Parameters
| Location | Default style | Supported styles |
|---|---|---|
| query | form, explode |
form, spaceDelimited, pipeDelimited, deepObject |
| path | simple |
simple, label, matrix |
| header | simple |
simple |
| cookie | form |
form |
| Value | style, explode | Wire |
|---|---|---|
[3,4] |
form, true | p=3&p=4 |
[3,4] |
form, false | p=3,4 |
[3,4] |
pipeDelimited | p=3\|4 |
{a:1,b:2} |
form, true | a=1&b=2 |
{a:1,b:2} |
form, false | p=a,1,b,2 |
{a:1,b:2} |
deepObject | p[a]=1&p[b]=2 |
5 in path |
label / matrix | .5 / ;id=5 |
Booleans serialize as true/false, enums by value, datetimes as ISO 8601, and path values are percent-encoded.
Bodies
| Content type | Generated parameter(s) |
|---|---|
application/json (or +json) |
body: Model (optional bodies default to None and are then omitted) |
multipart/form-data |
one keyword per property; format: binary properties are FileInput (bytes, a binary file object, (name, data) or (name, data, content_type)). Files are read eagerly so retries can resend them |
application/x-www-form-urlencoded |
one keyword per property; lists repeat the key, objects are JSON-encoded |
| anything else | body: bytes sent as-is |
Responses
- Keyed by status (
"200","4XX","default"); the lowest documented 2xx with content defines the return type. - JSON -> validated model;
text/*->str; other media types ->bytes(plus a<name>_stream()context manager yielding chunks); no content ->None. - Status 300 or above raises: the class for a documented error status (
NotFoundError, ...) when the body validates against the documented schema, otherwiseClientError(4xx),ServerError(5xx) orApiErrorwith the raw body. - Built-in class names: 400
BadRequestError, 401UnauthorizedError, 403ForbiddenError, 404NotFoundError, 405MethodNotAllowedError, 409ConflictError, 410GoneError, 422UnprocessableEntityError, 429RateLimitError, 500InternalServerError, 502BadGatewayError, 503ServiceUnavailableError, 504GatewayTimeoutError, othersHttp<status>Error.