Skip to content

Commit 0101a03

Browse files
dbantyNementonp1-ra
authored
fix: OpenAPI schema validation issues (#426, #568). Thanks @p1-ra!
BREAKING CHANGE: Validation of OpenAPI documents is now more strict. Co-authored-by: Nementon <[email protected]> Co-authored-by: p1-ra <[email protected]>
1 parent 821dac8 commit 0101a03

31 files changed

+99
-35
lines changed

openapi_python_client/parser/properties/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ def build_union_property(
453453
constructed `UnionProperty` or a `PropertyError` describing what went wrong.
454454
"""
455455
sub_properties: List[Property] = []
456+
456457
for i, sub_prop_data in enumerate(chain(data.anyOf, data.oneOf)):
457458
sub_prop, schemas = property_from_data(
458459
name=f"{name}_type_{i}",
@@ -570,8 +571,8 @@ def _property_from_data(
570571
if isinstance(data, oai.Reference):
571572
return _property_from_ref(name=name, required=required, parent=None, data=data, schemas=schemas, config=config)
572573

574+
sub_data: List[Union[oai.Schema, oai.Reference]] = data.allOf + data.anyOf + data.oneOf
573575
# A union of a single reference should just be passed through to that reference (don't create copy class)
574-
sub_data = (data.allOf or []) + data.anyOf + data.oneOf
575576
if len(sub_data) == 1 and isinstance(sub_data[0], oai.Reference):
576577
return _property_from_ref(
577578
name=name, required=required, parent=data, data=sub_data[0], schemas=schemas, config=config

openapi_python_client/parser/properties/model_property.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def _add_if_no_conflict(new_prop: Property) -> Optional[PropertyError]:
135135
return None
136136

137137
unprocessed_props = data.properties or {}
138-
for sub_prop in data.allOf or []:
138+
for sub_prop in data.allOf:
139139
if isinstance(sub_prop, oai.Reference):
140140
ref_path = parse_reference_path(sub_prop.ref)
141141
if isinstance(ref_path, ParseError):

openapi_python_client/schema/openapi_schema_pydantic/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
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.
22

3+
Included vendored version is the [following](https://github.com/kuimono/openapi-schema-pydantic/commit/0836b429086917feeb973de3367a7ac4c2b3a665)
4+
Small patches has been applied to it.
5+
36
## Alias
47

58
Due to the reserved words in python and pydantic,

openapi_python_client/schema/openapi_schema_pydantic/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@
3636
"ServerVariable",
3737
"Tag",
3838
"XML",
39+
"Callback",
3940
]
4041

42+
43+
from .callback import Callback
4144
from .components import Components
4245
from .contact import Contact
4346
from .discriminator import Discriminator
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from typing import TYPE_CHECKING, Dict
2+
3+
if TYPE_CHECKING: # pragma: no cover
4+
from .path_item import PathItem
5+
else:
6+
PathItem = "PathItem" # pylint: disable=invalid-name
7+
8+
Callback = Dict[str, PathItem]
9+
"""
10+
A map of possible out-of band callbacks related to the parent operation.
11+
Each value in the map is a [Path Item Object](#pathItemObject)
12+
that describes a set of requests that may be initiated by the API provider and the expected responses.
13+
The key value used to identify the path item object is an expression, evaluated at runtime,
14+
that identifies a URL to use for the callback operation.
15+
"""

openapi_python_client/schema/openapi_schema_pydantic/components.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from typing import Dict, Optional, Union
22

3-
from pydantic import BaseModel
3+
from pydantic import BaseModel, Extra
44

5+
from .callback import Callback
56
from .example import Example
67
from .header import Header
78
from .link import Link
@@ -32,8 +33,10 @@ class Components(BaseModel):
3233
headers: Optional[Dict[str, Union[Header, Reference]]] = None
3334
securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None
3435
links: Optional[Dict[str, Union[Link, Reference]]] = None
36+
callbacks: Optional[Dict[str, Union[Callback, Reference]]] = None
3537

3638
class Config: # pylint: disable=missing-class-docstring
39+
extra = Extra.allow
3740
schema_extra = {
3841
"examples": [
3942
{

openapi_python_client/schema/openapi_schema_pydantic/contact.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Optional
22

3-
from pydantic import AnyUrl, BaseModel
3+
from pydantic import AnyUrl, BaseModel, Extra
44

55

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

1818
class Config: # pylint: disable=missing-class-docstring
19+
extra = Extra.allow
1920
schema_extra = {
2021
"examples": [
2122
{"name": "API Support", "url": "http://www.example.com/support", "email": "[email protected]"}

openapi_python_client/schema/openapi_schema_pydantic/discriminator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Dict, Optional
22

3-
from pydantic import BaseModel
3+
from pydantic import BaseModel, Extra
44

55

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

2424
class Config: # pylint: disable=missing-class-docstring
25+
extra = Extra.allow
2526
schema_extra = {
2627
"examples": [
2728
{

openapi_python_client/schema/openapi_schema_pydantic/encoding.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
from typing import Dict, Optional
1+
from typing import TYPE_CHECKING, Dict, Optional, Union
22

3-
from pydantic import BaseModel
3+
from pydantic import BaseModel, Extra
44

55
from .reference import Reference
66

7+
if TYPE_CHECKING: # pragma: no cover
8+
from .header import Header
9+
else:
10+
Header = "Header" # pylint: disable=invalid-name
11+
712

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

1621
contentType: Optional[str] = None
17-
headers: Optional[Dict[str, Reference]] = None
22+
headers: Optional[Dict[str, Union[Header, Reference]]] = None
1823
style: Optional[str] = None
1924
explode: bool = False
2025
allowReserved: bool = False
2126

2227
class Config: # pylint: disable=missing-class-docstring
28+
extra = Extra.allow
2329
schema_extra = {
2430
"examples": [
2531
{

openapi_python_client/schema/openapi_schema_pydantic/example.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Any, Optional
22

3-
from pydantic import BaseModel
3+
from pydantic import BaseModel, Extra
44

55

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

1919
class Config: # pylint: disable=missing-class-docstring
20+
extra = Extra.allow
2021
schema_extra = {
2122
"examples": [
2223
{"summary": "A foo example", "value": {"foo": "bar"}},

0 commit comments

Comments
 (0)