[pypy-commit] pypy py3k: reapply our time module deltas from rctime

pjenvey noreply at buildbot.pypy.org
Wed Nov 19 20:36:09 CET 2014


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r74602:ae21f00a0b84
Date: 2014-11-19 11:35 -0800
http://bitbucket.org/pypy/pypy/changeset/ae21f00a0b84/

Log:	reapply our time module deltas from rctime

diff --git a/pypy/module/time/interp_time.py b/pypy/module/time/interp_time.py
--- a/pypy/module/time/interp_time.py
+++ b/pypy/module/time/interp_time.py
@@ -168,10 +168,8 @@
 TM_P = lltype.Ptr(tm)
 c_clock = external('clock', [rffi.TIME_TP], clock_t)
 c_time = external('time', [rffi.TIME_TP], rffi.TIME_T)
-c_ctime = external('ctime', [rffi.TIME_TP], rffi.CCHARP)
 c_gmtime = external('gmtime', [rffi.TIME_TP], TM_P)
 c_mktime = external('mktime', [TM_P], rffi.TIME_T)
-c_asctime = external('asctime', [TM_P], rffi.CCHARP)
 c_localtime = external('localtime', [rffi.TIME_TP], TM_P)
 if _POSIX:
     c_tzset = external('tzset', [], lltype.Void)
@@ -185,12 +183,12 @@
                              "RPY_EXTERN "
                              "char** pypy_get_tzname();\n"
                              "RPY_EXTERN "
-                             "void pypy__tzset();"],
+                             "void* pypy__tzset();"],
         separate_module_sources = ["""
         long pypy_get_timezone() { return timezone; }
         int pypy_get_daylight() { return daylight; }
         char** pypy_get_tzname() { return tzname; }
-        void pypy__tzset() { _tzset(); }
+        void pypy__tzset() { return _tzset(); }
         """])
     # Ensure sure that we use _tzset() and timezone from the same C Runtime.
     c_tzset = external('pypy__tzset', [], lltype.Void, win_eci)
@@ -412,24 +410,24 @@
                     "argument must be sequence of length 9, not %d",
                     len(tup_w))
 
-    y = space.int_w(tup_w[0])
-    tm_mon = space.int_w(tup_w[1])
+    y = space.c_int_w(tup_w[0])
+    tm_mon = space.c_int_w(tup_w[1])
     if tm_mon == 0:
         tm_mon = 1
-    tm_mday = space.int_w(tup_w[2])
+    tm_mday = space.c_int_w(tup_w[2])
     if tm_mday == 0:
         tm_mday = 1
-    tm_yday = space.int_w(tup_w[7])
+    tm_yday = space.c_int_w(tup_w[7])
     if tm_yday == 0:
         tm_yday = 1
     rffi.setintfield(glob_buf, 'c_tm_mon', tm_mon)
     rffi.setintfield(glob_buf, 'c_tm_mday', tm_mday)
-    rffi.setintfield(glob_buf, 'c_tm_hour', space.int_w(tup_w[3]))
-    rffi.setintfield(glob_buf, 'c_tm_min', space.int_w(tup_w[4]))
-    rffi.setintfield(glob_buf, 'c_tm_sec', space.int_w(tup_w[5]))
-    rffi.setintfield(glob_buf, 'c_tm_wday', space.int_w(tup_w[6]))
+    rffi.setintfield(glob_buf, 'c_tm_hour', space.c_int_w(tup_w[3]))
+    rffi.setintfield(glob_buf, 'c_tm_min', space.c_int_w(tup_w[4]))
+    rffi.setintfield(glob_buf, 'c_tm_sec', space.c_int_w(tup_w[5]))
+    rffi.setintfield(glob_buf, 'c_tm_wday', space.c_int_w(tup_w[6]))
     rffi.setintfield(glob_buf, 'c_tm_yday', tm_yday)
-    rffi.setintfield(glob_buf, 'c_tm_isdst', space.int_w(tup_w[8]))
+    rffi.setintfield(glob_buf, 'c_tm_isdst', space.c_int_w(tup_w[8]))
     if _POSIX:
         if _CYGWIN:
             pass
@@ -438,24 +436,23 @@
             glob_buf.c_tm_zone = lltype.nullptr(rffi.CCHARP.TO)
             rffi.setintfield(glob_buf, 'c_tm_gmtoff', 0)
 
