# HG changeset patch # User Paul Boddie # Date 1512337522 -3600 # Node ID 864bd7461d3a3c8ccce0a9184974c0225c35dcee # Parent d1f864ab0a165810e1ab3ba843dd75748a86a7de Fixed inclusive (UNTIL) selection to avoid non-final selectors causing duplicate selection of values. Removed the 'first' attribute from all but the Pattern selector since it is only relevant to that selector's behaviour. diff -r d1f864ab0a16 -r 864bd7461d3a vRecurrence.py --- a/vRecurrence.py Sun Dec 03 21:59:54 2017 +0100 +++ b/vRecurrence.py Sun Dec 03 22:45:22 2017 +0100 @@ -534,6 +534,10 @@ # Add the qualifier to the combined list. + if isinstance(from_sel, Pattern): + if not have_sel: + have_sel = from_sel.first = True + l.append(from_sel) # Datetime value at same resolution. @@ -565,17 +569,16 @@ Take the selector 'from_sel' at the given resolution 'level', using it to create an initial selector, adding it to the combined list 'l' if required. - Return whether a frequency selector has been introduced or if 'from_sel' is - such a selector. + Return whether a frequency selector has been introduced. """ if isinstance(from_sel, Enum) and level > 0: parent_level = enum_parent_levels[level] - repeat = Pattern(parent_level, {"interval" : 1}, freq_levels[parent_level]) + repeat = Pattern(parent_level, {"interval" : 1}, freq_levels[parent_level], first=True) l.append(repeat) return True - return isinstance(from_sel, Pattern) + return False def add_datetime_selector(from_dt, l): @@ -871,7 +874,7 @@ "A generic selector." - def __init__(self, level, args, qualifier, selecting=None, first=False): + def __init__(self, level, args, qualifier, selecting=None): """ Initialise at the given 'level' a selector employing the given 'args' @@ -885,12 +888,11 @@ self.args = args or {} self.qualifier = qualifier self.selecting = selecting - self.first = first def __repr__(self): - return "%s(%s, %r, %r, %r)" % (self.__class__.__name__, - level_labels[self.level], - self.args, self.qualifier, self.first) + return "%s(%s, %r, %r)" % (self.__class__.__name__, + level_labels[self.level], + self.args, self.qualifier) def select(self, start, end, inclusive=False): @@ -926,8 +928,9 @@ "A selector of time periods according to a repeating pattern." def __init__(self, level, args, qualifier, selecting=None, first=False): - Selector.__init__(self, level, args, qualifier, selecting, first) + Selector.__init__(self, level, args, qualifier, selecting) multiple = get_multiple(self.qualifier) + self.first = first # Define the scale of a single period. @@ -977,8 +980,8 @@ "A generic value selector." - def __init__(self, level, args, qualifier, selecting=None, first=False): - Selector.__init__(self, level, args, qualifier, selecting, first) + def __init__(self, level, args, qualifier, selecting=None): + Selector.__init__(self, level, args, qualifier, selecting) self.step = scale(1, level) def materialise_items(self, context, start, end, inclusive=False): @@ -992,8 +995,8 @@ "A selector of instances specified in terms of day numbers." - def __init__(self, level, args, qualifier, selecting=None, first=False): - Selector.__init__(self, level, args, qualifier, selecting, first) + def __init__(self, level, args, qualifier, selecting=None): + Selector.__init__(self, level, args, qualifier, selecting) self.step = scale(1, WEEKS) def materialise_items(self, context, start, end, inclusive=False): @@ -1076,8 +1079,8 @@ "A result set position selector." - def __init__(self, level, args, qualifier, selecting=None, first=False): - Selector.__init__(self, level, args, qualifier, selecting, first) + def __init__(self, level, args, qualifier, selecting=None): + Selector.__init__(self, level, args, qualifier, selecting) if level is not None: self.set_level(level) else: @@ -1181,9 +1184,13 @@ def at_limit(self): - "Obtain periods before the end (and also at the end if inclusive)." + """ + Obtain periods before the end. If inclusive and selecting in the final + selector, obtain the period at the end. + """ - return not self.inclusive and self.current == self.end or \ + inclusive = self.inclusive and not self.selector.selecting + return not inclusive and self.current == self.end or \ self.current > self.end class PatternIterator(SelectorIterator): @@ -1462,40 +1469,36 @@ "Return the next value, initially the start period." - while not self.at_limit(): - - # Obtain the next item. - - try: - result = self.next_item(self.start, self.end) - except StopIteration: + # Obtain the next item. - # With no more values, flush any waiting value. + try: + result = self.next_item(self.start, self.end) + except StopIteration: - if self.waiting is not None: - result = self.waiting - self.waiting = None - return result - else: - raise - - # Compare with any waiting value. + # With no more values, flush any waiting value. if self.waiting is not None: - - # Produce the waiting value, queue the latest result. + result = self.waiting + self.waiting = None + return result + else: + raise - if result != self.waiting: - result, self.waiting = self.waiting, result + # Compare with any waiting value. + + if self.waiting is not None: - # Remove the waiting value if identical to the latest result. + # Produce the waiting value, queue the latest result. + + if result != self.waiting: + result, self.waiting = self.waiting, result - else: - self.waiting = None + # Remove the waiting value if identical to the latest result. - return result + else: + self.waiting = None - raise StopIteration + return result def connect_selectors(selectors): @@ -1506,18 +1509,10 @@ """ current = selectors[0] - current.first = first = True for selector in selectors[1:]: current.selecting = selector - - # Allow selectors within the limit selector to act as if they are first - # in the chain and will operate using the supplied datetime context. - - first = isinstance(current, (LimitSelector, StartSelector)) - current = selector - current.first = first return selectors[0]