Beispiel #1
0
def parse_frequency(
        frequency: Text) -> Optional[Union[datetime, RecurringEvent]]:
    """
    Parse frequency or date using `recurrent` and `dateparser` module.
    """
    if frequency.startswith("every"):
        rec = RecurringEvent()
        parsed_rrule = rec.parse(frequency)
        if rec.bymonthday or rec.byyearday:
            # not supported
            return None

        try:
            rrulestr(parsed_rrule)  # this validates the parsing
        except (ValueError, TypeError):
            return None
        else:
            # ensure that hours are set, otherwise default to 9am
            if not rec.byhour and not rec.byminute:
                rec.byhour.append("9")
                rec.byminute.append("0")
            return rec
    else:
        value = dateparser.parse(frequency,
                                 settings={"PREFER_DATES_FROM": "future"})
        if value and not value.hour and not value.minute:
            # default 9am if no times
            value = value.replace(hour=9)
        return value
Beispiel #2
0
    def test_get_rrule_end(self):
        """
        Test that get_rrule_end returns the rrule end correctly
        """
        # when until is provided
        # pylint: disable=line-too-long
        rule1 = "DTSTART:20180501T210000Z RRULE:FREQ=YEARLY;BYDAY=SU;BYSETPOS=1;BYMONTH=1;UNTIL=20480521T210000Z"  # noqa
        end1 = get_rrule_end(rrulestr(rule1))
        # must be timezone aware
        self.assertTrue(timezone.is_aware(end1))
        # must be 21 may 2018
        self.assertEqual(2048, end1.year)
        self.assertEqual(5, end1.month)
        self.assertEqual(21, end1.day)

        # when count is provided instead
        rule2 = "RRULE:FREQ=DAILY;COUNT=5"
        end2 = get_rrule_end(rrulestr(rule2))
        # must be timezone aware
        self.assertTrue(timezone.is_aware(end2))
        # must be 4 days from now (5 occurrences with today as the first)
        now = timezone.now().astimezone(pytz.timezone("Africa/Nairobi"))
        then = now + timedelta(days=4)
        self.assertEqual(then.year, end2.year)
        self.assertEqual(then.month, end2.month)
        self.assertEqual(then.day, end2.day)
Beispiel #3
0
    def test_get_occurrence_end_time(self):
        """
        Test get_occurrence_end_time
        """
        # pylint: disable=line-too-long
        rule = "DTSTART:20180501T070000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=500;UNTIL=20280521T210000Z"  # noqa
        the_rrule = rrulestr(rule)
        task = mommy.make("tasking.Task", timing_rule=rule)

        rule2 = "RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5"
        the_rrule2 = rrulestr(rule2)

        # when end_time is not input then return start_time from timing_rule
        self.assertEqual(
            "21:00:00",
            get_occurrence_end_time(task, the_rrule,
                                    end_time_input=None).isoformat(),
        )

        # when end_time is input then return start_time from timing_rule
        self.assertEqual(
            "19:15:00",
            get_occurrence_end_time(task,
                                    the_rrule,
                                    end_time_input=time(19, 15, 0,
                                                        0)).isoformat(),
        )

        # return the end of the day when timing_rule has no end and end_
        # time is not provided
        self.assertEqual(
            "23:59:59.999999",
            get_occurrence_end_time(task, the_rrule2,
                                    end_time_input=None).isoformat(),
        )
Beispiel #4
0
    def load(cls, data, slug, *, cities, venues):
        recurrence = data['series'].get('recurrence')
        if recurrence:
            rrule_str = recurrence['rrule']
            rrule.rrulestr(rrule_str)  # check rrule syntax
            recurrence_attrs = {
                'recurrence_rule': rrule_str,
                'recurrence_scheme': recurrence['scheme'],
                'recurrence_description_cs': recurrence['description']['cs'],
                'recurrence_description_en': recurrence['description']['en'],
            }
        else:
            recurrence_attrs = {
                'recurrence_rule': None,
                'recurrence_scheme': None,
                'recurrence_description_cs': None,
                'recurrence_description_en': None,
            }

        self = cls(
            events=sorted((Event.load(e, slug, cities=cities, venues=venues)
                           for slug, e in data.get('events', {}).items()),
                          key=lambda e: e.start),
            slug=slug,
            name=data['series']['name'],
            home_city=cities[data['series']['city']],
            description_cs=data['series']['description']['cs'],
            description_en=data['series']['description']['en'],
            organizers=[dict(o) for o in data['series']['organizer-info']],
            source=data['series']['_source'],
            **recurrence_attrs,
        )
        for event in self.events:
            event.series = self
        return self
Beispiel #5
0
 def create_rule_with_start(self, rule_string):
     try:
         return rrulestr(rule_string, dtstart=self.start)
     except ValueError:
         # string: FREQ=WEEKLY;UNTIL=20191023;BYDAY=TH;WKST=SU
         # start: 2019-08-01 14:00:00+01:00
         # ValueError: RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware
         rule_list = rule_string.split(";UNTIL=")
         assert len(rule_list) == 2
         date_end_index = rule_list[1].find(";")
         if date_end_index == -1:
             date_end_index = len(rule_list[1])
         until_string = rule_list[1][:date_end_index]
         if self.is_all_dates:
             until_string = until_string[:8]
         elif self.tzinfo is None:
             # remove the Z from the time zone
             until_string = until_string[:-1]
         else:
             # we assume the start is timezone aware but the until value is not, see the comment above
             if len(until_string) == 8:
                 until_string += "T000000"
             assert len(until_string) == 15
             until_string += "Z"  # https://stackoverflow.com/a/49991809
         new_rule_string = rule_list[0] + rule_list[1][
             date_end_index:] + ";UNTIL=" + until_string
         return rrulestr(new_rule_string, dtstart=self.start)
Beispiel #6
0
    def test_get_start_end_from_timing_rules(self):
        """
        Test get_start_end_from_timing_rules
        """
        zero = ['invalid']
        one = [None]
        two = []
        three = [None, 'RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5']
        four = [
            'RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5',
            'RRULE:FREQ=DAILY;INTERVAL=10;COUNT=17',
            'DTSTART:20170521T210000Z RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5'
        ]

        self.assertEqual((None, None), get_start_end_from_timing_rules(zero))
        self.assertEqual((None, None), get_start_end_from_timing_rules(one))
        self.assertEqual((None, None), get_start_end_from_timing_rules(two))
        self.assertEqual(
            (get_rrule_start(rrulestr('RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5')),
             get_rrule_end(rrulestr('RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5'))),
            get_start_end_from_timing_rules(three))
        self.assertEqual(
            (get_rrule_start(
                rrulestr('DTSTART:20170521T210000Z RRULE:FREQ=DAILY;COUNT=5')),
             get_rrule_end(rrulestr('RRULE:FREQ=DAILY;INTERVAL=10;COUNT=17'))),
            get_start_end_from_timing_rules(four))
Beispiel #7
0
def test_serialize_rruleset_clocks():
    s = ("DTSTART:20120201T023000Z\n"
         "RRULE:FREQ=MONTHLY;COUNT=5\n"
         "RDATE:20120701T023000Z,20120702T023000Z\n"
         "EXRULE:FREQ=MONTHLY;COUNT=2\n"
         "EXDATE:20120601T023000Z")
    rr = rrule.rrulestr(s)
    days = [
        pendulum.datetime(2012, 4, 1, 2, 30),
        pendulum.datetime(2012, 5, 1, 2, 30)
    ]
    t = schedules.Schedule(clocks=[clocks.RRuleClock(rrule_obj=rr)])
    assert t.next(2, after=pendulum.datetime(2012, 1, 1, 0, 0)) == days
    t2 = serialize_and_deserialize(t)
    assert t2.next(2, after=pendulum.datetime(2012, 1, 1, 0, 0)) == days

    s = ("DTSTART:20120201T023000Z\n"
         "RDATE:20120701T023000Z,20120702T023000Z\n"
         "EXDATE:20120601T023000Z")
    rr = rrule.rrulestr(s)
    days = [
        pendulum.datetime(2012, 7, 1, 2, 30),
        pendulum.datetime(2012, 7, 2, 2, 30)
    ]
    t = schedules.Schedule(clocks=[clocks.RRuleClock(rrule_obj=rr)])
    assert t.next(2, after=pendulum.datetime(2012, 1, 1, 0, 0)) == days
    t2 = serialize_and_deserialize(t)
    assert t2.next(2, after=pendulum.datetime(2012, 1, 1, 0, 0)) == days
