Philip Jenvey avatar Philip Jenvey committed de804d0

cpython issues #16029/16030: Fix pickling and repr of large xranges

Comments (0)

Files changed (2)

pypy/module/__builtin__/functional.py

 Interp-level definition of frequently used functionals.
 
 """
+import sys
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError
         return space.wrap(obj)
 
     def descr_repr(self):
-        stop = self.start + self.len * self.step
         if self.start == 0 and self.step == 1:
-            s = "xrange(%d)" % (stop,)
+            s = "xrange(%d)" % (self._get_stop(),)
         elif self.step == 1:
-            s = "xrange(%d, %d)" % (self.start, stop)
+            s = "xrange(%d, %d)" % (self.start, self._get_stop())
         else:
-            s = "xrange(%d, %d, %d)" %(self.start, stop, self.step)
+            s = "xrange(%d, %d, %d)" %(self.start, self._get_stop(), self.step)
         return self.space.wrap(s)
 
     def descr_len(self):
                                                     self.len, self.step))
 
     def descr_reversed(self):
-        lastitem = self.start + (self.len-1) * self.step
-        return self.space.wrap(W_XRangeIterator(self.space, lastitem,
-                                                self.len, -self.step))
+        last = self.start + (self.len - 1) * self.step
+        return self.space.wrap(W_XRangeIterator(self.space, last, self.len,
+                                                -self.step))
 
     def descr_reduce(self):
         space = self.space
         return space.newtuple(
             [space.type(self),
              space.newtuple([space.wrap(self.start),
-                             space.wrap(self.start + self.len * self.step),
+                             space.wrap(self._get_stop()),
                              space.wrap(self.step)])
              ])
 
+    def _get_stop(self):
+        if not self.len:
+            return self.start
+        step = self.step
+        last = self.start + (self.len - 1) * step
+        if step > 0:
+            return sys.maxint if last > sys.maxint - step else last + step
+        minint = -sys.maxint - 1
+        return minint if last < minint - step else last + step
+
 def _toint(space, w_obj):
     # this also supports float arguments.  CPython still does, too.
     # needs a bit more thinking in general...

pypy/module/__builtin__/test/test_functional.py

         x = xrange(1)
         assert type(reversed(x)) == type(iter(x))
 
+    def test_cpython_issue16029(self):
+        import sys
+        M = min(sys.maxint, sys.maxsize)
+        x = xrange(0, M, M - 1)
+        assert x.__reduce__() == (xrange, (0, M, M - 1))
+        x = xrange(0, -M, 1 - M)
+        assert x.__reduce__() == (xrange, (0, -M - 1, 1 - M))
+
+    def test_cpython_issue16030(self):
+        import sys
+        M = min(sys.maxint, sys.maxsize)
+        x = xrange(0, M, M - 1)
+        assert repr(x) == 'xrange(0, %s, %s)' % (M, M - 1)
+        x = xrange(0, -M, 1 - M)
+        assert repr(x) == 'xrange(0, %s, %s)' % (-M - 1, 1 - M)
+
 
 class AppTestReversed:
     def test_reversed(self):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.