1.1 --- a/vRecurrence.py Mon Oct 06 13:38:32 2014 +0200
1.2 +++ b/vRecurrence.py Mon Oct 06 15:04:31 2014 +0200
1.3 @@ -58,46 +58,40 @@
1.4 # Frequency levels, specified by FREQ in iCalendar.
1.5
1.6 freq_levels = (
1.7 - "SECONDLY",
1.8 - "MINUTELY",
1.9 - "HOURLY",
1.10 + "YEARLY",
1.11 + "MONTHLY",
1.12 + "WEEKLY",
1.13 "DAILY",
1.14 - "WEEKLY",
1.15 - "MONTHLY",
1.16 - "YEARLY"
1.17 + "HOURLY",
1.18 + "MINUTELY",
1.19 + "SECONDLY"
1.20 )
1.21
1.22 # Enumeration levels, employed by BY... qualifiers.
1.23
1.24 enum_levels = (
1.25 - ("BYSECOND",),
1.26 - ("BYMINUTE",),
1.27 + None,
1.28 + ("BYMONTH",),
1.29 + ("BYWEEKNO",),
1.30 + ("BYDAY", "BYMONTHDAY", "BYYEARDAY"),
1.31 ("BYHOUR",),
1.32 - ("BYDAY", "BYMONTHDAY", "BYYEARDAY"),
1.33 - ("BYWEEKNO",),
1.34 - ("BYMONTH",)
1.35 + ("BYMINUTE",),
1.36 + ("BYSECOND",)
1.37 )
1.38
1.39 # Map from levels to lengths of datetime tuples.
1.40
1.41 -lengths = [6, 5, 4, 3, 3, 2, 1]
1.42 +lengths = [1, 2, 3, 3, 4, 5, 6]
1.43 positions = [l-1 for l in lengths]
1.44
1.45 # Map from qualifiers to interval units. Here, weeks are defined as 7 days.
1.46
1.47 units = {"WEEKLY" : 7}
1.48
1.49 -# Map from tuple positions to base values at each resolution.
1.50 -
1.51 -bases = [0, 1, 1, 0, 0, 0]
1.52 -
1.53 -def basevalue(resolution):
1.54 - return bases[positions[resolution]]
1.55 -
1.56 # Make dictionaries mapping qualifiers to levels.
1.57
1.58 freq = dict([(level, i) for (i, level) in enumerate(freq_levels)])
1.59 -enum = dict([(level, i) for (i, levels) in enumerate(enum_levels) for level in levels])
1.60 +enum = dict([(level, i) for (i, levels) in enumerate(enum_levels) if levels for level in levels])
1.61
1.62 # Functions for structuring the recurrences.
1.63
1.64 @@ -125,10 +119,9 @@
1.65 level = freq[qualifier]
1.66 selector = Pattern
1.67
1.68 - pos = positions[level]
1.69 - l.append(selector(pos, args, qualifier))
1.70 + l.append(selector(level, args, qualifier))
1.71
1.72 - l.sort(key=lambda x: x.pos)
1.73 + l.sort(key=lambda x: x.level)
1.74 return l
1.75
1.76 def get_datetime_structure(datetime):
1.77 @@ -136,8 +129,11 @@
1.78 "Return the structure of 'datetime' for recurrence production."
1.79
1.80 l = []
1.81 - for pos, value in enumerate(datetime):
1.82 - l.append(Enum(pos, {"values" : [value]}, "DT"))
1.83 + offset = 0
1.84 + for level, value in enumerate(datetime):
1.85 + if level == 2:
1.86 + offset = 1
1.87 + l.append(Enum(level + offset, {"values" : [value]}, "DT"))
1.88 return l
1.89
1.90 def combine_datetime_with_qualifiers(datetime, qualifiers):
1.91 @@ -162,12 +158,12 @@
1.92 # Consume from both lists, merging entries.
1.93
1.94 while from_dt and from_q:
1.95 - _pos = from_dt.pos
1.96 - pos = from_q.pos
1.97 + _level = from_dt.level
1.98 + level = from_q.level
1.99
1.100 # Datetime value at wider resolution.
1.101
1.102 - if _pos < pos:
1.103 + if _level < level:
1.104 from_dt = get_next(iter_dt)
1.105 context.append(from_dt.args["values"][0])
1.106
1.107 @@ -175,8 +171,8 @@
1.108
1.109 else:
1.110 if not have_q:
1.111 - if isinstance(from_q, Enum) and pos > 0:
1.112 - repeat = Pattern(pos - 1, {"interval" : 1}, "REPEAT")
1.113 + if isinstance(from_q, Enum) and level > 0:
1.114 + repeat = Pattern(level - 1, {"interval" : 1}, "REPEAT")
1.115 repeat.context = tuple(context)
1.116 l.append(repeat)
1.117 else:
1.118 @@ -185,7 +181,7 @@
1.119
1.120 # Either introduce the qualifier first.
1.121
1.122 - if _pos > pos:
1.123 + if _level > level:
1.124 l.append(from_q)
1.125
1.126 # Or combine the qualifier and value details.
1.127 @@ -205,8 +201,8 @@
1.128
1.129 while from_q:
1.130 if not have_q:
1.131 - if isinstance(from_q, Enum) and pos > 0:
1.132 - repeat = Pattern(pos - 1, {"interval" : 1}, "REPEAT")
1.133 + if isinstance(from_q, Enum) and level > 0:
1.134 + repeat = Pattern(level - 1, {"interval" : 1}, "REPEAT")
1.135 repeat.context = tuple(context)
1.136 l.append(repeat)
1.137 else:
1.138 @@ -300,15 +296,16 @@
1.139 # Classes for producing instances from recurrence structures.
1.140
1.141 class Selector:
1.142 - def __init__(self, pos, args, qualifier, selecting=None):
1.143 - self.pos = pos
1.144 + def __init__(self, level, args, qualifier, selecting=None):
1.145 + self.level = level
1.146 + self.pos = positions[level]
1.147 self.args = args
1.148 self.qualifier = qualifier
1.149 self.context = ()
1.150 self.selecting = selecting
1.151
1.152 def __repr__(self):
1.153 - return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.pos, self.args, self.qualifier, self.context)
1.154 + return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.level, self.args, self.qualifier, self.context)
1.155
1.156 def materialise(self, start, end, count=None):
1.157 counter = count and [0, count]