Log message for revision 104432: Backported fix for timezone issues in date index tests from trunk.
Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/Products/PluginIndexes/DateIndex/tests/test_DateIndex.py U Zope/branches/2.12/src/Products/PluginIndexes/DateRangeIndex/tests/test_DateRangeIndex.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst =================================================================== --- Zope/branches/2.12/doc/CHANGES.rst 2009-09-22 17:14:00 UTC (rev 104431) +++ Zope/branches/2.12/doc/CHANGES.rst 2009-09-22 18:52:25 UTC (rev 104432) @@ -18,6 +18,8 @@ Bugs Fixed ++++++++++ +- Backported fix for timezone issues in date index tests from trunk. + - LP #414757 (backported from Zope trunk): don't emit a IEndRequestEvent when clearing a cloned request. Modified: Zope/branches/2.12/src/Products/PluginIndexes/DateIndex/tests/test_DateIndex.py =================================================================== --- Zope/branches/2.12/src/Products/PluginIndexes/DateIndex/tests/test_DateIndex.py 2009-09-22 17:14:00 UTC (rev 104431) +++ Zope/branches/2.12/src/Products/PluginIndexes/DateIndex/tests/test_DateIndex.py 2009-09-22 18:52:25 UTC (rev 104432) @@ -16,19 +16,7 @@ """ import unittest -import Testing -import Zope2 -Zope2.startup() -from datetime import date, datetime, tzinfo, timedelta -import time -from types import IntType, FloatType - -from DateTime import DateTime - -from Products.PluginIndexes.DateIndex.DateIndex import DateIndex, Local - - class Dummy: def __init__(self, name, date): @@ -48,67 +36,86 @@ ############################################################################### # excerpted from the Python module docs ############################################################################### -ZERO = timedelta(0) -HOUR = timedelta(hours=1) -def first_sunday_on_or_after(dt): - days_to_go = 6 - dt.weekday() - if days_to_go: - dt += timedelta(days_to_go) - return dt -# In the US, DST starts at 2am (standard time) on the first Sunday in April. -DSTSTART = datetime(1, 4, 1, 2) -# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. -# which is the first Sunday on or after Oct 25. -DSTEND = datetime(1, 10, 25, 1) +def _getEastern(): + from datetime import date + from datetime import datetime + from datetime import timedelta + from datetime import tzinfo + ZERO = timedelta(0) + HOUR = timedelta(hours=1) + def first_sunday_on_or_after(dt): + days_to_go = 6 - dt.weekday() + if days_to_go: + dt += timedelta(days_to_go) + return dt -class USTimeZone(tzinfo): + # In the US, DST starts at 2am (standard time) on the first Sunday in + # April... + DSTSTART = datetime(1, 4, 1, 2) + # and ends at 2am (DST time; 1am standard time) on the last Sunday of + # October, which is the first Sunday on or after Oct 25. + DSTEND = datetime(1, 10, 25, 1) - def __init__(self, hours, reprname, stdname, dstname): - self.stdoffset = timedelta(hours=hours) - self.reprname = reprname - self.stdname = stdname - self.dstname = dstname + class USTimeZone(tzinfo): - def __repr__(self): - return self.reprname + def __init__(self, hours, reprname, stdname, dstname): + self.stdoffset = timedelta(hours=hours) + self.reprname = reprname + self.stdname = stdname + self.dstname = dstname - def tzname(self, dt): - if self.dst(dt): - return self.dstname - else: - return self.stdname + def __repr__(self): + return self.reprname - def utcoffset(self, dt): - return self.stdoffset + self.dst(dt) + def tzname(self, dt): + if self.dst(dt): + return self.dstname + else: + return self.stdname - def dst(self, dt): - if dt is None or dt.tzinfo is None: - # An exception may be sensible here, in one or both cases. - # It depends on how you want to treat them. The default - # fromutc() implementation (called by the default astimezone() - # implementation) passes a datetime with dt.tzinfo is self. - return ZERO - assert dt.tzinfo is self + def utcoffset(self, dt): + return self.stdoffset + self.dst(dt) - # Find first Sunday in April & the last in October. - start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) - end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) + def dst(self, dt): + if dt is None or dt.tzinfo is None: + # An exception may be sensible here, in one or both cases. + # It depends on how you want to treat them. The default + # fromutc() implementation (called by the default astimezone() + # implementation) passes a datetime with dt.tzinfo is self. + return ZERO + assert dt.tzinfo is self - # Can't compare naive to aware objects, so strip the timezone from - # dt first. - if start <= dt.replace(tzinfo=None) < end: - return HOUR - else: - return ZERO + # Find first Sunday in April & the last in October. + start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) + end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) -Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") + # Can't compare naive to aware objects, so strip the timezone from + # dt first. + if start <= dt.replace(tzinfo=None) < end: + return HOUR + else: + return ZERO + + return USTimeZone(-5, "Eastern", "EST", "EDT") + ############################################################################### class DI_Tests(unittest.TestCase): - def setUp(self): - self._values = ( + + def _getTargetClass(self): + from Products.PluginIndexes.DateIndex.DateIndex import DateIndex + return DateIndex + + def _makeOne(self, id='date'): + return self._getTargetClass()(id) + + def _getValues(self): + from DateTime import DateTime + from datetime import date + from datetime import datetime + return [ (0, Dummy('a', None)), # None (1, Dummy('b', DateTime(0))), # 1055335680 (2, Dummy('c', DateTime('2002-05-08 15:16:17'))), # 1072667236 @@ -120,29 +127,15 @@ (8, Dummy('g', date(2034,2,5))), # 1073599200 (9, Dummy('h', datetime(2034,2,5,15,20,5))), # (varies) (10, Dummy('i', datetime(2034,2,5,10,17,5, - tzinfo=Eastern))), # 1073600117 - ) - self._index = DateIndex('date') - self._noop_req = {'bar': 123} - self._request = {'date': DateTime(0)} - self._min_req = {'date': {'query': DateTime('2032-05-08 15:16:17'), - 'range': 'min'}} - self._max_req = {'date': {'query': DateTime('2032-05-08 15:16:17'), - 'range': 'max'}} - self._range_req = {'date': {'query':(DateTime('2002-05-08 15:16:17'), - DateTime('2062-05-08 15:16:17')), - 'range': 'min:max'}} - self._zero_req = {'date': 0} - self._none_req = {'date': None} - self._float_req = {'date': 1072742620.0} - self._int_req = {'date': 1072742900} + tzinfo=_getEastern()))), # 1073600117 + ] - def _populateIndex( self ): - for k, v in self._values: - self._index.index_object(k, v) + def _populateIndex(self, index): + for k, v in self._getValues(): + index.index_object(k, v) - def _checkApply(self, req, expectedValues): - result, used = self._index._apply_index(req) + def _checkApply(self, index, req, expectedValues): + result, used = index._apply_index(req) if hasattr(result, 'keys'): result = result.keys() self.failUnlessEqual(used, ('date',)) @@ -152,8 +145,12 @@ self.failUnless(k in result) def _convert(self, dt): - if type(dt) in (FloatType, IntType): - yr, mo, dy, hr, mn = time.gmtime(dt)[:5] + from time import gmtime + from datetime import date + from datetime import datetime + from Products.PluginIndexes.DateIndex.DateIndex import Local + if isinstance(dt, (float, int)): + yr, mo, dy, hr, mn = gmtime(dt)[:5] elif type(dt) is date: yr, mo, dy, hr, mn = dt.timetuple()[:5] elif type(dt) is datetime: @@ -171,37 +168,50 @@ from Products.PluginIndexes.interfaces import IUniqueValueIndex from zope.interface.verify import verifyClass - verifyClass(IDateIndex, DateIndex) - verifyClass(IPluggableIndex, DateIndex) - verifyClass(ISortIndex, DateIndex) - verifyClass(IUniqueValueIndex, DateIndex) + verifyClass(IDateIndex, self._getTargetClass()) + verifyClass(IPluggableIndex, self._getTargetClass()) + verifyClass(ISortIndex, self._getTargetClass()) + verifyClass(IUniqueValueIndex, self._getTargetClass()) def test_empty(self): - empty = self._index + from DateTime import DateTime + index = self._makeOne() - self.failUnlessEqual(len(empty), 0) - self.failUnlessEqual(len(empty.referencedObjects()), 0) + self.failUnlessEqual(len(index), 0) + self.failUnlessEqual(len(index.referencedObjects()), 0) - self.failUnless(empty.getEntryForObject(1234) is None) + self.failUnless(index.getEntryForObject(1234) is None) marker = [] - self.failUnless(empty.getEntryForObject(1234, marker) is marker) - empty.unindex_object(1234) # shouldn't throw + self.failUnless(index.getEntryForObject(1234, marker) is marker) + index.unindex_object(1234) # shouldn't throw - self.failUnless(empty.hasUniqueValuesFor('date')) - self.failIf(empty.hasUniqueValuesFor('foo')) - self.failUnlessEqual(len(empty.uniqueValues('date')), 0) + self.failUnless(index.hasUniqueValuesFor('date')) + self.failIf(index.hasUniqueValuesFor('foo')) + self.failUnlessEqual(len(index.uniqueValues('date')), 0) - self.failUnless(empty._apply_index({'zed': 12345}) is None) + self.failUnless(index._apply_index({'zed': 12345}) is None) - self._checkApply(self._request, []) - self._checkApply(self._min_req, []) - self._checkApply(self._max_req, []) - self._checkApply(self._range_req, []) + self._checkApply(index, + {'date': DateTime(0)}, []) + self._checkApply(index, + {'date': {'query': DateTime('2032-05-08 15:16:17'), + 'range': 'min'}}, + []) + self._checkApply(index, + {'date': {'query': DateTime('2032-05-08 15:16:17'), + 'range': 'max'}}, + []) + self._checkApply(index, + {'date': {'query':(DateTime('2002-05-08 15:16:17'), + DateTime('2062-05-08 15:16:17')), + 'range': 'min:max'}}, + []) def test_retrieval( self ): - self._populateIndex() - values = self._values - index = self._index + from DateTime import DateTime + index = self._makeOne() + self._populateIndex(index) + values = self._getValues() self.failUnlessEqual(len(index), len(values) - 2) # One dupe, one empty self.failUnlessEqual(len(index.referencedObjects()), len(values) - 1) @@ -214,30 +224,43 @@ for k, v in values: if v.date(): - self.failUnlessEqual(self._index.getEntryForObject(k), + self.failUnlessEqual(index.getEntryForObject(k), self._convert(v.date())) self.failUnlessEqual(len(index.uniqueValues('date')), len(values) - 2) - self.failUnless(index._apply_index(self._noop_req) is None) + self.failUnless(index._apply_index({'bar': 123}) is None) - self._checkApply(self._request, values[1:2]) - self._checkApply(self._min_req, values[3:6] + values[8:]) - self._checkApply(self._max_req, values[1:4] + values[6:8]) - self._checkApply(self._range_req, values[2:] ) - self._checkApply(self._float_req, [values[6]] ) - self._checkApply(self._int_req, [values[7]] ) + self._checkApply(index, + {'date': DateTime(0)}, values[1:2]) + self._checkApply(index, + {'date': {'query': DateTime('2032-05-08 15:16:17'), + 'range': 'min'}}, + values[3:6] + values[8:]) + self._checkApply(index, + {'date': {'query': DateTime('2032-05-08 15:16:17'), + 'range': 'max'}}, + values[1:4] + values[6:8]) + self._checkApply(index, + {'date': {'query':(DateTime('2002-05-08 15:16:17'), + DateTime('2062-05-08 15:16:17')), + 'range': 'min:max'}}, + values[2:] ) + self._checkApply(index, + {'date': 1072742620.0}, [values[6]]) + self._checkApply(index, + {'date': 1072742900}, [values[7]]) def test_naive_convert_to_utc(self): - values = self._values - index = self._index + index = self._makeOne() + values = self._getValues() index.index_naive_time_as_local = False - self._populateIndex() + self._populateIndex(index) for k, v in values[9:]: # assert that the timezone is effectively UTC for item 9, # and still correct for item 10 yr, mo, dy, hr, mn = v.date().utctimetuple()[:5] val = (((yr * 12 + mo) * 31 + dy) * 24 + hr) * 60 + mn - self.failUnlessEqual(self._index.getEntryForObject(k), val) + self.failUnlessEqual(index.getEntryForObject(k), val) def test_removal(self): """ DateIndex would hand back spurious entries when used as a @@ -246,10 +269,11 @@ None. The catalog consults a sort_index's documentToKeyMap() to build the brains. """ - values = self._values - index = self._index - self._populateIndex() - self._checkApply(self._int_req, [values[7]]) + values = self._getValues() + index = self._makeOne() + self._populateIndex(index) + self._checkApply(index, + {'date': 1072742900}, [values[7]]) index.index_object(7, None) self.failIf(7 in index.documentToKeyMap().keys()) Modified: Zope/branches/2.12/src/Products/PluginIndexes/DateRangeIndex/tests/test_DateRangeIndex.py =================================================================== --- Zope/branches/2.12/src/Products/PluginIndexes/DateRangeIndex/tests/test_DateRangeIndex.py 2009-09-22 17:14:00 UTC (rev 104431) +++ Zope/branches/2.12/src/Products/PluginIndexes/DateRangeIndex/tests/test_DateRangeIndex.py 2009-09-22 18:52:25 UTC (rev 104432) @@ -16,15 +16,7 @@ """ import unittest -import Testing -import Zope2 -Zope2.startup() -import sys - -from Products.PluginIndexes.DateRangeIndex.DateRangeIndex import DateRangeIndex - - class Dummy: def __init__( self, name, start, stop ): @@ -74,12 +66,23 @@ class DRI_Tests( unittest.TestCase ): - def setUp( self ): - pass - def tearDown( self ): - pass + def _getTargetClass(self): + from Products.PluginIndexes.DateRangeIndex.DateRangeIndex \ + import DateRangeIndex + return DateRangeIndex + def _makeOne(self, + id, + since_field=None, + until_field=None, + caller=None, + extra=None, + ): + klass = self._getTargetClass() + return klass(id, since_field, until_field, caller, extra) + + def test_z3interfaces(self): from Products.PluginIndexes.interfaces import IDateRangeIndex from Products.PluginIndexes.interfaces import IPluggableIndex @@ -87,14 +90,14 @@ from Products.PluginIndexes.interfaces import IUniqueValueIndex from zope.interface.verify import verifyClass - verifyClass(IDateRangeIndex, DateRangeIndex) - verifyClass(IPluggableIndex, DateRangeIndex) - verifyClass(ISortIndex, DateRangeIndex) - verifyClass(IUniqueValueIndex, DateRangeIndex) + verifyClass(IDateRangeIndex, self._getTargetClass()) + verifyClass(IPluggableIndex, self._getTargetClass()) + verifyClass(ISortIndex, self._getTargetClass()) + verifyClass(IUniqueValueIndex, self._getTargetClass()) def test_empty( self ): - empty = DateRangeIndex( 'empty' ) + empty = self._makeOne( 'empty' ) assert empty.getEntryForObject( 1234 ) is None empty.unindex_object( 1234 ) # shouldn't throw @@ -111,18 +114,18 @@ def test_retrieval( self ): - work = DateRangeIndex( 'work', 'start', 'stop' ) + index = self._makeOne( 'work', 'start', 'stop' ) for i in range( len( dummies ) ): - work.index_object( i, dummies[i] ) + index.index_object( i, dummies[i] ) for i in range( len( dummies ) ): - assert work.getEntryForObject( i ) == dummies[i].datum() + self.assertEqual(index.getEntryForObject( i ), dummies[i].datum()) for value in range( -1, 15 ): matches = matchingDummies( value ) - results, used = work._apply_index( { 'work' : value } ) + results, used = index._apply_index( { 'work' : value } ) assert used == ( 'start', 'stop' ) assert len( matches ) == len( results ), ( '%s: %s == %s' @@ -131,46 +134,87 @@ matches.sort( lambda x, y: cmp( x.name(), y.name() ) ) for result, match in map( None, results, matches ): - assert work.getEntryForObject( result ) == match.datum() + self.assertEqual(index.getEntryForObject(result), match.datum()) def test_longdates( self ): self.assertRaises(OverflowError, self._badlong ) def _badlong(self): - work = DateRangeIndex ('work', 'start', 'stop' ) + import sys + index = self._makeOne ('work', 'start', 'stop' ) bad = Dummy( 'bad', long(sys.maxint) + 1, long(sys.maxint) + 1 ) - work.index_object( 0, bad ) + index.index_object( 0, bad ) def test_datetime(self): from datetime import datetime + from DateTime.DateTime import DateTime + from Products.PluginIndexes.DateIndex.tests.test_DateIndex \ + import _getEastern + before = datetime(2009, 7, 11, 0, 0, tzinfo=_getEastern()) + start = datetime(2009, 7, 13, 5, 15, tzinfo=_getEastern()) + between = datetime(2009, 7, 13, 5, 45, tzinfo=_getEastern()) + stop = datetime(2009, 7, 13, 6, 30, tzinfo=_getEastern()) + after = datetime(2009, 7, 14, 0, 0, tzinfo=_getEastern()) + + dummy = Dummy('test', start, stop) + index = self._makeOne( 'work', 'start', 'stop' ) + index.index_object(0, dummy) + + self.assertEqual(index.getEntryForObject(0), + (DateTime(start).millis() / 60000, + DateTime(stop).millis() / 60000)) + + results, used = index._apply_index( { 'work' : before } ) + self.assertEqual(len(results), 0) + + results, used = index._apply_index( { 'work' : start } ) + self.assertEqual(len(results), 1) + + results, used = index._apply_index( { 'work' : between } ) + self.assertEqual(len(results), 1) + + results, used = index._apply_index( { 'work' : stop } ) + self.assertEqual(len(results), 1) + + results, used = index._apply_index( { 'work' : after } ) + self.assertEqual(len(results), 0) + + def test_datetime_naive_timezone(self): + from datetime import datetime + from DateTime.DateTime import DateTime + from Products.PluginIndexes.DateIndex.DateIndex import Local before = datetime(2009, 7, 11, 0, 0) start = datetime(2009, 7, 13, 5, 15) + start_local = datetime(2009, 7, 13, 5, 15, tzinfo=Local) between = datetime(2009, 7, 13, 5, 45) stop = datetime(2009, 7, 13, 6, 30) + stop_local = datetime(2009, 7, 13, 6, 30, tzinfo=Local) after = datetime(2009, 7, 14, 0, 0) dummy = Dummy('test', start, stop) - work = DateRangeIndex( 'work', 'start', 'stop' ) - work.index_object(0, dummy) + index = self._makeOne( 'work', 'start', 'stop' ) + index.index_object(0, dummy) + + self.assertEqual(index.getEntryForObject(0), + (DateTime(start_local).millis() / 60000, + DateTime(stop_local).millis() / 60000)) + + results, used = index._apply_index( { 'work' : before } ) + self.assertEqual(len(results), 0) - assert work.getEntryForObject(0) == (20790915, 20790990) + results, used = index._apply_index( { 'work' : start } ) + self.assertEqual(len(results), 1) - results, used = work._apply_index( { 'work' : before } ) - assert len(results) == 0 + results, used = index._apply_index( { 'work' : between } ) + self.assertEqual(len(results), 1) - results, used = work._apply_index( { 'work' : start } ) - assert len(results) == 1 + results, used = index._apply_index( { 'work' : stop } ) + self.assertEqual(len(results), 1) - results, used = work._apply_index( { 'work' : between } ) - assert len(results) == 1 + results, used = index._apply_index( { 'work' : after } ) + self.assertEqual(len(results), 0) - results, used = work._apply_index( { 'work' : stop } ) - assert len(results) == 1 - results, used = work._apply_index( { 'work' : after } ) - assert len(results) == 0 - - def test_suite(): suite = unittest.TestSuite() suite.addTest( unittest.makeSuite( DRI_Tests ) ) _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins