graphql-python / graphql-python/graphene
Graphene ObjectType constructor does not make deep copy but instead shallow copy
- Ngôn ngữ chính
- Python
- Star
- 8.2k
- Fork
- 818
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Mô tả
**Note: for support questions, please use stackoverflow**. This repository's issues are reserved for feature requests and bug reports.
* **What is the current behavior?**
We have types:
```
ChildType(graphene.ObjectType):
enabled = graphene.Boolean(required=True, default_value=False)
def enable(self):
self.enabled = True
def disable(self):
self.enabled = False
ParentType(graphene.ObjectType):
p1prop1 = graphene.Field(ChildType, required=True, default_value=ChildType())
p1prop2 = graphene.Field(ChildType, required=True, default_value=ChildType())
def enable_children(self):
self.p1prop1.enable()
self.p1prop2.enable()
ParentType2(graphene.ObjectType):
p2prop1 = graphene.Field(ParentType, required=True, default_value=ParentType())
p2prop2 = graphene.Field(ParentType, required=True, default_value=ParentType())
```
In schema we call
```
class Query(graphene.ObjectType):
parent_two = graphene.Field(ParentType2)
def resolve_parent_two(self, info, *args, **kwargs):
parent_two = ParentType2()
parent_two.p2prop1.enable_children()
return parent_two
```
When querying parent_two trough localhost:8000/graphql, it returns:
```
parent_two {
p2prop1{
p1prop1{
enabled: True
}
p1prop2{
enabled: True
}
}
p2prop2{
p1prop1{
enabled: True
}
p1prop2{
enabled: True
}
}
}
```
The memory addresses of p2prop1 and p2prop2 are not equal which is right, but somehow mutating p2prop1.p1prop1 also affects to p2prop2.p1prop1 which leads to conclusion that calling constructor ParentType() when setting ParentType2 fields default_value leads to shallow copy instead of deep copy
* **What is the expected behavior?**
When querying parent_two trough localhost:8000/graphql, we expect it return:
```
parent_two {
p2prop1{
p1prop1{
enabled: True
}
p1prop2{
enabled: True
}
}
p2prop2{
p1prop1{
enabled: False
}
p1prop2{
enabled: False
}
}
}
```
We would want ParentType() constructor always make new object instead of shallow copy
* **What is the motivation / use case for changing the behavior?**
Current behaviour leads to unintuitive results
* **Please tell us about your environment:**
- Version:
graphene==2.1.8
graphene-django==2.10.1
- Platform:
Ubuntu 18.04, Pycharm, community edition, Chromium browser
* **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow)
We can fix the behaviour by calling
```
import copy
parentTypeInstance = ParentType()
ParentType2(graphene.ObjectType):
p2prop1 = graphene.Field(ParentType, required=True, default_value=copy.deepcopy(parentTypeInstance))
p2prop2 = graphene.Field(ParentType, required=True, default_value=copy.deepcopy(parentTypeInstance))
```
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Hướng nghiên cứu
Tái hiện ví dụ lồng nhau về ParentType2, ParentType và ChildType, đồng thời kiểm tra hàm khởi tạo ObjectType và cách xử lý default_value của Field. Xác nhận nơi các instance mặc định lồng nhau trở thành dùng chung, sau đó bổ sung coverage cho thấy việc thay đổi p2prop1 không ảnh hưởng đến p2prop2; hoàn tất khi kết quả GraphQL mong đợi được trả về mà không yêu cầu phía caller phải dùng deepcopy.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python
- Lĩnh vực
- api, backend
- 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