Skip to content

Commit 7fc8492

Browse files
committed
Break up EndpointCollection and add test
#3
1 parent 5878f10 commit 7fc8492

File tree

2 files changed

+95
-56
lines changed

2 files changed

+95
-56
lines changed

openapi_python_client/openapi_parser/openapi.py

Lines changed: 62 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -35,63 +35,10 @@ def from_dict(d: Dict[str, Dict[str, Dict[str, Any]]], /) -> Dict[str, EndpointC
3535
endpoints_by_tag: Dict[str, EndpointCollection] = {}
3636
for path, path_data in d.items():
3737
for method, method_data in path_data.items():
38-
query_parameters: List[Property] = []
39-
path_parameters: List[Property] = []
40-
responses: List[Response] = []
41-
tag = method_data.get("tags", ["default"])[0]
42-
collection = endpoints_by_tag.setdefault(tag, EndpointCollection(tag=tag))
43-
for param_dict in method_data.get("parameters", []):
44-
prop = property_from_dict(
45-
name=param_dict["name"], required=param_dict["required"], data=param_dict["schema"]
46-
)
47-
if isinstance(prop, (ListProperty, RefProperty, EnumProperty)) and prop.reference:
48-
collection.relative_imports.add(import_string_from_reference(prop.reference, prefix="..models"))
49-
if param_dict["in"] == ParameterLocation.QUERY:
50-
query_parameters.append(prop)
51-
elif param_dict["in"] == ParameterLocation.PATH:
52-
path_parameters.append(prop)
53-
else:
54-
raise ValueError(f"Don't know where to put this parameter: {param_dict}")
55-
56-
for code, response_dict in method_data["responses"].items():
57-
response = response_from_dict(status_code=int(code), data=response_dict)
58-
if isinstance(response, (RefResponse, ListRefResponse)):
59-
collection.relative_imports.add(
60-
import_string_from_reference(response.reference, prefix="..models")
61-
)
62-
responses.append(response)
63-
form_body_reference = None
64-
json_body = None
65-
if "requestBody" in method_data:
66-
form_body_reference = Endpoint.parse_request_form_body(method_data["requestBody"])
67-
json_body = Endpoint.parse_request_json_body(method_data["requestBody"])
68-
69-
endpoint = Endpoint(
70-
path=path,
71-
method=method,
72-
description=method_data.get("description"),
73-
name=method_data["operationId"],
74-
query_parameters=query_parameters,
75-
path_parameters=path_parameters,
76-
responses=responses,
77-
form_body_reference=form_body_reference,
78-
json_body=json_body,
79-
requires_security=bool(method_data.get("security")),
80-
)
81-
38+
endpoint = Endpoint.from_data(data=method_data, path=path, method=method)
39+
collection = endpoints_by_tag.setdefault(endpoint.tag, EndpointCollection(tag=endpoint.tag))
8240
collection.endpoints.append(endpoint)
83-
if form_body_reference:
84-
collection.relative_imports.add(
85-
import_string_from_reference(form_body_reference, prefix="..models")
86-
)
87-
if (
88-
json_body is not None
89-
and isinstance(json_body, (ListProperty, RefProperty, EnumProperty))
90-
and json_body.reference is not None
91-
):
92-
collection.relative_imports.add(
93-
import_string_from_reference(json_body.reference, prefix="..models")
94-
)
41+
collection.relative_imports.update(endpoint.relative_imports)
9542
return endpoints_by_tag
9643

9744

@@ -111,6 +58,8 @@ class Endpoint:
11158
requires_security: bool
11259
form_body_reference: Optional[Reference]
11360
json_body: Optional[Property]
61+
tag: str
62+
relative_imports: Set[str]
11463

11564
@staticmethod
11665
def parse_request_form_body(body: Dict[str, Any], /) -> Optional[Reference]:
@@ -130,6 +79,63 @@ def parse_request_json_body(body: Dict[str, Any], /) -> Optional[Property]:
13079
return property_from_dict("json_body", required=True, data=json_body["schema"])
13180
return None
13281

82+
@staticmethod
83+
def from_data(*, data: Dict[str, Any], path: str, method: str) -> Endpoint:
84+
""" Construct an endpoint from the OpenAPI data """
85+
query_parameters: List[Property] = []
86+
path_parameters: List[Property] = []
87+
responses: List[Response] = []
88+
tag = data.get("tags", ["default"])[0]
89+
relative_imports: Set[str] = set()
90+
91+
for param_dict in data.get("parameters", []):
92+
prop = property_from_dict(
93+
name=param_dict["name"], required=param_dict["required"], data=param_dict["schema"]
94+
)
95+
if isinstance(prop, (ListProperty, RefProperty, EnumProperty)) and prop.reference:
96+
relative_imports.add(import_string_from_reference(prop.reference, prefix="..models"))
97+
if param_dict["in"] == ParameterLocation.QUERY:
98+
query_parameters.append(prop)
99+
elif param_dict["in"] == ParameterLocation.PATH:
100+
path_parameters.append(prop)
101+
else:
102+
raise ValueError(f"Don't know where to put this parameter: {param_dict}")
103+
104+
for code, response_dict in data["responses"].items():
105+
response = response_from_dict(status_code=int(code), data=response_dict)
106+
if isinstance(response, (RefResponse, ListRefResponse)):
107+
relative_imports.add(import_string_from_reference(response.reference, prefix="..models"))
108+
responses.append(response)
109+
form_body_reference = None
110+
json_body = None
111+
if "requestBody" in data:
112+
form_body_reference = Endpoint.parse_request_form_body(data["requestBody"])
113+
json_body = Endpoint.parse_request_json_body(data["requestBody"])
114+
115+
if form_body_reference:
116+
relative_imports.add(import_string_from_reference(form_body_reference, prefix="..models"))
117+
if (
118+
json_body is not None
119+
and isinstance(json_body, (ListProperty, RefProperty, EnumProperty))
120+
and json_body.reference is not None
121+
):
122+
relative_imports.add(import_string_from_reference(json_body.reference, prefix="..models"))
123+
124+
return Endpoint(
125+
path=path,
126+
method=method,
127+
description=data.get("description"),
128+
name=data["operationId"],
129+
query_parameters=query_parameters,
130+
path_parameters=path_parameters,
131+
responses=responses,
132+
form_body_reference=form_body_reference,
133+
json_body=json_body,
134+
requires_security=bool(data.get("security")),
135+
tag=tag,
136+
relative_imports=relative_imports,
137+
)
138+
133139

134140
@dataclass
135141
class Schema:

tests/test_openapi_parser/test_openapi.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,36 @@ def test_import_string_from_reference_with_prefix(self, mocker):
246246
result = import_string_from_reference(reference=reference, prefix=prefix)
247247

248248
assert result == f"from {prefix}.{reference.module_name} import {reference.class_name}"
249+
250+
251+
class TestEndpointCollection:
252+
def test_from_dict(self, mocker):
253+
from openapi_python_client.openapi_parser.openapi import EndpointCollection, Endpoint
254+
255+
data_1 = mocker.MagicMock()
256+
data_2 = mocker.MagicMock()
257+
data_3 = mocker.MagicMock()
258+
data = {
259+
"path_1": {"method_1": data_1, "method_2": data_2,},
260+
"path_2": {"method_1": data_3,},
261+
}
262+
endpoint_1 = mocker.MagicMock(autospec=Endpoint, tag="tag_1", relative_imports={"1", "2"})
263+
endpoint_2 = mocker.MagicMock(autospec=Endpoint, tag="tag_2", relative_imports={"2"})
264+
endpoint_3 = mocker.MagicMock(autospec=Endpoint, tag="tag_1", relative_imports={"2", "3"})
265+
endpoint_from_data = mocker.patch.object(
266+
Endpoint, "from_data", side_effect=[endpoint_1, endpoint_2, endpoint_3]
267+
)
268+
269+
result = EndpointCollection.from_dict(data)
270+
271+
endpoint_from_data.assert_has_calls(
272+
[
273+
mocker.call(data=data_1, path="path_1", method="method_1"),
274+
mocker.call(data=data_2, path="path_1", method="method_2"),
275+
mocker.call(data=data_3, path="path_2", method="method_1"),
276+
]
277+
)
278+
assert result == {
279+
"tag_1": EndpointCollection("tag_1", endpoints=[endpoint_1, endpoint_3], relative_imports={"1", "2", "3"}),
280+
"tag_2": EndpointCollection("tag_2", endpoints=[endpoint_2], relative_imports={"2"}),
281+
}

0 commit comments

Comments
 (0)