from_dict raises when nullable ref is set to None

オープン
#679 コメント 7 件 リアクション 13 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
停滞
技術スタック
openapi, python
領域
tooling

調査の方向性

まず、生成された myapp_client/models/my_object.py と my_child_object.py を調査し、特にレポートに示されている from_dict のパスを確認してから、それを生成しているジェネレーターコードを追跡します。nullable なスカラーの処理と nullable な $ref の処理を比較します。from_dict が MyChildObject.from_dict(None) を呼び出さずに myRef の None 値を受け入れ、同時に UNSET の動作を維持できれば完了です。

索引モデルが issue の本文から書いたものです。

説明

🐞bug

Describe the bug
from_dict when we set a nullable field ref to None. This behavior:

  • differs from class constructor which accepts None ref fields
  • differs from others fields : from_dict accept nullable string, object, array, etc to be set to None

To Reproduce
Steps to reproduce the behavior:

  1. take the following swagger:
components:
  schemas:
    MyObject:
      properties:
        myId:
          title: MyId
          type: string
          nullable: true
        myArray:
          title: MyArray
          type: array
          nullable: true
          items:
            type: string
        myString:
          title: MyString
          type: string
          nullable: true
        myObject:
          title: myObject
          type: object
          nullable: true
        myRef:
          $ref: '#/components/schemas/MyChildObject'
          nullable: true
      required:
        - myId
      title: MyObject
      type: object
    MyChildObject:
      properties:
        aField:
          items:
            type: string
          nullable: true
          title: AField
          type: array
      title: MyChildObject
      type: object
info:
  title: myapp
  version: 1.9.4a5
openapi: 3.0.2
paths:
  /myroute:
    get:
      parameters:
      requestBody:
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MyChildObject'
          description: Successful Response
  1. generate the client from this swagger
  2. run the following code snippet:
from myapp_client.models import MyObject, MyChildObject
MyObject(my_id="id", my_object=None, my_array=None, my_string=None, my_ref=None) # pass
MyObject.from_dict({"myId":"id", "myObject": None, "myArray": None, "myString": None, "myRef": None}) # raise
MyObject.from_dict({"myId":"id", "myObject": None, "myArray": None, "myString": None}) # pass
  1. See error
In [1]: from myapp_client.models import MyObject, MyChildObject

In [2]: MyObject(my_id="id", my_object=None, my_array=None, my_string=None, my_ref=None)
Out[2]: MyObject(my_id='id', my_array=None, my_string=None, my_object=None, my_ref=None, additional_properties={})

In [3]: MyObject.from_dict({"myId":"id", "myObject": None, "myArray": None, "myString": None, "myRef": None})
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In [3], line 1
----> 1 MyObject.from_dict({"myId":"id", "myObject": None, "myArray": None, "myString": None, "myRef": None})

File ~/CF/amp-client/myapp-client/myapp_client/models/my_object.py:89, in MyObject.from_dict(cls, src_dict)
     87     my_ref = UNSET
     88 else:
---> 89     my_ref = MyChildObject.from_dict(_my_ref)
     91 my_object = cls(
     92     my_id=my_id,
     93     my_array=my_array,
   (...)
     96     my_ref=my_ref,
     97 )
     99 my_object.additional_properties = d

File ~/CF/amp-client/myapp-client/myapp_client/models/my_child_object.py:38, in MyChildObject.from_dict(cls, src_dict)
     36 @classmethod
     37 def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
---> 38     d = src_dict.copy()
     39     a_field = cast(List[str], d.pop("aField", UNSET))
     41     my_child_object = cls(
     42         a_field=a_field,
     43     )

AttributeError: 'NoneType' object has no attribute 'copy'

In [4]: MyObject.from_dict({"myId":"id", "myObject": None, "myArray": None, "myString": None})
Out[4]: MyObject(my_id='id', my_array=None, my_string=None, my_object=None, my_ref=<myapp_client.types.Unset object at 0x7f9f73a4f8e0>, additional_properties={})

In [5]: MyObject.from_dict({"myId":"id", "myObject": None, "myArray": None, "myString": None})

Expected behavior
We expect MyObject.from_dict({"myId":"id", "myObject": None, "myArray": None, "myString": None, "myRef": None}) to run without errors.

Some debug
having a look in the debugger, it raises there::

        _my_ref = d.pop("myRef", UNSET)
        my_ref: Union[Unset, MyChildObject]
        if isinstance(_my_ref, Unset):
            my_ref = UNSET
        else:
->          my_ref = MyChildObject.from_dict(_my_ref)

The code generated should rather look like:

        _my_ref = d.pop("myRef", UNSET)
        my_ref: Union[Unset, None, MyChildObject]
        if _my_ref is None:
            my_ref = None
        elif isinstance(_my_ref, Unset):
            my_ref = UNSET
        else:
            my_ref = MyChildObject.from_dict(_my_ref)
主要言語
Python
スター
2k
フォーク
293
平均マージ
34分
マージ済み PR(30日)
1

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

openapi-generators/openapi-python-client のほかの issue

openapi-generators/openapi-python-client の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。