Skip to content

Commit c730b9f

Browse files
committed
WIP support reference requestBodies
1 parent ba1dbee commit c730b9f

File tree

12 files changed

+57
-23
lines changed

12 files changed

+57
-23
lines changed

end_to_end_tests/test_end_to_end.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import os
21
import shutil
32
from filecmp import cmpfiles, dircmp
43
from pathlib import Path
5-
from typing import Dict, List, Optional
4+
from typing import Dict, List
65

76
import pytest
87
from typer.testing import CliRunner

openapi_python_client/parser/openapi.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
Property,
2121
Schemas,
2222
build_parameters,
23+
build_request_bodies,
2324
build_schemas,
2425
property_from_data,
2526
)
26-
from .properties.schemas import parameter_from_reference
27+
from .properties.schemas import RequestBodies, parameter_from_reference
2728
from .responses import Response, response_from_data
2829

2930
_PATH_PARAM_REGEX = re.compile("{([a-zA-Z_][a-zA-Z0-9_]*)}")
@@ -44,7 +45,12 @@ class EndpointCollection:
4445

4546
@staticmethod
4647
def from_data(
47-
*, data: Dict[str, oai.PathItem], schemas: Schemas, parameters: Parameters, config: Config
48+
*,
49+
data: Dict[str, oai.PathItem],
50+
schemas: Schemas,
51+
parameters: Parameters,
52+
request_bodies: RequestBodies,
53+
config: Config,
4854
) -> Tuple[Dict[utils.PythonIdentifier, "EndpointCollection"], Schemas, Parameters]:
4955
"""Parse the openapi paths data to get EndpointCollections by tag"""
5056
endpoints_by_tag: Dict[utils.PythonIdentifier, EndpointCollection] = {}
@@ -65,6 +71,7 @@ def from_data(
6571
tag=tag,
6672
schemas=schemas,
6773
parameters=parameters,
74+
request_bodies=request_bodies,
6875
config=config,
6976
)
7077
# Add `PathItem` parameters
@@ -191,15 +198,19 @@ def _add_body(
191198
endpoint: "Endpoint",
192199
data: oai.Operation,
193200
schemas: Schemas,
201+
request_bodies: RequestBodies,
194202
config: Config,
195203
) -> Tuple[Union[ParseError, "Endpoint"], Schemas]:
196204
"""Adds form or JSON body to Endpoint if included in data"""
197205
endpoint = deepcopy(endpoint)
198-
if data.requestBody is None or isinstance(data.requestBody, oai.Reference):
206+
if data.requestBody is None:
199207
return endpoint, schemas
200-
208+
if isinstance(data.requestBody, oai.Reference):
209+
request_body = request_bodies.bodies_by_reference[data.requestBody.ref]
210+
else:
211+
request_body = data.requestBody
201212
form_body, schemas = Endpoint.parse_request_form_body(
202-
body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config
213+
body=request_body, schemas=schemas, parent_name=endpoint.name, config=config
203214
)
204215

205216
if isinstance(form_body, ParseError):
@@ -213,7 +224,7 @@ def _add_body(
213224
)
214225

