Skip to content

fix: OpenAPI schema validation issues. #568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion openapi_python_client/parser/properties/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ def build_union_property(
constructed `UnionProperty` or a `PropertyError` describing what went wrong.
"""
sub_properties: List[Property] = []

for i, sub_prop_data in enumerate(chain(data.anyOf, data.oneOf)):
sub_prop, schemas = property_from_data(
name=f"{name}_type_{i}",
Expand Down Expand Up @@ -570,8 +571,8 @@ def _property_from_data(
if isinstance(data, oai.Reference):
return _property_from_ref(name=name, required=required, parent=None, data=data, schemas=schemas, config=config)

sub_data: List[Union[oai.Schema, oai.Reference]] = data.allOf + data.anyOf + data.oneOf
# A union of a single reference should just be passed through to that reference (don't create copy class)
sub_data = (data.allOf or []) + data.anyOf + data.oneOf
if len(sub_data) == 1 and isinstance(sub_data[0], oai.Reference):
return _property_from_ref(
name=name, required=required, parent=data, data=sub_data[0], schemas=schemas, config=config
Expand Down
2 changes: 1 addition & 1 deletion openapi_python_client/parser/properties/model_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def _add_if_no_conflict(new_prop: Property) -> Optional[PropertyError]:
return None

unprocessed_props = data.properties or {}
for sub_prop in data.allOf or []:
for sub_prop in data.allOf:
if isinstance(sub_prop, oai.Reference):
ref_path = parse_reference_path(sub_prop.ref)
if isinstance(ref_path, ParseError):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Everything in this directory (including the rest of this file after this paragraph) is a vendored copy of [openapi-schem-pydantic](https://github.com/kuimono/openapi-schema-pydantic) and is licensed under the LICENSE file in this directory.

Included vendored version is the [following](https://github.com/kuimono/openapi-schema-pydantic/commit/0836b429086917feeb973de3367a7ac4c2b3a665)
Small patches has been applied to it.

## Alias

Due to the reserved words in python and pydantic,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@
"ServerVariable",
"Tag",
"XML",
"Callback",
]


from .callback import Callback
from .components import Components
from .contact import Contact
from .discriminator import Discriminator
Expand Down
15 changes: 15 additions & 0 deletions openapi_python_client/schema/openapi_schema_pydantic/callback.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import TYPE_CHECKING, Dict

if TYPE_CHECKING: # pragma: no cover
from .path_item import PathItem
else:
PathItem = "PathItem" # pylint: disable=invalid-name

Callback = Dict[str, PathItem]
"""
A map of possible out-of band callbacks related to the parent operation.
Each value in the map is a [Path Item Object](#pathItemObject)
that describes a set of requests that may be initiated by the API provider and the expected responses.
The key value used to identify the path item object is an expression, evaluated at runtime,
that identifies a URL to use for the callback operation.
"""
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Dict, Optional, Union

from pydantic import BaseModel
from pydantic import BaseModel, Extra

from .callback import Callback
from .example import Example
from .header import Header
from .link import Link
Expand Down Expand Up @@ -32,8 +33,10 @@ class Components(BaseModel):
headers: Optional[Dict[str, Union[Header, Reference]]] = None
securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None
links: Optional[Dict[str, Union[Link, Reference]]] = None
callbacks: Optional[Dict[str, Union[Callback, Reference]]] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import AnyUrl, BaseModel
from pydantic import AnyUrl, BaseModel, Extra


class Contact(BaseModel):
Expand All @@ -16,6 +16,7 @@ class Contact(BaseModel):
email: Optional[str] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{"name": "API Support", "url": "http://www.example.com/support", "email": "[email protected]"}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict, Optional

from pydantic import BaseModel
from pydantic import BaseModel, Extra


class Discriminator(BaseModel):
Expand All @@ -22,6 +22,7 @@ class Discriminator(BaseModel):
mapping: Optional[Dict[str, str]] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{
Expand Down
12 changes: 9 additions & 3 deletions openapi_python_client/schema/openapi_schema_pydantic/encoding.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from typing import Dict, Optional
from typing import TYPE_CHECKING, Dict, Optional, Union

from pydantic import BaseModel
from pydantic import BaseModel, Extra

from .reference import Reference

if TYPE_CHECKING: # pragma: no cover
from .header import Header
else:
Header = "Header" # pylint: disable=invalid-name


class Encoding(BaseModel):
"""A single encoding definition applied to a single schema property.
Expand All @@ -14,12 +19,13 @@ class Encoding(BaseModel):
"""

contentType: Optional[str] = None
headers: Optional[Dict[str, Reference]] = None
headers: Optional[Dict[str, Union[Header, Reference]]] = None
style: Optional[str] = None
explode: bool = False
allowReserved: bool = False

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Optional

from pydantic import BaseModel
from pydantic import BaseModel, Extra


class Example(BaseModel):
Expand All @@ -17,6 +17,7 @@ class Example(BaseModel):
externalValue: Optional[str] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{"summary": "A foo example", "value": {"foo": "bar"}},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import AnyUrl, BaseModel
from pydantic import AnyUrl, BaseModel, Extra


class ExternalDocumentation(BaseModel):
Expand All @@ -14,4 +14,5 @@ class ExternalDocumentation(BaseModel):
url: AnyUrl

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {"examples": [{"description": "Find more info here", "url": "https://example.com"}]}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import Field
from pydantic import Extra, Field

from ..parameter_location import ParameterLocation
from .parameter import Parameter
Expand All @@ -22,6 +22,7 @@ class Header(Parameter):
param_in = Field(default=ParameterLocation.HEADER, const=True, alias="in")

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
allow_population_by_field_name = True
schema_extra = {
"examples": [
Expand Down
3 changes: 2 additions & 1 deletion openapi_python_client/schema/openapi_schema_pydantic/info.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import AnyUrl, BaseModel
from pydantic import AnyUrl, BaseModel, Extra

from .contact import Contact
from .license import License
Expand All @@ -25,6 +25,7 @@ class Info(BaseModel):
version: str

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import AnyUrl, BaseModel
from pydantic import AnyUrl, BaseModel, Extra


class License(BaseModel):
Expand All @@ -15,4 +15,5 @@ class License(BaseModel):
url: Optional[AnyUrl] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {"examples": [{"name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html"}]}
3 changes: 2 additions & 1 deletion openapi_python_client/schema/openapi_schema_pydantic/link.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict, Optional

from pydantic import BaseModel
from pydantic import BaseModel, Extra

from .server import Server

Expand Down Expand Up @@ -31,6 +31,7 @@ class Link(BaseModel):
server: Optional[Server] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{"operationId": "getUserAddressByUUID", "parameters": {"userUuid": "$response.body#/uuid"}},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict, Optional, Union

from pydantic import BaseModel, Field
from pydantic import BaseModel, Extra, Field

from .encoding import Encoding
from .example import Example
Expand All @@ -22,6 +22,7 @@ class MediaType(BaseModel):
encoding: Optional[Dict[str, Encoding]] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
allow_population_by_field_name = True
schema_extra = {
"examples": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict, Optional

from pydantic import AnyUrl, BaseModel
from pydantic import AnyUrl, BaseModel, Extra


class OAuthFlow(BaseModel):
Expand All @@ -13,11 +13,12 @@ class OAuthFlow(BaseModel):
"""

authorizationUrl: Optional[AnyUrl] = None
tokenUrl: Optional[str] = None
tokenUrl: Optional[AnyUrl] = None
refreshUrl: Optional[AnyUrl] = None
scopes: Dict[str, str]

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import BaseModel
from pydantic import BaseModel, Extra

from .oauth_flow import OAuthFlow

Expand All @@ -18,3 +18,6 @@ class OAuthFlows(BaseModel):
password: Optional[OAuthFlow] = None
clientCredentials: Optional[OAuthFlow] = None
authorizationCode: Optional[OAuthFlow] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys
from typing import List, Optional, Union

from pydantic import BaseModel
from pydantic import BaseModel, Extra

from .components import Components
from .external_documentation import ExternalDocumentation
Expand Down Expand Up @@ -34,3 +34,6 @@ class OpenAPI(BaseModel):
tags: Optional[List[Tag]] = None
externalDocs: Optional[ExternalDocumentation] = None
openapi: 'Union[Literal["3.0.0"], Literal["3.0.1"], Literal["3.0.2"], Literal["3.0.3"]]'

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import List, Optional, Union
from typing import Dict, List, Optional, Union

from pydantic import BaseModel
from pydantic import BaseModel, Extra

from .callback import Callback
from .external_documentation import ExternalDocumentation
from .parameter import Parameter
from .reference import Reference
Expand All @@ -27,11 +28,14 @@ class Operation(BaseModel):
parameters: Optional[List[Union[Parameter, Reference]]] = None
requestBody: Optional[Union[RequestBody, Reference]] = None
responses: Responses
callbacks: Optional[Dict[str, Callback]] = None

deprecated: bool = False
security: Optional[List[SecurityRequirement]] = None
servers: Optional[List[Server]] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict, Optional, Union

from pydantic import BaseModel, Field
from pydantic import BaseModel, Extra, Field

from ..parameter_location import ParameterLocation
from .example import Example
Expand Down Expand Up @@ -36,6 +36,7 @@ class Parameter(BaseModel):
content: Optional[Dict[str, MediaType]] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
allow_population_by_field_name = True
schema_extra = {
"examples": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List, Optional, Union

from pydantic import BaseModel, Field
from pydantic import BaseModel, Extra, Field

from .operation import Operation
from .parameter import Parameter
Expand Down Expand Up @@ -35,6 +35,7 @@ class PathItem(BaseModel):
parameters: Optional[List[Union[Parameter, Reference]]] = None

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
allow_population_by_field_name = True
schema_extra = {
"examples": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import BaseModel, Field
from pydantic import BaseModel, Extra, Field


class Reference(BaseModel):
Expand All @@ -19,6 +19,7 @@ class Reference(BaseModel):
ref: str = Field(alias="$ref")

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
allow_population_by_field_name = True
schema_extra = {
"examples": [{"$ref": "#/components/schemas/Pet"}, {"$ref": "Pet.json"}, {"$ref": "definitions.json#/Pet"}]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict, Optional

from pydantic import BaseModel
from pydantic import BaseModel, Extra

from .media_type import MediaType

Expand All @@ -18,6 +18,7 @@ class RequestBody(BaseModel):
required: bool = False

class Config: # pylint: disable=missing-class-docstring
extra = Extra.allow
schema_extra = {
"examples": [
{
Expand Down
Loading