Exemplo n.º 1
0
 def occurrences(self, limit_start=None, limit_end=None):
     starts = recurrence_sequence_ical(
             self.context.start,
             recrule=self.context.recurrence,
             from_=limit_start, until=limit_end)
     ends = recurrence_sequence_ical(
             self.context.end,
             recrule=self.context.recurrence,
             from_=limit_start, until=limit_end)
     events = map(lambda start,end:(start, end), starts, ends)
     return events
Exemplo n.º 2
0
def occurences_start(obj,
                     propertyname,
                     from_=None,
                     until=None,
                     hours=None,
                     minutes=None):
    oid = get_oid(obj, None)
    if oid is not None:
        index = find_catalog('lac')[dates_mapping.get(
            propertyname + '_start_date', propertyname + '_start_date')]
        results = index._rev_index.get(oid, ())
        results = occurences_until(until, results, True)
        results = occurences_from(from_, results, True)
        results = [int2dt(d, hours, minutes) for d in results]
    else:
        start = getattr(obj, propertyname + '_start_date', None)
        if hours is not None and minutes is not None:
            start = datetime.datetime.combine(
                start, datetime.time(hours, minutes, 0, tzinfo=pytz.UTC))

        recurrence = getattr(obj, propertyname + '_recurrence', '')
        if not recurrence:
            results = [start]
        else:
            results = list(
                recurrence_sequence_ical(start,
                                         recrule=recurrence,
                                         from_=from_,
                                         until=until))
    return results
Exemplo n.º 3
0
 def test_start(self):
     from plone.event.recurrence import recurrence_sequence_ical
     from datetime import datetime
     start = datetime(2011, 11, 23)
     seq = recurrence_sequence_ical(start)
     results = [res for res in seq]
     self.assertEqual(len(results), 1)
Exemplo n.º 4
0
def occurences_start(obj, propertyname, from_=None, until=None,
                     hours=None, minutes=None):
    oid = get_oid(obj, None)
    if oid is not None:
        index = find_catalog('lac')[
            dates_mapping.get(
                propertyname + '_start_date',
                propertyname + '_start_date')]
        results = index._rev_index.get(oid, ())
        results = occurences_until(until, results, True)
        results = occurences_from(from_, results, True)
        results = [int2dt(d, hours, minutes) for d in results]
    else:
        start = getattr(obj, propertyname + '_start_date', None)
        if hours is not None and minutes is not None:
            start = datetime.datetime.combine(
                start, datetime.time(hours, minutes, 0, tzinfo=pytz.UTC))

        recurrence = getattr(obj, propertyname + '_recurrence', '')
        if not recurrence:
            results = [start]
        else:
            results = list(recurrence_sequence_ical(start, recrule=recurrence,
                                                    from_=from_, until=until))
    return results
Exemplo n.º 5
0
    def test_recrule_until_with_timezone(self):
        from plone.event.recurrence import recurrence_sequence_ical
        from datetime import datetime

        start = datetime(2011, 11, 24)
        recrule = "RRULE:FREQ=DAILY;UNTIL=20111130T000000Z"
        seq = list(recurrence_sequence_ical(start, recrule=recrule))
        self.assertEqual(len(seq), 7)
Exemplo n.º 6
0
 def test_recrule_str_more_than_MAXCOUNT(self):
     from plone.event.recurrence import recurrence_sequence_ical
     from datetime import datetime
     start = datetime(2011, 11, 23)
     recrule = "FREQ=DAILY;INTERVAL=10;COUNT=1001"
     seq = recurrence_sequence_ical(start, recrule=recrule)
     results = [res for res in seq]
     self.assertEqual(len(results), 1000)
Exemplo n.º 7
0
def occurrences_over_limit(rule, start, limit):

    assert rule and start and limit

    for i, o in enumerate(recurrence_sequence_ical(start=start, recrule=rule)):
        if i + 1 > limit:
            return True

    return False
Exemplo n.º 8
0
def occurrences_over_limit(rule, start, limit):

    assert rule and start and limit

    for i, o in enumerate(recurrence_sequence_ical(start=start, recrule=rule)):
        if i + 1 > limit:
            return True

    return False
Exemplo n.º 9
0
 def test_recrule_until(self):
     from plone.event.recurrence import recurrence_sequence_ical
     from datetime import datetime
     start = datetime(2011, 11, 24)
     recrule = "FREQ=DAILY;INTERVAL=1;COUNT=5"
     from_ = datetime(2011, 11, 23)
     until = datetime(2011, 11, 27)
     seq = recurrence_sequence_ical(start, recrule=recrule,
                                    from_=from_, until=until)
     results = [res for res in seq]
     self.assertEqual(len(results), 4)
