Esempio n. 1
0
        class SensorInitUndoTest(trellis.Component):
            trellis.attrs(v1=False)

            @trellis.maintain
            def a(self):
                if self.v1:
                    return _Comp()

            @trellis.maintain
            def b(self):
                if self.v1:
                    self.a
Esempio n. 2
0
class TriagePosition(ItemAddOn):
    trellis.attrs(pinned_triage_section=None, pinned_position=None)

    @trellis.compute
    def _triage_addon(self):
        return Triage(self._item)

    @trellis.compute
    def default_position(self):
        triage = Triage(self._item)
        if self._triage_addon.calculated == LATER:
            future_choices = list(filter_on_time(triage, future=True))
            if future_choices:
                return min(future_choices)[0]
        # if LATER but no known triage change in the future, use NOW behavior
        last_past = max(filter_on_time(triage, future=False))
        # never return a timestamp less than the item's creation timestamp
        return max(self._item.created, last_past[0])

    @trellis.compute
    def default_triage_section(self):
        return self._triage_addon.calculated

    @trellis.compute
    def position(self):
        if self.pinned_position is None:
            return self.default_position
        else:
            return self.pinned_position

    @trellis.compute
    def triage_section(self):
        if self.pinned_triage_section is None:
            return self.default_triage_section
        else:
            return self.pinned_triage_section

    ### Modifiers ###
    @trellis.modifier
    def pin(self):
        if self.pinned_triage_section is None and self.pinned_position is None:
            self.pinned_triage_section = self.default_triage_section
            self.pinned_position = self.default_position

    @trellis.modifier
    def clear_pinned(self):
        self.pinned_position = self.pinned_triage_section = None

    @trellis.modifier
    def pin_to_now(self):
        self.pinned_triage_section = NOW
        self.pinned_position = nowTimestamp()
Esempio n. 3
0
            class IdleTimer(trellis.Component):
                trellis.attrs(
                    idle_timeout=20,
                    busy=False,
                )
                idle_for = trellis.maintain(
                    lambda self: self.idle_for.begins_with(not self.busy),
                    initially=NOT_YET)

                @trellis.maintain  # XXX should be perform
                def alarm(self):
                    if self.idle_for[self.idle_timeout] and EventLoop.running:
                        log.append(5)
                        EventLoop.stop()
Esempio n. 4
0
        class FalseCircularity(trellis.Component):
            trellis.attrs(v1=False, v2=False)

            @trellis.maintain
            def a(self):
                if self.v1:
                    self.v2
                    return True

            @trellis.maintain
            def b(self):
                if self.v1:
                    self.v2 = True
                else:
                    self.a
Esempio n. 5
0
        class InfiniteLoop(trellis.Component):
            trellis.attrs(v1=False, v2=False)

            @trellis.maintain
            def a(self):
                #print 'A'
                if self.v1:
                    self.v2
                    return True

            @trellis.maintain
            def b(self):
                #print 'B'
                if self.v1:
                    self.a
                    self.v2 = True
Esempio n. 6
0
class EIM(Extension):
    uuid = trellis.make(lambda x: uuid4())
    well_known_name = trellis.compute(lambda self: self._well_known_name)
    trellis.attrs(
        _well_known_name=None,
        ical_uid=None,
        ical_extra=None,
    )

    @trellis.modifier
    def add(self, name=None, **kw):
        super(EIM, self).add(**kw)
        if name is None:
            name = getattr(self._item, 'well_known_name', None)
        if name is not None:
            self._well_known_name = name
            set_item_for_name(name, self.item)
        set_item_for_uuid(self.uuid, self.item)
        return self
Esempio n. 7
0
        class TaskExample(trellis.Component):
            trellis.attrs(start=False, stop=False)

            def wait_for_start(self):
                log.append("waiting to start")
                while not self.start:
                    yield activity.Pause

            def wait_for_stop(self):
                while not self.stop:
                    log.append("waiting to stop")
                    yield activity.Pause

            @activity.task
            def demo(self):
                yield self.wait_for_start()
                log.append("starting")
                yield self.wait_for_stop()
                log.append("stopped")
Esempio n. 8
0
class Reminder(trellis.Component):
    trellis.attrs(
        item=None,
        delta=None,
        fixed_trigger=None,
        description="",
        snooze=None,
        cleared=False,
        type='triage',
    )

    @trellis.compute
    def trigger(self):
        if self.fixed_trigger is not None:
            return self.fixed_trigger
        elif self.delta is not None and self.item is not None:
            if Event.installed_on(self.item):
                start = Event(self.item).start
                if start is not None:
                    return start + self.delta
