openapi-generators / openapi-generators/openapi-python-client

Incorrect generation of `_parse_response `

未關閉
#1,125 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

主要語言
Python
星號
2k
分支
293
平均合併
34 分鐘
30 天內合併 PR
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

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

使用提供的 OpenAPI 規範重現產生的用戶端,比較 response 以 inline 方式定義與透過 $ref 定義時的 response 解析路徑。追蹤建構 _parse_response 的程式碼產生路徑;完成標準是,被參照的 200 response 產生 TaskSummary.from_dict(response.json()),而其他狀態保留其預期處理方式。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
openapi, python
領域
api, tooling
Issue 類型
缺陷
難度
3/5
預估耗時
1-2 天
活躍度
停滯
描述清晰度
基本清楚
新手友好度
48/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。