Skip to content
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

Add support for "XX" status code specifications #973

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
63 changes: 39 additions & 24 deletions openapi_python_client/parser/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ def __call__(
... # pragma: no cover


def get_status_codes_from_string(code: Union[int, str]) -> List[HTTPStatus]:
"""Interpret HTTP status code patterns and return a list of HTTPStatus instances."""
if isinstance(code, str) and "XX" in code:
start_number = int(code[0])

start_range = start_number * 100
end_range = start_range + 100

return [
HTTPStatus(status) for status in range(start_range, end_range) if status in HTTPStatus._value2member_map_
]

return [HTTPStatus(int(code))]


@dataclass
class Endpoint:
"""
Expand Down Expand Up @@ -149,9 +164,8 @@ def _add_responses(
) -> Tuple["Endpoint", Schemas]:
endpoint = deepcopy(endpoint)
for code, response_data in data.items():
status_code: HTTPStatus
try:
status_code = HTTPStatus(int(code))
parsable_codes = get_status_codes_from_string(code)
except ValueError:
endpoint.errors.append(
ParseError(
Expand All @@ -164,30 +178,31 @@ def _add_responses(
)
continue

response, schemas = response_from_data(
status_code=status_code,
data=response_data,
schemas=schemas,
parent_name=endpoint.name,
config=config,
)
if isinstance(response, ParseError):
detail_suffix = "" if response.detail is None else f" ({response.detail})"
endpoint.errors.append(
ParseError(
detail=(
f"Cannot parse response for status code {status_code}{detail_suffix}, "
f"response will be ommitted from generated client"
),
data=response.data,
)
for status_code in parsable_codes:
response, schemas = response_from_data(
status_code=status_code,
data=response_data,
schemas=schemas,
parent_name=endpoint.name,
config=config,
)
continue
if isinstance(response, ParseError):
detail_suffix = "" if response.detail is None else f" ({response.detail})"
endpoint.errors.append(
ParseError(
detail=(
f"Cannot parse response for status code {status_code}{detail_suffix}, "
f"response will be ommitted from generated client"
),
data=response.data,
)
)
continue

# No reasons to use lazy imports in endpoints, so add lazy imports to relative here.
endpoint.relative_imports |= response.prop.get_lazy_imports(prefix=models_relative_prefix)
endpoint.relative_imports |= response.prop.get_imports(prefix=models_relative_prefix)
endpoint.responses.append(response)
# No reasons to use lazy imports in endpoints, so add lazy imports to relative here.
endpoint.relative_imports |= response.prop.get_lazy_imports(prefix=models_relative_prefix)
endpoint.relative_imports |= response.prop.get_imports(prefix=models_relative_prefix)
endpoint.responses.append(response)
return endpoint, schemas

@staticmethod
Expand Down
30 changes: 30 additions & 0 deletions tests/test_parser/test_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,36 @@ def test__add_responses_status_code_error(self, response_status_code, mocker):
]
response_from_data.assert_not_called()

def test__add_responses__wildcard_response(self, mocker):
from openapi_python_client.parser.openapi import Endpoint, Schemas

schemas = Schemas()
response_1_data = mocker.MagicMock()
data = {
"2XX": response_1_data,
}
endpoint = self.make_endpoint()
parse_error = ParseError(data=mocker.MagicMock())
response_from_data = mocker.patch(f"{MODULE_NAME}.response_from_data", return_value=(parse_error, schemas))
config = MagicMock()

response, schemas = Endpoint._add_responses(endpoint=endpoint, data=data, schemas=schemas, config=config)

response_from_data.assert_has_calls(
[
mocker.call(status_code=200, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=201, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=202, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=203, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=204, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=205, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=206, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=207, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=208, data=response_1_data, schemas=schemas, parent_name="name", config=config),
mocker.call(status_code=226, data=response_1_data, schemas=schemas, parent_name="name", config=config),
]
)

def test__add_responses_error(self, mocker):
from openapi_python_client.parser.openapi import Endpoint, Schemas

Expand Down