Beispiel #8
0
    def next_occurrence(self):
        # if not messages have been queued yet, then the next occurrence
        # is the start time
        next_occur = None
        if (not self.last_occurrence_in_utc):
            next_occur = self.start_datetime_in_utc.datetime
            return next_occur, arrow.utcnow().replace(minutes=+10)
        else:
            start = self.start_datetime_in_utc.datetime
            rule = rrulestr(self.ical, dtstart=start)
            next_after_now = rule.after(arrow.utcnow())
            if not next_after_now:
                logging.info('No next_after_now, so next_occur=N/A')
                return 'N/A', arrow.utcnow()
            next_before_now = rule.before(next_after_now)
            if (self.last_occurrence_in_utc > next_before_now):
                next_occur = next_after_now
            else:
                next_occur = next_before_now

        rule = rrulestr(self.ical, dtstart=next_occur)
        expires = rule.after(next_occur)
        if not expires:
            return 'N/A', arrow.utcnow().replace(minutes=+10)
        if (expires > self.end_datetime_in_utc):
            expires = self.end_datetime_in_utc
        return arrow.get(next_occur), arrow.get(expires)
Beispiel #9
0
    def validate(cls, value):
        # type: (unicode) -> List[str]
        """Returns a list of errors if value is not a valid serialized run window."""

        data = json.loads(value)
        if not isinstance(data, list):
            return ["Serialized run window should be list."]

        errors = []
        for w in data:
            try:
                timezone.datetime.strptime(w['start_time'],
                                           CheckRunWindow._TIME_FMT)
                timezone.datetime.strptime(w['end_time'],
                                           CheckRunWindow._TIME_FMT)
            except ValueError:
                errors.append("Invalid start/end time.")

            # ensure all windows have a valid recurrence rule
            try:
                rrule.rrulestr(w['rrule'])
            except ValueError as e:
                errors.append("You must select at least one day to run on. (" +
                              str(e) + ").")
        return errors
Beispiel #10
0
def get_start_end_from_timing_rules(timing_rules: list):
    """
    Get the start and end times from timing rules

    Will return the very very first start
    and the very very last end from the provided timing_rules
    """
    start, end = None, None
    start_list = []
    end_list = []

    # remove obviously invalid
    timing_rules = [x for x in timing_rules if x]

    for timing_rule in timing_rules:
        try:
            start_list.append(get_rrule_start(rrulestr(timing_rule)))
        except ValueError:
            pass

        try:
            end_list.append(get_rrule_end(rrulestr(timing_rule)))
        except ValueError:
            pass

    if start_list:
        start = min(start_list)

    if end_list:
        end = max(end_list)

    return (start, end)
def get_recurrent_dates(rrulestring, exdate, startdate=None, exrule=None):
    """
    Get recurrent dates based on Rule string considering exdate and start date.
    @param rrulestring: rulestring
    @param exdate: list of exception dates for rrule
    @param startdate: startdate for computing recurrent dates
    @return: list of Recurrent dates
    """
    def todate(date):
        val = parser.parse(''.join((re.compile('\d')).findall(date)))
        return val

    if not startdate:
        startdate = datetime.now()

    if not exdate:
        exdate = []

    rset1 = rrule.rrulestr(str(rrulestring), dtstart=startdate, forceset=True)
    for date in exdate:
        datetime_obj = todate(date)
        rset1._exdate.append(datetime_obj)

    if exrule:
        rset1.exrule(rrule.rrulestr(str(exrule), dtstart=startdate))

    return list(rset1)
Beispiel #12
0
def get_recurrent_dates(rrulestring, exdate, startdate=None, exrule=None):
    """
    Get recurrent dates based on Rule string considering exdate and start date.
    @param rrulestring: rulestring
    @param exdate: list of exception dates for rrule
    @param startdate: startdate for computing recurrent dates
    @return: list of Recurrent dates
    """
    def todate(date):
        val = parser.parse(''.join((re.compile('\d')).findall(date)))
        return val

    if not startdate:
        startdate = datetime.now()

    if not exdate:
        exdate = []

    rset1 = rrule.rrulestr(str(rrulestring), dtstart=startdate, forceset=True)
    for date in exdate:
        datetime_obj = todate(date)
        rset1._exdate.append(datetime_obj)

    if exrule:
        rset1.exrule(rrule.rrulestr(str(exrule), dtstart=startdate))

    return list(rset1)
Beispiel #13
0
    def test_get_occurrence_start_time(self):
        """
        Test get_occurrence_start_time
        """
        # pylint: disable=line-too-long
        rule = "DTSTART:20180501T070000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=500;UNTIL=20280521T210000Z"  # noqa
        the_rrule = rrulestr(rule)

        rule2 = "RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5"
        the_rrule2 = rrulestr(rule2)

        # when start_time is not input then return start_time from timing_rule
        self.assertEqual(
            "07:00:00",
            get_occurrence_start_time(the_rrule,
                                      start_time_input=None).isoformat(),
        )

        # if given an input, return that input
        self.assertEqual(
            "09:15:00",
            get_occurrence_start_time(the_rrule,
                                      start_time_input=time(9, 15, 0,
                                                            0)).isoformat(),
        )

        # when timing_rule has no explicit start then we get back is right now
        now = timezone.now().astimezone(pytz.timezone("Africa/Nairobi")).time()
        result = get_occurrence_start_time(the_rrule2, start_time_input=None)

        diff = datetime.combine(timezone.now().date(), now) - datetime.combine(
            timezone.now().date(), result)
        # should be within one minutes of each other
        self.assertTrue(diff.seconds < 60)
Beispiel #14
0
def create_entries(
    settings: Settings,
    config: Config,
    spec_row: CollectionRowBlock,
) -> Generator[Dict[str, Any], None, None]:
    r = RecurringEvent(now_date=spec_row.start_date.start)
    times = r.parse(spec_row.recurrence)
    rr = rrule.rrulestr(r.get_RFC_rrule(), dtstart=spec_row.start_date.start)

    if get_row_prop(spec_row, 'not_on'):
        not_r = RecurringEvent(now_date=spec_row.start_date.start)
        not_times = not_r.parse(spec_row.not_on)
        not_dates = {
            d.date()
            for d in rrule.rrulestr(
                not_r.get_RFC_rrule(),
                dtstart=spec_row.start_date.start,
            )
        }

    for dt in rr:
        if get_row_prop(spec_row, 'not_on') and dt.date() in not_dates:
            continue

        to_insert = {
            key: spec_row.get_property(key)
            for key in config.properties_to_sync
        }
        to_insert['title'] = spec_row.title
        if config.tags_property in to_insert:
            to_insert[config.tags_property].append(config.scheduled_tag)
        if config.status_property:
            to_insert[
                config.status_property] = config.status_after_today if dt.date(
                ) >= datetime.date.today() else config.status_before_today

        reminder = None
        if get_row_prop(spec_row, 'reminder'):
            reminder = parse_reminder(spec_row.reminder)

        if get_row_prop(spec_row, 'include_time'):
            if get_row_prop(spec_row, 'duration'):
                duration = datetime.timedelta(
                    minutes=Duration(spec_row.duration).to_minutes())
                to_insert[spec_row.date_field] = NotionDate(dt,
                                                            dt + duration,
                                                            reminder=reminder)
            else:
                to_insert[spec_row.date_field] = NotionDate(dt,
                                                            reminder=reminder)
        else:
            to_insert[spec_row.date_field] = NotionDate(dt.date(),
                                                        reminder=reminder)

        if not settings.dry_run:
            yield to_insert
        logging.info(
            f"Added row '{to_insert.get('title', 'Untitled')}' for {dt:%Y-%m-%d}"
        )
