graphql-python / graphql-python/graphene

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

Ouverte
#1,256 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
🐛 bug
Langage dominant
Python
Étoiles
8.2k
Forks
818
Métriques de merge des PR
Aucune PR mergée en 30 j

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

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Piste de recherche

Reproduisez l’exemple imbriqué de ParentType2, ParentType et ChildType et examinez le constructeur de ObjectType ainsi que la gestion de default_value de Field. Confirmez à quel endroit les instances par défaut imbriquées deviennent partagées, puis ajoutez une couverture montrant que la mutation de p2prop1 n’affecte pas p2prop2 ; c’est terminé lorsque le résultat GraphQL attendu est renvoyé sans nécessiter de deepcopy du côté de l’appelant.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
api, backend
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.