openapi-generators / openapi-generators/openapi-python-client
Incorrect generation of `_parse_response `
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 2k
- フォーク
- 293
- 平均マージ
- 34分
- マージ済み PR(30日)
- 1
説明
Lovely package BTW!
Describe the bug
Code generation for parsing API response does not generate the code that creates the Python model after the response is completed. This happens when using a $ref to define the response instead of just defining the response body inside the path definition.
OpenAPI Spec File
openapi: 3.0.3
info:
title: Example
description: |
Example API definition.
version: 1.0.0
security:
- BearerAuth: []
paths:
/v2/task/{task_id}:
get:
summary: Get the summary of a task.
responses:
'200':
$ref: '#/components/responses/task_summary'
'400':
$ref: '#/components/responses/bad_request'
'403':
$ref: '#/components/responses/not_authorized'
parameters:
- $ref: '#/components/parameters/task_id'
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
task_id:
name: task_id
in: path
description: The unique identifier of the task targeted by the request.
required: true
schema:
$ref: '#/components/schemas/TaskId'
responses:
task_summary:
description: Summary of the task at the time the request was made.
content:
application/json:
schema:
$ref: '#/components/schemas/TaskSummary'
bad_submit_task_request:
description: |
The request is invalid. This may indicate an error when parsing a parameter, or an error when parsing or validating the request body. The response body may contain a JSON array with a list of validation errors.
content:
application/json:
schema:
type: object
properties:
validation_errors:
type: array
minItems: 1
items:
type: string
not_authorized:
description: |
User is not authorized to perform this task.
bad_request:
description: |
The request is invalid. This may indicate an error when parsing a parameter.
schemas:
TaskId:
type: string
minLength: 1
maxLength: 256
pattern: "^[a-zA-Z0-9][a-zA-Z0-9-]*$"
example: '80cf75f2-4700-4006-9203-4376b091ee4e'
description: A unique identifier for a task. Must not be an empty string.
TaskSummary:
type: "object"
description: Summary of existing task, including task status.
properties:
task_status:
$ref: '#/components/schemas/TaskStatus'
required:
- task_status
TaskStatus:
type: string
enum:
- Created
- PayloadProcessing
- Scheduled
- Completed
- Cancelled
- Failed
description: |
Reports status of the task. Lifecycle of a normal task is Created -> PayloadProcessing -> Scheduled -> Completed.
where PayloadProcessing - the task is going trough additional compilation/validation/optimization,
Scheduled - the task is in the qpu queue, Completed - the task has been executed.
the code that gets generated here is:
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
if response.status_code == HTTPStatus.OK:
return None
if response.status_code == HTTPStatus.BAD_REQUEST:
return None
if response.status_code == HTTPStatus.FORBIDDEN:
return None
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
which is not correct. The additional context shows the expected behavior.
Desktop (please complete the following information):
- OS: macOS: 14.4.1
- Python Version: 3.12.1
- openapi-python-client: 0.21.5 [e.g. 0.1.0]
Additional context
Note if I modify the path:
/v2/task/{task_id}:
get:
summary: Get the summary of a task.
responses:
'200':
description: Summary of the task at the time the request was made.
content:
application/json:
schema:
$ref: '#/components/schemas/TaskSummary'
'400':
$ref: '#/components/responses/bad_request'
'403':
$ref: '#/components/responses/not_authorized'
parameters:
- $ref: '#/components/parameters/task_id'
it generates the correct code:
def _parse_response(
*, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, TaskSummary]]:
if response.status_code == HTTPStatus.OK:
response_200 = TaskSummary.from_dict(response.json())
return response_200
if response.status_code == HTTPStatus.BAD_REQUEST:
response_400 = cast(Any, None)
return response_400
if response.status_code == HTTPStatus.FORBIDDEN:
response_403 = cast(Any, None)
return response_403
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
提供された OpenAPI 仕様を使用して生成されたクライアントを再現し、レスポンスが inline で定義されている場合と $ref を通じて定義されている場合のレスポンス解析パスを比較します。_parse_response を構築するコード生成パスを追跡します。参照された 200 レスポンスが TaskSummary.from_dict(response.json()) を生成し、その他のステータスが期待される処理を維持すれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- openapi, python
- 領域
- api, tooling
- issue の種類
- バグ
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 48/100