Beispiel #15
0
 def _next_time(self, entry):
     """
     Here we examine an entry of the list of points in time and return the next execution time and the next value
     """
     try:
         if not isinstance(entry, dict):
             return None, None
         if not 'value' in entry:
             return None, None
         if not 'active' in entry:
             return None, None
         if not 'time' in entry:
             return None, None
         now = datetime.now()
         value = entry['value']
         active = entry['active']
         today = datetime.today()
         yesterday = today - timedelta(days=1)
         time = entry['time']
         if not active:
             return None, None
         if 'date' in entry:
             date = entry['date']
         if 'rrule' in entry:
             if 'dtstart' in entry:
                 rrule = rrulestr(entry['rrule'], dtstart=entry['dtstart'])
             else:
                 try:
                     rrule = rrulestr(entry['rrule'], dtstart=datetime.combine(yesterday, parser.parse(time.strip()).time()))
                 except Exception as e:
                     self.logger.debug("Tolerated Exception '{}' while examining '{}' with function rrulestr()".format(e,time))
                     if 'sun' in time:
                         self.logger.debug("Looking for next sun-related time with rulestr()")
                         rrule = rrulestr(entry['rrule'], dtstart=datetime.combine(yesterday, self._sun(datetime.combine(yesterday.date(), datetime.min.time()).replace(tzinfo=self._sh.tzinfo()), time).time()))
                     else:
                         self.logger.debug("Looking for next time with rulestr()")
                         rrule = rrulestr(entry['rrule'], dtstart=datetime.combine(yesterday, datetime.min.time()))
             dt = now
             while self.alive:
                 dt = rrule.after(dt)
                 if dt is None:
                     return None, None
                 if 'sun' in time:
                     next = self._sun(datetime.combine(dt.date(), datetime.min.time()).replace(tzinfo=self._sh.tzinfo()), time)
                     self.logger.debug("Result parsing time (rrule){}: {}".format(time, next))                 
                 else:
                     next = datetime.combine(dt.date(), parser.parse(time.strip()).time()).replace(tzinfo=self._sh.tzinfo())
                 if next and next.date() == dt.date() and next > datetime.now(self._sh.tzinfo()):
                     return next, value
         if 'sun' in time:
             next = self.sun(datetime.combine(today, datetime.min.time()).replace(tzinfo=self._sh.tzinfo()), time)
             self.logger.debug("Result parsing time (sun) {}: {}".format(time, next))              
         else:
             next = datetime.combine(today, parser.parse(time.strip()).time()).replace(tzinfo=self._sh.tzinfo())
         if next and next.date() == today and next > datetime.now(self._sh.tzinfo()):
             return next, value
     except Exception as e:
         self.logger.error("Error '{}' parsing time: {}".format(time, e))
     return None, None
Beispiel #16
0
 def _search_next_date(self, operator, value):
     if operator == '=':
         _after = parser.parse(value)
         _recs = self.search([])
         _res = _recs.filtered(
             lambda r: rrule.rrulestr(r.rrule_str).after(_after, inc=True)
             and rrule.rrulestr(r.rrule_str).after(_after, inc=True).
             strftime('%Y-%m-%d') == _after.strftime('%Y-%m-%d'))
         return [('id', 'in', _res._ids)]
Beispiel #17
0
    def __call__(self, value, *args, **kwargs):
        try:
            rrule.rrulestr(value)  # TODO: rm dep. on rrule. check with regex
            assert('FREQ' in value)  # TODO: check if freq before other
                                     # recurrence parms
        except (ValueError, TypeError, AssertionError):
            return "Validation failed: Please enter valid recurrence data."

        return True
Beispiel #18
0
    def __call__(self, value, *args, **kwargs):
        try:
            rrule.rrulestr(value)  # TODO: rm dep. on rrule. check with regex
            assert ('FREQ' in value)  # TODO: check if freq before other
            # recurrence parms
        except (ValueError, TypeError, AssertionError):
            return "Validation failed: Please enter valid recurrence data."

        return True
Beispiel #19
0
def recurrence_rule(value):
    """
    Validate that a ``rruleset`` object can be creted from ``value``.
    """
    try:
        rrule.rrulestr(value)
    except ValueError:
        raise ValidationError(
            _('Enter a valid iCalendar (RFC2445) recurrence rule.'),
            code='invalid')
Beispiel #20
0
 def test_(self):
     date = RecurringEvent(NOW)
     val = date.parse(string)
     back_again = date.format(val)
     expected_params = expected
     known_failure = False
     if isinstance(expected, ExpectedFailure):
         known_failure = True
         expected_params = expected.correct_value
     try:
         if expected_params is None:
             self.assertTrue(
                 val is None
                 or list(date.get_params().keys()) == ['interval'],
                 "Non-date error: '%s' -> '%s', expected '%s'" %
                 (string, val, expected_params))
         elif isinstance(expected_params, datetime.datetime) or isinstance(
                 expected_params, datetime.date):
             if isinstance(expected_params, datetime.datetime):
                 self.assertEqual(
                     val, expected_params,
                     "Date parse error: '%s' -> '%s', expected '%s'" %
                     (string, val, expected_params))
             else:
                 self.assertEqual(
                     val.date(), expected_params,
                     "Date parse error: '%s' -> '%s', expected '%s'" %
                     (string, val, expected_params))
         else:
             actual_params = date.get_params()
             for k, v in list(expected_params.items()):
                 av = actual_params.pop(k, None)
                 self.assertEqual(
                     av, v,
                     "Rule mismatch on rule '%s' for '%s'. Expected %s, got %s\nRules: %s"
                     % (k, string, v, av, date.get_params()))
             # make sure any extra params are empty/false
             for k, v in list(actual_params.items()):
                 self.assertFalse(v)  # pragma nocover
             # ensure rrule string can be parsed by dateutil
             rrule.rrulestr(val)
     except AssertionError as e:
         if known_failure:
             print("Expected failure:", expected_params)
             return
         raise e  # pragma nocover
     if known_failure:
         raise AssertionError("Known failure passed:", expected_params,
                              string)  # pragma nocover
     self.maxDiff = 1000
     if de is not None:
         self.assertEqual(de, back_again)
         if back_again is not None and back_again != string:
             self.assertEqual(back_again, date.format(
                 date.parse(back_again)))  # Run it thru again!
 def testEuropeanDaylightToStandardChange(self):
     dststart = datetime(1970, 03, 29, 2)
     stdstart = datetime(1970, 10, 25, 3)
     stdrrule = rrule.rrulestr("FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU", dtstart=stdstart)
     dstrrule = rrule.rrulestr("FREQ=YEARLY;BYMONTH=03;BYDAY=-1SU", dtstart=dststart)
     tzinfo = self.makeTimezone(stdstart, dststart, stdrrule, dstrrule)
     self.assertEquals(datetime(2011, 10, 29, 1, tzinfo=tzinfo).tzname(), "DAYLIGHT")
     self.assertEquals(datetime(2011, 10, 31, 1, tzinfo=tzinfo).tzname(), "STANDARD")
     self.assertEquals(datetime(2011, 10, 30, 1, tzinfo=tzinfo).tzname(), "DAYLIGHT")
     self.assertEquals(datetime(2011, 10, 30, 3, tzinfo=tzinfo).tzname(), "STANDARD")
     delta = datetime(2011, 10, 30, 4, tzinfo=tzinfo) - datetime(2011, 10, 30, 1, tzinfo=tzinfo.copy())
     self.assertEquals(delta, timedelta(hours=4))
