[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