Browse Source

PyPy: Utils: OrderedDict: Dicts always ordered in recent PyPy

Ask Solem 8 years ago
parent
commit
2e21ca2f7c
1 changed files with 50 additions and 28 deletions
  1. 50 28
      celery/datastructures.py

+ 50 - 28
celery/datastructures.py

@@ -22,10 +22,16 @@ from billiard.einfo import ExceptionInfo  # noqa
 from kombu.utils.encoding import safe_str, bytes_to_str
 from kombu.utils.limits import TokenBucket  # noqa
 
-from celery.five import Empty, items, python_2_unicode_compatible, values
+from celery.five import Empty, items, keys, python_2_unicode_compatible, values
 from celery.utils.functional import LRUCache, first, uniq  # noqa
 from celery.utils.text import match_case
 
+try:
+    # pypy: dicts are ordered in recent versions
+    from __pypy__ import reversed_dict as _dict_is_ordered
+except ImportError:
+    _dict_is_ordered = None
+
 try:
     from django.utils.functional import LazyObject, LazySettings
 except ImportError:
@@ -39,6 +45,8 @@ __all__ = [
     'ConfigurationView', 'LimitedSet',
 ]
 
+PY3 = sys.version_info[0] >= 3
+
 DOT_HEAD = """
 {IN}{type} {id} {{
 {INp}graph [{attrs}]
@@ -883,38 +891,52 @@ class LimitedSet(object):
 MutableSet.register(LimitedSet)
 
 
-if not hasattr(_OrderedDict, 'move_to_end'):
-
-    class OrderedDict(_OrderedDict):
-        def move_to_end(self, key, last=True):
-            link = self._OrderedDict__map[key]
-            link_prev = link[0]
-            link_next = link[1]
-            link_prev[1] = link_next
-            link_next[0] = link_prev
-            root = self._OrderedDict__root
-            if last:
-                last = root[0]
-                link[0] = last
-                link[1] = root
-                last[1] = root[0] = link
-            else:
-                first = root[1]
-                link[0] = root
-                link[1] = first
-                root[1] = first[0] = link
+class OrderedDict(_OrderedDict):
 
+    if PY3:  # pragma: no cover
         def _LRUkey(self):
-            return self._OrderedDict__root[1][2]
+            # return value of od.keys does not support __next__,
+            # but this version will also not create a copy of the list.
+            return next(iter(keys(self)))
+    else:
+        if _dict_is_ordered:  # pragma: no cover
+            def _LRUkey(self):
+                # iterkeys is iterable.
+                return next(self.iterkeys())
+        else:
+            def _LRUkey(self):
+                return self._OrderedDict__root[1][2]
 
-else:  # pragma: no cover
+    if not hasattr(_OrderedDict, 'move_to_end'):
+        if _dict_is_ordered:  # pragma: no cover
 
-    class OrderedDict(_OrderedDict):  # noqa
+            def move_to_end(self, key, last=True):
+                if not last:
+                    # we don't use this argument, and the only way to
+                    # implement this on PyPy seems to be O(n): creating a
+                    # copy with the order changed, so we just raise.
+                    raise NotImplementedError('no last=True on PyPy')
+                self[key] = self.pop(key)
 
-        def _LRUkey(self):
-            # return value of od.keys does not support __next__,
-            # but this version will also not create a copy of the list.
-            return next(iter(self.keys()))
+        else:
+
+            def move_to_end(self, key, last=True):
+                link = self._OrderedDict__map[key]
+                link_prev = link[0]
+                link_next = link[1]
+                link_prev[1] = link_next
+                link_next[0] = link_prev
+                root = self._OrderedDict__root
+                if last:
+                    last = root[0]
+                    link[0] = last
+                    link[1] = root
+                    last[1] = root[0] = link
+                else:
+                    first = root[1]
+                    link[0] = root
+                    link[1] = first
+                    root[1] = first[0] = link
 
 
 class Evictable(object):