Exemplo n.º 10
0
 def test_recrule_from_until(self):
     from plone.event.recurrence import recurrence_sequence_ical
     from datetime import datetime
     start = datetime(2011, 11, 23)
     recrule = None
     from_ = datetime(2011, 11, 01)
     until = datetime(2011, 12, 31)
     seq = recurrence_sequence_ical(start, recrule=recrule,
                                    from_=from_, until=until)
     results = [res for res in seq]
     self.assertEqual(len(results), 1)
Exemplo n.º 11
0
def has_future_occurrences(item, reference_date):

    if not item.recurrence:
        return reference_date <= item.start

    futures = recurrence_sequence_ical(
        item.start, recrule=item.recurrence, from_=reference_date
    )

    try:
        return bool(futures.next())
    except StopIteration:
        return False
Exemplo n.º 12
0
def has_future_occurrences(item, reference_date):

    if not item.recurrence:
        return reference_date <= item.start

    futures = recurrence_sequence_ical(item.start,
                                       recrule=item.recurrence,
                                       from_=reference_date)

    try:
        return bool(futures.next())
    except StopIteration:
        return False
Exemplo n.º 13
0
    def test_recrule_str_rdate(self):
        """Test, if an RDATE date has the correct time set.
            See: "BUGFIX WRONG RDATE TIME" in recurrence.py
        """
        from plone.event.recurrence import recurrence_sequence_ical
        from datetime import datetime
        start = datetime(2011, 11, 23, 10, 10)
        recrule = """FREQ=DAILY;INTERVAL=1;COUNT=3
RDATE:20111129T000000"""
        seq = recurrence_sequence_ical(start, recrule=recrule)
        results = [res for res in seq]
        self.assertEqual(len(results), 4)
        self.assertEqual(results[0].time(), results[-1].time())
Exemplo n.º 14
0
    def occurrences(self, range_start=None, range_end=None):
        """Return all occurrences of an event, possibly within a start and end
        limit.

        :param range_start: Optional start datetime, from which you want
                            occurrences be returned.
        :type range_start: Python datetime
        :param range_end: Optional start datetime, from which you want
                          occurrences be returned.
        :type range_end: Python datetime
        :returns: List of occurrences, including the start event.
        :rtype: IEvent or IOccurrence based objects

        Please note: Events beginning before range_start but ending afterwards
                     won't be found.

        TODO: really?

        TODO: test with event start = 21st feb, event end = start+36h,
        recurring for 10 days, range_start = 1st mar, range_end = last Mark
        """
        event = IEventAccessor(self.context)

        # We get event ends by adding a duration to the start. This way, we
        # prevent that the start and end lists are of different size if an
        # event starts before range_start but ends afterwards.
        duration = event.duration

        starts = recurrence_sequence_ical(event.start,
                                          recrule=event.recurrence,
                                          from_=range_start,
                                          until=range_end,
                                          duration=duration)

        # XXX potentially occurrence won't need to be wrapped anymore
        # but doing it for backwards compatibility as views/templates
        # still rely on acquisition-wrapped objects.
        def get_obj(start):
            if pydt(event.start.replace(microsecond=0)) == start:
                # If the occurrence date is the same as the event object, the
                # occurrence is the event itself. return it as such.
                # Dates from recurrence_sequence_ical are explicitly without
                # microseconds, while event.start may contain it. So we have to
                # remove it for a valid comparison.
                return self.context
            return Occurrence(id=str(start.date()),
                              start=start,
                              end=start + duration).__of__(self.context)

        for start in starts:
            yield get_obj(start)
