Skip to content

Commit bce9df9

Browse files
authored
Make ReturnDict support dict union operators on Python 3.9 and later (#8302)
Fixes issue #8301
1 parent 45082b3 commit bce9df9

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

rest_framework/utils/serializer_helpers.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from collections import OrderedDict
23
from collections.abc import Mapping, MutableMapping
34

@@ -28,6 +29,22 @@ def __reduce__(self):
2829
# but preserve the raw data.
2930
return (dict, (dict(self),))
3031

32+
if sys.version_info >= (3, 9):
33+
# These are basically copied from OrderedDict, with `serializer` added.
34+
def __or__(self, other):
35+
if not isinstance(other, dict):
36+
return NotImplemented
37+
new = self.__class__(self, serializer=self.serializer)
38+
new.update(other)
39+
return new
40+
41+
def __ror__(self, other):
42+
if not isinstance(other, dict):
43+
return NotImplemented
44+
new = self.__class__(other, serializer=self.serializer)
45+
new.update(self)
46+
return new
47+
3148

3249
class ReturnList(list):
3350
"""

tests/test_serializer.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,3 +740,25 @@ class TestSerializer(A, B):
740740
'f4': serializers.CharField,
741741
'f5': serializers.CharField,
742742
}
743+
744+
745+
class Test8301Regression:
746+
@pytest.mark.skipif(
747+
sys.version_info < (3, 9),
748+
reason="dictionary union operator requires Python 3.9 or higher",
749+
)
750+
def test_ReturnDict_merging(self):
751+
# Serializer.data returns ReturnDict, this is essentially a test for that.
752+
753+
class TestSerializer(serializers.Serializer):
754+
char = serializers.CharField()
755+
756+
s = TestSerializer(data={'char': 'x'})
757+
assert s.is_valid()
758+
assert s.data | {} == {'char': 'x'}
759+
assert s.data | {'other': 'y'} == {'char': 'x', 'other': 'y'}
760+
assert {} | s.data == {'char': 'x'}
761+
assert {'other': 'y'} | s.data == {'char': 'x', 'other': 'y'}
762+
763+
assert (s.data | {}).__class__ == s.data.__class__
764+
assert ({} | s.data).__class__ == s.data.__class__

0 commit comments

Comments
 (0)