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

from_dict raises when nullable ref is set to None

Đang mở
#679 7 bình luận 13 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

🐞bug
Ngôn ngữ chính
Python
Star
2k
Fork
293
Merge trung bình
34 phút
Pull request đã merge (30 ngày)
1

Mô tả

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)

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu bằng cách kiểm tra myapp_client/models/my_object.py và my_child_object.py đã được tạo, đặc biệt là đường dẫn from_dict được nêu trong báo cáo, sau đó truy vết đoạn mã generator nào tạo ra nó. So sánh cách xử lý scalar nullable với cách xử lý $ref nullable. Được xem là hoàn tất khi from_dict chấp nhận giá trị None cho myRef mà không gọi MyChildObject.from_dict(None), đồng thời vẫn giữ nguyên hành vi của UNSET.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
openapi, python
Lĩnh vực
tooling
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.