215226
json_body, schemas = Endpoint.parse_request_json_body(
216-
body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config
227+
body=request_body, schemas=schemas, parent_name=endpoint.name, config=config
217228
)
218229
if isinstance(json_body, ParseError):
219230
return (
@@ -226,7 +237,7 @@ def _add_body(
226237
)
227238

228239
multipart_body, schemas = Endpoint.parse_multipart_body(
229-
body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config
240+
body=request_body, schemas=schemas, parent_name=endpoint.name, config=config
230241
)
231242
if isinstance(multipart_body, ParseError):
232243
return (
@@ -465,6 +476,7 @@ def from_data(
465476
tag: str,
466477
schemas: Schemas,
467478
parameters: Parameters,
479+
request_bodies: RequestBodies,
468480
config: Config,
469481
) -> Tuple[Union["Endpoint", ParseError], Schemas, Parameters]:
470482
"""Construct an endpoint from the OpenAPI data"""
@@ -490,7 +502,9 @@ def from_data(
490502
if isinstance(result, ParseError):
491503
return result, schemas, parameters
492504
result, schemas = Endpoint._add_responses(endpoint=result, data=data.responses, schemas=schemas, config=config)
493-
result, schemas = Endpoint._add_body(endpoint=result, data=data, schemas=schemas, config=config)
505+
result, schemas = Endpoint._add_body(
506+
endpoint=result, data=data, schemas=schemas, request_bodies=request_bodies, config=config
507+
)
494508

495509
return result, schemas, parameters
496510

@@ -549,8 +563,10 @@ def from_dict(data: Dict[str, Any], *, config: Config) -> Union["GeneratorData",
549563
schemas = build_schemas(components=openapi.components.schemas, schemas=schemas, config=config)
550564
if openapi.components and openapi.components.parameters:
551565
parameters = build_parameters(components=openapi.components.parameters, parameters=parameters)
566+
if openapi.components and openapi.components.requestBodies:
567+
request_bodies = build_request_bodies(components=openapi.components.requestBodies)
552568
endpoint_collections_by_tag, schemas, parameters = EndpointCollection.from_data(
553-
data=openapi.paths, schemas=schemas, parameters=parameters, config=config
569+
data=openapi.paths, schemas=schemas, parameters=parameters, request_bodies=request_bodies, config=config
554570
)
555571

556572
enums = (prop for prop in schemas.classes_by_name.values() if isinstance(prop, EnumProperty))

openapi_python_client/parser/properties/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from ... import Config
2020
from ... import schema as oai
2121
from ... import utils
22+
from ...schema import Reference, RequestBody
2223
from ..errors import ParameterError, ParseError, PropertyError, ValidationError
2324
from .converter import convert, convert_chain
2425
from .enum_property import EnumProperty
@@ -27,6 +28,7 @@
2728
from .schemas import (
2829
Class,
2930
Parameters,
31+
RequestBodies,
3032
Schemas,
3133
parse_reference_path,
3234
update_parameters_with_data,
@@ -776,3 +778,15 @@ def build_parameters(
776778

777779
parameters.errors.extend(errors)
778780
return parameters
781+
782+
783+
def build_request_bodies(components: Dict[str, Union[RequestBody, Reference]]):
784+
785+
direct_entries = {
786+
f"#/components/requestBodies/{name}": body for name, body in components.items() if isinstance(body, RequestBody)
787+
}
788+
result = RequestBodies(bodies_by_reference=direct_entries)
789+
ref_entries: Dict[str, Reference] = {name: body for name, body in components.items() if isinstance(body, Reference)}
790+
for name, ref in ref_entries.items():
791+
result.errors.append(ParseError(detail=f"Unimplemented support for reference request body: {name}"))
792+
return result

openapi_python_client/parser/properties/schemas.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from ... import Config
1818
from ... import schema as oai
19+
from ...schema import RequestBody
1920
from ...schema.openapi_schema_pydantic import Parameter
2021
from ...utils import ClassName, PythonIdentifier
2122
from ..errors import ParameterError, ParseError, PropertyError
@@ -126,6 +127,14 @@ class Parameters:
126127
errors: List[ParseError] = attr.ib(factory=list)
127128

128129

130+
@attr.s(auto_attribs=True, frozen=True)
131+
class RequestBodies:
132+
"""Structure for containing all defined, shareable, and reusable request bodies"""
133+
134+
bodies_by_reference: Dict[str, RequestBody] = attr.ib(factory=dict)
135+
errors: List[ParseError] = attr.ib(factory=list)
136+
137+
129138
def parameter_from_data(
130139
*,
131140
name: str,

tests/test___main__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ def test_main(mocker):
22
app = mocker.patch("openapi_python_client.cli.app")
33

44
# noinspection PyUnresolvedReferences
5-
from openapi_python_client import __main__
65

76
app.assert_called_once()

tests/test_cli.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import pytest
55
from typer.testing import CliRunner
66

7-
from openapi_python_client import Config
87
from openapi_python_client.parser.errors import GeneratorError, ParseError
98

109
runner = CliRunner()
@@ -149,7 +148,7 @@ def test_generate_encoding(self, _create_new_client):
149148
def test_generate_encoding_errors(self, _create_new_client):
150149
path = "cool/path"
151150
file_encoding = "error-file-encoding"
152-
from openapi_python_client.cli import MetaType, app
151+
from openapi_python_client.cli import app
153152

154153
result = runner.invoke(app, ["generate", f"--path={path}", f"--file-encoding={file_encoding}"])
155154

@@ -286,7 +285,7 @@ def test_update_encoding(self, _update_existing_client):
286285
def test_update_encoding_errors(self, _update_existing_client):
287286
path = "cool/path"
288287
file_encoding = "error-file-encoding"
289-
from openapi_python_client.cli import MetaType, app
288+
from openapi_python_client.cli import app
290289

291290
result = runner.invoke(app, ["update", f"--path={path}", f"--file-encoding={file_encoding}"])
292291

tests/test_parser/test_properties/test_init.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ def test_property_from_data_str_enum_with_null(self, enum_property_factory):
338338
}
339339

340340
def test_property_from_data_null_enum(self, enum_property_factory, none_property_factory):
341-
from openapi_python_client.parser.properties import Class, Schemas, property_from_data
341+
from openapi_python_client.parser.properties import Schemas, property_from_data
342342
from openapi_python_client.schema import Schema
343343

344344
data = Schema(title="AnEnumWithOnlyNull", enum=[None], nullable=False, default=None)
@@ -459,7 +459,7 @@ def test_property_from_data_ref_enum_with_invalid_default(self, enum_property_fa
459459
assert prop == PropertyError(data=data, detail="x is an invalid default for enum MyEnum")
460460

461461
def test_property_from_data_ref_model(self, model_property_factory):
462-
from openapi_python_client.parser.properties import Class, ModelProperty, Schemas, property_from_data
462+
from openapi_python_client.parser.properties import Class, Schemas, property_from_data
463463

464464
name = "new_name"
465465
required = False
@@ -646,7 +646,7 @@ def test_property_from_data_union(self, mocker):
646646
)
647647

648648
def test_property_from_data_union_of_one_element(self, mocker, model_property_factory):
649-
from openapi_python_client.parser.properties import Class, ModelProperty, Schemas, property_from_data
649+
from openapi_python_client.parser.properties import Schemas, property_from_data
650650

651651
name = "new_name"
652652
required = False

tests/test_parser/test_properties/test_schemas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def test_cannot_parse_parameters_by_reference(self):
5757
def test_parameters_without_schema_are_ignored(self):
5858
from openapi_python_client.parser.properties import Parameters
5959
from openapi_python_client.parser.properties.schemas import parameter_from_data
60-
from openapi_python_client.schema import ParameterLocation, Schema
60+
from openapi_python_client.schema import ParameterLocation
6161

6262
param = Parameter(name="a_schemaless_param", param_in=ParameterLocation.QUERY)
6363
parameters = Parameters()

tests/test_parser/test_responses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import openapi_python_client.schema as oai
44
from openapi_python_client.parser.errors import ParseError, PropertyError
5-
from openapi_python_client.parser.properties import AnyProperty, Schemas, StringProperty
5+
from openapi_python_client.parser.properties import Schemas
66

77
MODULE_NAME = "openapi_python_client.parser.responses"
88

tests/test_templates/test_property_templates/test_date_property/optional_nullable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from datetime import date
2-
from typing import cast, Union
2+
from typing import Union
33

44
from dateutil.parser import isoparse
55
some_source = date(2020, 10, 12)

tests/test_templates/test_property_templates/test_date_property/required_not_null.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import date
2-
from typing import cast, Union
32

43
from dateutil.parser import isoparse
54
some_source = date(2020, 10, 12)

tests/test_templates/test_property_templates/test_date_property/required_nullable.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import date
2-
from typing import cast, Union
32

43
from dateutil.parser import isoparse
54
some_source = date(2020, 10, 12)

0 commit comments

Comments
 (0)