Beispiel #22
0
 def _next_time(self, entry):
     try:
         if not isinstance(entry, dict):
             return None, None
         if not 'value' in entry:
             return None, None
         if not 'active' in entry:
             return None, None
         if not 'time' in entry:
             return None, None
         now = datetime.now()
         value = entry['value']
         active = entry['active']
         today = datetime.today()
         yesterday = today - timedelta(days=1)
         time = entry['time']
         if not active:
             return None, None
         if 'date' in entry:
             date = entry['date']
         if 'rrule' in entry:
             if 'dtstart' in entry:
                 rrule = rrulestr(entry['rrule'], dtstart=entry['dtstart'])
             else:
                 try:
                     rrule = rrulestr(entry['rrule'], dtstart=datetime.combine(yesterday, parser.parse(time.strip()).time()))
                 except:
                     if 'sun' in time:
                         rrule = rrulestr(entry['rrule'], dtstart=datetime.combine(yesterday, self._sun(datetime.combine(yesterday.date(), datetime.min.time()).replace(tzinfo=self._sh.tzinfo()), time).time()))
                     else:
                         rrule = rrulestr(entry['rrule'], dtstart=datetime.combine(yesterday, datetime.min.time()))
             dt = now
             while self.alive:
                 dt = rrule.after(dt)
                 if dt is None:
                     return None, None
                 if 'sun' in time:
                     next = self._sun(datetime.combine(dt.date(), datetime.min.time()).replace(tzinfo=self._sh.tzinfo()), time)
                 else:
                     next = datetime.combine(dt.date(), parser.parse(time.strip()).time()).replace(tzinfo=self._sh.tzinfo())
                 if next and next.date() == dt.date() and next > datetime.now(self._sh.tzinfo()):
                     return next, value
         if 'sun' in time:
             next = self.sun(datetime.combine(today, datetime.min.time()).replace(tzinfo=self._sh.tzinfo()), time)
         else:
             next = datetime.combine(today, parser.parse(time.strip()).time()).replace(tzinfo=self._sh.tzinfo())
         if next and next.date() == today and next > datetime.now(self._sh.tzinfo()):
             return next, value
     except Exception as e:
         logger.error("Error parsing time {}: {}".format(time, e))
     return None, None
Beispiel #23
0
def validate_rrule(rule_string):
    """
    Validates an rrule string; returns True or False
    """
    try:
        rrulestr(rule_string)
    except ValueError:
        # this string is not a valid rrule
        return False
    except TypeError:
        # this is not even a string
        return False
    else:
        return True
Beispiel #24
0
def test_rrule_to_json():
    # Generate more test cases!
    # http://jakubroztocil.github.io/rrule/
    r = "RRULE:FREQ=WEEKLY;UNTIL=20140918T203000Z;BYDAY=TH"
    r = rrulestr(r, dtstart=None)
    j = rrule_to_json(r)
    assert j.get("freq") == "WEEKLY"
    assert j.get("byweekday") == "TH"

    r = "FREQ=HOURLY;COUNT=30;WKST=MO;BYMONTH=1;BYMINUTE=42;BYSECOND=24"
    r = rrulestr(r, dtstart=None)
    j = rrule_to_json(r)
    assert j.get("until") is None
    assert j.get("byminute") == 42
Beispiel #25
0
def test_rrule_to_json():
    # Generate more test cases!
    # http://jakubroztocil.github.io/rrule/
    r = 'RRULE:FREQ=WEEKLY;UNTIL=20140918T203000Z;BYDAY=TH'
    r = rrulestr(r, dtstart=None)
    j = rrule_to_json(r)
    assert j.get('freq') == 'WEEKLY'
    assert j.get('byweekday') == 'TH'

    r = 'FREQ=HOURLY;COUNT=30;WKST=MO;BYMONTH=1;BYMINUTE=42;BYSECOND=24'
    r = rrulestr(r, dtstart=None)
    j = rrule_to_json(r)
    assert j.get('until') is None
    assert j.get('byminute') is 42
Beispiel #26
0
def test_rrule_to_json():
    # Generate more test cases!
    # http://jakubroztocil.github.io/rrule/
    r = 'RRULE:FREQ=WEEKLY;UNTIL=20140918T203000Z;BYDAY=TH'
    r = rrulestr(r, dtstart=None)
    j = rrule_to_json(r)
    assert j.get('freq') == 'WEEKLY'
    assert j.get('byweekday') == 'TH'

    r = 'FREQ=HOURLY;COUNT=30;WKST=MO;BYMONTH=1;BYMINUTE=42;BYSECOND=24'
    r = rrulestr(r, dtstart=None)
    j = rrule_to_json(r)
    assert j.get('until') is None
    assert j.get('byminute') is 42
Beispiel #27
0
    def _apply_recurrence_to_dt(self, dt):
        if not dt:
            return None

        recurrence = rrulestr(self.rrule, dtstart=dt)

        # Nasty hack around: https://github.com/dateutil/dateutil/issues/341
        try:
            return recurrence.after(dt)
        except TypeError:
            tz = dt.tzinfo
            dt = dt.replace(tzinfo=LOCAL_TIMEZONE)
            recurrence = rrulestr(self.rrule, dtstart=dt)
            return recurrence.after(dt).replace(tzinfo=tz)
Beispiel #28
0
    def get(self, request):

        passcode = self.request.query_params.get('passcode', None)
        queryset = Resident.objects.all().filter(passcode=passcode).first()
        print(queryset)
        rule_string = queryset.recurrance_str
        isValid = False
        print(rule_string)
        if rule_string:
            dtstart = ''
            str_without_dtstart = ''
            rule_string_perameters = rule_string.split(";")

            for pera in rule_string_perameters:
                if pera.split("=")[0] == 'DTSTART':
                    dtstart = pera.split("=")[1]
                    rule_string_perameters.remove(pera)

            if dtstart != '':
                final_rule_string = "DTSTART:" + dtstart + ";\n" + "RRULE:" + ";".join(
                    rule_string_perameters)
                rule = rrulestr(final_rule_string)
                launchTime = datetime.now(tz=timezone.utc)
                next_occurance = rule.after(launchTime, inc=True)
            else:
                final_rule_string = "RRULE:" + ";".join(rule_string_perameters)
                rule = rrulestr(final_rule_string)
                launchTime = datetime.utcnow()
                next_occurance = rule.after(launchTime, inc=True)

            print(next_occurance.strftime("%d/%m/%Y"))
            print(datetime.now(tz=timezone.utc).strftime("%d/%m/%Y"))

            if next_occurance.strftime("%d/%m/%Y") == datetime.now(
                    tz=timezone.utc).strftime("%d/%m/%Y"):
                if queryset.time_from and queryset.time_to:
                    begin_time = datetime.time(queryset.time_from)
                    end_time = datetime.time(queryset.time_to)
                    check_time = datetime.utcnow().time()
                    if begin_time < end_time:
                        isValid = check_time >= begin_time and check_time <= end_time
                    else:  # crosses midnight
                        isValid = check_time >= begin_time or check_time <= end_time
                else:
                    isValid = True
        else:
            isValid = True

        return Response({'isValid': isValid})
 def test_(self):
     date = RecurringEvent(NOW)
     val = date.parse(string)
     expected_params = expected
     known_failure = False
     if isinstance(expected, ExpectedFailure):
         known_failure = True
         expected_params = expected.correct_value
     try:
         if expected_params is None:
             self.assertTrue(
                 val is None or date.get_params().keys() == ["interval"],
                 "Non-date error: '%s' -> '%s', expected '%s'" % (string, val, expected_params),
             )
         elif isinstance(expected_params, datetime.datetime) or isinstance(expected_params, datetime.date):
             if isinstance(expected_params, datetime.datetime):
                 self.assertEqual(
                     val,
                     expected_params,
                     "Date parse error: '%s' -> '%s', expected '%s'" % (string, val, expected_params),
                 )
             else:
                 self.assertEqual(
                     val.date(),
                     expected_params,
                     "Date parse error: '%s' -> '%s', expected '%s'" % (string, val, expected_params),
                 )
         else:
             actual_params = date.get_params()
             for k, v in expected_params.items():
                 av = actual_params.pop(k, None)
                 self.assertEqual(
                     av,
                     v,
                     "Rule mismatch on rule '%s' for '%s'. Expected %s, got %s\nRules: %s"
                     % (k, string, v, av, date.get_params()),
                 )
             # make sure any extra params are empty/false
             for k, v in actual_params.items():
                 self.assertFalse(v)
             # ensure rrule string can be parsed by dateutil
             rrule.rrulestr(val)
     except AssertionError as e:
         if known_failure:
             print("Expected failure:", expected_params)
             return
         raise e
     if known_failure:
         raise AssertionError("Known failure passed:", expected_params, string)
