-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make ReturnDict support dict union operators on Python 3.9 and later #8302
Make ReturnDict support dict union operators on Python 3.9 and later #8302
Conversation
@@ -28,6 +29,22 @@ def __reduce__(self): | |||
# but preserve the raw data. | |||
return (dict, (dict(self),)) | |||
|
|||
if sys.version_info >= (3, 9): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for the version gate here?
The methods could be always defined, even if only python >= 3.9 uses them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a case of only Python 3.9 using them - no matter what your Python version, if you define those methods, then |
will do dictionary merging like it does in 3.9 (I have confirmed this). So the question is - if I'm on Python 3.8, what do I expect these would do:
>>> {} | {}
>>> serializer_instance.data | {}
On Python 3.8, the first one will produce TypeError: unsupported operand type(s) for |: 'dict' and 'dict'
and there is nothing we can do about that. So I expect most people would expect the second to do that as well.
I think we are asking for confusion and trouble if we effectively backport PEP 584 to earlier Python versions, but only for the return value of Serializer.data
, and nowhere else (because we can't).
I'm +0 on the general idea of this, I think it is a nice thing to have when it comes to overall compatibility. As for restricting this to just Python 3.9+, I understand the concerns around expectations but I personally would rather just see us keep this consistent from the DRF side for all versions. It doesn't really make sense for us to limit it just because the language version itself doesn't support it in the other direction. |
@kevin-brown It's impossible to keep things get that kind of consistency, since you can't change the behaviour of built-in types. If you have a Python 3.8 project, then having the Regarding the PR in general, the current DRF behaviour is a very clear bug on Python 3.9. The
With the patch as it is, there is no resulting inconsistency:
Without the patch, 2 is not true. DRF nowhere advertises support for
So the only consistency to aim for here is consistency with Python dictionaries. |
Neat - thanks Luke! |
Fixes issue #8301
Notes
For tests, as there were no other direct tests of
ReturnDict
, I thought it best to consider this as an implementation detail ofSerializer
, and just added it to the serializer tests.As the union operator was added in PEP 584 for Python 3.9, I think it makes most sense to only add this support for Python 3.9 upwards.
One decision made here is that the union operator, both for left hand and right hand versions, produces a
ReturnDict
, instead of just anOrderedDict
or adict
. My rationale is as follows:If you do:
then
d
ends up as an instance ofReturnDict
. If you refactored this to:you would probably expect it to stay the same type. Also, usually the additional behaviour of
ReturnDict
(access to serializer instance) is not going to get in the way if you don't need it, but it will be an issue if you did need it and it wasn't there.A counter argument would be that the dictionary
|
operator could be considered an upgrade for this idiom:The above code produces a
dict
, notReturnDict
. I find this argument less convincing.