Author: Armin Rigo <ar...@tunes.org>
Branch: py3.5
Changeset: r89936:5764bb3f54a2
Date: 2017-02-05 11:08 +0100
http://bitbucket.org/pypy/pypy/changeset/5764bb3f54a2/

Log:    PyPy's simplified version of OrderedDict

diff --git a/lib_pypy/_collections.py b/lib_pypy/_collections.py
--- a/lib_pypy/_collections.py
+++ b/lib_pypy/_collections.py
@@ -439,3 +439,8 @@
         return (type(self), (self.default_factory,), None, None,
                 iter(self.items()))
 
+
+try:
+    from _pypy_collections import OrderedDict
+except ImportError:
+    pass
diff --git a/lib_pypy/_pypy_collections.py b/lib_pypy/_pypy_collections.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_pypy_collections.py
@@ -0,0 +1,69 @@
+from __pypy__ import reversed_dict, move_to_end
+from reprlib import recursive_repr as _recursive_repr
+
+class OrderedDict(dict):
+    '''Dictionary that remembers insertion order.
+
+    In PyPy all dicts are ordered anyway.  This is mostly useful as a
+    placeholder to mean "this dict must be ordered even on CPython".
+
+    Known difference: iterating over an OrderedDict which is being
+    concurrently modified raises RuntimeError in PyPy.  In CPython
+    instead we get some behavior that appears reasonable in some
+    cases but is nonsensical in other cases.  This is officially
+    forbidden by the CPython docs, so we forbid it explicitly for now.
+    '''
+
+    def __reversed__(self):
+        return reversed_dict(self)
+
+    def popitem(self, last=True):
+        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
+        Pairs are returned in LIFO order if last is true or FIFO order if 
false.
+
+        '''
+        if last:
+            return dict.popitem(self)
+        else:
+            it = dict.__iter__(self)
+            try:
+                k = it.next()
+            except StopIteration:
+                raise KeyError('dictionary is empty')
+            return (k, self.pop(k))
+
+    def move_to_end(self, key, last=True):
+        '''Move an existing element to the end (or beginning if last==False).
+
+        Raises KeyError if the element does not exist.
+        When last=True, acts like a fast version of self[key]=self.pop(key).
+
+        '''
+        return move_to_end(self, key, last)
+
+    @_recursive_repr()
+    def __repr__(self):
+        'od.__repr__() <==> repr(od)'
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, list(self.items()))
+
+    def __reduce__(self):
+        'Return state information for pickling'
+        inst_dict = vars(self).copy()
+        return self.__class__, (), inst_dict or None, None, iter(self.items())
+
+    def copy(self):
+        'od.copy() -> a shallow copy of od'
+        return self.__class__(self)
+
+    def __eq__(self, other):
+        '''od.__eq__(y) <==> od==y.  Comparison to another OD is 
order-sensitive
+        while comparison to a regular mapping is order-insensitive.
+
+        '''
+        if isinstance(other, OrderedDict):
+            return dict.__eq__(self, other) and all(map(_eq, self, other))
+        return dict.__eq__(self, other)
+
+    __ne__ = object.__ne__
diff --git a/pypy/module/_collections/__init__.py 
b/pypy/module/_collections/__init__.py
--- a/pypy/module/_collections/__init__.py
+++ b/pypy/module/_collections/__init__.py
@@ -25,3 +25,15 @@
         space = self.space
         space.getattr(self, space.wrap('defaultdict'))  # force importing
         space.delattr(self, space.wrap('__missing__'))
+
+    def startup(self, space):
+        # OrderedDict is normally present, but in some cases the line
+        # "from __pypy__ import reversed_dict, move_to_end" from
+        # _pypy_collections.py raises
+        space.appexec([space.wrap(self)], """(mod):
+            try:
+                from _pypy_collections import OrderedDict
+                mod.OrderedDict = OrderedDict
+            except ImportError:
+                pass
+        """)
diff --git a/pypy/module/_collections/test/test_ordereddict.py 
b/pypy/module/_collections/test/test_ordereddict.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_collections/test/test_ordereddict.py
@@ -0,0 +1,8 @@
+
+class AppTestBasic:
+    spaceconfig = dict(usemodules=['_collections'])
+
+    def test_ordereddict_present(self):
+        from _collections import OrderedDict
+        assert issubclass(OrderedDict, dict)
+        assert hasattr(OrderedDict, 'move_to_end')
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to