[CalendarServer-changes] [13707] PyCalendar/trunk/src/pycalendar
source_changes at macosforge.org
source_changes at macosforge.org
Tue Jul 1 09:36:05 PDT 2014
Revision: 13707
http://trac.calendarserver.org//changeset/13707
Author: cdaboo at apple.com
Date: 2014-07-01 09:36:05 -0700 (Tue, 01 Jul 2014)
Log Message:
-----------
Add caching and standard timezone indicator. Support different variants of automatically including timezones in text representations.
Modified Paths:
--------------
PyCalendar/trunk/src/pycalendar/icalendar/calendar.py
PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py
PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py
PyCalendar/trunk/src/pycalendar/timezonedb.py
Added Paths:
-----------
PyCalendar/trunk/src/pycalendar/tests/test_timezonedb.py
PyCalendar/trunk/src/pycalendar/tests/utils.py
Modified: PyCalendar/trunk/src/pycalendar/icalendar/calendar.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/icalendar/calendar.py 2014-06-30 14:57:51 UTC (rev 13706)
+++ PyCalendar/trunk/src/pycalendar/icalendar/calendar.py 2014-07-01 16:36:05 UTC (rev 13707)
@@ -42,6 +42,11 @@
FIND_EXACT = 0
FIND_MASTER = 1
+ # Enums for includeTimezone parameter
+ ALL_TIMEZONES = 0 # Always include referenced timezones
+ NONSTD_TIMEZONES = 1 # Only include non-standard referenced timezones
+ NO_TIMEZONES = 2 # Never include timezones other than those already present
+
sContainerDescriptor = "iCalendar"
sComponentType = Component
sPropertyType = Property
@@ -70,6 +75,14 @@
self.mOverriddenComponentsByUID = collections.defaultdict(list)
+ def __str__(self):
+ """
+ Override this to generate text without adding timezones - i.e., this will not change the
+ underlying object in any way.
+ """
+ return self.getText(includeTimezones=Calendar.NO_TIMEZONES)
+
+
def duplicate(self):
other = super(Calendar, self).duplicate()
other.mName = self.mName
@@ -338,32 +351,30 @@
del self.mMasterComponentsByTypeAndUID[component.getType()][uid]
- def getText(self, includeTimezones=False, format=None):
+ def getText(self, includeTimezones=None, format=None):
if format is None or format == self.sFormatText:
s = StringIO()
self.generate(s, includeTimezones=includeTimezones)
return s.getvalue()
elif format == self.sFormatJSON:
- return self.getTextJSON(includeTimezones)
+ return self.getTextJSON(includeTimezones=includeTimezones)
- def generate(self, os, includeTimezones=False):
+ def generate(self, os, includeTimezones=None):
# Make sure all required timezones are in this object
- if includeTimezones:
- self.includeTimezones()
+ self.includeMissingTimezones(includeTimezones=includeTimezones)
super(Calendar, self).generate(os)
- def getTextXML(self, includeTimezones=False):
+ def getTextXML(self, includeTimezones=None):
node = self.writeXML(includeTimezones)
return xmlutils.toString(node)
- def writeXML(self, includeTimezones=False):
+ def writeXML(self, includeTimezones=None):
# Make sure all required timezones are in this object
- if includeTimezones:
- self.includeTimezones()
+ self.includeMissingTimezones(includeTimezones=includeTimezones)
# Root node structure
root = XML.Element(xmlutils.makeTag(xmldefinitions.iCalendar20_namespace, xmldefinitions.icalendar))
@@ -371,16 +382,15 @@
return root
- def getTextJSON(self, includeTimezones=False):
+ def getTextJSON(self, includeTimezones=None):
jobject = []
self.writeJSON(jobject, includeTimezones)
return json.dumps(jobject[0], indent=2, separators=(',', ':'))
- def writeJSON(self, jobject, includeTimezones=False):
+ def writeJSON(self, jobject, includeTimezones=None):
# Make sure all required timezones are in this object
- if includeTimezones:
- self.includeTimezones()
+ self.includeMissingTimezones(includeTimezones=includeTimezones)
# Root node structure
super(Calendar, self).writeJSON(jobject)
@@ -588,7 +598,23 @@
return True
- def includeTimezones(self):
+ def includeMissingTimezones(self, includeTimezones=None):
+ """
+ For each timezone referenced in this L{Calendar}, if the corresponding VTIMEZONE component
+ is not present, then add the matching component from the timezone database. If
+ L{includeTimezones} is L{False}, then only add VTIMEZONEs that are not part of the standard
+ timezone database.
+
+ @param includeTimezones: indicated whether all or only non-standard timezones are included
+ @type includeTimezones: L{bool}
+ """
+
+ # Don't add anything in this case
+ if includeTimezones == Calendar.NO_TIMEZONES:
+ return
+ if includeTimezones is None:
+ includeTimezones = Calendar.NONSTD_TIMEZONES
+
# Get timezone names from each component
tzids = set()
for component in self.mComponents:
@@ -598,6 +624,9 @@
# Make sure each timezone is in current calendar
from pycalendar.timezonedb import TimezoneDatabase
for tzid in tzids:
+ # Skip standard timezones if requested
+ if includeTimezones == Calendar.NONSTD_TIMEZONES and TimezoneDatabase.isStandardTimezone(tzid):
+ continue
tz = self.getTimezone(tzid)
if tz is None:
# Find it in the static object
@@ -605,3 +634,22 @@
if tz is not None:
dup = tz.duplicate()
self.addComponent(dup)
+
+
+ def stripStandardTimezones(self):
+ """
+ Remove VTIMEZONE components from this L{Calendar} if the corresponding TZIDs are
+ in the timezone database.
+
+ @return: L{True} if changes were made, L{False} otherwise
+ @rtype: L{bool}
+ """
+ from pycalendar.timezonedb import TimezoneDatabase
+ changed = False
+ for component in self.getComponents(definitions.cICalComponent_VTIMEZONE):
+ tz = TimezoneDatabase.getTimezone(component.getID())
+ if tz is not None and TimezoneDatabase.isStandardTimezone(component.getID()):
+ self.removeComponent(component)
+ changed = True
+
+ return changed
Modified: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py 2014-06-30 14:57:51 UTC (rev 13706)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py 2014-07-01 16:36:05 UTC (rev 13707)
@@ -16,9 +16,9 @@
from pycalendar.exceptions import ValidationError
from pycalendar.icalendar.calendar import Calendar
-import unittest
+from pycalendar.tests.utils import TestPyCalendar
-class TestValidation(unittest.TestCase):
+class TestValidation(TestPyCalendar):
def test_basic(self):
@@ -1682,7 +1682,7 @@
for title, test_old, test_new, test_fixed, test_unfixed in data:
cal = Calendar.parseText(test_old)
fixed, unfixed = cal.validate(doFix=True)
- self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
+ self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (str(cal),))
self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
self.assertEqual(set(unfixed), test_unfixed, msg="Failed test: %s" % (title,))
Modified: PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py 2014-06-30 14:57:51 UTC (rev 13706)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py 2014-07-01 16:36:05 UTC (rev 13707)
@@ -106,4 +106,18 @@
definitions.cICalProperty_DTEND,
)
+
+ def getTimezones(self, tzids):
+ """
+ In addition to looking in the VAVAILABILITY component, we must also return any TZIDs used
+ in AVAILABLE child components.
+
+ @param tzids: result to report back
+ @type tzids: L{set}
+ """
+
+ super(VAvailability, self).getTimezones(tzids)
+ for available in self.getComponents(definitions.cICalComponent_AVAILABLE):
+ available.getTimezones(tzids)
+
Component.registerComponent(definitions.cICalComponent_VAVAILABILITY, VAvailability)
Added: PyCalendar/trunk/src/pycalendar/tests/test_timezonedb.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/tests/test_timezonedb.py (rev 0)
+++ PyCalendar/trunk/src/pycalendar/tests/test_timezonedb.py 2014-07-01 16:36:05 UTC (rev 13707)
@@ -0,0 +1,405 @@
+##
+# Copyright (c) 2012-2013 Cyrus Daboo. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from cStringIO import StringIO
+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.tests.utils import TestPyCalendar
+from pycalendar.timezonedb import TimezoneDatabase
+
+StandardTZs = (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//calendarserver.org//Zonal//EN
+BEGIN:VTIMEZONE
+TZID:America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:STANDARD
+DTSTART:18831118T120358
+RDATE:18831118T120358
+TZNAME:EST
+TZOFFSETFROM:-045602
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19180331T020000
+RRULE:FREQ=YEARLY;UNTIL=19190330T070000Z;BYDAY=-1SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19181027T020000
+RRULE:FREQ=YEARLY;UNTIL=19191026T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19200101T000000
+RDATE:19200101T000000
+RDATE:19420101T000000
+RDATE:19460101T000000
+RDATE:19670101T000000
+TZNAME:EST
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19200328T020000
+RDATE:19200328T020000
+RDATE:19740106T020000
+RDATE:19750223T020000
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19201031T020000
+RDATE:19201031T020000
+RDATE:19450930T020000
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19210424T020000
+RRULE:FREQ=YEARLY;UNTIL=19410427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19210925T020000
+RRULE:FREQ=YEARLY;UNTIL=19410928T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19420209T020000
+RDATE:19420209T020000
+TZNAME:EWT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19450814T190000
+RDATE:19450814T190000
+TZNAME:EPT
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19460428T020000
+RRULE:FREQ=YEARLY;UNTIL=19660424T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19460929T020000
+RRULE:FREQ=YEARLY;UNTIL=19540926T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19551030T020000
+RRULE:FREQ=YEARLY;UNTIL=19661030T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19670430T020000
+RRULE:FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;UNTIL=20061029T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19760425T020000
+RRULE:FREQ=YEARLY;UNTIL=19860427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//calendarserver.org//Zonal//EN
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+X-LIC-LOCATION:America/Los_Angeles
+BEGIN:STANDARD
+DTSTART:18831118T120702
+RDATE:18831118T120702
+TZNAME:PST
+TZOFFSETFROM:-075258
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19180331T020000
+RRULE:FREQ=YEARLY;UNTIL=19190330T100000Z;BYDAY=-1SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19181027T020000
+RRULE:FREQ=YEARLY;UNTIL=19191026T090000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19420209T020000
+RDATE:19420209T020000
+TZNAME:PWT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19450814T160000
+RDATE:19450814T160000
+TZNAME:PPT
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19450930T020000
+RDATE:19450930T020000
+RDATE:19490101T020000
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19460101T000000
+RDATE:19460101T000000
+RDATE:19670101T000000
+TZNAME:PST
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19480314T020000
+RDATE:19480314T020000
+RDATE:19740106T020000
+RDATE:19750223T020000
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19500430T020000
+RRULE:FREQ=YEARLY;UNTIL=19660424T100000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19500924T020000
+RRULE:FREQ=YEARLY;UNTIL=19610924T090000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19621028T020000
+RRULE:FREQ=YEARLY;UNTIL=19661030T090000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19670430T020000
+RRULE:FREQ=YEARLY;UNTIL=19730429T100000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;UNTIL=20061029T090000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19760425T020000
+RRULE:FREQ=YEARLY;UNTIL=19860427T100000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;UNTIL=20060402T100000Z;BYDAY=1SU;BYMONTH=4
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+""",
+)
+
+NonStandardTZs = (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//calendarserver.org//Zonal//EN
+BEGIN:VTIMEZONE
+TZID:America/Cupertino
+X-LIC-LOCATION:America/Cupertino
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+""",
+)
+
+
+class TestTimezoneDB(TestPyCalendar):
+
+ def setUp(self):
+ super(TestTimezoneDB, self).setUp()
+
+ # Standard components explicitly added
+ for vtz in StandardTZs:
+ cal = Calendar()
+ TimezoneDatabase.getTimezoneDatabase()._addStandardTimezone(cal.parseComponent(StringIO(vtz)))
+
+ # Just parsing will add as non-standard
+ for vtz in NonStandardTZs:
+ Calendar.parseData(vtz)
+
+
+ def test_getTimezone(self):
+ """
+ L{TimezoneDatabase.getTimezone} returns correct result.
+ """
+
+ data = (
+ ("America/New_York", True),
+ ("America/Los_Angeles", True),
+ ("America/Cupertino", True),
+ ("America/FooBar", False),
+ )
+
+ for tzid, result in data:
+ tz = TimezoneDatabase.getTimezone(tzid)
+ if result:
+ self.assertTrue(tz is not None)
+ self.assertEqual(tz.getID(), tzid)
+ else:
+ self.assertTrue(tz is None)
+
+
+ def test_getTimezoneInCalendar(self):
+ """
+ L{TimezoneDatabase.getTimezoneInCalendar} returns correct result.
+ """
+
+ data = (
+ ("America/New_York", True),
+ ("America/Los_Angeles", True),
+ ("America/Cupertino", True),
+ ("America/FooBar", False),
+ )
+
+ for tzid, result in data:
+ cal = TimezoneDatabase.getTimezoneInCalendar(tzid)
+ if result:
+ self.assertTrue(cal is not None)
+ self.assertEqual(cal.getComponents()[0].getID(), tzid)
+ else:
+ self.assertTrue(cal is None)
+
+
+ def test_isStandardTimezone(self):
+ """
+ L{TimezoneDatabase.isStandardTimezone} returns correct result.
+ """
+
+ data = (
+ ("America/New_York", True),
+ ("America/Los_Angeles", True),
+ ("America/Cupertino", False),
+ ("America/FooBar", False),
+ )
+
+ for tzid, result in data:
+ self.assertEqual(TimezoneDatabase.isStandardTimezone(tzid), result, "Failed {}".format(tzid))
Added: PyCalendar/trunk/src/pycalendar/tests/utils.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/tests/utils.py (rev 0)
+++ PyCalendar/trunk/src/pycalendar/tests/utils.py 2014-07-01 16:36:05 UTC (rev 13707)
@@ -0,0 +1,29 @@
+##
+# Copyright (c) 2012-2013 Cyrus Daboo. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from pycalendar.timezonedb import TimezoneDatabase
+import unittest
+
+class TestPyCalendar(unittest.TestCase):
+ """
+ Base class for all tests. This will do common setup/clean-up.
+ """
+
+ def setUp(self):
+ TimezoneDatabase.createTimezoneDatabase(None)
+
+ def tearDown(self):
+ TimezoneDatabase.clearTimezoneDatabase()
Modified: PyCalendar/trunk/src/pycalendar/timezonedb.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/timezonedb.py 2014-06-30 14:57:51 UTC (rev 13706)
+++ PyCalendar/trunk/src/pycalendar/timezonedb.py 2014-07-01 16:36:05 UTC (rev 13707)
@@ -43,6 +43,8 @@
from pycalendar.icalendar.calendar import Calendar
self.dbpath = None
self.calendar = Calendar()
+ self.tzcache = {}
+ self.stdtzcache = set()
def setPath(self, dbpath):
@@ -52,6 +54,8 @@
def clear(self):
from pycalendar.icalendar.calendar import Calendar
self.calendar = Calendar()
+ self.tzcache.clear()
+ self.stdtzcache.clear()
@staticmethod
@@ -63,20 +67,9 @@
@staticmethod
def getTimezone(tzid):
+ return TimezoneDatabase.getTimezoneDatabase()._getTimezone(tzid)
- # Check whether current cached
- tzdb = TimezoneDatabase.getTimezoneDatabase()
- tz = tzdb.calendar.getTimezone(tzid)
- if tz is None:
- try:
- tzdb.cacheTimezone(tzid)
- except NoTimezoneInDatabase:
- pass
- tz = tzdb.calendar.getTimezone(tzid)
- return tz
-
-
@staticmethod
def getTimezoneInCalendar(tzid):
"""
@@ -113,8 +106,20 @@
return ""
+ @staticmethod
+ def isStandardTimezone(tzid):
+ return TimezoneDatabase.getTimezoneDatabase()._isStandardTimezone(tzid)
+
+
def cacheTimezone(self, tzid):
+ """
+ Load the specified timezone identifier's timezone data from a file and parse it
+ into the L{Calendar} used to store timezones used by this object.
+ @param tzid: the timezone identifier to load
+ @type tzid: L{str}
+ """
+
if self.dbpath is None:
return
@@ -130,10 +135,67 @@
def addTimezone(self, tz):
+ """
+ Add the specified VTIMEZONE component to this object's L{Calendar} cache. This component
+ is assumed to be a non-standard timezone - i.e., not loaded from the timezone database.
+
+ @param tz: the VTIMEZONE component to add
+ @type tz: L{Component}
+ """
copy = tz.duplicate(self.calendar)
self.calendar.addComponent(copy)
+ self.tzcache[copy.getID()] = copy
+ def _addStandardTimezone(self, tz):
+ """
+ Same as L{addTimezone} except that the timezone is marked as a standard timezone. This
+ is only meant to be used for testing which happens int he absence of a real standard
+ timezone database.
+
+ @param tz: the VTIMEZONE component to add
+ @type tz: L{Component}
+ """
+ if tz.getID() not in self.tzcache:
+ self.addTimezone(tz)
+ self.stdtzcache.add(tz.getID())
+
+
+ def _isStandardTimezone(self, tzid):
+ """
+ Add the specified VTIMEZONE component to this object's L{Calendar} cache. This component
+ is assumed to be a non-standard timezone - i.e., not loaded from the timezone database.
+
+ @param tzid: the timezone identifier to lookup
+ @type tzid: L{str}
+ """
+ return tzid in self.stdtzcache
+
+
+ def _getTimezone(self, tzid):
+ """
+ Get a timezone matching the specified timezone identifier. Use this object's
+ cache - if not in the cache try to load it from a tz database file and store in
+ this object's calendar.
+
+ @param tzid: the timezone identifier to lookup
+ @type tzid: L{str}
+ """
+ if tzid not in self.tzcache:
+ tz = self.calendar.getTimezone(tzid)
+ if tz is None:
+ try:
+ self.cacheTimezone(tzid)
+ except NoTimezoneInDatabase:
+ pass
+ tz = self.calendar.getTimezone(tzid)
+ self.tzcache[tzid] = tz
+ if tz is not None and tzid is not None:
+ self.stdtzcache.add(tzid)
+
+ return self.tzcache[tzid]
+
+
@staticmethod
def mergeTimezones(cal, tzs):
"""
@@ -156,5 +218,5 @@
If the supplied VTIMEZONE is not in our cache then store it in memory.
"""
- if self.getTimezone(tz.getID()) is None:
+ if self._getTimezone(tz.getID()) is None:
self.addTimezone(tz)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140701/4ed2fa3e/attachment-0001.html>
More information about the calendarserver-changes
mailing list