Esempio n. 9
0
class Triage(ItemAddOn):
    trellis.attrs(manual=None, manual_timestamp=None, auto_source=None)

    @trellis.compute
    def auto(self):
        max_timestamp, status = max(filter_on_time(self, future=False))
        return status

    @trellis.compute
    def calculated(self):
        if self.manual is not None and self.manual_timestamp is None:
            return self.manual
        if self.auto is not None:
            return self.auto
        return NOW

    @trellis.maintain
    def constraints(self):
        for cell in (self.manual, self.auto):
            if cell is not None and int(cell) < 100:
                raise TriageRangeError(cell)
Esempio n. 10
0
class Recurrence(Extension):
    trellis.attrs(frequency=None,
                  byday='',
                  triaged_done_before=None,
                  start_extension=Event,
                  start_extension_cellname='start',
                  recurrence_id_override='base_start')
    trellis.make.attrs(triaged_recurrence_ids=trellis.Dict,
                       modification_recipes=trellis.Dict,
                       _recurrence_dashboard_entries=trellis.Dict,
                       rdates=trellis.Set,
                       exdates=trellis.Set,
                       _occurrence_cache=dict,
                       _pre_modification_cells=dict)

    @trellis.compute
    def start(self):
        if not self.start_extension.installed_on(self.item):
            return None
        else:
            return self.start_for(self.item)

    def start_for(self, item):
        extension = self.start_extension(item)
        return getattr(extension, self.start_extension_cellname)

    def build_rrule(self, count=None, until=None):
        """Return a dateutil rrule based on self.

        The time-limit for the series can be overridden by setting
        either count or until.

        """
        kwds = dict(dtstart=self.start,
                    freq=to_dateutil_frequency(self.frequency),
                    byweekday=to_dateutil_byweekday(self.byday),
                    cache=True)

        if count is not None:
            kwds['count'] = count
        elif until is not None:
            kwds['until'] = until
        elif self.count is not None:
            kwds['count'] = self.count
        else:
            kwds['until'] = self.until

        return rrule(**kwds)

    @trellis.maintain(initially=None)
    def until(self):
        """The last possible date for the series."""
        if self.count is None:
            return self.until
        elif not self.frequency:
            pass
        else:
            rule = self.build_rrule(count=self.count)
            return rule[-1]

    @trellis.maintain(initially=None)
    def count(self):
        if self.count is None:
            self.until  # make sure the rule depends on until
            return None
        elif self.until is None:
            return None
        else:
            rule = self.build_rrule(until=self.until)
            return rule.count()

    @trellis.compute
    def rruleset(self):
        if self.start is None:
            return None
        rrs = rruleset(cache=True)
        if self.frequency is not None:
            rrs.rrule(self.build_rrule())
        elif not self.rdates:
            # no rules or rdates, nothing to do
            return None
        for dt in self.rdates:
            rrs.rdate(dt)
        for dt in self.exdates:
            rrs.exdate(dt)
        return rrs

    def get_occurrence(self, recurrence_id):
        """Return Occurrence for recurrence_id, cache it for later."""
        recurrence_id = to_hashable(recurrence_id)
        occ = self._occurrence_cache.get(recurrence_id)
        if not occ:
            occ = Occurrence(self.item, recurrence_id)
            self._occurrence_cache[recurrence_id] = occ
        return occ

    @trellis.maintain
    def dashboard_recurrence_ids(self):
        """The set of recurrence_ids which should have DashboardEntries.

        Updates self._recurrence_dashboard_entries when re-calculated.

        """
        old_set = self.dashboard_recurrence_ids
        if old_set is None:
            old_set = frozenset()

        if not self in self.item.extensions or not self.start or not self.rruleset:
            new_set = frozenset()
        else:
            now_dt = getNow()
            past_done = None
            future_later = None
            new_set = set()
            for recurrence_id in self.rruleset:
                # XXX inefficient, creating an Occurrence for every past recurrence-id,
                # probably should be optimized by walking backwards from triaged_done_before
                triage = Triage(self.get_occurrence(recurrence_id)).calculated
                if triage not in (LATER, DONE):
                    new_set.add(to_hashable(recurrence_id))
                else:
                    if triage == DONE and recurrence_id < now_dt:
                        past_done = recurrence_id
                    elif triage == LATER and recurrence_id > now_dt:
                        future_later = recurrence_id
                        break

            for recurrence_id in past_done, future_later:
                if recurrence_id is not None:
                    new_set.add(to_hashable(recurrence_id))

            new_set.update(self.triaged_recurrence_ids)
            new_set.update(self.modification_recipes)

        for recurrence_id in old_set - new_set:
            del self._recurrence_dashboard_entries[recurrence_id]
        for recurrence_id in new_set - old_set:
            entry = DashboardEntry(self.get_occurrence(recurrence_id))
            self._recurrence_dashboard_entries[recurrence_id] = entry

        return new_set

    @trellis.maintain
    def _update_dashboard_entries(self):
        """Keep Item.dashboard_entries in sync with self._recurrence_dashboard_entries."""
        recurrence_entries = self._recurrence_dashboard_entries
        entries = self.item.dashboard_entries
        # keep the master in entries iff there's no recurrence
        if len(recurrence_entries) > 0:
            entries.discard(self.item._default_dashboard_entry)
        else:
            entries.add(self.item._default_dashboard_entry)

        for recurrence_id, entry in recurrence_entries.deleted.iteritems():
            entries.discard(entry)
        for recurrence_id, entry in recurrence_entries.added.iteritems():
            entries.add(entry)
        if recurrence_entries.changed:
            msg = "a value in recurrence_dashboard_entries changed: %s"
            raise Exception, msg % recurrence_entries.changed

    def occurrences_between(self, range_start, range_end):
        for dt in self.rruleset.between(range_start, range_end, True):
            yield self.get_occurrence(dt)

    def pick_dashboard_entry(self, recurrence_id):
        """Return the DashboardEntry associated with recurrence_id, or None."""
        return self._recurrence_dashboard_entries.get(
            to_hashable(recurrence_id))

    def triage_occurrence(self, recurrence_id, timestamp, status):
        self.triaged_recurrence_ids[to_hashable(recurrence_id)] = (timestamp,
                                                                   status)

    def clear_occurrence_triage(self, recurrence_id):
        recurrence_id = to_hashable(recurrence_id)
        if recurrence_id in self.triaged_recurrence_ids:
            del self.triaged_recurrence_ids[recurrence_id]
