Skip to content

Instantly share code, notes, and snippets.

@adriangb
Created October 18, 2021 04:06
Show Gist options
  • Save adriangb/d3ea3416906af9cd11287770b1d88bdf to your computer and use it in GitHub Desktop.
Save adriangb/d3ea3416906af9cd11287770b1d88bdf to your computer and use it in GitHub Desktop.
from __future__ import annotations
from dataclasses import dataclass as dataclass
from dataclasses import field
from typing import Any, Dict, List, Literal, Mapping, Optional, Union
ParameterLocations = Literal["header", "path", "query", "cookie"]
PathParamStyles = Literal["simple", "label", "matrix"]
QueryParamStyles = Literal["form", "spaceDelimited", "pipeDelimited", "deepObject"]
HeaderParamStyles = Literal["simple"]
CookieParamStyles = Literal["form"]
FormDataStyles = QueryParamStyles
@dataclass
class Contact:
name: Optional[str] = None
url: Optional[str] = None
email: Optional[str] = None
@dataclass
class License:
name: str
url: Optional[str] = None
@dataclass
class Info:
title: str
version: str
description: Optional[str] = None
termsOfService: Optional[str] = None
contact: Optional[Contact] = None
license: Optional[License] = None
@dataclass
class ServerVariable:
default: str
enum: Optional[List[str]] = None
description: Optional[str] = None
@dataclass
class Server:
url: Union[str, str]
description: Optional[str] = None
variables: Optional[Dict[str, ServerVariable]] = None
@dataclass
class Reference:
ref: str
@dataclass
class Discriminator:
propertyName: str
mapping: Optional[Dict[str, str]] = None
@dataclass
class XML:
name: Optional[str] = None
namespace: Optional[str] = None
prefix: Optional[str] = None
attribute: Optional[bool] = None
wrapped: Optional[bool] = None
@dataclass
class ExternalDocumentation:
url: str
description: Optional[str] = None
@dataclass
class Schema:
ref: Optional[str] = field(default=None)
title: Optional[str] = None
multipleOf: Optional[float] = None
maximum: Optional[float] = None
exclusiveMaximum: Optional[float] = None
minimum: Optional[float] = None
exclusiveMinimum: Optional[float] = None
maxLength: Optional[int] = field(default=None)
minLength: Optional[int] = field(default=None)
pattern: Optional[str] = None
maxItems: Optional[int] = field(default=None)
minItems: Optional[int] = field(default=None)
uniqueItems: Optional[bool] = None
maxProperties: Optional[int] = field(default=None)
minProperties: Optional[int] = field(default=None)
required: Optional[List[str]] = None
enum: Optional[List[Any]] = None
type: Optional[str] = None
allOf: Optional[List[Schema]] = None
oneOf: Optional[List[Schema]] = None
anyOf: Optional[List[Schema]] = None
not_: Optional[Schema] = field(default=None)
items: Optional[Schema] = None
properties: Optional[Dict[str, Schema]] = None
additionalProperties: Optional[Union[Schema, Reference, bool]] = None
description: Optional[str] = None
format: Optional[str] = None
default: Any = None
nullable: Optional[bool] = None
discriminator: Optional[Discriminator] = None
readOnly: Optional[bool] = None
writeOnly: Optional[bool] = None
xml: Optional[XML] = None
externalDocs: Optional[ExternalDocumentation] = None
deprecated: Optional[bool] = None
@dataclass
class Example:
summary: Optional[str] = None
description: Optional[str] = None
value: Any = None
external_value: Optional[str] = field(default=None)
@dataclass
class Encoding:
contentType: Optional[str] = None
headers: Optional[Dict[str, Union[Header, Reference]]] = None
style: Optional[str] = None
explode: Optional[bool] = None
allowReserved: Optional[bool] = None
@dataclass
class MediaType:
schema_: Optional[Union[Schema, Reference]] = None
examples: Optional[Dict[str, Union[Example, Reference]]] = None
encoding: Optional[Dict[str, Encoding]] = None
@dataclass
class ParameterBase:
description: Optional[str] = None
required: Optional[bool] = None
deprecated: Optional[bool] = None
# Serialization rules for simple scenarios
style: Optional[str] = None
explode: Optional[bool] = None
allowReserved: Optional[bool] = None
schema_: Optional[Union[Schema, Reference]] = None
examples: Optional[Dict[str, Union[Example, Reference]]] = None
# Serialization rules for more complex scenarios
content: Optional[Dict[str, MediaType]] = None
@dataclass
class ConcreteParameter:
name: str
in_: ParameterLocations
@dataclass
class Header(ParameterBase, ConcreteParameter):
in_: Literal["header"] = "header"
style: HeaderParamStyles = "simple"
explode: bool = False
@dataclass
class Query(ParameterBase, ConcreteParameter):
in_: Literal["header"] = "header"
style: QueryParamStyles = "form"
explode: bool = True
@dataclass
class Path(ParameterBase, ConcreteParameter):
in_: Literal["path"] = "path"
style: PathParamStyles = "simple"
explode: bool = False
required: Literal[True] = True
@dataclass
class Cookie(ParameterBase, ConcreteParameter):
in_: Literal["cookie"] = "cookie"
style: CookieParamStyles = "form"
explode: bool = True
Parameter = Union[Query, Header, Cookie, Path]
@dataclass
class RequestBody:
content: Dict[str, MediaType]
description: Optional[str] = None
required: Optional[bool] = None
@dataclass
class Link:
operationRef: Optional[str] = None
operationId: Optional[str] = None
parameters: Optional[Dict[str, Union[str]]] = None
requestBody: Optional[Union[str]] = None
description: Optional[str] = None
server: Optional[Server] = None
@dataclass
class Response:
description: str
headers: Optional[Dict[str, Union[Header, Reference]]] = None
content: Optional[Dict[str, MediaType]] = None
links: Optional[Dict[str, Union[Link, Reference]]] = None
@dataclass
class Operation:
responses: Dict[str, Response]
tags: Optional[List[str]] = None
summary: Optional[str] = None
description: Optional[str] = None
externalDocs: Optional[ExternalDocumentation] = None
operationId: Optional[str] = None
parameters: Optional[List[Union[Parameter, Reference]]] = None
requestBody: Optional[Union[RequestBody, Reference]] = None
# Using Any for Specification Extensions
callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference]]] = None
deprecated: Optional[bool] = None
security: Optional[List[Dict[str, List[str]]]] = None
servers: Optional[List[Server]] = None
@dataclass
class PathItem:
ref: Optional[str] = None
summary: Optional[str] = None
description: Optional[str] = None
get: Optional[Operation] = None
put: Optional[Operation] = None
post: Optional[Operation] = None
delete: Optional[Operation] = None
options: Optional[Operation] = None
head: Optional[Operation] = None
patch: Optional[Operation] = None
trace: Optional[Operation] = None
servers: Optional[List[Server]] = None
parameters: Optional[List[Union[Parameter, Reference]]] = None
SecuritySchemeName = Literal["apiKey", "http", "oauth2", "openIdConnect"]
class SecurityBase:
type: SecuritySchemeName
description: Optional[str] = None
APIKeyLocation = Literal["query", "header", "cookie"]
@dataclass
class APIKey(SecurityBase):
name: str
in_: APIKeyLocation
type: Literal["apiKey"] = "apiKey"
@dataclass
class HTTPBase(SecurityBase):
scheme: str
type: Literal["http"] = "http"
@dataclass
class HTTPBearer(HTTPBase):
scheme = "bearer"
bearerFormat: Optional[str] = None
@dataclass
class OAuthFlow:
refreshUrl: Optional[str] = None
scopes: Optional[Mapping[str, str]] = field(default_factory=dict) # type: ignore
@dataclass
class OAuthFlowImplicitBase:
authorizationUrl: str
@dataclass
class OAuthFlowImplicit(OAuthFlow, OAuthFlowImplicitBase):
...
@dataclass
class OAuthFlowPasswordBase:
tokenUrl: str
@dataclass
class OAuthFlowPassword(OAuthFlow, OAuthFlowPasswordBase):
...
@dataclass
class OAuthFlowClientCredentialsBase:
tokenUrl: str
@dataclass
class OAuthFlowClientCredentials(OAuthFlow, OAuthFlowClientCredentialsBase):
...
@dataclass
class OAuthFlowAuthorizationCodeBase:
authorizationUrl: str
tokenUrl: str
@dataclass
class OAuthFlowAuthorizationCode(OAuthFlow, OAuthFlowAuthorizationCodeBase):
...
@dataclass
class OAuthFlows:
implicit: Optional[OAuthFlowImplicit] = None
password: Optional[OAuthFlowPassword] = None
clientCredentials: Optional[OAuthFlowClientCredentials] = None
authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
@dataclass
class OAuth2(SecurityBase):
flows: OAuthFlows
type: Literal["oauth2"] = "oauth2"
@dataclass
class OpenIdConnect(SecurityBase):
openIdConnectUrl: str
type: Literal["openIdConnect"] = "openIdConnect"
SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]
@dataclass
class Components:
schemas: Optional[Dict[str, Union[Schema, Reference]]] = None
responses: Optional[Dict[str, Union[Response, Reference]]] = None
parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None
examples: Optional[Dict[str, Union[Example, Reference]]] = None
requestBodies: Optional[Dict[str, Union[RequestBody, Reference]]] = None
headers: Optional[Dict[str, Union[Header, Reference]]] = None
securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None
links: Optional[Dict[str, Union[Link, Reference]]] = None
# Using Any for Specification Extensions
callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference]]] = None
@dataclass
class Tag:
name: str
description: Optional[str] = None
externalDocs: Optional[ExternalDocumentation] = None
@dataclass
class OpenAPI:
openapi: str
info: Info
paths: Dict[str, Union[PathItem]] = field(default_factory=dict)
servers: Optional[List[Server]] = None
# Using Any for Specification Extensions
components: Optional[Components] = None
security: Optional[List[Dict[str, List[str]]]] = None
tags: Optional[List[Tag]] = None
externalDocs: Optional[ExternalDocumentation] = None
if __name__ == "__main__":
from time import time
from apischema import serialize
data = OpenAPI(info=Info(title="A", version="1"), openapi="1", paths={})
start = time()
serialize(OpenAPI, data)
print(f"apischema took {time()-start:e} sec on first go")
start = time()
serialize(OpenAPI, data)
print(f"apischema took {time()-start:e} sec on second go")
from fastapi.openapi import models as pydantic_models
data2 = pydantic_models.OpenAPI(info=pydantic_models.Info(title="A", version="1"), openapi="1", paths={})
start = time()
data2.dict()
print(f"pydantic took {time()-start:e} sec on first go")
start = time()
data2.dict()
print(f"pydantic took {time()-start:e} sec on second go")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment