[pypy-commit] pypy gc_no_cleanup_nursery: hg merge default

arigo noreply at buildbot.pypy.org
Fri Sep 26 09:25:54 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: gc_no_cleanup_nursery
Changeset: r73716:bf10e6f91f1a
Date: 2014-09-26 09:25 +0200
http://bitbucket.org/pypy/pypy/changeset/bf10e6f91f1a/

Log:	hg merge default

diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py
--- a/lib_pypy/datetime.py
+++ b/lib_pypy/datetime.py
@@ -1242,7 +1242,7 @@
                         (other._hour, other._minute, other._second,
                          other._microsecond))
         if myoff is None or otoff is None:
-            raise TypeError("cannot compare naive and aware times")
+            raise TypeError("can't compare offset-naive and offset-aware times")
         myhhmm = self._hour * 60 + self._minute - myoff
         othhmm = other._hour * 60 + other._minute - otoff
         return _cmp((myhhmm, self._second, self._microsecond),
@@ -1838,7 +1838,7 @@
                          other._hour, other._minute, other._second,
                          other._microsecond))
         if myoff is None or otoff is None:
-            raise TypeError("cannot compare naive and aware datetimes")
+            raise TypeError("can't compare offset-naive and offset-aware datetimes")
         # XXX What follows could be done more efficiently...
         diff = self - other     # this will take offsets into account
         if diff.days < 0:
@@ -1885,7 +1885,7 @@
         if myoff == otoff:
             return base
         if myoff is None or otoff is None:
-            raise TypeError("cannot mix naive and timezone-aware time")
+            raise TypeError("can't subtract offset-naive and offset-aware datetimes")
         return base + timedelta(minutes = otoff-myoff)
 
     def __hash__(self):
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -38,14 +38,16 @@
     no JIT: windows, linux, os/x
     sandbox: linux, os/x
 
+* repackage and upload source tar.bz2 to bitbucket and to cobra, as some packagers 
+  prefer a clearly labeled source package
 * write release announcement pypy/doc/release-x.y(.z).txt
   the release announcement should contain a direct link to the download page
 * update pypy.org (under extradoc/pypy.org), rebuild and commit
 
 * post announcement on morepypy.blogspot.com
-* send announcements to pypy-dev, python-list,
+* send announcements to twitter.com, pypy-dev, python-list,
   python-announce, python-dev ...
 
 * add a tag on the pypy/jitviewer repo that corresponds to pypy release
 * add a tag on the codespeed web site that corresponds to pypy release
-
+* revise versioning at https://readthedocs.org/projects/pypy
diff --git a/pypy/doc/release-2.4.0.rst b/pypy/doc/release-2.4.0.rst
--- a/pypy/doc/release-2.4.0.rst
+++ b/pypy/doc/release-2.4.0.rst
@@ -105,7 +105,7 @@
   
 * Many issues were resolved_ since the 2.3.1 release on June 8
 
-.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.3.1.html
+.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.4.0.html
 .. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
 .. _sandbox: http://doc.pypy.org/en/latest/sandbox.html   
 
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -407,8 +407,19 @@
         --------
         numpy.swapaxes : equivalent function
         """
-        if self.is_scalar():
+        if axis1 == axis2:
             return self
+        n = len(self.get_shape())
+        if n <= 1:
+            return self
+        if axis1 < 0:
+            axis1 += n
+        if axis2 < 0:
+            axis2 += n
+        if axis1 < 0 or axis1 >= n:
+            raise oefmt(space.w_ValueError, "bad axis1 argument to swapaxes")
+        if axis2 < 0 or axis2 >= n:
+            raise oefmt(space.w_ValueError, "bad axis2 argument to swapaxes")
         return self.implementation.swapaxes(space, self, axis1, axis2)
 
     def descr_nonzero(self, space):
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -2020,6 +2020,14 @@
 
     def test_swapaxes(self):
         from numpypy import array
+        x = array([])
+        assert x.swapaxes(0, 2) is x
+        x = array([[1, 2]])
+        assert x.swapaxes(0, 0) is x
+        exc = raises(ValueError, x.swapaxes, -3, 0)
+        assert exc.value.message == "bad axis1 argument to swapaxes"
+        exc = raises(ValueError, x.swapaxes, 0, 3)
+        assert exc.value.message == "bad axis2 argument to swapaxes"
         # testcases from numpy docstring
         x = array([[1, 2, 3]])
         assert (x.swapaxes(0, 1) == array([[1], [2], [3]])).all()
diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py
--- a/pypy/module/select/interp_select.py
+++ b/pypy/module/select/interp_select.py
@@ -173,9 +173,9 @@
 On Windows, only sockets are supported; on Unix, all file descriptors.
 """
 
