From 23993f5a2b470b9795f8348a0bfe5bf79797862e Mon Sep 17 00:00:00 2001 From: "George V. Reilly" Date: Thu, 22 Dec 2011 08:54:29 -0800 Subject: [PATCH] Added sorted_items. --- src/icalendar/caselessdict.py | 39 +++++++++++++++++++++++++++-------- src/icalendar/prop.py | 11 ++++------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/icalendar/caselessdict.py b/src/icalendar/caselessdict.py index 70c5554..2fc6287 100644 --- a/src/icalendar/caselessdict.py +++ b/src/icalendar/caselessdict.py @@ -1,29 +1,41 @@ # -*- coding: latin-1 -*- -def canonsort(keys, canonical_order=None): +def canonsort_keys(keys, canonical_order=None): """ Sorts leading keys according to canonical_order. Keys not specified in canonical_order will appear alphabetically at the end. - Keys are expected to be uppercase. >>> keys = ['DTEND', 'DTSTAMP', 'DTSTART', 'UID', 'SUMMARY', 'LOCATION'] - >>> canonsort(keys) + >>> canonsort_keys(keys) ['DTEND', 'DTSTAMP', 'DTSTART', 'LOCATION', 'SUMMARY', 'UID'] - >>> canonsort(keys, ('SUMMARY', 'DTSTART', 'DTEND', )) + >>> canonsort_keys(keys, ('SUMMARY', 'DTSTART', 'DTEND', )) ['SUMMARY', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'UID'] - >>> canonsort(keys, ('UID', 'DTSTART', 'DTEND', )) + >>> canonsort_keys(keys, ('UID', 'DTSTART', 'DTEND', )) ['UID', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'SUMMARY'] - >>> canonsort(keys, ('UID', 'DTSTART', 'DTEND', 'RRULE', 'EXDATE')) + >>> canonsort_keys(keys, ('UID', 'DTSTART', 'DTEND', 'RRULE', 'EXDATE')) ['UID', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'SUMMARY'] """ - canonical_map = dict((k.upper(), i) for i, k in enumerate(canonical_order or [])) + canonical_map = dict((k, i) for i, k in enumerate(canonical_order or [])) head = [k for k in keys if k in canonical_map] tail = [k for k in keys if k not in canonical_map] return sorted(head, key=lambda k: canonical_map[k]) + sorted(tail) +def canonsort_items(dict1, canonical_order=None): + """ + Returns a list of items from dict1, sorted by canonical_order. + + >>> d = dict(i=7, c='at', a=3.5, l=(2,3), e=[4,5], n=13, d={'x': 'y'}, r=1.0) + >>> canonsort_items(d) + [('a', 3.5), ('c', 'at'), ('d', {'x': 'y'}), ('e', [4, 5]), ('i', 7), ('l', (2, 3)), ('n', 13), ('r', 1.0)] + >>> canonsort_items(d, ('i', 'c', 'a')) + [('i', 7), ('c', 'at'), ('a', 3.5), ('d', {'x': 'y'}), ('e', [4, 5]), ('l', (2, 3)), ('n', 13), ('r', 1.0)] + """ + return [(k, dict1[k]) for k in canonsort_keys(dict1.keys(), canonical_order)] + class CaselessDict(dict): """ - A dictionary that isn't case sensitive, and only use string as keys. + A dictionary that isn't case sensitive, and only uses strings as keys. + Values retain their case. >>> ncd = CaselessDict(key1='val1', key2='val2') >>> ncd @@ -113,6 +125,8 @@ class CaselessDict(dict): def __repr__(self): return 'CaselessDict(' + dict.__repr__(self) + ')' + # A list of keys that must appear first in sorted_keys and sorted_items; + # must be uppercase. canonical_order = None def sorted_keys(self): @@ -120,4 +134,11 @@ class CaselessDict(dict): Sorts keys according to the canonical_order for the derived class. Keys not specified in canonical_order will appear at the end. """ - return canonsort(self.keys(), self.canonical_order) + return canonsort_keys(self.keys(), self.canonical_order) + + def sorted_items(self): + """ + Sorts items according to the canonical_order for the derived class. + Items not specified in canonical_order will appear at the end. + """ + return canonsort_items(self, self.canonical_order) diff --git a/src/icalendar/prop.py b/src/icalendar/prop.py index 6ce4f1f..48b8dc6 100644 --- a/src/icalendar/prop.py +++ b/src/icalendar/prop.py @@ -984,9 +984,11 @@ class vRecur(CaselessDict): frequencies = ["SECONDLY", "MINUTELY", "HOURLY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"] - canonical_order = [ "FREQ", "UNTIL", "COUNT", "INTERVAL", + # Mac iCal ignores RRULEs where FREQ is not the first rule part. + # Sorts parts according to the order listed in RFC 5545, section 3.3.10. + canonical_order = ( "FREQ", "UNTIL", "COUNT", "INTERVAL", "BYSECOND", "BYMINUTE", "BYHOUR", "BYDAY", "BYMONTHDAY", "BYYEARDAY", - "BYWEEKNO", "BYMONTH", "BYSETPOS", "WKST" ] + "BYWEEKNO", "BYMONTH", "BYSETPOS", "WKST" ) types = CaselessDict({ 'COUNT':vInt, @@ -1019,11 +1021,6 @@ class vRecur(CaselessDict): result.append('%s=%s' % (key, vals)) return ';'.join(result) - def sorted_items(self): - """Mac iCal ignores RRULEs where FREQ is not the first rule part. - Sorts parts according to the order listed in RFC 5545, section 3.3.10.""" - return [(k, self[k]) for k in self.canonical_order if self.get(k)] - def parse_type(key, values): # integers parser = vRecur.types.get(key, vText)