gh-152405: Fix crash of rich-comparing MappingProxyType objects#152483
gh-152405: Fix crash of rich-comparing MappingProxyType objects#152483sobolevn wants to merge 9 commits into
MappingProxyType objects#152483Conversation
|
Would it be worth optimizing the common case where an exact (any?)dict is ultimately being compared with another exact (any?)dict. Because if it's just going to go through the dict comparison operator then it should be safe? |
|
The other variation that I was thinking about (but is untested so I might have missed a detail), is to do exact (any?)dict <-> exact (any?)dict specifically*, and then return not implemented for anything else. I think the result of that is that it would then fall back to the other classes' comparison operator, which would presumably be able to use the mapping interface of the proxy type to do the comparison. [*] possibly also with a a check for the comparison operator because the collections.OrderDict just uses the dict comparison operator |
This comment was marked as outdated.
This comment was marked as outdated.
That does suggest it might be get you a huge amount of benefit. Ah well... |
|
On more comment (then I stop thinking about this): if you're only concerned about the crash and not the leak then the only case you're really worried about is |
|
@da-woods thanks a lot for your help and ideas! I am not sure that |
I think it's just "not the dict comparison operator". I've put an alternative (draft) proposal in #152489 mostly to see if it works and passes everything. It intentionally isn't complete though and is just a quick C code suggestion right now. |
| static PyObject * | ||
| mappingproxy_or(PyObject *left, PyObject *right) | ||
| { | ||
| if (PyObject_TypeCheck(left, &PyDictProxy_Type)) { |
There was a problem hiding this comment.
I think in principle this needs fixing too.
There was a problem hiding this comment.
Yes, we can apply the same idea to many other methods. Let's keep this one about the actual rich-compare and the algorithm though :)
|
Behaviour change: import types
from collections.abc import Mapping
class CustomMapping1(Mapping):
def __init__(self, data):
self._data = data
def __getitem__(self, key):
return self._data[key]
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
def __contains__(self, item):
return item in self._data
class CustomMapping2(CustomMapping1):
def __eq__(self, other):
return isinstance(other, CustomMapping1) and self._data == other._data
m = types.MappingProxyType(CustomMapping1({'a': 1}))
assert m == CustomMapping2({'a': 1})This code passes on |
|
@da-woods please, check my new approach :) |
|
Yes - I believe that will work. It may be worth special casing not making the copy when you know the right-hand side is another exact anydict. But that's a minor implementation detail. If I was starting from scratch with no existing tests or behaviour then I think I'd prefer my approach. But obviously Python is very much not starting from scratch. So yeah - I'd agree that this fixes the important problem in the least modifying way. |
This is an alternative to #152449
Now I send a copy of the
dictif it is under a mapping, so it can't be mutated.Credit for this idea goes to @da-woods in this comment