-    iwtd_w = space.listview(w_iwtd)
-    owtd_w = space.listview(w_owtd)
-    ewtd_w = space.listview(w_ewtd)
+    iwtd_w = space.unpackiterable(w_iwtd)
+    owtd_w = space.unpackiterable(w_owtd)
+    ewtd_w = space.unpackiterable(w_ewtd)
 
     if space.is_w(w_timeout, space.w_None):
         timeout = -1.0
diff --git a/pypy/module/select/test/test_select.py b/pypy/module/select/test/test_select.py
--- a/pypy/module/select/test/test_select.py
+++ b/pypy/module/select/test/test_select.py
@@ -244,6 +244,20 @@
         raises(OverflowError, pollster.modify, 1, -1)
         raises(OverflowError, pollster.modify, 1, 1 << 64)
 
+    def test_resize_list_in_select(self):
+        import select
+        class Foo(object):
+            def fileno(self):
+                print len(l)
+                if len(l) < 100:
+                    l.append(Foo())
+                return 0
+        l = [Foo()]
+        select.select(l, (), (), 0)
+        assert 1 <= len(l) <= 100    
+        # ^^^ CPython gives 100, PyPy gives 1.  I think both are OK as
+        # long as there is no crash.
+
 
 class AppTestSelectWithPipes(_AppTestSelect):
     "Use a pipe to get pairs of file descriptors"
diff --git a/pypy/module/test_lib_pypy/test_datetime.py b/pypy/module/test_lib_pypy/test_datetime.py
--- a/pypy/module/test_lib_pypy/test_datetime.py
+++ b/pypy/module/test_lib_pypy/test_datetime.py
@@ -1,193 +1,221 @@
 """Additional tests for datetime."""
 
 from __future__ import absolute_import
-from lib_pypy import datetime
 import py
 
-def test_repr():
-    print datetime
-    expected = "datetime.datetime(1, 2, 3, 0, 0)"
-    assert repr(datetime.datetime(1,2,3)) == expected
+class BaseTestDatetime:
+    def test_repr(self):
+        print datetime
+        expected = "datetime.datetime(1, 2, 3, 0, 0)"
+        assert repr(datetime.datetime(1,2,3)) == expected
 
-def test_attributes():
-    for x in [datetime.date.today(),
-              datetime.time(),
-              datetime.datetime.utcnow(),
-              datetime.timedelta(),
-              datetime.tzinfo()]:
-        raises(AttributeError, 'x.abc = 1')
+    def test_attributes(self):
+        for x in [datetime.date.today(),
+                  datetime.time(),
+                  datetime.datetime.utcnow(),
+                  datetime.timedelta(),
+                  datetime.tzinfo()]:
+            raises(AttributeError, 'x.abc = 1')
 
-def test_timedelta_init_long():
-    td = datetime.timedelta(microseconds=20000000000000000000)
-    assert td.days == 231481481
-    assert td.seconds == 41600
-    td = datetime.timedelta(microseconds=20000000000000000000.)
-    assert td.days == 231481481
-    assert td.seconds == 41600
+    def test_timedelta_init_long(self):
+        td = datetime.timedelta(microseconds=20000000000000000000)
+        assert td.days == 231481481
+        assert td.seconds == 41600
+        td = datetime.timedelta(microseconds=20000000000000000000.)
+        assert td.days == 231481481
+        assert td.seconds == 41600
 
-def test_unpickle():
-    e = raises(TypeError, datetime.date, '123')
-    assert e.value.args[0] == 'an integer is required'
-    e = raises(TypeError, datetime.time, '123')
-    assert e.value.args[0] == 'an integer is required'
-    e = raises(TypeError, datetime.datetime, '123')
-    assert e.value.args[0] == 'an integer is required'
+    def test_unpickle(self):
+        e = raises(TypeError, datetime.date, '123')
+        assert e.value.args[0] == 'an integer is required'
+        e = raises(TypeError, datetime.time, '123')
+        assert e.value.args[0] == 'an integer is required'
+        e = raises(TypeError, datetime.datetime, '123')
+        assert e.value.args[0] == 'an integer is required'
 
-    datetime.time('\x01' * 6, None)
-    with raises(TypeError) as e:
-        datetime.time('\x01' * 6, 123)
-    assert str(e.value) == "bad tzinfo state arg"
+        datetime.time('\x01' * 6, None)
+        with raises(TypeError) as e:
+            datetime.time('\x01' * 6, 123)
+        assert str(e.value) == "bad tzinfo state arg"
 
-    datetime.datetime('\x01' * 10, None)
-    with raises(TypeError) as e:
-        datetime.datetime('\x01' * 10, 123)
-    assert str(e.value) == "bad tzinfo state arg"
+        datetime.datetime('\x01' * 10, None)
+        with raises(TypeError) as e:
+            datetime.datetime('\x01' * 10, 123)
+        assert str(e.value) == "bad tzinfo state arg"
 