Esempio n. 11
0
class Occurrence(Item):

    # override master attributes
    trellis.attrs(dashboard_entries=None, _default_dashboard_entry=None)

    inherited_attrs(title=None, )

    def inherited_value(self, add_on_instance, name):
        """Inherit values from modifications, then master."""
        cls = None if add_on_instance is self else type(add_on_instance)
        key = cls, name
        recipe = self.modification_recipe
        if recipe and key in recipe.changes:
            return recipe.changes[key]
        elif (cls == Recurrence(self.master).start_extension
              and name == Recurrence(self.master).recurrence_id_override):
            return self.recurrence_id
        else:
            master = self.master if cls is None else cls(self.master)
            return getattr(master, name)

    @trellis.compute
    def created(self):
        return self.master.created

    @trellis.compute
    def _extension_types(self):
        return frozenset(t for t in self.master._extension_types
                         if t is not Recurrence)

    @trellis.compute
    def collections(self):
        return self.master.collections

    @property
    def recurrence_id(self):
        if isinstance(self.hashable_recurrence_id, datetime):
            return self.hashable_recurrence_id.replace(
                tzinfo=TimeZone.floating)
        master_event = Recurrence(self.master).start_extension(self.master)
        return datetime.fromtimestamp(self.hashable_recurrence_id,
                                      master_event.tzinfo)

    def __init__(self, master, recurrence_id):
        self.master = master
        self.hashable_recurrence_id = to_hashable(recurrence_id)
        return super(Occurrence, self).__init__()

    def __repr__(self):
        return "<Occurrence: %s>" % self.recurrence_id

    @trellis.modifier
    def modify(self, add_on=None, name=None, value=None):
        """Adjust ModificationRecipe such that add_on(self).name == value.

        If no ModificationRecipe exists, create it.  With no
        arguments, just create a ModificationRecipe for this
        recurrence-id if one doesn't already exist.

        """
        recipes = Recurrence(self.master).modification_recipes
        recipe = recipes.get(self.hashable_recurrence_id)
        if not recipe:
            recipe = recipes.added.get(self.hashable_recurrence_id)
        if not recipe:
            recipe = ModificationRecipe()
            recipes[self.hashable_recurrence_id] = recipe

        if name:
            recipe.make_change(add_on, name, value)

    @trellis.modifier
    def remove_change(self, add_on=None, name=None):
        """Remove a single change from existing ModificationRecipes."""
        if self.modification_recipe:
            self.modification_recipe.remove_change(add_on, name)

    @trellis.compute
    def modification_recipe(self):
        return Recurrence(self.master).modification_recipes.get(
            self.hashable_recurrence_id)

    @trellis.modifier
    def unmodify(self):
        if self.modification_recipe:
            del Recurrence(
                self.master).modification_recipes[self.hashable_recurrence_id]