Beispiel #30
0
    def __init__(self, values, default=None):
        values = lowercase_keys_recursively(values)

        # anything not defined in the "values" dict will be defaulted
        init = self._defaults.copy()
        init.update(values)

        # convert the dict to attributes
        self.__dict__.update(init)

        try:
            self.first = parser.parse(self.first, default=default)
            if not self.first.tzinfo:
                self.first = self.first.replace(tzinfo=tz.tzutc())
        except Exception as e:
            raise ValueError('Error parsing date from `first`.')

        try:
            if self.repeat:
                match = self.repeat_regex.match(self.repeat)
                interval = int(match.group(1))
                if interval == 0:
                    raise ValueError('Invalid repeat interval.')
                self.rrule = rrule.rrule(self.freq_dict[match.group(2)],
                                         interval=interval,
                                         dtstart=self.first)
            elif self.rrule:
                self.rrule = rrule.rrulestr(self.rrule, dtstart=self.first)
        except Exception as e:
            raise ValueError('Error parsing repeat interval.')

        self.title = self.replace_placeholders(self.title)
        self.text = self.replace_placeholders(self.text)
Beispiel #31
0
def schedule_station(station_id):
    station = Station.query.filter_by(id=station_id).first_or_404()

    # TODO: move this logic to an ajax call, like scheduled_block_json
    scheduled_blocks = ScheduledBlock.query.filter_by(station_id=station.id)
    block_list = []
    for block in scheduled_blocks:
        r = rrule.rrulestr(block.recurrence)
        for instance in r[:
                          30]:  # TODO: dynamically determine instance limit from calendar view
            d = {
                'title': block.name,
                'start': datetime.combine(instance, block.start_time),
                'end': datetime.combine(instance, block.end_time)
            }
            block_list.append(d)

    form = ScheduleProgramForm()

    all_programs = Program.query.join(Program, Network.programs).join(
        User, Network.networkusers).filter(User.id == current_user.id).all()
    # TODO: filter by language?

    return render_template('radio/schedule.html',
                           form=form,
                           station=station,
                           block_list=block_list,
                           addable_programs=all_programs,
                           active='schedule')
    def target_dates(self):
        """ Returns the dates this reservation targets. Those should not be
        confused with the dates this reservation actually reserved.

        The reason for this difference is the fact that after the reservation
        is created, certain dates might be removed through removing reserved
        slots.

        This function only returns dates the reservation was originally
        targeted at.

        """
        if self.target_type == u'allocation':
            return ((self.start, self.end),)

        if self.target_type == u'group':
            return self._target_allocations().with_entities(
                self.models.Allocation._start,
                self.models.Allocation._end
            ).all()

        if self.target_type == u'recurrence':
            time_start = self.start.time()
            time_end = self.end.time()

            date_start = self.start.date()
            from dateutil.rrule import rrulestr

            rule = rrulestr(self.rrule, dtstart=date_start)
            return [get_date_range(date, time_start, time_end)
                    for date in rule]

        raise NotImplementedError
 def testGetPoints(self):
     start = datetime(2007, 12, 22, 9, 0, 0, 0, LOCAL)
     end = datetime(2007, 12, 22, 11, 0, 0, 0, LOCAL)
     eventSet1 = eventcalendar.EventSet('uid1')
     eventSet2 = eventcalendar.EventSet('uid2')
     event1 = eventcalendar.Event('uid1', start, end, 'content')
     eventSet1.addEvent(event1)
     event2 = eventcalendar.Event('uid2', start, end, 'content')
     eventSet2.addEvent(event2)
     rid = self._events[0].get('RECURRENCE-ID')
     self.failUnless(rid)
     riddatetime = parser.parse(str(rid))
     self.failUnless(str(rid).endswith('Z'))
     start = self._events[1].decoded('dtstart')
     self.failUnless(start)
     if start.tzinfo is None:
         tzinfo = tz.gettz(
             self._events[1]['dtstart'].params['TZID'])
         start = datetime(start.year, start.month, start.day,
             start.hour, start.minute, start.second,
             start.microsecond, tzinfo)
     rrulestr = str(self._events[1].get('RRULE'))
     self.failUnless(rrulestr)
     r = rrule.rrulestr(rrulestr, dtstart=start)
     self.failUnless(riddatetime in r)
Beispiel #34
0
def scheduled_block_json(station_id):
    scheduled_blocks = ScheduledBlock.query.filter_by(station_id=station_id)

    if not ('start' in request.args and 'end' in request.args):
        return {
            'status': 'error',
            'errors': 'scheduledblocks.json requires start and end',
            'status_code': 400
        }

    # TODO: fullcalendar updates based on these params
    start = dateutil.parser.parse(request.args.get('start'))
    end = dateutil.parser.parse(request.args.get('end'))

    resp = []
    for block in scheduled_blocks:
        r = rrule.rrulestr(block.recurrence)
        for instance in r.between(start, end):
            d = {
                'title': block.name,
                'start': datetime.combine(instance, block.start_time),
                'end': datetime.combine(instance, block.end_time),
                'id': block.id,
                'isBackground':
                True,  # the magic flag that tells full calendar to render as block
            }
            resp.append(d)
    return resp
Beispiel #35
0
    def __call__(self, *args, **kwargs):
        # Pop out custom keyword arguments added during scheduling and
        # previous run so as not to pollute the task function's
        # namespace.
        scheduled_task_id = kwargs.pop('scheduled_task_id')
        rrule_string = kwargs.pop('rrule_string')
        _first_eta = kwargs.pop('first_eta')
        _eta = kwargs.pop('eta')
        _until = kwargs.pop('until')

        first_eta = TaskScheduler.strptime(_first_eta)
        eta = TaskScheduler.strptime(_eta)
        until = TaskScheduler.strptime(_until)
        scheduled_task = ScheduledTask.objects.get(pk=scheduled_task_id)

        # If the task been manually set as ScheduledTask.STATUS_CANCELLED,
        # stop the execution.
        if scheduled_task.status == ScheduledTask.STATUS_CANCELLED:
            return

        scheduled_task.save_status(ScheduledTask.STATUS_RUNNING)
        ScheduledTaskRunLog.objects.create(task_id=self.request.id,
                                           scheduled_task=scheduled_task)

        # If a CancelSchedule exception is raied by the function,
        # cancel the schedule and exit.
        try:
            result = super(RepeatTask, self).__call__(*args, **kwargs)
        except CancelSchedule:
            TaskScheduler.cancel(scheduled_task_id=scheduled_task.id)
            return
        else:
            scheduled_task.save_status(ScheduledTask.STATUS_SUCCESS)

        # If rrule string is not specified, assume it to be a one time
        # task.
        if not rrule_string:
            return result

        # Preserve the start and end of rrule cycle.
        rrule_ = rrulestr(rrule_string).replace(dtstart=first_eta, until=until)

        next_eta = TaskScheduler.calculate_next_eta(rrule_=rrule_,
                                                    current_eta=eta)
        # If rrule does not return an ETA, assume it to be the end of
        # schedule and exit.
        if not next_eta:
            return result

        # Add custom keyword arguments again for the next run.
        kwargs.update({
            'scheduled_task_id': scheduled_task.id,
            'rrule_string': rrule_string,
            'first_eta': _first_eta,
            'eta': TaskScheduler.strftime(next_eta),
            'until': TaskScheduler.strftime(until),
        })

        self.apply_async(eta=next_eta, args=args, kwargs=kwargs)
        return result
    def get_rrule(self, dtstart):
        if self.complex_rule:
            d = dtstart.date()
            weekday = weekdays[d.weekday()]
            n = 1 + (d.day - 1) / 7

            start_day, days_in_month = calendar.monthrange(d.year, d.month)
            days_from_end = days_in_month - d.day

            minus_n = -1 - (days_from_end / 7)
            cr = (
                self.complex_rule.replace("%date%", dtstart.strftime("%Y%m%d"))
                .replace("%day%", dtstart.strftime("%d"))
                .replace("%month%", dtstart.strftime("%m"))
                .replace("%year%", dtstart.strftime("%Y"))
                .replace("%time%", dtstart.strftime("%H%M%S"))
                .replace("%datetime%", dtstart.strftime("%Y%m%dT%H%M%S"))
                .replace("%nthday%", "%s%s" % (n, weekday))
                .replace("%-nthday%", "%s%s" % (minus_n, weekday))
            )
            try:
                return rrule.rrulestr(str(cr), dtstart=dtstart)
            except ValueError:  # eg. unsupported property
                pass
        params = self.get_params()
        frequency = "rrule.%s" % self.frequency
        simple_rule = rrule.rrule(eval(frequency), dtstart=dtstart, **params)
        rs = rrule.rruleset()
        rs.rrule(simple_rule)
        return rs