-def test_strptime():
-    import time, sys
-    if sys.version_info < (2, 6):
-        py.test.skip("needs the _strptime module")
+    def test_strptime(self):
+        import time, sys
+        if sys.version_info < (2, 6):
+            py.test.skip("needs the _strptime module")
 
-    string = '2004-12-01 13:02:47'
-    format = '%Y-%m-%d %H:%M:%S'
-    expected = datetime.datetime(*(time.strptime(string, format)[0:6]))
-    got = datetime.datetime.strptime(string, format)
-    assert expected == got
+        string = '2004-12-01 13:02:47'
+        format = '%Y-%m-%d %H:%M:%S'
+        expected = datetime.datetime(*(time.strptime(string, format)[0:6]))
+        got = datetime.datetime.strptime(string, format)
+        assert expected == got
 
-def test_datetime_rounding():
-    b = 0.0000001
-    a = 0.9999994
+    def test_datetime_rounding(self):
+        b = 0.0000001
+        a = 0.9999994
 
-    assert datetime.datetime.utcfromtimestamp(a).microsecond == 999999
-    assert datetime.datetime.utcfromtimestamp(a).second == 0
-    a += b
-    assert datetime.datetime.utcfromtimestamp(a).microsecond == 999999
-    assert datetime.datetime.utcfromtimestamp(a).second == 0
-    a += b
-    assert datetime.datetime.utcfromtimestamp(a).microsecond == 0
-    assert datetime.datetime.utcfromtimestamp(a).second == 1
+        assert datetime.datetime.utcfromtimestamp(a).microsecond == 999999
+        assert datetime.datetime.utcfromtimestamp(a).second == 0
+        a += b
+        assert datetime.datetime.utcfromtimestamp(a).microsecond == 999999
+        assert datetime.datetime.utcfromtimestamp(a).second == 0
+        a += b
+        assert datetime.datetime.utcfromtimestamp(a).microsecond == 0
+        assert datetime.datetime.utcfromtimestamp(a).second == 1
 
-def test_more_datetime_rounding():
-    # this test verified on top of CPython 2.7 (using a plain
-    # "import datetime" above)
-    expected_results = {
-        -1000.0: 'datetime.datetime(1969, 12, 31, 23, 43, 20)',
-        -999.9999996: 'datetime.datetime(1969, 12, 31, 23, 43, 20)',
-        -999.4: 'datetime.datetime(1969, 12, 31, 23, 43, 20, 600000)',
-        -999.0000004: 'datetime.datetime(1969, 12, 31, 23, 43, 21)',
-        -1.0: 'datetime.datetime(1969, 12, 31, 23, 59, 59)',
-        -0.9999996: 'datetime.datetime(1969, 12, 31, 23, 59, 59)',
-        -0.4: 'datetime.datetime(1969, 12, 31, 23, 59, 59, 600000)',
-        -0.0000004: 'datetime.datetime(1970, 1, 1, 0, 0)',
-        0.0: 'datetime.datetime(1970, 1, 1, 0, 0)',
-        0.0000004: 'datetime.datetime(1970, 1, 1, 0, 0)',
-        0.4: 'datetime.datetime(1970, 1, 1, 0, 0, 0, 400000)',
-        0.9999996: 'datetime.datetime(1970, 1, 1, 0, 0, 1)',
-        1000.0: 'datetime.datetime(1970, 1, 1, 0, 16, 40)',
-        1000.0000004: 'datetime.datetime(1970, 1, 1, 0, 16, 40)',
-        1000.4: 'datetime.datetime(1970, 1, 1, 0, 16, 40, 400000)',
-        1000.9999996: 'datetime.datetime(1970, 1, 1, 0, 16, 41)',
-        1293843661.191: 'datetime.datetime(2011, 1, 1, 1, 1, 1, 191000)',
-        }
-    for t in sorted(expected_results):
-        dt = datetime.datetime.utcfromtimestamp(t)
-        assert repr(dt) == expected_results[t]
+    def test_more_datetime_rounding(self):
+        # this test verified on top of CPython 2.7 (using a plain
+        # "import datetime" above)
+        expected_results = {
+            -1000.0: 'datetime.datetime(1969, 12, 31, 23, 43, 20)',
+            -999.9999996: 'datetime.datetime(1969, 12, 31, 23, 43, 20)',
+            -999.4: 'datetime.datetime(1969, 12, 31, 23, 43, 20, 600000)',
+            -999.0000004: 'datetime.datetime(1969, 12, 31, 23, 43, 21)',
+            -1.0: 'datetime.datetime(1969, 12, 31, 23, 59, 59)',
+            -0.9999996: 'datetime.datetime(1969, 12, 31, 23, 59, 59)',
+            -0.4: 'datetime.datetime(1969, 12, 31, 23, 59, 59, 600000)',
+            -0.0000004: 'datetime.datetime(1970, 1, 1, 0, 0)',
+            0.0: 'datetime.datetime(1970, 1, 1, 0, 0)',
+            0.0000004: 'datetime.datetime(1970, 1, 1, 0, 0)',
+            0.4: 'datetime.datetime(1970, 1, 1, 0, 0, 0, 400000)',
+            0.9999996: 'datetime.datetime(1970, 1, 1, 0, 0, 1)',
+            1000.0: 'datetime.datetime(1970, 1, 1, 0, 16, 40)',
+            1000.0000004: 'datetime.datetime(1970, 1, 1, 0, 16, 40)',
+            1000.4: 'datetime.datetime(1970, 1, 1, 0, 16, 40, 400000)',
+            1000.9999996: 'datetime.datetime(1970, 1, 1, 0, 16, 41)',
+            1293843661.191: 'datetime.datetime(2011, 1, 1, 1, 1, 1, 191000)',
+            }
+        for t in sorted(expected_results):
+            dt = datetime.datetime.utcfromtimestamp(t)
+            assert repr(dt) == expected_results[t]
 
