pykolab/xml tests/unit

Thomas Brüderli bruederli at kolabsys.com
Tue Feb 17 17:19:14 CET 2015


 pykolab/xml/event.py         |   64 +++++++++++++++++++++++++++++++++++++++----
 tests/unit/test-003-event.py |    7 ++++
 2 files changed, 66 insertions(+), 5 deletions(-)

New commits:
commit 2eaa92b373c72e677bd72ff2a721c0e0cdcae86d
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Feb 16 20:33:59 2015 +0100

    Support RECURRENCE-ID property for iCal import/export

diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index 6242eaf..78a26dd 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -58,6 +58,7 @@ def event_from_message(message):
 
 class Event(object):
     type = 'event'
+    thisandfuture = False
 
     status_map = {
             None: kolabformat.StatusUndefined,
@@ -191,8 +192,9 @@ class Event(object):
 
         # NOTE: Make sure to list(set()) or duplicates may arise
         for attr in list(set(event.singletons)):
-            ical_getter = 'get_ical_%s' % (attr.lower())
-            default_getter = 'get_%s' % (attr.lower())
+            _attr = attr.lower().replace('-', '')
+            ical_getter = 'get_ical_%s' % (_attr)
+            default_getter = 'get_%s' % (_attr)
             retval = None
             if hasattr(self, ical_getter):
                 retval = getattr(self, ical_getter)()
@@ -205,8 +207,9 @@ class Event(object):
 
         # NOTE: Make sure to list(set()) or duplicates may arise
         for attr in list(set(event.multiple)):
-            ical_getter = 'get_ical_%s' % (attr.lower())
-            default_getter = 'get_%s' % (attr.lower())
+            _attr = attr.lower().replace('-', '')
+            ical_getter = 'get_ical_%s' % (_attr)
+            default_getter = 'get_%s' % (_attr)
             retval = None
             if hasattr(self, ical_getter):
                 retval = getattr(self, ical_getter)()
@@ -575,6 +578,16 @@ class Event(object):
             return [ comment ]
         return None
 
+    def get_ical_recurrenceid(self):
+        rid = self.get_recurrence_id()
+        if isinstance(rid, datetime.datetime) or isinstance(rid, datetime.date):
+            prop = icalendar.vDatetime(rid)
+            if self.thisandfuture:
+                prop.params.update({'RANGE':'THISANDFUTURE'})
+            return prop
+
+        return None
+
     def get_location(self):
         return self.event.location()
 
@@ -616,6 +629,14 @@ class Event(object):
             self.set_uid(uuid.uuid4())
             return self.get_uid()
 
+    def get_recurrence_id(self):
+        self.thisandfuture = self.event.thisAndFuture();
+        return xmlutils.from_cdatetime(self.event.recurrenceID(), True)
+
+    def get_thisandfuture(self):
+        self.thisandfuture = self.event.thisAndFuture();
+        return self.thisandfuture
+
     def get_sequence(self):
         return self.event.sequence()
 
@@ -698,6 +719,7 @@ class Event(object):
         attr = attr.replace('-', '')
         ical_setter = 'set_ical_' + attr
         default_setter = 'set_' + attr
+        params = value.params if hasattr(value, 'params') else {}
 
         if isinstance(value, icalendar.vDDDTypes) and hasattr(value, 'dt'):
             value = value.dt
@@ -706,6 +728,8 @@ class Event(object):
             self.add_category(value)
         elif attr == "class":
             self.set_classification(value)
+        elif attr == "recurrenceid":
+            self.set_ical_recurrenceid(value, params)
         elif hasattr(self, ical_setter):
             getattr(self, ical_setter)(value)
         elif hasattr(self, default_setter):
@@ -800,6 +824,13 @@ class Event(object):
     def set_ical_uid(self, uid):
         self.set_uid(str(uid))
 
+    def set_ical_recurrenceid(self, value, params):
+        try:
+            self.thisandfuture = params.get('RANGE', '') == 'THISANDFUTURE'
+            self.set_recurrence_id(value, self.thisandfuture)
+        except InvalidEventDateError, e:
+            pass
+
     def set_lastmodified(self, _datetime=None):
         valid_datetime = False
         if isinstance(_datetime, datetime.date):
@@ -875,6 +906,27 @@ class Event(object):
         self.uid = uid
         self.event.setUid(str(uid))
 
+    def set_recurrence_id(self, _datetime, _thisandfuture=None):
+        valid_datetime = False
+        if isinstance(_datetime, datetime.date):
+            valid_datetime = True
+
+        if isinstance(_datetime, datetime.datetime):
+            # If no timezone information is passed on, use the one from event start
+            if _datetime.tzinfo == None:
+                _start = self.get_start()
+                _datetime = _datetime.replace(tzinfo=_start.tzinfo)
+
+            valid_datetime = True
+
+        if not valid_datetime:
+            raise InvalidEventDateError, _("Event recurrence-id needs datetime.datetime instance")
+
+        if _thisandfuture is None:
+            _thisandfuture = self.thisandfuture
+
+        self.event.setRecurrenceID(xmlutils.to_cdatetime(_datetime), _thisandfuture)
+
     def set_transparency(self, transp):
         return self.event.setTransparency(transp)
 
@@ -1194,11 +1246,13 @@ class Event(object):
             instance = Event(from_string=str(self))
             instance.set_start(next_start)
             instance.set_recurrence(kolabformat.RecurrenceRule())  # remove recurrence rules
-            instance.event.setRecurrenceID(instance.event.start(), False)
+            instance.event.setRecurrenceID(xmlutils.to_cdatetime(next_start), False)
             next_end = self.get_occurence_end_date(next_start)
             if next_end:
                 instance.set_end(next_end)
 
+            # TODO: copy data from matching exception
+
             return instance
 
         return None
diff --git a/tests/unit/test-003-event.py b/tests/unit/test-003-event.py
index 67481e3..876dd57 100644
--- a/tests/unit/test-003-event.py
+++ b/tests/unit/test-003-event.py
@@ -25,6 +25,7 @@ UID:7a35527d-f783-4b58-b404-b1389bd2fc57
 DTSTAMP;VALUE=DATE-TIME:20140407T122311Z
 CREATED;VALUE=DATE-TIME:20140407T122245Z
 LAST-MODIFIED;VALUE=DATE-TIME:20140407T122311Z
+RECURRENCE-ID;TZID=Europe/Zurich;RANGE=THISANDFUTURE:20140523T110000
 DTSTART;TZID=Europe/Zurich;VALUE=DATE-TIME:20140523T110000
 DURATION:PT1H30M0S
 RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=10
@@ -389,6 +390,8 @@ METHOD:REQUEST
         self.assertIsInstance(event.get_exception_dates()[0], datetime.datetime)
         self.assertEqual(len(event.get_alarms()), 1)
         self.assertEqual(len(event.get_attachments()), 2)
+        self.assertIsInstance(event.get_recurrence_id(), datetime.datetime)
+        self.assertEqual(event.thisandfuture, True)
 
     def test_018_ical_to_message(self):
         event = event_from_ical(ical_event)
@@ -436,6 +439,7 @@ END:VEVENT
         self.event.set_sequence(3)
         self.event.set_classification('CONFIDENTIAL')
         self.event.add_custom_property('X-Custom', 'check')
+        self.event.set_recurrence_id(datetime.datetime(2014, 05, 23, 11, 0, 0), True)
 
         ical = icalendar.Calendar.from_ical(self.event.as_string_itip())
         event = ical.walk('VEVENT')[0]
@@ -446,6 +450,8 @@ END:VEVENT
         self.assertEqual(event['X-CUSTOM'], "check")
         self.assertIsInstance(event['dtstamp'].dt, datetime.datetime)
         self.assertEqual(event['class'], "CONFIDENTIAL")
+        self.assertIsInstance(event['recurrence-id'].dt, datetime.datetime)
+        self.assertEqual(event['recurrence-id'].params.get('RANGE'), 'THISANDFUTURE')
 
     def test_019_to_message_itip(self):
         self.event = Event()
@@ -529,6 +535,7 @@ END:VEVENT
         # check get_next_instance() which returns a clone of the base event
         next_instance = self.event.get_next_instance(next_date)
         self.assertIsInstance(next_instance, Event)
+        self.assertIsInstance(next_instance.get_recurrence_id(), datetime.datetime)
         self.assertEqual(self.event.get_summary(), next_instance.get_summary())
         self.assertEqual(next_instance.get_start().month, 7)
         self.assertFalse(next_instance.is_recurring())




More information about the commits mailing list