Beispiel #37
0
 def run(self):
     self.logger.info('Running Scheduler')
     poll_interval = 5
     try:
         while 1:
             
             next_event = now() + timedelta(1)
              
             for rule in self.rules:
                 n = now() 
                 rrule = rrulestr(rule['rule'], dtstart=rule['created'])
                 items = rrule.between(rule['checked'], n)
                 if len(items) > 1:
                     self.logger.warn("Schedular missed %i tasks! Enqueuing latest" % (len(items)))
                 if items:
                     if self.check_rule(rule, n):
                         self.logger.info("Enqueueing task %r (%s)" % (rule['task'], items[0].ctime()))
                         self.enqueue_from_rule(rule)
                     else:
                         self.logger.warn("Another schedular has already run this task. moving on")
                 
                 next_event = min(next_event, rrule.after(n))
             
             self.logger.debug("Next event %s" % next_event.ctime())
             next_event = (next_event - now()).total_seconds()
             self.logger.debug("Next event in %i seconds" % next_event)
             
             sleep = max(1, min(next_event, poll_interval)) 
             self.logger.debug("Sleping for %i seconds" % sleep)
             time.sleep(sleep)
     
     except KeyboardInterrupt:
         self.logger.exception('Exiting main loop')
Beispiel #38
0
def _recurring_component_to_events(component):
    """
    Given an icalendar component with an "RRULE"
    Return a list of events as dictionaries
    """
    rrule_as_str = component.get('rrule').to_ical()
    recur_rule = rrule.rrulestr(rrule_as_str,
                                dtstart=component.decoded('dtstart'))
    recur_set = rrule.rruleset()
    recur_set.rrule(recur_rule)
    if 'exdate' in component:
        for exdate_line in component.decoded('exdate'):
            for exdate in exdate_line.dts:
                recur_set.exdate(exdate.dt)

    # get list of events in MAX_FUTURE days
    utcnow = now()
    later = utcnow + datetime.timedelta(days=MAX_FUTURE)
    start_times = recur_set.between(utcnow, later)

    # build list of events
    event_length = component.decoded('dtend') - component.decoded('dtstart')
    events = []
    for start in start_times:
        events.append({
            'start': start,
            'end': start + event_length,
            'summary': component.decoded('summary'),
            'uid': component.decoded('uid'),
            'last_modified': component.decoded('last-modified'),
        })
    return events
Beispiel #39
0
def get_events_from_rrule(ical_event, event_template, start_date, end_date):
    events = []

    ical_rrule = ical_event.get('rrule')
    ical_rrule_str = ical_rrule.to_ical().decode('utf-8')
    rrule = rrulestr(ical_rrule_str,
                     ignoretz=True,
                     dtstart=start_date.replace(tzinfo=None))
    ruleset = rruleset()
    ruleset.rrule(rrule)

    exdates = get_exdates(ical_event)
    for exdate in exdates:
        for exdate_date in exdate.dts:
            ruleset.exdate(exdate_date.dt.replace(tzinfo=None))

    after = datetime.utcnow() - timedelta(**INTO_PAST)
    before = datetime.utcnow() + timedelta(**INTO_FUTURE)
    rrule_instances = list(ruleset.between(after, before))
    for rrule_instance in rrule_instances:
        event = copy(event_template)
        event['start'] = berlin.localize(rrule_instance).isoformat()

        if not event["allDay"]:
            instance_end_date = datetime(rrule_instance.year,
                                         rrule_instance.month,
                                         rrule_instance.day, end_date.hour,
                                         end_date.minute, end_date.second)
            event["end"] = berlin.localize(instance_end_date).isoformat()

        events.append(event)

    return events
Beispiel #40
0
 def getRecurrence(observance, dtstart):
     if 'RRULE' in observance:
         return rrule.rrulestr(str(observance['RRULE']), dtstart=dtstart,
                               cache=True)
     if 'RDATE' in observance:
         return rrule.rrule('YEARLY', str(observance['RDATE']), cache=True)
     return None
Beispiel #41
0
 def _genere_occurrences(self):
     """Generate a list of occurrences."""
     if self.start.is_datetime() and self.end.is_datetime():
         delta = self.end.datetime - self.start.datetime
     elif self.start.is_date() and self.end.is_date():
         delta = self.end.date - self.start.date
     else:
         raise ValueError('datetime or date must be set for both start and end')
     self.occurrences = []
     if not self.recurrence:
         self.occurrences.append(self._create_occurrence(self.start.date_or_dt(), delta))
     else:
         rrs = shrink_rruleset(rrulestr(self.recurrence, dtstart=self.start.date_or_dt(), forceset=True))
         is_date = self.start.is_date()
         tz = self.get_start_timezone()
         for occurrence in rrs:
             # rruleset creates datetime objects
             if is_date:
                 if occurrence.time() == time():
                     # If time is 0, consider that occurrence is a date
                     occurrence = occurrence.date()
                 elif is_naive(occurrence):
                     # Else localize occurrence with event or calendar timezone
                     occurrence = tz.localize(occurrence)
             self.occurrences.append(self._create_occurrence(occurrence, delta))
Beispiel #42
0
def get_events(ics, start, end):
    events = []
    cal = Calendar.from_ical(res.text)
    start_no_tz = start.replace(tzinfo=None)
    end_no_tz = end.replace(tzinfo=None)
    for event in cal.walk('vevent'):
        this_event = {
            'title': unicode(event.get('summary', '')),
            'description': unicode(event.get('description', '')),
            'location': unicode(event.get('location', '')),
            'raw': event
        }
        if 'rrule' in event:
            duration = event['dtstart'].dt - event['dtend'].dt
            rrule = rrulestr(event['rrule'].to_ical(),
                             dtstart=event['dtstart'].dt)
            if not isinstance(event['dtstart'].dt, datetime):
                occurances = rrule.between(start_no_tz, end_no_tz)
            else:
                occurances = rrule.between(start, end)
            for occ in occurances:
                print (dt_cmp(occ, start))
                if dt_cmp(occ, start) >= 0:
                    if dt_cmp(occ+duration, end) <= 0:
                        new_event = this_event.copy()
                        new_event['start'] = occ
                        new_event['end'] = occ+duration
                        events.append(new_event)
        elif dt_cmp(event['dtstart'].dt, start) >= 0:
            if dt_cmp(event['dtend'].dt, end) <= 0:
                this_event['start'] = event['dtstart'].dt
                this_event['end'] = event['dtend'].dt
                events.append(this_event)
    return events
Beispiel #43
0
    def beat(self):
        self.logger.info('Reload jobs')

        now = int(time())
        prev = now - self.beat_interval

        jobs = self.storage.find({'$and': [
            {'crecord_type': 'job'},
            {'$or': [
                {'last_execution': {'$lte': prev}},
                {'last_execution': None},
            ]}
        ]})

        for job in jobs:
            job = job.dump()

            self.logger.info('Job: {0}'.format(job))

            if job['last_execution'] <= 0:
                self.do_job(job)

            else:
                jobStart = datetime.fromtimestamp(job['start'])

                dtstart = datetime.fromtimestamp(prev)
                dtend = datetime.fromtimestamp(now)

                occurences = list(
                    rrulestr(job['rrule'], dtstart=jobStart).between(
                        dtstart, dtend))

                if len(occurences) > 0:
                    self.do_job(job)