-def test_utcfromtimestamp():
-    """Confirm that utcfromtimestamp and fromtimestamp give consistent results.
+    def test_utcfromtimestamp(self):
+        """Confirm that utcfromtimestamp and fromtimestamp give consistent results.
 
-    Based on danchr's test script in https://bugs.pypy.org/issue986
-    """
-    import os
-    import time
-    if os.name == 'nt':
-        skip("setting os.environ['TZ'] ineffective on windows")
-    try:
-        prev_tz = os.environ.get("TZ")
-        os.environ["TZ"] = "GMT"
-        time.tzset()
-        for unused in xrange(100):
-            now = time.time()
-            delta = (datetime.datetime.utcfromtimestamp(now) -
-                     datetime.datetime.fromtimestamp(now))
-            assert delta.days * 86400 + delta.seconds == 0
-    finally:
-        if prev_tz is None:
-            del os.environ["TZ"]
-        else:
-            os.environ["TZ"] = prev_tz
-        time.tzset()
+        Based on danchr's test script in https://bugs.pypy.org/issue986
+        """
+        import os
+        import time
+        if os.name == 'nt':
+            skip("setting os.environ['TZ'] ineffective on windows")
+        try:
+            prev_tz = os.environ.get("TZ")
+            os.environ["TZ"] = "GMT"
+            time.tzset()
+            for unused in xrange(100):
+                now = time.time()
+                delta = (datetime.datetime.utcfromtimestamp(now) -
+                         datetime.datetime.fromtimestamp(now))
+                assert delta.days * 86400 + delta.seconds == 0
+        finally:
+            if prev_tz is None:
+                del os.environ["TZ"]
+            else:
+                os.environ["TZ"] = prev_tz
+            time.tzset()
 
-def test_utcfromtimestamp_microsecond():
-    dt = datetime.datetime.utcfromtimestamp(0)
-    assert isinstance(dt.microsecond, int)
+    def test_utcfromtimestamp_microsecond(self):
+        dt = datetime.datetime.utcfromtimestamp(0)
+        assert isinstance(dt.microsecond, int)
 
-def test_default_args():
-    with py.test.raises(TypeError):
-        datetime.datetime()
-    with py.test.raises(TypeError):
-        datetime.datetime(10)
-    with py.test.raises(TypeError):
-        datetime.datetime(10, 10)
-    datetime.datetime(10, 10, 10)
+    def test_default_args(self):
+        with py.test.raises(TypeError):
+            datetime.datetime()
+        with py.test.raises(TypeError):
+            datetime.datetime(10)
+        with py.test.raises(TypeError):
+            datetime.datetime(10, 10)
+        datetime.datetime(10, 10, 10)
 
-def test_check_arg_types():
-    import decimal
-    class Number:
-        def __init__(self, value):
-            self.value = value
-        def __int__(self):
-            return self.value
+    def test_check_arg_types(self):
+        import decimal
+        class Number:
+            def __init__(self, value):
+                self.value = value
+            def __int__(self):
+                return self.value
 
-    for xx in [10L,
-               decimal.Decimal(10),
-               decimal.Decimal('10.9'),
-               Number(10),
-               Number(10L)]:
-        assert datetime.datetime(10, 10, 10, 10, 10, 10, 10) == \
-               datetime.datetime(xx, xx, xx, xx, xx, xx, xx)
+        for xx in [10L,
+                   decimal.Decimal(10),
+                   decimal.Decimal('10.9'),
+                   Number(10),
+                   Number(10L)]:
+            assert datetime.datetime(10, 10, 10, 10, 10, 10, 10) == \
+                   datetime.datetime(xx, xx, xx, xx, xx, xx, xx)
 