Exemplo n.º 15
0
    def occurrences(self, range_start=None, range_end=None):
        """Return all occurrences of an event, possibly within a start and end
        limit.

        :param range_start: Optional start datetime, from which you want
                            occurrences be returned.
        :type range_start: Python datetime
        :param range_end: Optional start datetime, from which you want
                          occurrences be returned.
        :type range_end: Python datetime
        :returns: List of occurrences, including the start event.
        :rtype: IEvent or IOccurrence based objects

        Please note: Events beginning before range_start but ending afterwards
                     won't be found.

        TODO: really?

        TODO: test with event start = 21st feb, event end = start+36h,
        recurring for 10 days, range_start = 1st mar, range_end = last Mark
        """
        event = IEventAccessor(self.context)

        # We get event ends by adding a duration to the start. This way, we
        # prevent that the start and end lists are of different size if an
        # event starts before range_start but ends afterwards.
        duration = event.duration

        starts = recurrence_sequence_ical(event.start,
                                          recrule=event.recurrence,
                                          from_=range_start, until=range_end,
                                          duration=duration)

        # XXX potentially occurrence won't need to be wrapped anymore
        # but doing it for backwards compatibility as views/templates
        # still rely on acquisition-wrapped objects.
        def get_obj(start):
            if pydt(event.start.replace(microsecond=0)) == start:
                # If the occurrence date is the same as the event object, the
                # occurrence is the event itself. return it as such.
                # Dates from recurrence_sequence_ical are explicitly without
                # microseconds, while event.start may contain it. So we have to
                # remove it for a valid comparison.
                return self.context
            return Occurrence(
                id=str(start.date()),
                start=start,
                end=start + duration).__of__(self.context)

        for start in starts:
            yield get_obj(start)
Exemplo n.º 16
0
    def discriminate(self, obj, default):
        """ See interface IIndexInjection """
        if callable(self.discriminator):
            value = self.discriminator(obj, _marker)
        else:
            value = getattr(obj, self.discriminator, _marker)

        if value is _marker:
            return default

        if isinstance(value, Persistent):
            raise ValueError('Catalog cannot index persistent object %s' %
                             value)

        if isinstance(value, Broken):
            raise ValueError('Catalog cannot index broken object %s' %
                             value)

        if not isinstance(value, dict):
            raise ValueError('Catalog can only index dict with '
                'attr and date keys, or date and recurdef keys, given %s' %
                             value)
        # examples:
        # {'attr': 'dates',
        #  'date': datetime.datetime.now()}
        # will get dates_recurrence attribute on the obj to get iCal string
        # for recurrence definition
        # or
        # {'date': datetime.datetime.now(),
        #  'recurdef': ICALSTRING}
        # no access to obj attributes at all

        date = value.get('date')
        default_recurdef = value.get('recurdef', _marker)
        if default_recurdef is not _marker:
            recurdef = default_recurdef
        else:
            attr_recurdef = value.get('attr') + '_recurrence'
            recurdef = getattr(obj, attr_recurdef, None)

        if callable(recurdef):
            recurdef = recurdef()

        if not recurdef:
            dates = [date]
        else:
            dates = recurrence_sequence_ical(date, recrule=recurdef)

        # dates is a generator
        return tuple(dates)
Exemplo n.º 17
0
    def discriminate(self, obj, default):
        """ See interface IIndexInjection """
        if callable(self.discriminator):
            value = self.discriminator(obj, _marker)
        else:
            value = getattr(obj, self.discriminator, _marker)

        if value is _marker:
            return default

        if isinstance(value, Persistent):
            raise ValueError('Catalog cannot index persistent object %s' %
                             value)

        if isinstance(value, Broken):
            raise ValueError('Catalog cannot index broken object %s' % value)

        if not isinstance(value, dict):
            raise ValueError(
                'Catalog can only index dict with '
                'attr and date keys, or date and recurdef keys, given %s' %
                value)
        # examples:
        # {'attr': 'dates',
        #  'date': datetime.datetime.now()}
        # will get dates_recurrence attribute on the obj to get iCal string
        # for recurrence definition
        # or
        # {'date': datetime.datetime.now(),
        #  'recurdef': ICALSTRING}
        # no access to obj attributes at all

        date = value.get('date')
        default_recurdef = value.get('recurdef', _marker)
        if default_recurdef is not _marker:
            recurdef = default_recurdef
        else:
            attr_recurdef = value.get('attr') + '_recurrence'
            recurdef = getattr(obj, attr_recurdef, None)

        if callable(recurdef):
            recurdef = recurdef()

        if not recurdef:
            dates = [date]
        else:
            dates = recurrence_sequence_ical(date, recrule=recurdef)

        # dates is a generator
        return tuple(dates)
Exemplo n.º 18
0
 def test_recrule_from_until_with_duration(self):
     """Should include events ranging into the queried timerange.
     """
     from plone.event.recurrence import recurrence_sequence_ical
     from datetime import datetime
     from datetime import timedelta
     start = datetime(2011, 11, 23)
     recrule = "FREQ=DAILY;INTERVAL=1;COUNT=5"
     from_ = datetime(2011, 11, 26)
     until = datetime(2011, 11, 27)
     seq = recurrence_sequence_ical(start, recrule=recrule,
                                    from_=from_, until=until,
                                    duration=timedelta(days=2))
     results = [res for res in seq]
     self.assertEqual(len(results), 4)