-    if y < 1900:
+    if y < 1000:
         w_accept2dyear = _get_module_object(space, "accept2dyear")
-        accept2dyear = space.int_w(w_accept2dyear)
+        accept2dyear = space.is_true(w_accept2dyear)
 
-        if not accept2dyear:
-            raise OperationError(space.w_ValueError,
-                space.wrap("year >= 1900 required"))
-
-        if 69 <= y <= 99:
-            y += 1900
-        elif 0 <= y <= 68:
-            y += 2000
-        else:
-            raise OperationError(space.w_ValueError,
-                space.wrap("year out of range"))
+        if accept2dyear:
+            if 69 <= y <= 99:
+                y += 1900
+            elif 0 <= y <= 68:
+                y += 2000
+            else:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap("year out of range"))
+            space.warn(space.wrap("Century info guessed for a 2-digit year."),
+                       space.w_DeprecationWarning)
 
     # tm_wday does not need checking of its upper-bound since taking "%
-    #  7" in gettmarg() automatically restricts the range.
+    #  7" in _gettmarg() automatically restricts the range.
     if rffi.getintfield(glob_buf, 'c_tm_wday') < -1:
         raise OperationError(space.w_ValueError,
                              space.wrap("day of week out of range"))
@@ -470,6 +467,32 @@
 
     return glob_buf
 
+def _checktm(space, t_ref):
+    """Checks added to make sure strftime() and asctime() do not crash
+    Python by indexing blindly into some array for a textual
+    representation by some bad index (fixes bug #897625).  No check for
+    year or wday since handled in _gettmarg()."""
+    if not 0 <= rffi.getintfield(t_ref, 'c_tm_mon') <= 11:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("month out of range"))
+    if not 1 <= rffi.getintfield(t_ref, 'c_tm_mday') <= 31:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("day of month out of range"))
+    if not 0 <= rffi.getintfield(t_ref, 'c_tm_hour') <= 23:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("hour out of range"))
+    if not 0 <= rffi.getintfield(t_ref, 'c_tm_min') <= 59:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("minute out of range"))
+    if not 0 <= rffi.getintfield(t_ref, 'c_tm_sec') <= 61:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("seconds out of range"))
+    # tm_wday does not need checking: "% 7" in _gettmarg() automatically
+    # restricts the range
+    if not 0 <= rffi.getintfield(t_ref, 'c_tm_yday') <= 365:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("day of year out of range"))
+
 def time(space):
     """time() -> floating point number
 
@@ -503,16 +526,13 @@
     not present, current time as returned by localtime() is used."""
 
     seconds = _get_inttime(space, w_seconds)
-
-    t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw')
-    t_ref[0] = seconds
-    p = c_ctime(t_ref)
-    lltype.free(t_ref, flavor='raw')
+    with lltype.scoped_alloc(rffi.TIME_TP.TO, 1) as t_ref:
+        t_ref[0] = seconds
+        p = c_localtime(t_ref)
     if not p:
         raise OperationError(space.w_ValueError,
-            space.wrap("unconvertible time"))
-
-    return space.wrap(rffi.charp2str(p)[:-1]) # get rid of new line
+                             space.wrap("unconvertible time"))
+    return _asctime(space, p)
 
 # by now w_tup is an optional argument (and not *args)
 # because of the ext. compiler bugs in handling such arguments (*args, **kwds)
@@ -523,12 +543,26 @@
     When the time tuple is not present, current time as returned by localtime()
     is used."""
     buf_value = _gettmarg(space, w_tup)
-    p = c_asctime(buf_value)
-    if not p:
-        raise OperationError(space.w_ValueError,
-            space.wrap("unconvertible time"))
+    _checktm(space, buf_value)
+    return _asctime(space, buf_value)
 
-    return space.wrap(rffi.charp2str(p)[:-1]) # get rid of new line
+_wday_names = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
+_mon_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+              "Oct", "Nov", "Dec"]
+
+def _asctime(space, t_ref):
+    # Inspired by Open Group reference implementation available at
+    # http://pubs.opengroup.org/onlinepubs/009695399/functions/asctime.html
+    w, getif = space.wrap, rffi.getintfield
+    args = [w(_wday_names[getif(t_ref, 'c_tm_wday')]),
+            w(_mon_names[getif(t_ref, 'c_tm_mon')]),
+            w(getif(t_ref, 'c_tm_mday')),
+            w(getif(t_ref, 'c_tm_hour')),
+            w(getif(t_ref, 'c_tm_min')),
+            w(getif(t_ref, 'c_tm_sec')),
+            w(getif(t_ref, 'c_tm_year') + 1900)]
+    return space.mod(w("%.3s %.3s%3d %.2d:%.2d:%.2d %d"),
+                     space.newtuple(args))
 
 def gmtime(space, w_seconds=None):
     """gmtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min,