-    with py.test.raises(TypeError) as e:
-        datetime.datetime(10, 10, '10')
-    assert str(e.value) == 'an integer is required'
+        with py.test.raises(TypeError) as e:
+            datetime.datetime(10, 10, '10')
+        assert str(e.value) == 'an integer is required'
 
-    f10 = Number(10.9)
-    with py.test.raises(TypeError) as e:
-        datetime.datetime(10, 10, f10)
-    assert str(e.value) == '__int__ method should return an integer'
+        f10 = Number(10.9)
+        with py.test.raises(TypeError) as e:
+            datetime.datetime(10, 10, f10)
+        assert str(e.value) == '__int__ method should return an integer'
 
-    class Float(float):
-        pass
-    s10 = Float(10.9)
-    with py.test.raises(TypeError) as e:
-        datetime.datetime(10, 10, s10)
-    assert str(e.value) == 'integer argument expected, got float'
+        class Float(float):
+            pass
+        s10 = Float(10.9)
+        with py.test.raises(TypeError) as e:
+            datetime.datetime(10, 10, s10)
+        assert str(e.value) == 'integer argument expected, got float'
 
-    with py.test.raises(TypeError):
-        datetime.datetime(10., 10, 10)
-    with py.test.raises(TypeError):
-        datetime.datetime(10, 10., 10)
-    with py.test.raises(TypeError):
-        datetime.datetime(10, 10, 10.)
-    with py.test.raises(TypeError):
-        datetime.datetime(10, 10, 10, 10.)
-    with py.test.raises(TypeError):
-        datetime.datetime(10, 10, 10, 10, 10.)
-    with py.test.raises(TypeError):
-        datetime.datetime(10, 10, 10, 10, 10, 10.)
-    with py.test.raises(TypeError):
-        datetime.datetime(10, 10, 10, 10, 10, 10, 10.)
+        with py.test.raises(TypeError):
+            datetime.datetime(10., 10, 10)
+        with py.test.raises(TypeError):
+            datetime.datetime(10, 10., 10)
+        with py.test.raises(TypeError):
+            datetime.datetime(10, 10, 10.)
+        with py.test.raises(TypeError):
+            datetime.datetime(10, 10, 10, 10.)
+        with py.test.raises(TypeError):
+            datetime.datetime(10, 10, 10, 10, 10.)
+        with py.test.raises(TypeError):
+            datetime.datetime(10, 10, 10, 10, 10, 10.)
+        with py.test.raises(TypeError):
+            datetime.datetime(10, 10, 10, 10, 10, 10, 10.)
 
-def test_utcnow_microsecond():
-    import copy
+    def test_utcnow_microsecond(self):
+        import copy
 
-    dt = datetime.datetime.utcnow()
-    assert type(dt.microsecond) is int
+        dt = datetime.datetime.utcnow()
+        assert type(dt.microsecond) is int
 
-    copy.copy(dt)
+        copy.copy(dt)
 
-def test_radd():
-    class X(object):
-        def __radd__(self, other):
-            return "radd"
-    assert datetime.date(10, 10, 10) + X() == "radd"
+    def test_radd(self):
+        class X(object):
+            def __radd__(self, other):
+                return "radd"
+        assert datetime.date(10, 10, 10) + X() == "radd"
+
+    def test_raises_if_passed_naive_datetime_and_start_or_end_time_defined(self):
+        class Foo(datetime.tzinfo):
+            def utcoffset(self, dt):
+                return datetime.timedelta(0.1)
+        naive = datetime.datetime(2014, 9, 22)
+        aware = datetime.datetime(2014, 9, 22, tzinfo=Foo())
+        with py.test.raises(TypeError) as e:
+            naive == aware
+        assert str(e.value) == "can't compare offset-naive and offset-aware datetimes"
+        with py.test.raises(TypeError) as e:
+            naive - aware
+        assert str(e.value) == "can't subtract offset-naive and offset-aware datetimes"
+        naive = datetime.time(7, 32, 12)
+        aware = datetime.time(7, 32, 12, tzinfo=Foo())
+        with py.test.raises(TypeError) as e:
+            naive == aware
+        assert str(e.value) == "can't compare offset-naive and offset-aware times"
+
+class TestDatetimeCPython(BaseTestDatetime):
+    def setup_class(cls):
+        global datetime
+        import datetime
+
+class TestDatetimePyPy(BaseTestDatetime):
+    def setup_class(cls):
+        global datetime
+        from lib_pypy import datetime
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -15,6 +15,7 @@
 from rpython.rlib.rbigint import rbigint
 from rpython.rlib import rfloat
 from rpython.tool.sourcetools import func_with_new_name
+from rpython.rtyper.lltypesystem.module.ll_math import math_fmod
 
 from pypy.objspace.std.intobject import W_IntObject
 
@@ -360,21 +361,17 @@
     y = w_float2.floatval
     if y == 0.0:
         raise FailedToImplementArgs(space.w_ZeroDivisionError, space.wrap("float modulo"))