Exemplo n.º 19
0
def _get_ical_dates(obj, name, date_type):
    attr_recurdef = name + '_recurrence'
    recurdef = getattr(obj, attr_recurdef, None)
    date = getattr(obj, name + date_type)
    if callable(recurdef):
        recurdef = recurdef()

    if date:
        if not recurdef:
            dates = [date]
        else:
            dates = recurrence_sequence_ical(date, recrule=recurdef)

        return dates

    return []
Exemplo n.º 20
0
    def occurrences(self, range_start=None, range_end=None):
        """ Return all occurrences of an event, possibly within a start and end
        limit.

        Please note: Events beginning before range_start but ending afterwards
                     won't be found.

        TODO: test with event start = 21st feb, event end = start+36h,
        recurring for 10 days, range_start = 1st mar, range_end = last Mark

        """
        event = IEventAccessor(self.context)
        starts = recurrence_sequence_ical(event.start,
                                          recrule=event.recurrence,
                                          from_=range_start,
                                          until=range_end)

        if range_start and\
            event.start < range_start and\
            event.end >= range_start and\
            event.start not in starts:
            # Include event, which started before range but lasts until it.
            starts = itertools.chain(starts, [event.start])

        # We get event ends by adding a duration to the start. This way, we
        # prevent that the start and end lists are of different size if an
        # event starts before range_start but ends afterwards.
        duration = event.duration

        # XXX potentially occurrence won't need to be wrapped anymore
        # but doing it for backwards compatibility as views/templates
        # still rely on acquisition-wrapped objects.
        def get_obj(start):
            if event.start.replace(microsecond=0) == start:
                # If the occurrence date is the same as the event object, the
                # occurrence is the event itself. return it as such.
                # Dates from recurrence_sequence_ical are explicitly without
                # microseconds, while event.start may contain it. So we have to
                # remove it for a valid comparison.
                return self.context
            return Occurrence(id=str(start.date()),
                              start=start,
                              end=start + duration).__of__(self.context)

        events = map(get_obj, starts)
        return events
Exemplo n.º 21
0
 def test_recrule_str_exdate(self):
     """Test, if an EXDATE date are not in the resulting recurrence set.
     """
     from plone.event.recurrence import recurrence_sequence_ical
     from datetime import datetime
     import pytz
     at = pytz.timezone("Europe/Vienna")
     start = at.localize(datetime(2013, 6, 29, 10, 10))
     recrule = 'RRULE:FREQ=DAILY;COUNT=4\r\nEXDATE:20130630T000000,20130701T000000\r\nRDATE:20130706T000000,20130809T000000'
     seq = recurrence_sequence_ical(start, recrule=recrule)
     res = [res for res in seq]
     res_test = [at.localize(datetime(2013, 6, 29, 10, 10)),
                 at.localize(datetime(2013, 7, 2, 10, 10)),
                 at.localize(datetime(2013, 7, 6, 10, 10)),
                 at.localize(datetime(2013, 8, 9, 10, 10))]
     self.assertEqual(len(res), 4)
     self.assertEqual(res, res_test)
Exemplo n.º 22
0
    def occurrences(self, range_start=None, range_end=None):
        """ Return all occurrences of an event, possibly within a start and end
        limit.

        Please note: Events beginning before range_start but ending afterwards
                     won't be found.

        TODO: test with event start = 21st feb, event end = start+36h,
        recurring for 10 days, range_start = 1st mar, range_end = last Mark

        """
        event = IEventAccessor(self.context)
        starts = recurrence_sequence_ical(event.start,
                                          recrule=event.recurrence,
                                          from_=range_start, until=range_end)

        if range_start and\
            event.start < range_start and\
            event.end >= range_start and\
            event.start not in starts:
            # Include event, which started before range but lasts until it.
            starts = itertools.chain(starts, [event.start])

        # We get event ends by adding a duration to the start. This way, we
        # prevent that the start and end lists are of different size if an
        # event starts before range_start but ends afterwards.
        duration = event.duration

        # XXX potentially occurrence won't need to be wrapped anymore
        # but doing it for backwards compatibility as views/templates
        # still rely on acquisition-wrapped objects.
        def get_obj(start):
            if event.start.replace(microsecond=0) == start:
                # If the occurrence date is the same as the event object, the
                # occurrence is the event itself. return it as such.
                # Dates from recurrence_sequence_ical are explicitly without
                # microseconds, while event.start may contain it. So we have to
                # remove it for a valid comparison.
                return self.context
            return Occurrence(
                id=str(start.date()),
                start=start,
                end=start + duration).__of__(self.context)

        events = map(get_obj, starts)
        return events
