graphql-python / graphql-python/graphene

Graphene ObjectType constructor does not make deep copy but instead shallow copy

Open
#1,256 0 comments 0 reactions 0 assignees View on GitHub
🐛 bug
Dominant language
Python
Stars
8.2k
Forks
818
PR merge metrics
No merged PRs in 30d

Description

**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))
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.