-    try:
-        mod = math.fmod(x, y)
-    except ValueError:
-        mod = rfloat.NAN
+    mod = math_fmod(x, y)
+    if mod:
+        # ensure the remainder has the same sign as the denominator
+        if (y < 0.0) != (mod < 0.0):
+            mod += y
     else:
-        if mod:
-            # ensure the remainder has the same sign as the denominator
-            if (y < 0.0) != (mod < 0.0):
-                mod += y
-        else:
-            # the remainder is zero, and in the presence of signed zeroes
-            # fmod returns different results across platforms; ensure
-            # it has the same sign as the denominator; we'd like to do
-            # "mod = y * 0.0", but that may get optimized away
-            mod = copysign(0.0, y)
+        # the remainder is zero, and in the presence of signed zeroes
+        # fmod returns different results across platforms; ensure
+        # it has the same sign as the denominator; we'd like to do
+        # "mod = y * 0.0", but that may get optimized away
+        mod = copysign(0.0, y)
 
     return W_FloatObject(mod)
 
@@ -383,10 +380,7 @@
     y = w_float2.floatval
     if y == 0.0:
         raise FailedToImplementArgs(space.w_ZeroDivisionError, space.wrap("float modulo"))
-    try:
-        mod = math.fmod(x, y)
-    except ValueError:
-        return [W_FloatObject(rfloat.NAN), W_FloatObject(rfloat.NAN)]
+    mod = math_fmod(x, y)
     # fmod is typically exact, so vx-mod is *mathematically* an
     # exact multiple of wx.  But this is fp arithmetic, and fp
     # vx - mod is an approximation; the result is that div may
diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py
--- a/pypy/objspace/std/newformat.py
+++ b/pypy/objspace/std/newformat.py
@@ -580,11 +580,11 @@
             elif self._thousands_sep:
                 dec = "."
                 thousands = ","
-                grouping = "\3\0"
+                grouping = "\3"
             else:
                 dec = "."
                 thousands = ""
-                grouping = "\256"
+                grouping = "\xFF"    # special value to mean 'stop'
             if self.is_unicode:
                 self._loc_dec = dec.decode("ascii")
                 self._loc_thousands = thousands.decode("ascii")
@@ -677,14 +677,16 @@
             done = False
             previous = 0
             while True:
-                group = ord(grouping[grouping_state])
-                if group > 0:
-                    if group == 256:
+                if grouping_state >= len(grouping):
+                    group = previous     # end of string
+                else:
+                    # else, get the next value from the string
+                    group = ord(grouping[grouping_state])
+                    if group == 0xFF:    # special value to mean 'stop'
                         break
                     grouping_state += 1
                     previous = group
-                else:
-                    group = previous
+                #
                 final_grouping = min(group, max(left, max(min_width, 1)))
                 n_zeros = max(0, final_grouping - left)
                 n_chars = max(0, min(left, final_grouping))
diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -794,7 +794,7 @@
         raises(ValueError, float.fromhex, "0P")
 
     def test_division_edgecases(self):
-        import math
+        import math, os
 
         # inf
         inf = float("inf")
@@ -803,6 +803,16 @@
         x, y = divmod(inf, 3)
         assert math.isnan(x)
         assert math.isnan(y)
+        x, y = divmod(3, inf)
+        z = 3 % inf
+        if os.name == 'nt':
+            assert math.isnan(x)
+            assert math.isnan(y)
+            assert math.isnan(z)
+        else:
+            assert x == 0
+            assert y == 3
+            assert z == 3
 
         # divide by 0
         raises(ZeroDivisionError, lambda: inf % 0)
diff --git a/pypy/objspace/std/test/test_newformat.py b/pypy/objspace/std/test/test_newformat.py
--- a/pypy/objspace/std/test/test_newformat.py
+++ b/pypy/objspace/std/test/test_newformat.py
@@ -372,6 +372,7 @@
         try:
             assert locale.format('%g', x, grouping=True) == '1,234.57'
             assert format(x, 'n') == '1,234.57'
+            assert format(12345678901234, 'n') == '12,345,678,901,234'
         finally:
             locale.setlocale(locale.LC_NUMERIC, 'C')
 
