[CalendarServer-changes] [3384] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Thu Nov 13 20:15:55 PST 2008


Revision: 3384
          http://trac.macosforge.org/projects/calendarserver/changeset/3384
Author:   cdaboo at apple.com
Date:     2008-11-13 20:15:55 -0800 (Thu, 13 Nov 2008)
Log Message:
-----------
Improve diff'ing of calendar data by doing more rigorous normalization of properties/parameters.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
    CalendarServer/trunk/twistedcaldav/test/test_icalendar.py

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2008-11-13 22:06:32 UTC (rev 3383)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2008-11-14 04:15:55 UTC (rev 3384)
@@ -58,6 +58,66 @@
     #"VAVAILABILITY",
 )
 
+# 2445 default values and parameters
+# Structure: propname: (<default value>, <parameter defaults dict>)
+
+normalizeProps = {
+    "CALSCALE":     ("GREGORIAN", {"VALUE": "TEXT"}),
+    "METHOD":       (None, {"VALUE": "TEXT"}),
+    "PRODID":       (None, {"VALUE": "TEXT"}),
+    "VERSION":      (None, {"VALUE": "TEXT"}),
+    "ATTACH":       (None, {"VALUE": "URI"}),
+    "CATEGORIES":   (None, {"VALUE": "TEXT"}),
+    "CLASS":        (None, {"VALUE": "TEXT"}),
+    "COMMENT":      (None, {"VALUE": "TEXT"}),
+    "DESCRIPTION":  (None, {"VALUE": "TEXT"}),
+    "GEO":          (None, {"VALUE": "FLOAT"}),
+    "LOCATION":     (None, {"VALUE": "TEXT"}),
+    "PERCENT-COMPLETE": (None, {"VALUE": "INTEGER"}),
+    "PRIORITY":     ("0", {"VALUE": "INTEGER"}),
+    "RESOURCES":    (None, {"VALUE": "TEXT"}),
+    "STATUS":       (None, {"VALUE": "TEXT"}),
+    "SUMMARY":      (None, {"VALUE": "TEXT"}),
+    "COMPLETED":    (None, {"VALUE": "DATE-TIME"}),
+    "DTEND":        (None, {"VALUE": "DATE-TIME"}),
+    "DUE":          (None, {"VALUE": "DATE-TIME"}),
+    "DTSTART":      (None, {"VALUE": "DATE-TIME"}),
+    "DURATION":     (None, {"VALUE": "DURATION"}),
+    "FREEBUSY":     (None, {"VALUE": "PERIOD"}),
+    "TRANSP":       ("OPAQUE", {"VALUE": "TEXT"}),
+    "TZID":         (None, {"VALUE": "TEXT"}),
+    "TZNAME":       (None, {"VALUE": "TEXT"}),
+    "TZOFFSETFROM": (None, {"VALUE": "UTC-OFFSET"}),
+    "TZOFFSETTO":   (None, {"VALUE": "UTC-OFFSET"}),
+    "TZURL":        (None, {"VALUE": "URI"}),
+    "ATTENDEE":     (None, {
+        "VALUE": "CAL-ADDRESS",
+        "CUTYPE": "INDIVIDUAL",
+        "ROLE": "REQ-PARTICIPANT",
+        "PARTSTAT": "NEEDS-ACTION",
+        "RSVP": "FALSE",
+        
+    }),
+    "CONTACT":      (None, {"VALUE": "TEXT"}),
+    "ORGANIZER":    (None, {"VALUE": "CAL-ADDRESS"}),
+    "RECURRENCE-ID": (None, {"VALUE": "DATE-TIME"}),
+    "RELATED-TO":   (None, {"VALUE": "TEXT"}),
+    "URL":          (None, {"VALUE": "URI"}),
+    "UID":          (None, {"VALUE": "TEXT"}),
+    "EXDATE":       (None, {"VALUE": "DATE-TIME"}),
+    "EXRULE":       (None, {"VALUE": "RECUR"}),
+    "RDATE":        (None, {"VALUE": "DATE-TIME"}),
+    "RRULE":        (None, {"VALUE": "RECUR"}),
+    "ACTION":       (None, {"VALUE": "TEXT"}),
+    "REPEAT":       ("0", {"VALUE": "INTEGER"}),
+    "TRIGGER":      (None, {"VALUE": "DURATION"}),
+    "CREATED":      (None, {"VALUE": "DATE-TIME"}),
+    "DTSTAMP":      (None, {"VALUE": "DATE-TIME"}),
+    "LAST-MODIFIED": (None, {"VALUE": "DATE-TIME"}),
+    "SEQUENCE":     ("0", {"VALUE": "INTEGER"}),
+    "REQUEST-STATUS": (None, {"VALUE": "TEXT"}),
+}
+
 class Property (object):
     """
     iCalendar Property
@@ -1553,6 +1613,32 @@
                     except ValueError:
                         pass
 
+    def normalizeAll(self):
+        
+        # Normalize all properties
+        for prop in tuple(self.properties()):
+            result = normalizeProps.get(prop.name())
+            if result:
+                default_value, default_params = result
+            else:
+                # Assume default VALUE is TEXT
+                default_value = None
+                default_params = {"VALUE": "TEXT"}
+            
+            # Remove any default parameters
+            for name, value in prop.params().items():
+                if value == [default_params.get(name),]:
+                    del prop.params()[name]
+            
+            # If there are no parameters, remove the property if it has the default value
+            if len(prop.params()) == 0:
+                if prop.value() == default_value:
+                    self.removeProperty(prop)
+
+        # Do to all sub-components too
+        for component in self.subcomponents():
+            component.normalizeAll()
+
     def normalizePropertyValueLists(self, propname):
         """
         Convert properties that have a list of values into single properties, to make it easier