@@ -610,32 +644,15 @@
     See the library reference manual for formatting codes. When the time tuple
     is not present, current time as returned by localtime() is used."""
     buf_value = _gettmarg(space, w_tup)
+    _checktm(space, buf_value)
 
-    # Checks added to make sure strftime() does not crash Python by
-    # indexing blindly into some array for a textual representation
-    # by some bad index (fixes bug #897625).
-    # No check for year since handled in gettmarg().
-    if rffi.getintfield(buf_value, 'c_tm_mon') < 0 or rffi.getintfield(buf_value, 'c_tm_mon') > 11:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("month out of range"))
-    if rffi.getintfield(buf_value, 'c_tm_mday') < 1 or rffi.getintfield(buf_value, 'c_tm_mday') > 31:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("day of month out of range"))
-    if rffi.getintfield(buf_value, 'c_tm_hour') < 0 or rffi.getintfield(buf_value, 'c_tm_hour') > 23:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("hour out of range"))
-    if rffi.getintfield(buf_value, 'c_tm_min') < 0 or rffi.getintfield(buf_value, 'c_tm_min') > 59:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("minute out of range"))
-    if rffi.getintfield(buf_value, 'c_tm_sec') < 0 or rffi.getintfield(buf_value, 'c_tm_sec') > 61:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("seconds out of range"))
-    if rffi.getintfield(buf_value, 'c_tm_yday') < 0 or rffi.getintfield(buf_value, 'c_tm_yday') > 365:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("day of year out of range"))
-    if rffi.getintfield(buf_value, 'c_tm_isdst') < -1 or rffi.getintfield(buf_value, 'c_tm_isdst') > 1:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("daylight savings flag out of range"))
+    # Normalize tm_isdst just in case someone foolishly implements %Z
+    # based on the assumption that tm_isdst falls within the range of
+    # [-1, 1]
+    if rffi.getintfield(buf_value, 'c_tm_isdst') < -1:
+        rffi.setintfield(buf_value, 'c_tm_isdst', -1)
+    elif rffi.getintfield(buf_value, 'c_tm_isdst') > 1:
+        rffi.setintfield(buf_value, 'c_tm_isdst', 1)
 
     if _WIN:
         # check that the format string contains only valid directives
diff --git a/pypy/module/time/test/test_time.py b/pypy/module/time/test/test_time.py
--- a/pypy/module/time/test/test_time.py
+++ b/pypy/module/time/test/test_time.py
@@ -44,6 +44,15 @@
         time.ctime(time.time())
         raises(ValueError, time.ctime, 1E200)
         raises(OverflowError, time.ctime, 10**900)
+        for year in [-100, 100, 1000, 2000, 10000]:
+            try:
+                testval = time.mktime((year, 1, 10) + (0,)*6)
+            except (ValueError, OverflowError):
+                # If mktime fails, ctime will fail too.  This may happen
+                # on some platforms.
+                pass
+            else:
+                assert time.ctime(testval)[20:] == str(year)
 
     def test_gmtime(self):
         import time
@@ -94,14 +103,14 @@
         ltime = time.localtime()
         time.accept2dyear == 0
         ltime = list(ltime)
-        ltime[0] = 1899
+        ltime[0] = -1
         raises(ValueError, time.mktime, tuple(ltime))
         time.accept2dyear == 1
 
         ltime = list(ltime)
         ltime[0] = 67
         ltime = tuple(ltime)
-        if os.name != "nt" and sys.maxint < 1<<32:   # time_t may be 64bit
+        if os.name != "nt" and sys.maxsize < 1<<32:   # time_t may be 64bit
             raises(OverflowError, time.mktime, ltime)
 
         ltime = list(ltime)
@@ -109,8 +118,8 @@
         raises(ValueError, time.mktime, tuple(ltime))
 
         t = time.time()
-        assert long(time.mktime(time.localtime(t))) == long(t)
-        assert long(time.mktime(time.gmtime(t))) - time.timezone == long(t)
+        assert int(time.mktime(time.localtime(t))) == int(t)
+        assert int(time.mktime(time.gmtime(t))) - time.timezone == int(t)
         ltime = time.localtime()
         assert time.mktime(tuple(ltime)) == time.mktime(ltime)
         if os.name != 'nt':
@@ -132,6 +141,7 @@
         raises(TypeError, time.asctime, (1, 2))
         raises(TypeError, time.asctime, (1, 2, 3, 4, 5, 6, 'f', 8, 9))
         raises(TypeError, time.asctime, "foo")
+        raises(ValueError, time.asctime, (1900, -1, 1, 0, 0, 0, 0, 1, -1))
         res = time.asctime()
         assert isinstance(res, str)
         time.asctime(time.localtime())
@@ -146,6 +156,18 @@
         except ValueError:
             pass  # some OS (ie POSIXes besides Linux) reject year > 9999
 
+    def test_asctime_large_year(self):
+        import time
+        assert time.asctime((12345,) +
+                              (0,) * 8) == 'Mon Jan  1 00:00:00 12345'
+        assert time.asctime((123456789,) +
+                              (0,) * 8) == 'Mon Jan  1 00:00:00 123456789'
+        sizeof_int = 4
+        bigyear = (1 << 8 * sizeof_int - 1) - 1
+        asc = time.asctime((bigyear, 6, 1) + (0,)*6)
+        assert asc[-len(str(bigyear)):] == str(bigyear)
+        raises(OverflowError, time.asctime, (bigyear + 1,) + (0,)*8)
+
     def test_accept2dyear_access(self):
         import time
 
@@ -157,6 +179,17 @@
         finally:
             time.accept2dyear = accept2dyear
 
+    def test_accept2dyear_bad(self):
+        import time
+        class X:
+            def __bool__(self):
+                raise RuntimeError('boo')
+        orig, time.accept2dyear = time.accept2dyear, X()
+        try:
+            raises(RuntimeError, time.asctime, (200,)  + (0,) * 8)
+        finally:
+            time.accept2dyear = orig
+
     def test_struct_time(self):
         import time
         raises(TypeError, time.struct_time)
@@ -228,7 +261,7 @@
             # rely on it.
             if org_TZ is not None:
                 os.environ['TZ'] = org_TZ
-            elif os.environ.has_key('TZ'):
+            elif 'TZ' in os.environ:
                 del os.environ['TZ']
             time.tzset()
 
@@ -280,10 +313,12 @@
         # of the time tuple.
 
         # check year
-        raises(ValueError, time.strftime, '', (1899, 1, 1, 0, 0, 0, 0, 1, -1))
         if time.accept2dyear:
             raises(ValueError, time.strftime, '', (-1, 1, 1, 0, 0, 0, 0, 1, -1))
             raises(ValueError, time.strftime, '', (100, 1, 1, 0, 0, 0, 0, 1, -1))
+        time.strftime('', (1899, 1, 1, 0, 0, 0, 0, 1, -1))
+        time.strftime('', (0, 1, 1, 0, 0, 0, 0, 1, -1))
+
         # check month
         raises(ValueError, time.strftime, '', (1900, 13, 1, 0, 0, 0, 0, 1, -1))
         # check day of month
@@ -307,8 +342,8 @@
         # check day of the year
         raises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, 0, 0, 367, -1))
         # check daylight savings flag
-        raises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, 0, 0, 1, -2))
-        raises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, 0, 0, 1, 2))
+        time.strftime('', (1900, 1, 1, 0, 0, 0, 0, 1, -2))
+        time.strftime('', (1900, 1, 1, 0, 0, 0, 0, 1, 2))
 
     def test_strptime(self):
         import time
@@ -321,7 +356,7 @@
                           'j', 'm', 'M', 'p', 'S',
                           'U', 'w', 'W', 'x', 'X', 'y', 'Y', 'Z', '%'):
             format = ' %' + directive
-            print format
+            print(format)
             time.strptime(time.strftime(format, tt), format)
 
     def test_pickle(self):


More information about the pypy-commit mailing list