|
From: <bov...@us...> - 2006-10-23 21:15:58
|
Revision: 1274
http://svn.sourceforge.net/pywebsvcs/?rev=1274&view=rev
Author: boverhof
Date: 2006-10-23 14:15:52 -0700 (Mon, 23 Oct 2006)
Log Message:
-----------
A test/test_TCtimes.py
M ZSI/TCtimes.py
M CHANGES
-- [ 1558078 ] Problem receiving date/time values with time zones
added patch with several modifications, and created a new unittest
Modified Paths:
--------------
trunk/zsi/CHANGES
trunk/zsi/ZSI/TCtimes.py
Added Paths:
-----------
trunk/zsi/test/test_TCtimes.py
Modified: trunk/zsi/CHANGES
===================================================================
--- trunk/zsi/CHANGES 2006-10-21 00:09:11 UTC (rev 1273)
+++ trunk/zsi/CHANGES 2006-10-23 21:15:52 UTC (rev 1274)
@@ -7,11 +7,19 @@
- Remove Send()'s kwargs out of _args list <ef...@bo...>
Change for 2.0.0rc3 released xxx:
+ - Updated ZSI developers guide
+ - Added ZSI wsdl2py users guide
+ - Added support for setuptools in setup script. If setuptools is installed
+ use it, else revert to distutils.
- Removed "requestclass" keyword argument to Binding.Send
- - simplified and retooled Binding/NamedParamBinding and dispatch.
+ - simplified and retooled Binding/NamedParamBinding and dispatch, added
+ "typesmodule" back into Binding. Now it's mirror image of dispatch.
+ - Microseconds to TCtime
- BUG [ 1525567 ] Amazon ECommerce Issues: local element declarations
overriding global element declarations with the same name within the
same namespace.
+ - new module "schema", contains "all" the code for dealing with global
+ Schema instance.
Change for 2.0.0rc2 released 28-March-2006:
- Replace many/most id() with _get_idstr() to hide negative numbers
Modified: trunk/zsi/ZSI/TCtimes.py
===================================================================
--- trunk/zsi/ZSI/TCtimes.py 2006-10-21 00:09:11 UTC (rev 1273)
+++ trunk/zsi/ZSI/TCtimes.py 2006-10-23 21:15:52 UTC (rev 1274)
@@ -6,7 +6,11 @@
from ZSI import _copyright, _floattypes, _inttypes, _get_idstr, EvaluateException
from ZSI.TC import TypeCode, SimpleType
from ZSI.wstools.Namespaces import SCHEMA
-import operator, re, time
+import operator, re, time as _time
+from time import mktime as _mktime, localtime as _localtime, gmtime as _gmtime
+from datetime import tzinfo as _tzinfo, timedelta as _timedelta,\
+ datetime as _datetime
+from math import modf as _modf
_niltime = [
0, 0, 0, # year month day
@@ -14,36 +18,119 @@
0, 0, 0 # weekday, julian day, dst flag
]
+#### Code added to check current timezone offset
+_zero = _timedelta(0)
+_dstoffset = _stdoffset = _timedelta(seconds=-_time.timezone)
+if _time.daylight: _dstoffset = _timedelta(seconds=-_time.altzone)
+_dstdiff = _dstoffset - _stdoffset
+
+
+class _localtimezone(_tzinfo):
+ """ """
+ def dst(self, dt):
+ """datetime -> DST offset in minutes east of UTC."""
+ tt = _localtime(_mktime((dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)))
+ if tt.tm_isdst > 0: return _dstdiff
+ return _zero
+
+ #def fromutc(...)
+ #datetime in UTC -> datetime in local time.
+
+ def tzname(self, dt):
+ """datetime -> string name of time zone."""
+ tt = _localtime(_mktime((dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)))
+ return _time.tzname[tt.tm_isdst > 0]
+
+ def utcoffset(self, dt):
+ """datetime -> minutes east of UTC (negative for west of UTC)."""
+ tt = _localtime(_mktime((dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)))
+ if tt.tm_isdst > 0: return _dstoffset
+ return _stdoffset
+
+class _fixedoffset(_tzinfo):
+ """Fixed offset in minutes east from UTC.
+
+ A class building tzinfo objects for fixed-offset time zones.
+ Note that _fixedoffset(0, "UTC") is a different way to build a
+ UTC tzinfo object.
+ """
+ #def __init__(self, offset, name):
+ def __init__(self, offset):
+ self.__offset = _timedelta(minutes=offset)
+ #self.__name = name
+
+ def dst(self, dt):
+ """datetime -> DST offset in minutes east of UTC."""
+ return _zero
+
+ def tzname(self, dt):
+ """datetime -> string name of time zone."""
+ #return self.__name
+ return "server"
+
+ def utcoffset(self, dt):
+ """datetime -> minutes east of UTC (negative for west of UTC)."""
+ return self.__offset
+
+
def _dict_to_tuple(d):
'''Convert a dictionary to a time tuple. Depends on key values in the
regexp pattern!
- '''
+ '''
retval = _niltime[:]
for k,i in ( ('Y', 0), ('M', 1), ('D', 2), ('h', 3), ('m', 4), ):
v = d.get(k)
if v: retval[i] = int(v)
+
v = d.get('s')
- if v: retval[5] = int(float(v))
+ if v:
+ msec,sec = _modf(float(v))
+ retval[6],retval[5] = int(round(msec*1000)), int(sec)
+
v = d.get('tz')
if v and v != 'Z':
h,m = map(int, v.split(':'))
- if h < 0:
- retval[3] += abs(h)
- retval[4] += m
- else:
- retval[3] -= abs(h)
- retval[4] -= m
+ # check for time zone offset, if within the same timezone,
+ # ignore offset specific calculations
+ offset=_localtimezone().utcoffset(_datetime.now())
+ local_offset_hour = offset.seconds/3600
+ local_offset_min = (offset.seconds%3600)%60
+ if local_offset_hour > 12:
+ local_offset_hour -= 24
+
+ if local_offset_hour != h or local_offset_min != m:
+ if h<0:
+ #TODO: why is this set to server
+ #foff = _fixedoffset(-((abs(h)*60+m)),"server")
+ foff = _fixedoffset(-((abs(h)*60+m)))
+ else:
+ #TODO: why is this set to server
+ #foff = _fixedoffset((abs(h)*60+m),"server")
+ foff = _fixedoffset((abs(h)*60+m))
+
+ dt = _datetime(retval[0],retval[1],retval[2],retval[3],retval[4],
+ retval[5],0,foff)
+
+ # update dict with calculated timezone
+ localdt=dt.astimezone(_localtimezone())
+ retval[0] = localdt.year
+ retval[1] = localdt.month
+ retval[2] = localdt.day
+ retval[3] = localdt.hour
+ retval[4] = localdt.minute
+ retval[5] = localdt.second
+
if d.get('neg', 0):
retval[0:5] = map(operator.__neg__, retval[0:5])
return tuple(retval)
-
class Duration(SimpleType):
'''Time duration.
- TODO: NOT FIXED YET...
'''
-
parselist = [ (None,'duration') ]
lex_pattern = re.compile('^' r'(?P<neg>-?)P' \
r'((?P<Y>\d+)Y)?' r'((?P<M>\d+)M)?' r'((?P<D>\d+)D)?' \
@@ -74,7 +161,7 @@
def get_formatted_content(self, pyobj):
if type(pyobj) in _floattypes or type(pyobj) in _inttypes:
- pyobj = time.gmtime(pyobj)
+ pyobj = _gmtime(pyobj)
d = {}
pyobj = tuple(pyobj)
@@ -107,23 +194,16 @@
try:
retval = _dict_to_tuple(m.groupdict())
except ValueError, e:
- raise EvaluateException(str(e))
+ #raise EvaluateException(str(e))
+ raise
if self.pyclass is not None:
return self.pyclass(retval)
return retval
-# def parse(self, elt, ps):
-# self.checkname(elt, ps)
-# elt = self.SimpleHREF(elt, ps, 'Gregorian')
-# if not elt: return None
-# if self.nilled(elt, ps): return Nilled
-# v = self.simple_value(elt, ps)
-# return self.text_to_data(text)
-
def get_formatted_content(self, pyobj):
if type(pyobj) in _floattypes or type(pyobj) in _inttypes:
- pyobj = time.gmtime(pyobj)
+ pyobj = _gmtime(pyobj)
d = {}
pyobj = tuple(pyobj)
@@ -133,12 +213,20 @@
else:
d['neg'] = ''
+ ms = pyobj[6]
+ if not ms:
+ d = { 'Y': pyobj[0], 'M': pyobj[1], 'D': pyobj[2],
+ 'h': pyobj[3], 'm': pyobj[4], 's': pyobj[5], }
+ return self.format % d
+
+ if ms > 999:
+ raise ValueError, 'milliseconds must be a integer between 0 and 999'
+
d = { 'Y': pyobj[0], 'M': pyobj[1], 'D': pyobj[2],
- 'h': pyobj[3], 'm': pyobj[4], 's': pyobj[5], }
- val = self.format % d
- return val
+ 'h': pyobj[3], 'm': pyobj[4], 's': pyobj[5], 'ms':ms, }
+ return self.format_ms % d
+
-
class gDateTime(Gregorian):
'''A date and time.
'''
@@ -148,6 +236,7 @@
r'(?P<h>\d\d):' r'(?P<m>\d\d):' r'(?P<s>\d*(\.\d+)?)' \
r'(?P<tz>(Z|([-+]\d\d:\d\d))?)' '$')
tag, format = 'dateTime', '%(Y)04d-%(M)02d-%(D)02dT%(h)02d:%(m)02d:%(s)02dZ'
+ format_ms = format[:-1] + '.%(ms)03dZ'
type = (SCHEMA.XSD3, 'dateTime')
class gDate(Gregorian):
@@ -219,6 +308,7 @@
r'(?P<h>\d\d):' r'(?P<m>\d\d):' r'(?P<s>\d*(\.\d+)?)' \
r'(?P<tz>Z|([-+]\d\d:\d\d))?' '$')
tag, format = 'time', '%(h)02d:%(m)02d:%(s)02dZ'
+ format_ms = format[:-1] + '.%(ms)03dZ'
type = (SCHEMA.XSD3, 'time')
if __name__ == '__main__': print _copyright
Added: trunk/zsi/test/test_TCtimes.py
===================================================================
--- trunk/zsi/test/test_TCtimes.py (rev 0)
+++ trunk/zsi/test/test_TCtimes.py 2006-10-23 21:15:52 UTC (rev 1274)
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+import unittest, sys, tests_good, tests_bad, time
+from ZSI import *
+try:
+ import cStringIO as StringIO
+except ImportError:
+ import StringIO
+
+
+class TestCase(unittest.TestCase):
+ '''Examples from "Definitive XML Schema, Priscilla Walmsley, p237-246
+ '''
+ def check_dateTime_local_offset(self):
+ # UTC with local timezone offset
+ #
+ typecode = TC.gDateTime()
+ off_hour = time.altzone/60/60
+ off_min = time.altzone%60
+ stamp_offset = '1968-04-02T13:20:00+%02d:%02d' %(off_hour,off_min)
+ data = typecode.text_to_data(stamp_offset, None, None)
+ stamp = typecode.get_formatted_content(data)
+
+ correct = "1968-04-01T22:20:00Z"
+ self.failUnless(stamp == correct,
+ 'dateTime with local offset(%s), expecting "%s" got "%s"' %(
+ stamp_offset, correct, stamp))
+
+ def check_valid_dateTime(self):
+ typecode = TC.gDateTime()
+ for i in ('1968-04-02T13:20:00', '1968-04-02T13:20:15.5',
+ '1968-04-02T13:20:00-05:00', '1968-04-02T13:20:00Z'):
+ data = typecode.text_to_data(i, None, None)
+ text = typecode.get_formatted_content(data)
+
+ def check_parse_microseconds(self):
+ good = (1968, 4, 2, 13, 20, 15, 511, 0, 0)
+ typecode = TC.gDateTime()
+ data = typecode.text_to_data('1968-04-02T13:20:15.511', None, None)
+ self.failUnless(data == good,
+ 'did not parse something %s, not equal %s' %(data,good))
+
+ def check_serialize_microseconds(self):
+ dateTime = '1968-04-02T13:20:15.511Z'
+ typecode = TC.gDateTime()
+ text = typecode.get_formatted_content((1968, 4, 2, 13, 20, 15, 511, 0, 0))
+ self.failUnless(text == dateTime,
+ 'did not serialze correctly %s, not equal %s' %(text, dateTime))
+
+ def check_serialize_microseconds_1000(self):
+ bad = (1968, 4, 2, 13, 20, 15, 1000, 0)
+ typecode = TC.gDateTime()
+ self.failUnlessRaises(ValueError, typecode.get_formatted_content, bad)
+
+ def check_serialize_microseconds_lessZero(self):
+ '''ignore negative microseconds
+ '''
+ bad = (1968, 4, 2, 13, 20, 15, -1, 0)
+ typecode = TC.gDateTime()
+ text = typecode.get_formatted_content(bad)
+ typecode.get_formatted_content(bad)
+
+ def check_parse_microseconds2(self):
+ good = (1968, 4, 2, 13, 20, 15, 500, 0, 0)
+ typecode = TC.gDateTime()
+ data = typecode.text_to_data('1968-04-02T13:20:15.5Z', None,None)
+ self.failUnless(data == good,
+ 'did not serialze correctly %s, not equal %s' %(data, good))
+
+ #text = typecode.get_formatted_content((1968, 4, 2, 13, 20, 15, 5, 0, 500))
+ #self.failUnless(text == dateTime,
+ # 'did not serialze correctly %s, not equal %s' %(text, dateTime))
+
+ def check_invalid_dateTime(self):
+ typecode = TC.gDateTime()
+
+ def check_valid_time(self):
+ typecode = TC.gTime()
+ for i in ('13:20:00', '13:20:30.5555', '13:20:00Z'):
+ data = typecode.text_to_data(i, None, None)
+ text = typecode.get_formatted_content(data)
+
+ def broke_valid_time(self):
+ typecode = TC.gTime()
+ data = typecode.text_to_data('13:20:00-05:00', None, None)
+
+ def check_invalid_time(self):
+ typecode = TC.gTime()
+ for i in ('5:20:00', '13:20.5:00',):
+ self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None),
+
+ def broke_invalid_time_no_seconds(self):
+ typecode = TC.gTime()
+ i = '13:20:'
+ self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None)
+
+ def broke_invalid_time_bad_timeofday(self):
+ typecode = TC.gTime()
+ i = '13:65:00'
+ self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None)
+
+ def check_valid_date(self):
+ typecode = TC.gDate()
+ for i in ('1968-04-02', '-0045-01-01', '11968-04-02', '1968-04-02+05:00', '1968-04-02Z'):
+ data = typecode.text_to_data(i, None, None)
+ text = typecode.get_formatted_content(data)
+
+ def check_invalid_date(self):
+ typecode = TC.gDate()
+ for i in ('68-04-02', '1968-4-2', '1968/04/02', '04-02-1968',):
+ self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None),
+
+ def broke_invalid_date_april31(self):
+ # No checks for valid date April 30 days
+ typecode = TC.gDate()
+ self.failUnlessRaises(Exception, typecode.text_to_data, '1968-04-31', None, None),
+
+#
+# Creates permutation of test options: "check", "check_any", etc
+#
+_SEP = '_'
+for t in [i[0].split(_SEP) for i in filter(lambda i: callable(i[1]), TestCase.__dict__.items())]:
+ test = ''
+ for f in t:
+ test += f
+ if globals().has_key(test): test += _SEP; continue
+ def _closure():
+ name = test
+ def _makeTestSuite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestCase, name))
+ return suite
+ return _makeTestSuite
+
+ globals()[test] = _closure()
+ test += _SEP
+
+
+makeTestSuite = check
+def main():
+ unittest.main(defaultTest="makeTestSuite")
+if __name__ == "__main__" : main()
+
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|