



An entry has an expiry time of X (so it will self-delete at time X or later).dict happily bypasses custom _getitem_/ delitem calls when it uses pop/popitem.Įxplaining expiringdict's issue: It's two race conditions, with itself, not another thread.
#Popkey ordereddict code
The only reason OrderedDict has the problem and dict doesn't is that OrderedDict was trying to be subclassing friendly (perhaps to ensure it remains compatible with code that subclassed the old Python implementation), while dict makes no such efforts. The Sequence_Contains check is needed to avoid accidentally invoking _missing_ (though if _missing_ is not defined for the subclass, the Sequence_Contains check could be skipped). The general PyObject_GetItem/DelItem are needed to work with arbitrary subclasses correctly. The original code should probably be restored here. The expiringdict's flaw seems to be that its _contains_ call and its _getitem_ are not idempotent, which the original code assumed (reasonably) they would be. _setitem_ might add some tracking data to the value that _getitem_ strips). The old code meant that pop and popitem didn't need to be overridden even if you overrode _getitem_/ delitem in a way that differed from the default (e.g.
#Popkey ordereddict Patch
Serhiy, doesn't this patch "fix" the issue by making subclasses with custom _getitem_/ delitem implementations not have them invoked by the superclass's pop/popitem? Priority = 'normal' resolution = 'fixed' stage = 'resolved' status = 'closed' superseder = None type = 'behavior' url = '' versions = Print('= Tests before key change finished =')Īssert list(reversed(d)) = list(reversed(keys))Īssert list(reversed(d.keys())) = list(reversed(keys))Īssert list(reversed(d.Activity = actor = 'lukasz.langa' assignee = 'serhiy.storchaka' closed = True closed_date = closer = 'lukasz.langa' components = Ĭreation = creator = 'kaniini' dependencies = Return self.OrderedDictXItemsView(self, super().items()) Return self.OrderedDictXKeysView(self, super().keys()) Yield self._odx._keys_int2ext.get(k, k), v # employ this trick: make it such that it appears as if k_ext has also been renamed to kįor (k, v), (k_other, v_other) in zip(ems(), ems()):įor k, v in OrderedDict(*args, **kwargs).items():ĭef _init_(self, odx: 'OrderedDictX', orig_keys):ĭef _init_(self, odx: 'OrderedDictX', orig_items): # If the key exists in the internal state but was renamed to a k_ext, Return super()._setitem_(self._keys_ext2int, v) Return super()._getitem_(self._keys_ext2int.get(k, k)) # Intentionally raise KeyError in ext2int # Check if new key matches the internal key # Change the key using internal dicts mechanism Raise Exception(f'Cannot rename key already in dict') # Validate that the old key is part of the dict Here it is: from collections import OrderedDict Please comment if you see issues or have improvements to propose as this might still be error-prone. as they appear externally to the user) to the ones in the underlying OrderedDict ("internal"). It uses 2 extra dictionaries to remap the changed keys ("external" - i.e. I was not satisfied with the dictionary needing reconstruction (at least partially), obviously for efficiency reasons, so I've put together a class that extends OrderedDict and allows you to do key changes efficiently.
