# HG changeset patch # User Paul Boddie # Date 1412600671 -7200 # Node ID 5c163feb89b58da90ecd2cd5d50ff6f3475adc76 # Parent f05956c21b4eaf68f7a71b4ba73d6c0d96f90343 Reversed the frequency level ordering and ordered criteria by levels instead of tuple positions, thus accommodating weekly criteria explicitly. diff -r f05956c21b4e -r 5c163feb89b5 vRecurrence.py --- a/vRecurrence.py Mon Oct 06 13:38:32 2014 +0200 +++ b/vRecurrence.py Mon Oct 06 15:04:31 2014 +0200 @@ -58,46 +58,40 @@ # Frequency levels, specified by FREQ in iCalendar. freq_levels = ( - "SECONDLY", - "MINUTELY", - "HOURLY", + "YEARLY", + "MONTHLY", + "WEEKLY", "DAILY", - "WEEKLY", - "MONTHLY", - "YEARLY" + "HOURLY", + "MINUTELY", + "SECONDLY" ) # Enumeration levels, employed by BY... qualifiers. enum_levels = ( - ("BYSECOND",), - ("BYMINUTE",), + None, + ("BYMONTH",), + ("BYWEEKNO",), + ("BYDAY", "BYMONTHDAY", "BYYEARDAY"), ("BYHOUR",), - ("BYDAY", "BYMONTHDAY", "BYYEARDAY"), - ("BYWEEKNO",), - ("BYMONTH",) + ("BYMINUTE",), + ("BYSECOND",) ) # Map from levels to lengths of datetime tuples. -lengths = [6, 5, 4, 3, 3, 2, 1] +lengths = [1, 2, 3, 3, 4, 5, 6] positions = [l-1 for l in lengths] # Map from qualifiers to interval units. Here, weeks are defined as 7 days. units = {"WEEKLY" : 7} -# Map from tuple positions to base values at each resolution. - -bases = [0, 1, 1, 0, 0, 0] - -def basevalue(resolution): - return bases[positions[resolution]] - # Make dictionaries mapping qualifiers to levels. freq = dict([(level, i) for (i, level) in enumerate(freq_levels)]) -enum = dict([(level, i) for (i, levels) in enumerate(enum_levels) for level in levels]) +enum = dict([(level, i) for (i, levels) in enumerate(enum_levels) if levels for level in levels]) # Functions for structuring the recurrences. @@ -125,10 +119,9 @@ level = freq[qualifier] selector = Pattern - pos = positions[level] - l.append(selector(pos, args, qualifier)) + l.append(selector(level, args, qualifier)) - l.sort(key=lambda x: x.pos) + l.sort(key=lambda x: x.level) return l def get_datetime_structure(datetime): @@ -136,8 +129,11 @@ "Return the structure of 'datetime' for recurrence production." l = [] - for pos, value in enumerate(datetime): - l.append(Enum(pos, {"values" : [value]}, "DT")) + offset = 0 + for level, value in enumerate(datetime): + if level == 2: + offset = 1 + l.append(Enum(level + offset, {"values" : [value]}, "DT")) return l def combine_datetime_with_qualifiers(datetime, qualifiers): @@ -162,12 +158,12 @@ # Consume from both lists, merging entries. while from_dt and from_q: - _pos = from_dt.pos - pos = from_q.pos + _level = from_dt.level + level = from_q.level # Datetime value at wider resolution. - if _pos < pos: + if _level < level: from_dt = get_next(iter_dt) context.append(from_dt.args["values"][0]) @@ -175,8 +171,8 @@ else: if not have_q: - if isinstance(from_q, Enum) and pos > 0: - repeat = Pattern(pos - 1, {"interval" : 1}, "REPEAT") + if isinstance(from_q, Enum) and level > 0: + repeat = Pattern(level - 1, {"interval" : 1}, "REPEAT") repeat.context = tuple(context) l.append(repeat) else: @@ -185,7 +181,7 @@ # Either introduce the qualifier first. - if _pos > pos: + if _level > level: l.append(from_q) # Or combine the qualifier and value details. @@ -205,8 +201,8 @@ while from_q: if not have_q: - if isinstance(from_q, Enum) and pos > 0: - repeat = Pattern(pos - 1, {"interval" : 1}, "REPEAT") + if isinstance(from_q, Enum) and level > 0: + repeat = Pattern(level - 1, {"interval" : 1}, "REPEAT") repeat.context = tuple(context) l.append(repeat) else: @@ -300,15 +296,16 @@ # Classes for producing instances from recurrence structures. class Selector: - def __init__(self, pos, args, qualifier, selecting=None): - self.pos = pos + def __init__(self, level, args, qualifier, selecting=None): + self.level = level + self.pos = positions[level] self.args = args self.qualifier = qualifier self.context = () self.selecting = selecting def __repr__(self): - return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.pos, self.args, self.qualifier, self.context) + return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.level, self.args, self.qualifier, self.context) def materialise(self, start, end, count=None): counter = count and [0, count]