Make ReturnDict support dict union operators on Python 3.9 and later (#8302)

Fixes issue #8301
This commit is contained in:
Luke Plant 2021-12-22 15:08:58 +00:00 committed by GitHub
parent 45082b3936
commit bce9df9b5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 0 deletions

View File

@ -1,3 +1,4 @@
import sys
from collections import OrderedDict
from collections.abc import Mapping, MutableMapping
@ -28,6 +29,22 @@ class ReturnDict(OrderedDict):
# but preserve the raw data.
return (dict, (dict(self),))
if sys.version_info >= (3, 9):
# These are basically copied from OrderedDict, with `serializer` added.
def __or__(self, other):
if not isinstance(other, dict):
return NotImplemented
new = self.__class__(self, serializer=self.serializer)
new.update(other)
return new
def __ror__(self, other):
if not isinstance(other, dict):
return NotImplemented
new = self.__class__(other, serializer=self.serializer)
new.update(self)
return new
class ReturnList(list):
"""

View File

@ -740,3 +740,25 @@ class TestDeclaredFieldInheritance:
'f4': serializers.CharField,
'f5': serializers.CharField,
}
class Test8301Regression:
@pytest.mark.skipif(
sys.version_info < (3, 9),
reason="dictionary union operator requires Python 3.9 or higher",
)
def test_ReturnDict_merging(self):
# Serializer.data returns ReturnDict, this is essentially a test for that.
class TestSerializer(serializers.Serializer):
char = serializers.CharField()
s = TestSerializer(data={'char': 'x'})
assert s.is_valid()
assert s.data | {} == {'char': 'x'}
assert s.data | {'other': 'y'} == {'char': 'x', 'other': 'y'}
assert {} | s.data == {'char': 'x'}
assert {'other': 'y'} | s.data == {'char': 'x', 'other': 'y'}
assert (s.data | {}).__class__ == s.data.__class__
assert ({} | s.data).__class__ == s.data.__class__