diff --git a/pypy/sandbox/pypy_interact.py b/pypy/sandbox/pypy_interact.py
--- a/pypy/sandbox/pypy_interact.py
+++ b/pypy/sandbox/pypy_interact.py
@@ -55,7 +55,7 @@
 
         return Dir({
             'bin': Dir({
-                'pypy-c': RealFile(self.executable),
+                'pypy-c': RealFile(self.executable, mode=0111),
                 'lib-python': RealDir(os.path.join(libroot, 'lib-python'),
                                       exclude=exclude), 
                 'lib_pypy': RealDir(os.path.join(libroot, 'lib_pypy'),
diff --git a/rpython/translator/backendopt/storesink.py b/rpython/translator/backendopt/storesink.py
--- a/rpython/translator/backendopt/storesink.py
+++ b/rpython/translator/backendopt/storesink.py
@@ -1,6 +1,8 @@
 
 from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.flowspace.model import mkentrymap, Variable
 from rpython.translator.backendopt import removenoops
+from rpython.translator import simplify
 
 def has_side_effects(op):
     if op.opname == 'debug_assert':
@@ -10,38 +12,86 @@
     except AttributeError:
         return True
 
+
 def storesink_graph(graph):
+    """ remove superfluous getfields. use a super-local method: all non-join
+    blocks inherit the heap information from their (single) predecessor
+    """
+    added_some_same_as = False
+    entrymap = mkentrymap(graph)
 
+    # all merge blocks are starting points
+    todo = [(block, None, None) for (block, prev_blocks) in entrymap.iteritems()
+                if len(prev_blocks) > 1 or block is graph.startblock]
+
+    visited = 0
+
+    while todo:
+        block, cache, inputlink = todo.pop()
+        visited += 1
+        if cache is None:
+            cache = {}
+
+        if block.operations:
+            changed_block = _storesink_block(block, cache, inputlink)
+            added_some_same_as = changed_block or added_some_same_as
+        for link in block.exits:
+            if len(entrymap[link.target]) == 1:
+                new_cache = _translate_cache(cache, link)
+                todo.append((link.target, new_cache, link))
+
+    assert visited == len(entrymap)
+    if added_some_same_as:
+        removenoops.remove_same_as(graph)
+        simplify.transform_dead_op_vars(graph)
+
+def _translate_cache(cache, link):
+    if link.target.operations == (): # exit or except block:
+        return {}
+    block = link.target
+    local_versions = {var1: var2 for var1, var2 in zip(link.args, block.inputargs)}
+    def _translate_arg(arg):
+        if isinstance(arg, Variable):
+            res = local_versions.get(arg, None)
+            if res is None:
+                res = Variable(arg)
+                res.concretetype = arg.concretetype
+                link.args.append(arg)
+                block.inputargs.append(res)
+                local_versions[arg] = res
+            return res
+        else:
+            return arg
+    new_cache = {}
+    for (var, field), res in cache.iteritems():
+        if var in local_versions or not isinstance(var, Variable):
+            new_cache[_translate_arg(var), field] = _translate_arg(res)
+    return new_cache
+
+def _storesink_block(block, cache, inputlink):
     def clear_cache_for(cache, concretetype, fieldname):
         for k in cache.keys():
             if k[0].concretetype == concretetype and k[1] == fieldname:
                 del cache[k]
 
     added_some_same_as = False
-
-    for block in graph.iterblocks():
-        newops = []
-        cache = {}
-        for op in block.operations:
-            if op.opname == 'getfield':
-                tup = (op.args[0], op.args[1].value)
-                res = cache.get(tup, None)
-                if res is not None:
-                    op.opname = 'same_as'
-                    op.args = [res]
-                    added_some_same_as = True
-                else:
-                    cache[tup] = op.result
-            elif op.opname in ['setarrayitem', 'setinteriorfield']:
-                pass
-            elif op.opname == 'setfield':
-                clear_cache_for(cache, op.args[0].concretetype,
-                                op.args[1].value)
-            elif has_side_effects(op):
-                cache = {}
-            newops.append(op)
-        if block.operations:
-            block.operations = newops
-
-    if added_some_same_as:
-        removenoops.remove_same_as(graph)
+    for op in block.operations:
+        if op.opname == 'getfield':
+            tup = (op.args[0], op.args[1].value)
+            res = cache.get(tup, None)
+            if res is not None:
+                op.opname = 'same_as'
+                op.args = [res]
+                added_some_same_as = True
+            else:
+                cache[tup] = op.result
+        elif op.opname in ('setarrayitem', 'setinteriorfield', "malloc", "malloc_varsize"):
+            pass
+        elif op.opname == 'setfield':
+            target = op.args[0]
+            field = op.args[1].value
+            clear_cache_for(cache, target.concretetype, field)
+            cache[target, field] = op.args[2]
+        elif has_side_effects(op):
+            cache.clear()
+    return added_some_same_as
diff --git a/rpython/translator/backendopt/test/test_storesink.py b/rpython/translator/backendopt/test/test_storesink.py
--- a/rpython/translator/backendopt/test/test_storesink.py
+++ b/rpython/translator/backendopt/test/test_storesink.py
@@ -42,7 +42,7 @@
             a.x = i
             return a.x
 
-        self.check(f, [int], 1)
+        self.check(f, [int], 0)
 
     def test_simple(self):
         class A(object):
@@ -53,7 +53,7 @@
             a.x = i
             return a.x + a.x
 
-        self.check(f, [int], 1)
+        self.check(f, [int], 0)
 
     def test_irrelevant_setfield(self):
         class A(object):
@@ -67,7 +67,7 @@
             two = a.x
             return one + two
 
-        self.check(f, [int], 1)
+        self.check(f, [int], 0)
 
     def test_relevant_setfield(self):
         class A(object):
@@ -101,7 +101,7 @@
             two = a.x
             return one + two
 
-        self.check(f, [int], 1)
+        self.check(f, [int], 0)
 
     def test_subclass(self):
         class A(object):
@@ -119,7 +119,7 @@
             two = a.x
             return one + two
 
-        self.check(f, [int], 2)
+        self.check(f, [int], 1)
 
     def test_bug_1(self):
         class A(object):
@@ -133,4 +133,37 @@
                 return True
             return n
 
-        self.check(f, [int], 1)
+        self.check(f, [int], 0)
+
+
+    def test_cfg_splits(self):
+        class A(object):
+            pass
+
+        def f(i):
+            a = A()
+            j = i
+            for i in range(i):
+                a.x = i
+                if i:
+                    j = a.x + a.x
+                else:
+                    j = a.x * 5
+            return j
+
+        self.check(f, [int], 0)
+
+    def test_malloc_does_not_invalidate(self):
+        class A(object):
+            pass
+        class B(object):
+            pass
+
+        def f(i):
+            a = A()
+            a.x = i
+            b = B()
+            return a.x
+
+        self.check(f, [int], 0)
+
diff --git a/rpython/translator/sandbox/sandlib.py b/rpython/translator/sandbox/sandlib.py
--- a/rpython/translator/sandbox/sandlib.py
+++ b/rpython/translator/sandbox/sandlib.py
@@ -459,6 +459,15 @@
 
     do_ll_os__ll_os_lstat = do_ll_os__ll_os_stat
 
+    def do_ll_os__ll_os_access(self, vpathname, mode):
+        try:
+            node = self.get_node(vpathname)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                return False
+            raise
+        return node.access(mode)
+
     def do_ll_os__ll_os_isatty(self, fd):
         return self.virtual_console_isatty and fd in (0, 1, 2)
 
diff --git a/rpython/translator/sandbox/test/test_vfs.py b/rpython/translator/sandbox/test/test_vfs.py
--- a/rpython/translator/sandbox/test/test_vfs.py
+++ b/rpython/translator/sandbox/test/test_vfs.py
@@ -33,6 +33,8 @@
     py.test.raises(OSError, d.join, 'bar')
     st = d.stat()
     assert stat.S_ISDIR(st.st_mode)
+    assert d.access(os.R_OK | os.X_OK)
+    assert not d.access(os.W_OK)
 
 def test_file():
     f = File('hello world')
@@ -46,6 +48,8 @@
     st = f.stat()
     assert stat.S_ISREG(st.st_mode)
     assert st.st_size == 11
+    assert f.access(os.R_OK)
+    assert not f.access(os.W_OK)
 
 def test_realdir_realfile():
     for show_dotfiles in [False, True]:
@@ -78,6 +82,7 @@
 
                 f = v_test_vfs.join('symlink2')
                 assert stat.S_ISREG(f.stat().st_mode)
+                assert f.access(os.R_OK)
                 assert f.open().read() == 'secret'
             else:
                 py.test.raises(OSError, v_test_vfs.join, 'symlink1')
diff --git a/rpython/translator/sandbox/vfs.py b/rpython/translator/sandbox/vfs.py
--- a/rpython/translator/sandbox/vfs.py
+++ b/rpython/translator/sandbox/vfs.py
@@ -22,7 +22,7 @@
         st_size = self.getsize()
         st_mode = self.kind
         st_mode |= stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH
-        if self.kind == stat.S_IFDIR:
+        if stat.S_ISDIR(self.kind):
             st_mode |= stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
         if self.read_only:
             st_uid = 0       # read-only files are virtually owned by root
@@ -37,6 +37,15 @@
             (st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid,
              st_size, st_atime, st_mtime, st_ctime))
 
+    def access(self, mode):
+        s = self.stat()
+        e_mode = s.st_mode & stat.S_IRWXO
+        if UID == s.st_uid:
+            e_mode |= (s.st_mode & stat.S_IRWXU) >> 6
+        if GID == s.st_gid:
+            e_mode |= (s.st_mode & stat.S_IRWXG) >> 3
+        return (e_mode & mode) == mode
+
     def keys(self):
         raise OSError(errno.ENOTDIR, self)
 
@@ -114,8 +123,9 @@
         return cStringIO.StringIO(self.data)
 
 class RealFile(File):
-    def __init__(self, path):
+    def __init__(self, path, mode=0):
         self.path = path
+        self.kind |= mode
     def __repr__(self):
         return '<RealFile %s>' % (self.path,)
     def getsize(self):


More information about the pypy-commit mailing list