Beispiel #44
0
  def Poll (self, within_seconds=None):
    # print "poll within", within_seconds
    results = [ ]
    candidates = self.master.openaps.things.get('schedules', [ ])
    now = datetime.datetime.now( )
    # print "polling schedules", len(candidates), now.isoformat( ), 'for', self.MaxTasksAhead, 'MaxTasksAhead'
    for configured in candidates:
      # print "SCHEDULE", configured.item.fields
      # spec = recurrent.parse(configured.item.fields['rrule'], now=self.since)
      spec = configured.item.fields['rrule']
      rr = rrule.rrulestr(spec, dtstart=self.since)
      # print configured.item.fields['rrule'], spec
      upcoming = rr.after(now)
      # print "next", upcoming.isoformat( )
      # XXX: bug in making: need to fill out all events before within_seconds as well.
      # if (upcoming - now).total_seconds( ) <= within_seconds:
      for upcoming in iter_triggers(upcoming, rr, within_seconds):
        # print "ARM THING", configured.path
        # print "ATTEMPT ARM", configured.item.name, configured.path, spec
        # self.enqueue(upcoming, configured)
        trigger = Armable(upcoming, configured)
        # exists = self.schedules[(upcoming, configured.item.name)]
        results.append(trigger)


    return results
    pass
Beispiel #45
0
def _set_recurring_reminder (r, orig_message):
    '''
        Set Recurring Reminder

        Record a recurring reminder in the database to be sent.

        #TODO: Implement this

        --
        @param  r:dict              The parsed message from the user
        @param  orig_message:str    The original message received

        @return str
    '''

    logger.debug('Storing reminder for {id}'.format(
        id = orig_message['chat']['id']
    ))

    RemindRecurring.create(
        orig_message = json.dumps(orig_message),
        rrules = r['parsed_time'],
        next_run = rrulestr(r['parsed_time'],
                            dtstart = datetime.datetime.now()).after(datetime.datetime.now()),
        message = r['message']
    )

    return
Beispiel #46
0
 def _get_next_date(self):
     for rec in self:
         _after = fields.Datetime.from_string(datetime.today().strftime('%Y-%m-%d 09:00:00'))
         rec.next_date = None
         _next_date = rrule.rrulestr(rec.rrule_str).after(_after, inc=False)
         if _next_date:
             rec.next_date = _next_date.strftime('%Y-%m-%d')
Beispiel #47
0
def _expand_rrule_all_day(rrule: str, start: date, exclusions: Iterable,
                          start_at: datetime,
                          end_at: datetime) -> Iterable[date]:
    """Expand an rrule for all-day events.

    To my mind, these events cannot have changes, just exclusions, because
    changes only affect the time, which doesn't exist for all-day events.
    """

    rules = rruleset()
    rules.rrule(rrulestr(rrule, dtstart=start, ignoretz=True))

    # add exclusions
    if exclusions:
        for xdate in exclusions:
            rules.exdate(datetime.combine(xdate.dts[0].dt,
                                          datetime.min.time()))

    dates = []
    # reduce start and end to datetimes without timezone that just represent a
    # date at midnight.
    for candidate in rules.between(
            datetime.combine(start_at.date(), datetime.min.time()),
            datetime.combine(end_at.date(), datetime.min.time()),
            inc=True,
    ):
        dates.append(candidate.date())
    return dates
Beispiel #48
0
def expand_event(event):
    "expands recurring events into each individual instance"
    if 'RRULE' in event:
        event_start = event['DTSTART'].dt
        dtdelta = event['DTEND'].dt - event_start
        tz = getattr(event_start, 'tzinfo', None)
        if isinstance(event_start, datetime):
            event_start = event_start.replace(tzinfo=None)

        onerrule = '\n'.join(get_recurrence_lines(event))
        ruleset = rrule.rrulestr(onerrule,
                                 dtstart=event_start,
                                 forceset=True,
                                 ignoretz=True)

        for event_dt_start in ruleset:

            newdate = event_dt_start.date()
            if newdate < startdate:
                continue
            if newdate > enddate:
                return

            newev = deepcopy(event)
            if isinstance(newev['DTSTART'].dt, datetime):
                newev['DTSTART'].dt = event_dt_start.replace(tzinfo=tz)
                newev['DTEND'].dt = (event_dt_start +
                                     dtdelta).replace(tzinfo=tz)
            else:
                newev['DTSTART'].dt = event_dt_start.date()
                newev['DTEND'].dt = event_dt_start.date() + dtdelta

            yield newev
    else:
        yield event
Beispiel #49
0
 def schedule(self, jobid, schedule, after=None, backoff=None):
     jobid = _e(jobid)
     schedule = _e(schedule)
     if schedule is None:
         self.unset(jobid)
     elif schedule == 'STOP':
         self.set_status(jobid, 'STP')
     elif schedule == 'CONTINUE' and backoff:
         self.add_to_timeline(jobid, int(time.time()) + backoff)
     elif schedule == 'CONTINUE':
         self.enqueue(jobid)
     elif schedule == 'NOW':
         self.set_schedule(jobid, 'STOP')
         self.enqueue(jobid)
     elif schedule.startswith("AT:"):
         self.set_schedule(jobid, 'STOP')
         self.add_to_timeline(jobid, schedule.split(":")[1])
     else:
         after_dt = (datetime.fromtimestamp(after)
                     if after else datetime.utcnow())
         try:
             rrule = rrulestr(schedule)
             next_run_dt = rrule.after(after_dt)
             if next_run_dt:
                 next_run = calendar.timegm(next_run_dt.timetuple())
                 self.add_to_timeline(jobid, next_run)
             else:
                 self.set_status(jobid, 'STP')
         except ValueError:
             self.set_status(jobid, 'BAD')
             self.log.warn("%s Bad RRULE", jobid)
Beispiel #50
0
def _recurring_component_to_events(component):
    """
    Given an icalendar component with an "RRULE"
    Return a list of events as dictionaries
    """
    rrule_as_str = component.get('rrule').to_ical()
    recur_rule = rrule.rrulestr(rrule_as_str,
                                dtstart=component.decoded('dtstart'))
    recur_set = rrule.rruleset()
    recur_set.rrule(recur_rule)
    if 'exdate' in component:
        for exdate_line in component.decoded('exdate'):
            for exdate in exdate_line.dts:
                recur_set.exdate(exdate.dt)

    # get list of events in MAX_FUTURE days
    utcnow = now()
    later = utcnow + datetime.timedelta(days=MAX_FUTURE)
    start_times = recur_set.between(utcnow, later)

    # build list of events
    event_length = component.decoded('dtend') - component.decoded('dtstart')
    events = []
    for start in start_times:
        events.append({
            'start': start,
            'end': start + event_length,
            'summary': component.decoded('summary'),
            'uid': component.decoded('uid'),
            'last_modified': component.decoded('last-modified'),
        })
    return events
Beispiel #51
0
 def init_rule(self):
     doc = self.doc
     self.rrule = rrulestr(doc['rule'], dtstart=now())
     self.irule = iter(self.rrule)
     self.queue = self.factory.queue(doc['queue'], tags=doc['tags'])
     
     if self.timer is not None:
         self.set()
    def failUnlessParseMatches(self, string, true_rep, canonical, passthru):
        rule = rrule.rrulestr(string)
        
        parsed = CustomRecurrenceDialog.parse_rrule(rule)

        self.failUnlessEqual(true_rep, parsed[0])
        self.failUnlessEqual(canonical, parsed[1])
        self.failUnlessEqual(passthru, parsed[2])
Beispiel #53
0
 def get_wakeup_dates(self):
     if self.parser.has_section("Wakeup"):
         for wakeuptimer, rrulestring in self.parser.items('Wakeup'):
             if rrulestring.startswith("RRULE"):
                 rrulestring = rrulestring+";COUNT=1"
                 self.wakeupTimer[wakeuptimer] = list(rrule.rrulestr(rrulestring))[0]
             else:
                 self.wakeupTimer[wakeuptimer] = parser.parse(rrulestring)
