[pypy-commit] pypy py3.5-time: extend structseqtype to allow invisible fields (see struct_time, tm_zone, tm_gmtoff)
plan_rich
pypy.commits at gmail.com
Tue Jan 3 07:53:44 EST 2017
Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5-time
Changeset: r89333:08e4f8a740d5
Date: 2017-01-03 13:52 +0100
http://bitbucket.org/pypy/pypy/changeset/08e4f8a740d5/
Log: extend structseqtype to allow invisible fields (see struct_time,
tm_zone, tm_gmtoff)
diff --git a/lib_pypy/_structseq.py b/lib_pypy/_structseq.py
--- a/lib_pypy/_structseq.py
+++ b/lib_pypy/_structseq.py
@@ -41,22 +41,31 @@
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
+ extra_off = 0
+ if 'n_sequence_fields' in dict:
+ n_sequence_fields = dict['n_sequence_fields']
+ extra_fields = extra_fields[:n_sequence_fields]
+ extra_off = n_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:
+ extra_fields = [field for index, field in extra_fields[extra_off:]]
+ for i,field in enumerate(extra_fields):
field.index = None # no longer relevant
assert '__new__' not in dict
dict['_extra_fields'] = tuple(extra_fields)
+ dict['_extra_off'] = extra_off
dict['__new__'] = structseq_new
dict['__reduce__'] = structseq_reduce
dict['__setattr__'] = structseq_setattr
@@ -70,34 +79,40 @@
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 1" % (
+ 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 2" \
+ % (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]
+ extra_off = cls._extra_off
+ sequence = sequence[:visible_count+extra_off]
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):
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
@@ -8,17 +8,21 @@
__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)
- tm_gmtoff = structseqfield(9)
- tm_zone = structseqfield(10)
+ 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,
@@ -200,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
@@ -542,12 +546,14 @@
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)
+ time_tuple.append(space.newunicode(tm_zone))
+ time_tuple.append(space.wrap(rffi.getintfield(t, 'c_tm_gmtoff')))
w_struct_time = _get_module_object(space, 'struct_time')
w_time_tuple = space.newtuple(time_tuple)
w_obj = space.call_function(w_struct_time, w_time_tuple)
- if HAS_TM_ZONE:
- space.setattr(w_obj, space.wrap("tm_gmoff"), space.wrap(rffi.getintfield(t, 'c_tm_gmtoff')))
- space.setattr(w_obj, space.wrap("tm_zone"), space.wrap(rffi.getintfield(t, 'c_tm_zone')))
return w_obj
def _gettmarg(space, w_tup, allowNone=True):
@@ -568,9 +574,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])
@@ -591,13 +597,16 @@
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)
+ if HAS_TM_ZONE:
+ #tm_zone = encode_utf8(space, space.unicode_w(tup_w[9]), allow_surrogates=True)
+ #glob_buf.c_tm_zone = rffi.str2charp(tm_zone)
+ # TODO using str2charp allocates an object that is never freed
+ # find a solution for this memory leak
+ glob_buf.c_tm_zone = lltype.nullptr(rffi.CCHARP.TO)
+ rffi.setintfield(glob_buf, 'c_tm_gmtoff', space.c_int_w(tup_w[10]))
+ else:
+ glob_buf.c_tm_zone = lltype.nullptr(rffi.CCHARP.TO)
+ rffi.setintfield(glob_buf, 'c_tm_gmtoff', 0)
# tm_wday does not need checking of its upper-bound since taking "%
# 7" in _gettmarg() automatically restricts the range.
More information about the pypy-commit
mailing list