Modified: CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2008-11-13 22:06:32 UTC (rev 3383)
+++ CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2008-11-14 04:15:55 UTC (rev 3384)
@@ -68,7 +68,7 @@
             ))
             calendar.removeXProperties()
             calendar.removePropertyParameters("ATTENDEE", ("RSVP", "SCHEDULE-AGENT", "SCHEDULE-STATUS",))
-            calendar.removePropertyParametersByValue("ATTENDEE", (("PARTSTAT", "NEEDS-ACTION"),))
+            calendar.normalizeAll()
             return calendar
         
         # Normalize components for comparison
@@ -229,6 +229,7 @@
             calendar = calendar.duplicate()
             calendar.normalizePropertyValueLists("EXDATE")
             calendar.removePropertyParameters("ORGANIZER", ("SCHEDULE-STATUS",))
+            calendar.normalizeAll()
             iTipGenerator.prepareSchedulingMessage(calendar, reply=True)
             return calendar
 

Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2008-11-13 22:06:32 UTC (rev 3383)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2008-11-14 04:15:55 UTC (rev 3384)
@@ -17,6 +17,7 @@
 import os
 import datetime
 from dateutil.tz import tzutc
+from difflib import unified_diff
 
 from twisted.trial.unittest import SkipTest
 
@@ -1956,4 +1957,71 @@
             component_result = Component.fromString(result)
             component_to.transferProperties(component_from, propnames)
             self.assertEqual(str(component_to), str(component_result), "%s: mismatch" % (description,))
-       
+
+    def test_normalize_all(self):
+        
+        data = (
+            (
+                "1.1",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART;VALUE=DATE-TIME:20071114T000000Z
+SEQUENCE:0
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+            (
+                "1.2",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART;VALUE=DATE-TIME:20071114T000000Z
+TRANSP:OPAQUE
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user03 at example.com
+ATTENDEE;RSVP=FALSE:mailto:user04 at example.com
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;RSVP=TRUE:mailto:user02 at example.com
+ATTENDEE:mailto:user03 at example.com
+ATTENDEE:mailto:user04 at example.com
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+        )
+        
+        for title, original, result in data:
+            ical1 = Component.fromString(original)
+            ical1.normalizeAll()
+            ical1 = str(ical1)
+            ical2 = Component.fromString(result)
+            ical2 = str(ical2)
+            diff = "\n".join(unified_diff(ical1.split("\n"), ical2.split("\n")))
+            self.assertEqual(str(ical1), str(ical2), "Failed comparison: %s\n%s" % (title, diff,))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20081113/72706f2b/attachment-0001.html>


More information about the calendarserver-changes mailing list