Exemplo n.º 23
0
 def test_recrule_str_until(self):
     """Test, if UNTIL stops the sequence at the end of the day, even if
     it's set to 0:00 by the recurrence widget.
     """
     from plone.event.recurrence import recurrence_sequence_ical
     from datetime import datetime
     import pytz
     at = pytz.timezone("Europe/Vienna")
     start = at.localize(datetime(2013, 6, 29, 10, 10))
     recrule = 'RRULE:FREQ=DAILY;UNTIL=20130702T000000'
     seq = recurrence_sequence_ical(start, recrule=recrule)
     res = [res for res in seq]
     res_test = [at.localize(datetime(2013, 6, 29, 10, 10)),
                 at.localize(datetime(2013, 6, 30, 10, 10)),
                 at.localize(datetime(2013, 7, 1, 10, 10)),
                 at.localize(datetime(2013, 7, 2, 10, 10))]
     self.assertEqual(len(res), 4)
     self.assertEqual(res, res_test)
Exemplo n.º 24
0
def occurrences(item, min_date, max_date):
    """ Returns the occurrences for item between min and max date.
    Will return a list with a single item if the given item has no recurrence.

    """

    if not isinstance(item.start, datetime):
        item_start = dates.to_utc(datetime.utcfromtimestamp(item.start))
    else:
        item_start = item.start

    if not isinstance(item.end, datetime):
        item_end = dates.to_utc(datetime.utcfromtimestamp(item.end))
    else:
        item_end = item.end

    if not item.recurrence:

        if not overlaps(min_date, max_date, item_start, item_end):
            return []
        else:
            return [Occurrence(item, item_start, item_end)]

    tz = pytz.timezone(item.timezone)
    local_start = tz.normalize(item_start)

    _occurrences = recurrence_sequence_ical(
        start=local_start,
        recrule=item.recurrence,
        from_=min_date,
        until=max_date
    )

    result = []
    duration = item_end - item_start

    for start in _occurrences:
        start = utcoffset_normalize(start, dstmode=DSTADJUST)
        result.append(Occurrence(item, start, start + duration))

    return result
Exemplo n.º 25
0
def occurrences(item, min_date, max_date):
    """ Returns the occurrences for item between min and max date.
    Will return a list with a single item if the given item has no recurrence.

    """

    if not isinstance(item.start, datetime):
        item_start = dates.to_utc(datetime.utcfromtimestamp(item.start))
    else:
        item_start = item.start

    if not isinstance(item.end, datetime):
        item_end = dates.to_utc(datetime.utcfromtimestamp(item.end))
    else:
        item_end = item.end

    if not item.recurrence:

        if not overlaps(min_date, max_date, item_start, item_end):
            return []
        else:
            return [Occurrence(item, item_start, item_end)]

    tz = pytz.timezone(item.timezone)
    local_start = tz.normalize(item_start)

    _occurrences = recurrence_sequence_ical(start=local_start,
                                            recrule=item.recurrence,
                                            from_=min_date,
                                            until=max_date)

    result = []
    duration = item_end - item_start

    for start in _occurrences:
        start = utcoffset_normalize(start, dstmode=DSTADJUST)
        result.append(Occurrence(item, start, start + duration))

    return result
Exemplo n.º 26
0
    def occurrences(self, range_start=None, range_end=None):
        """ Return all occurrences of an event, possibly within a start and end
        limit.

        Please note: Events beginning before range_start but ending afterwards
                     won't be found.

        TODO: test with event start = 21st feb, event end = start+36h,
        recurring for 10 days, range_start = 1st mar, range_end = last Mark

        """
        event = IEventAccessor(self.context)
        starts = recurrence_sequence_ical(event.start,
                                          recrule=event.recurrence,
                                          from_=range_start, until=range_end)

        # We get event ends by adding a duration to the start. This way, we
        # prevent that the start and end lists are of different size if an
        # event starts before range_start but ends afterwards.
        duration = event.duration

        # XXX potentially occurrence won't need to be wrapped anymore
        # but doing it for backwards compatibility as views/templates
        # still rely on acquisition-wrapped objects.
        def get_obj(start):
            if event.start == start:
                # If the occurrence date is the same as the event object, the
                # occurrence is the event itself. return it as such.
                return self.context
            return Occurrence(
                id=str(start.date()),
                start=start,
                end=start + duration).__of__(self.context)

        events = map(get_obj, starts)
        return events
