[pypy-commit] pypy py3.5: merged py3.5-time changes
plan_rich
pypy.commits at gmail.com
Mon Jan 9 09:09:30 EST 2017
Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5
Changeset: r89438:f58422e7ce44
Date: 2017-01-09 15:07 +0100
http://bitbucket.org/pypy/pypy/changeset/f58422e7ce44/
Log: merged py3.5-time changes
diff --git a/lib_pypy/_structseq.py b/lib_pypy/_structseq.py
--- a/lib_pypy/_structseq.py
+++ b/lib_pypy/_structseq.py
@@ -41,18 +41,25 @@
assert field._index not in fields_by_index
fields_by_index[field._index] = field
field.__name__ = name
- dict['n_fields'] = len(fields_by_index)
+ n_fields = len(fields_by_index)
+ dict['n_fields'] = n_fields
extra_fields = sorted(fields_by_index.items())
n_sequence_fields = 0
- while extra_fields and extra_fields[0][0] == n_sequence_fields:
- extra_fields.pop(0)
- n_sequence_fields += 1
+ invis_fields = []
+ if 'n_sequence_fields' in dict:
+ n_sequence_fields = dict['n_sequence_fields']
+ extra_fields = extra_fields[n_sequence_fields:]
+ else:
+ while extra_fields and extra_fields[0][0] == n_sequence_fields:
+ extra_fields.pop(0)
+ n_sequence_fields += 1
+
dict['n_sequence_fields'] = n_sequence_fields
dict['n_unnamed_fields'] = 0 # no fully anonymous fields in PyPy
extra_fields = [field for index, field in extra_fields]
- for field in extra_fields:
+ for i,field in enumerate(extra_fields):
field.index = None # no longer relevant
assert '__new__' not in dict
@@ -70,34 +77,39 @@
def structseq_new(cls, sequence, dict={}):
sequence = tuple(sequence)
dict = builtin_dict(dict)
- N = cls.n_sequence_fields
- if len(sequence) < N:
- if N < cls.n_fields:
+ # visible fields
+ visible_count = cls.n_sequence_fields
+ # total fields (unnamed are not yet supported, extra fields not included)
+ real_count = cls.n_fields
+ length = len(sequence)
+ if length < visible_count:
+ if visible_count < real_count:
msg = "at least"
else:
msg = "exactly"
- raise TypeError("expected a sequence with %s %d items" % (
- msg, N))
- if len(sequence) > N:
- if len(sequence) > cls.n_fields:
- if N < cls.n_fields:
+ raise TypeError("expected a sequence with %s %d items. has %d" % (
+ msg, visible_count, length))
+ if length > visible_count:
+ if length > real_count:
+ if visible_count < real_count:
msg = "at most"
else:
msg = "exactly"
- raise TypeError("expected a sequence with %s %d items" % (
- msg, cls.n_fields))
- for field, value in zip(cls._extra_fields, sequence[N:]):
+ raise TypeError("expected a sequence with %s %d items. has %d" \
+ % (msg, real_count, length))
+ for field, value in zip(cls._extra_fields, sequence[visible_count:]):
name = field.__name__
if name in dict:
raise TypeError("duplicate value for %r" % (name,))
dict[name] = value
- sequence = sequence[:N]
+ sequence = sequence[:visible_count]
result = tuple.__new__(cls, sequence)
object.__setattr__(result, '__dict__', dict)
for field in cls._extra_fields:
name = field.__name__
if name not in dict:
dict[name] = field._default(result)
+
return result
def structseq_reduce(self):
@@ -109,9 +121,11 @@
def structseq_repr(self):
fields = {}
+ visible_count = self.n_sequence_fields
for field in type(self).__dict__.values():
- if isinstance(field, structseqfield):
+ if isinstance(field, structseqfield) and \
+ field._index <= visible_count:
fields[field._index] = field
parts = ["%s=%r" % (fields[index].__name__, value)
- for index, value in enumerate(self)]
+ for index, value in enumerate(self[:visible_count])]
return "%s(%s)" % (self._name, ", ".join(parts))
diff --git a/pypy/module/time/app_time.py b/pypy/module/time/app_time.py
--- a/pypy/module/time/app_time.py
+++ b/pypy/module/time/app_time.py
@@ -3,19 +3,26 @@
from _structseq import structseqtype, structseqfield
from types import SimpleNamespace
import time
+
class struct_time(metaclass=structseqtype):
__module__ = 'time'
name = 'time.struct_time'
- tm_year = structseqfield(0)
- tm_mon = structseqfield(1)
- tm_mday = structseqfield(2)
- tm_hour = structseqfield(3)
- tm_min = structseqfield(4)
- tm_sec = structseqfield(5)
- tm_wday = structseqfield(6)
- tm_yday = structseqfield(7)
- tm_isdst = structseqfield(8)
+ n_sequence_fields = 9
+
+ tm_year = structseqfield(0, "year, for example, 1993")
+ tm_mon = structseqfield(1, "month of year, range [1, 12]")
+ tm_mday = structseqfield(2, "day of month, range [1, 31]")
+ tm_hour = structseqfield(3, "hours, range [0, 23]")
+ tm_min = structseqfield(4, "minutes, range [0, 59]")
+ tm_sec = structseqfield(5, "seconds, range [0, 61])")
+ tm_wday = structseqfield(6, "day of week, range [0, 6], Monday is 0")
+ tm_yday = structseqfield(7, "day of year, range [1, 366]")
+ tm_isdst = structseqfield(8, "1 if summer time is in effect, 0 if not"
+ ", and -1 if unknown")
+ tm_zone = structseqfield(9, "abbreviation of timezone name")
+ tm_gmtoff = structseqfield(10,"offset from UTC in seconds")
+
def strptime(string, format="%a %b %d %H:%M:%S %Y"):
"""strptime(string, format) -> struct_time
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
@@ -1,8 +1,10 @@
from rpython.rtyper.tool import rffi_platform as platform
from rpython.rtyper.lltypesystem import rffi
-from pypy.interpreter.error import OperationError, oefmt, strerror as _strerror, exception_from_saved_errno
+from pypy.interpreter.error import (OperationError, oefmt,
+ strerror as _strerror, exception_from_saved_errno)
from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter import timeutils
+from pypy.interpreter.unicodehelper import decode_utf8, encode_utf8
from rpython.rtyper.lltypesystem import lltype
from rpython.rlib.rarithmetic import intmask, r_ulonglong, r_longfloat, widen
from rpython.rlib.rtime import (GETTIMEOFDAY_NO_TZ, TIMEVAL,
@@ -164,6 +166,8 @@
CLOCKS_PER_SEC = platform.ConstantInteger("CLOCKS_PER_SEC")
has_gettimeofday = platform.Has('gettimeofday')
+HAS_TM_ZONE = False
+
if _POSIX:
calling_conv = 'c'
CConfig.timeval = platform.Struct("struct timeval",
@@ -180,6 +184,9 @@
("tm_mon", rffi.INT), ("tm_year", rffi.INT), ("tm_wday", rffi.INT),
("tm_yday", rffi.INT), ("tm_isdst", rffi.INT), ("tm_gmtoff", rffi.LONG),
("tm_zone", rffi.CCHARP)])
+
+ HAS_TM_ZONE = True
+
elif _WIN:
calling_conv = 'win'
CConfig.tm = platform.Struct("struct tm", [("tm_sec", rffi.INT),
@@ -195,6 +202,8 @@
# XXX: optionally support the 2 additional tz fields
_STRUCT_TM_ITEMS = 9
+if HAS_TM_ZONE:
+ _STRUCT_TM_ITEMS = 11
class cConfig:
pass
@@ -537,9 +546,18 @@
space.wrap(rffi.getintfield(t, 'c_tm_yday') + 1), # want january, 1 == 1
space.wrap(rffi.getintfield(t, 'c_tm_isdst'))]
+ if HAS_TM_ZONE:
+ # CPython calls PyUnicode_DecodeLocale here should we do the same?
+ tm_zone = decode_utf8(space, rffi.charp2str(t.c_tm_zone),
+ allow_surrogates=True)
+ extra = [space.newunicode(tm_zone),
+ space.wrap(rffi.getintfield(t, 'c_tm_gmtoff'))]
+ w_time_tuple = space.newtuple(time_tuple + extra)
+ else:
+ w_time_tuple = space.newtuple(time_tuple)
w_struct_time = _get_module_object(space, 'struct_time')
- w_time_tuple = space.newtuple(time_tuple)
- return space.call_function(w_struct_time, w_time_tuple)
+ w_obj = space.call_function(w_struct_time, w_time_tuple)
+ return w_obj
def _gettmarg(space, w_tup, allowNone=True):
if space.is_none(w_tup):
@@ -559,9 +577,9 @@
return pbuf
tup_w = space.fixedview(w_tup)
- if len(tup_w) != 9:
+ if len(tup_w) < 9:
raise oefmt(space.w_TypeError,
- "argument must be sequence of length 9, not %d",
+ "argument must be sequence of at least length 9, not %d",
len(tup_w))
y = space.c_int_w(tup_w[0])
@@ -582,13 +600,23 @@
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.c_int_w(tup_w[8]))
- if _POSIX:
- if _CYGWIN:
- pass
- else:
- # actually never happens, but makes annotator happy
- glob_buf.c_tm_zone = lltype.nullptr(rffi.CCHARP.TO)
- rffi.setintfield(glob_buf, 'c_tm_gmtoff', 0)
+ #
+ old_tm_zone = glob_buf.c_tm_zone
+ glob_buf.c_tm_zone = lltype.nullptr(rffi.CCHARP.TO)
+ rffi.setintfield(glob_buf, 'c_tm_gmtoff', 0)
+ if HAS_TM_ZONE :
+ if len(tup_w) >= 10:
+ # NOTE this is not cleanly solved!
+ # it saves the string that is later deleted when this
+ # function is called again. A refactoring of this module
+ # could remove this
+ tm_zone = encode_utf8(space, space.unicode_w(tup_w[9]), allow_surrogates=True)
+ malloced_str = rffi.str2charp(tm_zone, track_allocation=False)
+ if old_tm_zone != lltype.nullptr(rffi.CCHARP.TO):
+ rffi.free_charp(old_tm_zone, track_allocation=False)
+ glob_buf.c_tm_zone = malloced_str
+ if len(tup_w) >= 11:
+ rffi.setintfield(glob_buf, 'c_tm_gmtoff', space.c_int_w(tup_w[10]))
# tm_wday does not need checking of its upper-bound since taking "%
# 7" in _gettmarg() automatically restricts the range.
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
@@ -254,6 +254,22 @@
del os.environ['TZ']
time.tzset()
+ def test_localtime_timezone(self):
+ import os, time
+ org_TZ = os.environ.get('TZ', None)
+ try:
+ os.environ['TZ'] = 'Europe/Kiev'
+ time.tzset()
+ localtm = time.localtime(0)
+ assert localtm.tm_zone == "MSK"
+ assert localtm.tm_gmtoff == 10800
+ finally:
+ if org_TZ is not None:
+ os.environ['TZ'] = org_TZ
+ elif 'TZ' in os.environ:
+ del os.environ['TZ']
+ time.tzset()
+
def test_strftime(self):
import time
import os, sys
More information about the pypy-commit
mailing list