[Bug]: [python] Reading a model property detaches the container previously returned by __getitem__, dropping mutations

Đang mở Phù hợp với người mới
#12,360 1 bình luận 1 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

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

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
75/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
backend, testing

Hướng nghiên cứu

Bắt đầu với _RestField.__get__ trong packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 và các bài kiểm thử thất bại được mô tả trong packages/http-client-python/tests/unit/test_model_base_serialization.py. Kiểm tra cách các giá trị dạng list và dict được giải tuần tự hóa và lưu trong obj._data; tái hiện thứ tự truy cập dict trước rồi đến thuộc tính. Công việc hoàn tất khi các thay đổi thông qua tham chiếu mapping lấy được trước đó xuất hiện trong as_dict() và quá trình tuần tự hóa request, đồng thời các bài kiểm thử hiện có vẫn chạy thành công.

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

Mô tả

bug emitter:client:python
Describe the bug

In the Python emitter's generated model runtime (_utils/model_base.py, from packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2), _RestField.__get__ deserializes list, dict and set values. It then stores the new container back into obj._data[rest_name] and sets _deserialized_<rest_name>.

Any container a caller got earlier through mapping access (obj["rest_name"]) is now detached from the model, so later mutations through that reference are silently dropped from as_dict() and request serialization. No error is raised.

The problem is limited to mixing dict access and property access on the same field. Mutating through a property reference (model.field.append(...)) works correctly; the property caching fixed that, since older generated runtimes lost those mutations. The remaining gap is the dict-then-property order:

Access order Mutation kept?
dict → property → mutate dict ref ❌ lost
property → dict → mutate property ref ✅
property → mutate ✅
dict → mutate ✅
property → property → mutate first ref ✅

Lists of models aren't affected: their deserializer returns the original list. Lists and dicts of primitives (for example list[str], dict[str, str]) are affected.

Expected: mapping access and property access share one backing container, so a mutation through either reference serializes.

Reproduction

Failing unit tests: https://github.com/microsoft/typespec/pull/12359 (adds to packages/http-client-python/tests/unit/test_model_base_serialization.py). 2 new tests fail, the guard and existing tests pass:

FAIL test_list_getitem_reference_survives_attribute_access: assert ['.txt'] == ['.txt', '.csv']
FAIL test_dict_getitem_reference_survives_attribute_access: assert {'a': '1'} == {'a': '1', 'b': '2'}

Equivalent with a minimal hand-written model:

from specialwords._utils.model_base import Model, rest_field   # any generated package's model_base

class M(Model):
    tags: list[str] = rest_field()

m = M(tags=["a"])
ref = m["tags"]
_ = m.tags
ref.append("b")
assert m.as_dict()["tags"] == ["a", "b"]   # fails: ['a']
Checklist
Ngôn ngữ chính
Java
Star
5.9k
Fork
421
Merge trung bình
2 ngày 3 giờ
Pull request đã merge (30 ngày)
176

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

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.

Issue khác của microsoft/typespec

Tất cả issue của microsoft/typespec

Issue tương tự

Thêm issue về Java

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.