Exemplo n.º 27
0
    def index_object(self, documentId, obj, threshold=None):
        """index an object, normalizing the indexed value to an integer

           o Normalized value has granularity of one minute.

           o Objects which have 'None' as indexed value are *omitted*,
             by design.

           o Repeat by recurdef - a RFC2445 reccurence definition string

        """
        returnStatus = 0

        try:
            date_attr = getattr(obj, self.id)
            if safe_callable(date_attr):
                date_attr = date_attr()
        except AttributeError:
            return returnStatus

        recurdef = getattr(obj, self.attr_recurdef, None)
        if safe_callable(recurdef):
            recurdef = recurdef()

        if not recurdef:
            dates = [pydt(date_attr)]
        else:
            until = getattr(obj, self.attr_until, None)
            if safe_callable(until):
                until = until()

            dates = recurrence_sequence_ical(
                date_attr, recrule=recurdef, until=until)

        newvalues = IISet(map(dt2int, dates))
        oldvalues = self._unindex.get(documentId, _marker)
        if oldvalues is not _marker:
            oldvalues = IISet(oldvalues)

        if oldvalues is not _marker and newvalues is not _marker\
                and not difference(newvalues, oldvalues)\
                and not difference(oldvalues, newvalues):
            # difference is calculated relative to first argument, so we have
            # to use it twice here
            return returnStatus

        if oldvalues is not _marker:
            for oldvalue in oldvalues:
                self.removeForwardIndexEntry(oldvalue, documentId)
            if newvalues is _marker:
                try:
                    del self._unindex[documentId]
                except ConflictError:
                    raise
                except Exception:
                    LOG.error("Should not happen: oldvalues was there,"
                              " now it's not, for document with id %s" %
                              documentId)

        if newvalues is not _marker:
            inserted = False
            for value in newvalues:
                self.insertForwardIndexEntry(value, documentId)
                inserted = True
            if inserted:
                # store tuple values in reverse index entries for sorting
                self._unindex[documentId] = tuple(newvalues)
                returnStatus = 1

        if returnStatus > 0:
            self._increment_counter()

        return returnStatus
Exemplo n.º 28
0
    def index_object(self, documentId, obj, threshold=None):
        """index an object, normalizing the indexed value to an integer

           o Normalized value has granularity of one minute.

           o Objects which have 'None' as indexed value are *omitted*,
             by design.

           o Repeat by recurdef - a RFC2445 reccurence definition string

        """
        returnStatus = 0

        try:
            date_attr = getattr(obj, self.id)
            if safe_callable(date_attr):
                date_attr = date_attr()
        except AttributeError:
            return returnStatus

        recurdef = getattr(obj, self.attr_recurdef, None)
        if safe_callable(recurdef):
            recurdef = recurdef()

        if not recurdef:
            dates = [pydt(date_attr)]
        else:
            until = getattr(obj, self.attr_until, None)
            if safe_callable(until):
                until = until()

            dates = recurrence_sequence_ical(date_attr,
                                             recrule=recurdef,
                                             until=until)

        newvalues = IISet(map(dt2int, dates))
        oldvalues = self._unindex.get(documentId, _marker)
        if oldvalues is not _marker:
            oldvalues = IISet(oldvalues)

        if oldvalues is not _marker and newvalues is not _marker\
            and not difference(newvalues, oldvalues)\
            and not difference(oldvalues, newvalues):
            # difference is calculated relative to first argument, so we have to
            # use it twice here
            return returnStatus

        if oldvalues is not _marker:
            for oldvalue in oldvalues:
                self.removeForwardIndexEntry(oldvalue, documentId)
            if newvalues is _marker:
                try:
                    del self._unindex[documentId]
                except ConflictError:
                    raise
                except:
                    LOG.error("Should not happen: oldvalues was there,"
                              " now it's not, for document with id %s" %
                              documentId)

        if newvalues is not _marker:
            inserted = False
            for value in newvalues:
                self.insertForwardIndexEntry(value, documentId)
                inserted = True
            if inserted:
                # store tuple values in reverse index entries for sorting
                self._unindex[documentId] = tuple(newvalues)
                returnStatus = 1

        return returnStatus