Beispiel #54
0
def create_ami(instance):
    if not silent and verbose > 0:
        print "Creating AMI"
    create_time = datetime.now(pytz.utc)
    create_time_ISO = create_time.isoformat()
    name = '%s_Backup_%s' % ((instance.tags['Name'].replace(' ', '_') if instance.tags.has_key('Name') else instance.id), create_time.strftime('%Y%m%dT%H%M%SZ'))
    desc = '%s Backup on %s (%s)' % ((instance.tags['Name'] if instance.tags.has_key('Name') else instance.id), create_time.ctime(), str(create_time.tzinfo))

    reboot_rule_str = instance.tags[REBOOT_RRULE_TAG] if instance.tags.has_key(REBOOT_RRULE_TAG) else None
    force_reboot = False
    if reboot_rule_str:
        last_reboot = parser.parse(instance.tags[REBOOT_STAMP_TAG]) if instance.tags.has_key(REBOOT_STAMP_TAG) else parser.parse(instance.launch_time)
        try:
            force_reboot = True if rrulestr(reboot_rule_str+";byhour=0;byminute=0;bysecond=0", dtstart=last_reboot).before(datetime.now(pytz.utc)) else False
        except ValueError as e:
            if not silent:
                print e.message

    no_reboot = ((not force_reboot) and (instance.tags.has_key(NO_REBOOT_TAG) or instance.tags.has_key(REBOOT_RRULE_TAG))) or (instance.id == self_id)
    if not no_reboot:
        if not silent and verbose > 0:
            print "Tagging instance %s: %s" % (REBOOT_STAMP_TAG, create_time_ISO)
        instance.add_tag(REBOOT_STAMP_TAG, create_time_ISO)

    if not silent and verbose > 1:
        print '''Image parameters:
  Name:        %s
  Description: %s
  Source:      %s
  No-Reboot:   %s
  ''' % (name, desc, instance.id, no_reboot)

    ami_id = instance.create_image(name, description=desc, no_reboot=no_reboot)
    if not silent:
        print "Created AMI: %s" % (ami_id)

    # Wait for the image to appear
    if not silent and verbose > 0:
        print "Tagging image"
    tries_left = MAX_TRIES
    image = None
    while not image and tries_left:
        try:
            image = instance.connection.get_all_images(image_ids=[ami_id])[0]
        except exception.EC2ResponseError as e:
            if not silent:
                print e.message
            tries_left -= 1
    
    image.add_tag(STAMP_TAG, create_time_ISO)
    image.add_tag(SOURCE_TAG, instance.id)
    if not no_reboot:
        image.add_tag(CONSISTENT_TAG, "Yes")

    if not silent and verbose > 1:
        print "Created AMI tags: %s" % (image.tags)

    return ami_id
Beispiel #55
0
 def next_execution(self):
     if not self.activated:
         return None
     rule = rrulestr(self.rrule_string)
     utc_next_occurrence = rule.after(datetime.utcnow())
     if utc_next_occurrence:
         next_occurrence = utc_next_occurrence.replace(tzinfo=timezone.utc).astimezone(timezone.get_current_timezone())
         return next_occurrence
     return None
Beispiel #56
0
    def run(self):
        logging.info('psmqtt using config: %s', self.CONFIG)
        logging.info('you can set the configuration '
                     'with environment variable "PSMQTTCONFIG"')

        clientid = self.cf.get('mqtt_clientid', 'psmqtt-%s' % os.getpid())

        # additonal userdata for mqtt callbacks
        mqttc_userdata = MqttUserdata(
            self.request_topic, self.qos, self.run_task)

        # initialise MQTT broker connection
        mqttc = paho.Client(
            clientid, clean_session=True, userdata=mqttc_userdata)
        self.mqttc = mqttc

        mqttc.on_message = on_message
        mqttc.on_connect = on_connect
        mqttc.on_disconnect = on_disconnect

        mqttc.will_set('clients/psmqtt', payload="Adios!", qos=0, retain=False)

        # Delays will be: 3, 6, 12, 24, 30, 30, ...
        # mqttc.reconnect_delay_set(
        #   delay=3, delay_max=30, exponential_backoff=True)

        mqttc.username_pw_set(self.cf.get('mqtt_username'),
                              self.cf.get('mqtt_password'))

        mqttc.connect(self.cf.get('mqtt_broker', 'localhost'),
                      int(self.cf.get('mqtt_port', '1883')), 60)

        # parse schedule
        schedule = self.cf.get('schedule', {})
        s = sched.scheduler(time.time, time.sleep)
        now = datetime.now()
        for t in schedule:
            r = RecurringEvent()
            dt = r.parse(t)
            if not r.is_recurring:
                logging.error(t + " is not recurring time. Skipping")
                continue
            rrule = rrulestr(dt)
            delay = (rrule.after(now) - now).total_seconds()
            s.enter(delay, 1, self.on_timer, [s, rrule, schedule[t]])

        tt = TimerThread(s)
        tt.daemon = True
        tt.start()
        while True:
            try:
                mqttc.loop_forever()
            except socket.error:
                print('socket error retrying.')
                time.sleep(5)
            except KeyboardInterrupt:
                sys.exit(0)
Beispiel #57
0
def run_remind_recurring ():
    '''
        Run Remind Recurring

        Find and send all of the recurring reminders that are due

        --
        @return void
    '''

    logger.debug('Running Remind Recurring Job')

    try:

        # Get reminders have have not been marked as completed, as well as
        # have their next_run date ready or not set
        for reminder in RemindRecurring.select().where(RemindRecurring.sent == 0,
                                                       ((RemindRecurring.next_run <= datetime.now()) | (
                                                           RemindRecurring.next_run >> None))):

            # If we know the next_run date, send the message. If
            # we dont know the next_run, this will be skipped
            # and only the next_run determined
            if reminder.next_run is not None:
                logger.debug('Sending recurring reminder message with id {id}'.format(
                    id = reminder.id
                ))

                # Send the actual reminder
                Telegram.send_message(
                    _get_sender_information(reminder.orig_message),
                    'text',
                    reminder.message)

            # Lets parse the rrules and update the next_run time for
            # a message. We will use python-dateutil to help with
            # determinig the next run based on the parsed RRULE
            # relative from now.
            next_run = rrulestr(reminder.rrules,
                                dtstart = datetime.now()).after(datetime.now())

            # If there is no next run, consider the
            # schedule complete and mark it as
            # sent
            if not next_run:
                reminder.sent = 1
                reminder.save()

                continue

            # Save the next run
            reminder.next_run = next_run
            reminder.save()

    except Exception, e:

        print traceback.format_exc()
Beispiel #58
0
    def getActiveEventInstances(self, dt=None):
        """
        Get all event instances active at the given dt.

        @type  dt:     L{datetime.datetime}

        @rtype: list of L{EventInstance}
        """
        if not dt:
            dt = datetime.datetime.now(tz=UTC)

        result = []

        # handle recurrence events first
        recurring = self._getRecurringEvent()
        if recurring:
            # FIXME: support multiple RRULE; see 4.8.5.4 Recurrence Rule
            startRecurRule = rrule.rrulestr(recurring.rrules[0],
                dtstart=recurring.start)
            dtstart = startRecurRule.before(dt)

            if dtstart:
                skip = False
                # ignore if we have another event with this recurrence-id
                for event in self._events:
                    if event.recurrenceid:
                        if event.recurrenceid == dtstart:
                            self.log(
                                'event %r, recurrenceid %r matches dtstart %r',
                                    event, event.recurrenceid, dtstart)
                            skip = True

                # add if it's not on our list of exceptions
                if recurring.exdates and dtstart in recurring.exdates:
                    self.log('recurring event %r has exdate for %r',
                        recurring, dtstart)
                    skip = True

                if not skip:
                    delta = recurring.end - recurring.start
                    dtend = dtstart + delta
                    if dtend >= dt:
                        # starts before our dt, and ends after, so add
                        result.append(EventInstance(recurring, dtstart, dtend))

        # handle all other events
        for event in self._events:
            if event is recurring:
                continue

            if event.start < dt < event.end:
                result.append(EventInstance(event, event.start, event.end))

        self.log('events active at %s: %r', str(dt), result)

        return result