Пример #1
0
def _advance_recurring_todo_helper(p_todo, p_offset):
    """
    Given a Todo item, return a new instance of a Todo item with the dates
    shifted according to the recurrence rule.

    The new date is calculated from the given p_offset value.

    When no recurrence tag is present, an exception is raised.
    """

    todo = Todo(p_todo.source())
    pattern = todo.tag_value('rec')

    if not pattern:
        raise NoRecurrenceException()

    length = todo.length()
    new_due = relative_date_to_date(pattern, p_offset)

    if not new_due:
        raise NoRecurrenceException()

    # pylint: disable=E1103
    todo.set_tag(config().tag_due(), new_due.isoformat())

    if todo.start_date():
        new_start = new_due - timedelta(length)
        todo.set_tag(config().tag_start(), new_start.isoformat())

    todo.set_creation_date(date.today())

    return todo
Пример #2
0
    def match(self, p_todo):
        """
        Performs a match on a key:value tag in the todo.

        First it tries to convert the value and the user-entered expression to
        a date and makes a comparison if it succeeds, based on the given
        operator (default ==).
        Upon failure, it falls back to converting value and user-entered
        expression to an integer and makes a numerical comparison based on the
        given operator (default ==)
        As a last resort, it falls back to using a Grep filter to see if the
        user given expression is contained in the todo text.
        """
        if not self.key or not p_todo.has_tag(self.key):
            return False

        try:
            operand1 = date_string_to_date(p_todo.tag_value(self.key))
            operand2 = relative_date_to_date(self.value)

            if not operand2:
                operand2 = date_string_to_date(self.value)

        except ValueError:
            operand1 = p_todo.tag_value(self.key)
            operand2 = self.value

            try:
                operand1 = int(operand1)
                operand2 = int(operand2)
            except ValueError:
                grep = GrepFilter(self.expression)
                return grep.match(p_todo)

        return self.compare_operands(operand1, operand2)
Пример #3
0
 def test_weekday_next_week(self):
     """
     When entering "Friday" on a Friday, return next week Friday instead of
     today.
     """
     result = relative_date_to_date("fri")
     self.assertTrue(result, self.friday)
Пример #4
0
        def convert_date(p_tag):
            value = self.todo.tag_value(p_tag)

            if value:
                dateobj = relative_date_to_date(value)
                if dateobj:
                    self.todo.set_tag(p_tag, dateobj.isoformat())
Пример #5
0
    def _execute_multi_specific(self):
        def _get_offset(p_todo):
            offset = p_todo.tag_value(
                config().tag_due(), date.today().isoformat())
            offset_date = date_string_to_date(offset)

            if offset_date < date.today():
                offset_date = date.today()

            return offset_date

        pattern = self.args[-1]
        self.printer.add_filter(PrettyPrinterNumbers(self.todolist))

        for todo in self.todos:
            offset = _get_offset(todo)
            new_due = relative_date_to_date(pattern, offset)

            if new_due:
                if self.move_start_date and todo.has_tag(config().tag_start()):
                    length = todo.length()
                    new_start = new_due - timedelta(length)
                    # pylint: disable=E1103
                    todo.set_tag(config().tag_start(), new_start.isoformat())

                # pylint: disable=E1103
                todo.set_tag(config().tag_due(), new_due.isoformat())

                self.todolist.set_dirty()
                self.out(self.printer.print_todo(todo))
            else:
                self.error("Invalid date pattern given.")
                break
Пример #6
0
 def test_weekday_next_week(self):
     """
     When entering "Friday" on a Friday, return next week Friday instead of
     today.
     """
     result = relative_date_to_date("fri")
     self.assertTrue(result, self.friday)
Пример #7
0
    def _execute_multi_specific(self):
        def _get_offset(p_todo):
            offset = p_todo.tag_value(config().tag_due(),
                                      date.today().isoformat())
            offset_date = date_string_to_date(offset)

            if offset_date < date.today():
                offset_date = date.today()

            return offset_date

        pattern = self.args[-1]
        self.printer.add_filter(PrettyPrinterNumbers(self.todolist))

        for todo in self.todos:
            offset = _get_offset(todo)
            new_due = relative_date_to_date(pattern, offset)

            if new_due:
                if self.move_start_date and todo.has_tag(config().tag_start()):
                    length = todo.length()
                    new_start = new_due - timedelta(length)
                    # pylint: disable=E1103
                    todo.set_tag(config().tag_start(), new_start.isoformat())

                # pylint: disable=E1103
                todo.set_tag(config().tag_due(), new_due.isoformat())

                self.todolist.set_dirty()
                self.out(self.printer.print_todo(todo))
            else:
                self.error("Invalid date pattern given.")
                break
Пример #8
0
    def match(self, p_todo):
        if not self.key or not p_todo.has_tag(self.key):
            return False

        try:
            operand1 = date_string_to_date(p_todo.tag_value(self.key))
            operand2 = relative_date_to_date(self.value)

            if not operand2:
                operand2 = date_string_to_date(self.value)

        except ValueError:
            try:
                operand1 = int(p_todo.tag_value(self.key))
                operand2 = int(self.value)
            except ValueError:
                return False

        if self.operator == '<':
            return operand1 < operand2
        elif self.operator == '<=':
            return operand1 <= operand2
        elif self.operator == '=':
            return operand1 == operand2
        elif self.operator == '>=':
            return operand1 >= operand2
        elif self.operator == '>':
            return operand1 > operand2
        elif self.operator == '!':
            return operand1 != operand2

        return False
Пример #9
0
def _advance_recurring_todo_helper(p_todo, p_offset):
    """
    Given a Todo item, return a new instance of a Todo item with the dates
    shifted according to the recurrence rule.

    The new date is calculated from the given p_offset value.

    When no recurrence tag is present, an exception is raised.
    """

    todo = Todo(p_todo.source())
    pattern = todo.tag_value('rec')

    if not pattern:
        raise NoRecurrenceException()

    length = todo.length()
    new_due = relative_date_to_date(pattern, p_offset)

    if not new_due:
        raise NoRecurrenceException()

    # pylint: disable=E1103
    todo.set_tag(config().tag_due(), new_due.isoformat())

    if todo.start_date():
        new_start = new_due - timedelta(length)
        todo.set_tag(config().tag_start(), new_start.isoformat())

    todo.set_creation_date(date.today())

    return todo
Пример #10
0
            def convert_date(p_tag):
                value = p_todo.tag_value(p_tag)

                if value:
                    dateobj = relative_date_to_date(value)
                    if dateobj:
                        p_todo.set_tag(p_tag, dateobj.isoformat())
Пример #11
0
    def test_one_month_ext(self):
        test_date1 = date(2015, 1, 29)
        test_date2 = date(2016, 1, 31)
        test_date3 = date(2015, 12, 31)
        test_date4 = date(2015, 7, 31)
        test_date5 = date(2015, 10, 31)

        result1 = relative_date_to_date('1m', test_date1)
        result2 = relative_date_to_date('1m', test_date2)
        result3 = relative_date_to_date('1m', test_date3)
        result4 = relative_date_to_date('1m', test_date4)
        result5 = relative_date_to_date('1m', test_date5)

        self.assertEqual(result1, date(2015, 2, 28))
        self.assertEqual(result2, date(2016, 2, 29))
        self.assertEqual(result3, date(2016, 1, 31))
        self.assertEqual(result4, date(2015, 8, 31))
        self.assertEqual(result5, date(2015, 11, 30))
Пример #12
0
    def test_one_month_ext(self):
        test_date1 = date(2015, 1, 29)
        test_date2 = date(2016, 1, 31)
        test_date3 = date(2015, 12, 31)
        test_date4 = date(2015, 7, 31)
        test_date5 = date(2015, 10, 31)

        result1 = relative_date_to_date('1m', test_date1)
        result2 = relative_date_to_date('1m', test_date2)
        result3 = relative_date_to_date('1m', test_date3)
        result4 = relative_date_to_date('1m', test_date4)
        result5 = relative_date_to_date('1m', test_date5)

        self.assertEqual(result1, date(2015, 2, 28))
        self.assertEqual(result2, date(2016, 2, 29))
        self.assertEqual(result3, date(2016, 1, 31))
        self.assertEqual(result4, date(2015, 8, 31))
        self.assertEqual(result5, date(2015, 11, 30))
Пример #13
0
    def _convert_relative_dates(self):
        is_start_tag = self.tag == config().tag_start()
        is_due_tag = self.tag == config().tag_due()

        if self.relative_date or is_start_tag or is_due_tag:
            real_date = relative_date_to_date(self.value)

            if real_date:
                self.value = real_date.isoformat()
Пример #14
0
    def _convert_relative_dates(self):
        is_start_tag = self.tag == config().tag_start()
        is_due_tag = self.tag == config().tag_due()

        if self.relative_date or is_start_tag or is_due_tag:
            real_date = relative_date_to_date(self.value)

            if real_date:
                self.value = real_date.isoformat()
Пример #15
0
    def match(self, p_todo):
        operand1 = self.getter(p_todo)
        operand2 = relative_date_to_date(self.value)

        if not operand2:
            operand2 = date_string_to_date(self.value)

        if operand1 and operand2:
            return self.compare_operands(operand1, operand2)
        else:
            return False
Пример #16
0
    def _dates(self, p_word_before_cursor):
        to_absolute = lambda s: relative_date_to_date(s).isoformat()

        start_value_pos = p_word_before_cursor.find(':') + 1
        value = p_word_before_cursor[start_value_pos:]

        for reldate in _date_suggestions():
            if not reldate.startswith(value):
                continue

            yield Completion(reldate, -len(value), display_meta=to_absolute(reldate))
Пример #17
0
    def match(self, p_todo):
        operand1 = self.getter(p_todo)
        operand2 = relative_date_to_date(self.value)

        if not operand2:
            operand2 = date_string_to_date(self.value)

        if operand1 and operand2:
            return self.compare_operands(operand1, operand2)
        else:
            return False
Пример #18
0
    def process_flag(self, p_opt, p_value):
        super().process_flag(p_opt, p_value)

        if p_opt == "-s" or p_opt == "--strict":
            self.strict_recurrence = True
        elif p_opt == "-d" or p_opt == "--date":
            try:
                self.completion_date = relative_date_to_date(p_value)

                if not self.completion_date:
                    self.completion_date = date_string_to_date(p_value)
            except ValueError:
                self.completion_date = date.today()
Пример #19
0
    def process_flag(self, p_opt, p_value):
        super().process_flag(p_opt, p_value)

        if p_opt == "-s" or p_opt == "--strict":
            self.strict_recurrence = True
        elif p_opt == "-d" or p_opt == "--date":
            try:
                self.completion_date = relative_date_to_date(p_value)

                if not self.completion_date:
                    self.completion_date = date_string_to_date(p_value)
            except ValueError:
                self.completion_date = date.today()
Пример #20
0
    def match(self, p_todo):
        """
        Performs a match on a key:value tag in the todo.

        First it tries to convert the value and the user-entered expression to
        a date and makes a comparison if it succeeds, based on the given
        operator (default ==).
        Upon failure, it falls back to converting value and user-entered
        expression to an integer and makes a numerical comparison based on the
        given operator (default ==)
        As a last resort, it falls back to using a Grep filter to see if the
        user given expression is contained in the todo text.
        """
        if not self.key or not p_todo.has_tag(self.key):
            return False

        try:
            operand1 = date_string_to_date(p_todo.tag_value(self.key))
            operand2 = relative_date_to_date(self.value)

            if not operand2:
                operand2 = date_string_to_date(self.value)

        except ValueError:
            operand1 = p_todo.tag_value(self.key)
            operand2 = self.value

            try:
                operand1 = int(operand1)
                operand2 = int(operand2)
            except ValueError:
                grep = GrepFilter(self.expression)
                return grep.match(p_todo)

        if self.operator == '<':
            return operand1 < operand2
        elif self.operator == '<=':
            return operand1 <= operand2
        elif self.operator == '=':
            return operand1 == operand2
        elif self.operator == '>=':
            return operand1 >= operand2
        elif self.operator == '>':
            return operand1 > operand2
        elif self.operator == '!':
            return operand1 != operand2

        return False
Пример #21
0
def advance_recurring_todo(p_todo, p_offset=None, p_strict=False):
    """
    Given a Todo item, return a new instance of a Todo item with the dates
    shifted according to the recurrence rule.

    Strict means that the real due date is taken as a offset, not today or a
    future date to determine the offset.

    When the todo item has no due date, then the date is used passed by the
    caller (defaulting to today).

    When no recurrence tag is present, an exception is raised.
    """
    todo = Todo(p_todo.source())
    pattern = todo.tag_value('rec')

    if not pattern:
        raise NoRecurrenceException()
    elif pattern.startswith('+'):
        p_strict = True
        # strip off the +
        pattern = pattern[1:]

    if p_strict:
        offset = p_todo.due_date() or p_offset or date.today()
    else:
        offset = p_offset or date.today()

    length = todo.length()
    new_due = relative_date_to_date(pattern, offset)

    if not new_due:
        raise NoRecurrenceException()

    # pylint: disable=E1103
    todo.set_tag(config().tag_due(), new_due.isoformat())

    if todo.start_date():
        new_start = new_due - timedelta(length)
        todo.set_tag(config().tag_start(), new_start.isoformat())

    if config().auto_creation_date():
        todo.set_creation_date(date.today())

    return todo
Пример #22
0
def advance_recurring_todo(p_todo, p_offset=None, p_strict=False):
    """
    Given a Todo item, return a new instance of a Todo item with the dates
    shifted according to the recurrence rule.

    Strict means that the real due date is taken as a offset, not today or a
    future date to determine the offset.

    When the todo item has no due date, then the date is used passed by the
    caller (defaulting to today).

    When no recurrence tag is present, an exception is raised.
    """
    todo = Todo(p_todo.source())
    pattern = todo.tag_value('rec')

    if not pattern:
        raise NoRecurrenceException()
    elif pattern.startswith('+'):
        p_strict = True
        # strip off the +
        pattern = pattern[1:]

    if p_strict:
        offset = p_todo.due_date() or p_offset or date.today()
    else:
        offset = p_offset or date.today()

    length = todo.length()
    new_due = relative_date_to_date(pattern, offset)

    if not new_due:
        raise NoRecurrenceException()

    # pylint: disable=E1103
    todo.set_tag(config().tag_due(), new_due.isoformat())

    if todo.start_date():
        new_start = new_due - timedelta(length)
        todo.set_tag(config().tag_start(), new_start.isoformat())

    todo.set_creation_date(date.today())

    return todo
Пример #23
0
def _dates(p_word_before_cursor):
    """ Generator for date completion. """
    def _date_suggestions():
        """
        Returns a list of relative date that is presented to the user as auto
        complete suggestions.
        """
        # don't use strftime, prevent locales to kick in
        days_of_week = {
            0: "Monday",
            1: "Tuesday",
            2: "Wednesday",
            3: "Thursday",
            4: "Friday",
            5: "Saturday",
            6: "Sunday"
        }

        dates = [
            'today',
            'tomorrow',
        ]

        # show days of week up to next week
        dow = datetime.date.today().weekday()
        for i in range(dow + 2 % 7, dow + 7):
            dates.append(days_of_week[i % 7])

        # and some more relative days starting from next week
        dates += ["1w", "2w", "1m", "2m", "3m", "1y"]

        return dates

    to_absolute = lambda s: relative_date_to_date(s).isoformat()

    start_value_pos = p_word_before_cursor.find(':') + 1
    value = p_word_before_cursor[start_value_pos:]

    for reldate in _date_suggestions():
        if not reldate.startswith(value):
            continue

        yield Completion(reldate, -len(value), display_meta=to_absolute(reldate))
Пример #24
0
    def _execute_multi_specific(self):
        def _get_offset(p_todo):
            offset = p_todo.tag_value(config().tag_due(),
                                      date.today().isoformat())

            offset_date = date_string_to_date(offset)

            if offset_date < date.today():
                offset_date = date.today()

            return offset_date

        pattern = self.args[-1]
        self.printer.add_filter(PrettyPrinterNumbers(self.todolist))

        for todo in self.todos:
            try:
                offset = _get_offset(todo)
            except ValueError:
                self.error("Postponing todo item failed: invalid due date.")
                break

            new_due = relative_date_to_date(pattern, offset)

            if new_due:
                if self.move_start_date and todo.start_date():
                    length = todo.length()
                    new_start = new_due - timedelta(length)
                    # pylint: disable=E1103
                    todo.set_tag(config().tag_start(), new_start.isoformat())
                elif self.move_start_date and not todo.start_date():
                    self.error(
                        "Warning: todo item has no (valid) start date, therefore it was not adjusted."
                    )

                # pylint: disable=E1103
                todo.set_tag(config().tag_due(), new_due.isoformat())

                self.todolist.dirty = True
                self.out(self.printer.print_todo(todo))
            else:
                self.error("Invalid date pattern given.")
                break
Пример #25
0
    def match(self, p_todo):
        """
        Performs a match on a key:value tag in the todo.

        First it tries to convert the value and the user-entered expression to
        a date and makes a comparison if it succeeds, based on the given
        operator (default ==).
        Upon failure, it falls back to converting value and user-entered
        expression to an integer and makes a numerical comparison based on the
        given operator (default ==)
        As a last resort, it falls back to using a Grep filter to see if the
        user given expression is contained in the todo text.
        """
        def resort_to_grep_filter():
            grep = GrepFilter(self.expression)
            return grep.match(p_todo)

        if not self.key or not p_todo.has_tag(self.key):
            return False

        if len(p_todo.tag_values(self.key)) > 1:
            # we cannot apply an ordening on a tag that appears more than once
            # in this todo item, therefore use a simple value match
            return resort_to_grep_filter()

        try:
            operand1 = date_string_to_date(p_todo.tag_value(self.key))
            operand2 = relative_date_to_date(self.value)

            if not operand2:
                operand2 = date_string_to_date(self.value)

        except ValueError:
            operand1 = p_todo.tag_value(self.key)
            operand2 = self.value

            try:
                operand1 = int(operand1)
                operand2 = int(operand2)
            except ValueError:
                return resort_to_grep_filter()

        return self.compare_operands(operand1, operand2)
Пример #26
0
    def execute(self):
        def _get_offset(p_todo):
            offset = p_todo.tag_value(config().tag_due(),
                                      date.today().isoformat())
            offset_date = date_string_to_date(offset)

            if offset_date < date.today():
                offset_date = date.today()

            return offset_date

        if not super(PostponeCommand, self).execute():
            return False

        self._process_flags()

        try:
            todo = self.todolist.todo(self.argument(0))
            pattern = self.argument(1)

            offset = _get_offset(todo)
            new_due = relative_date_to_date(pattern, offset)

            if new_due:
                if self.move_start_date and todo.has_tag(config().tag_start()):
                    length = todo.length()
                    new_start = new_due - timedelta(length)
                    todo.set_tag(config().tag_start(), new_start.isoformat())

                todo.set_tag(config().tag_due(), new_due.isoformat())

                self.todolist.set_dirty()
                self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
                self.out(self.printer.print_todo(todo))
            else:
                self.error("Invalid date pattern given.")

        except InvalidCommandArgument:
            self.error(self.usage())
        except (InvalidTodoException):
            self.error("Invalid todo number given.")
Пример #27
0
 def test_zero_years(self):
     result = relative_date_to_date('0y')
     self.assertEqual(result, self.today)
Пример #28
0
 def test_leap_year(self):
     test_date = date(2016, 2, 29)
     result1 = relative_date_to_date('1y', test_date)
     result2 = relative_date_to_date('4y', test_date)
     self.assertEqual(result1, date(2017, 2, 28))
     self.assertEqual(result2, date(2020, 2, 29))
Пример #29
0
 def test_monday3(self):
     result = relative_date_to_date('mon')
     self.assertEqual(result, self.monday)
Пример #30
0
 def test_one_week(self):
     result = relative_date_to_date('1w')
     self.assertEqual(result, date(2015, 11, 13))
Пример #31
0
 def test_one_bday(self):
     result = relative_date_to_date('1b')
     self.assertEqual(result, self.monday)
Пример #32
0
 def test_monday4(self):
     result = relative_date_to_date('mondayy')
     self.assertFalse(result)
Пример #33
0
 def test_negative_period3(self):
     result = relative_date_to_date('-1b')
     self.assertEqual(result, date(2015, 11, 5))
Пример #34
0
 def test_offset1(self):
     result = relative_date_to_date('1d', self.tomorrow)
     self.assertEqual(result, date(2015, 11, 8))
Пример #35
0
 def test_leap_year(self):
     test_date = date(2016, 2, 29)
     result1 = relative_date_to_date('1y', test_date)
     result2 = relative_date_to_date('4y', test_date)
     self.assertEqual(result1, date(2017, 2, 28))
     self.assertEqual(result2, date(2020, 2, 29))
Пример #36
0
 def test_zero_bdays(self):
     result = relative_date_to_date('0b')
     self.assertEqual(result, self.today)
Пример #37
0
 def test_one_bday(self):
     result = relative_date_to_date('1b')
     self.assertEqual(result, self.monday)
Пример #38
0
 def test_one_bweek(self):
     result = relative_date_to_date('5b')
     self.assertEqual(result, self.friday)
Пример #39
0
 def test_one_week(self):
     result = relative_date_to_date('1w')
     self.assertEqual(result, date(2015, 11, 13))
Пример #40
0
 def test_one_month(self):
     test_date = date(2015, 1, 10)
     result = relative_date_to_date('1m', test_date)
     self.assertEqual(result, date(2015, 2, 10))
Пример #41
0
 def test_one_year(self):
     test_date = date(2015, 1, 10)
     result = relative_date_to_date('1y', test_date)
     self.assertEqual(result, date(2016, 1, 10))
Пример #42
0
 def test_monday4(self):
     result = relative_date_to_date('mondayy')
     self.assertFalse(result)
Пример #43
0
 def test_one_day(self):
     result = relative_date_to_date('1d')
     self.assertEqual(result, self.tomorrow)
Пример #44
0
 def test_negative_period2(self):
     result = relative_date_to_date('-0d')
     self.assertTrue(result, self.today)
Пример #45
0
 def test_negative_period4(self):
     result = relative_date_to_date('-5b')
     self.assertEqual(result, date(2015, 10, 30))
Пример #46
0
 def test_negative_period4(self):
     result = relative_date_to_date('-5b')
     self.assertEqual(result, date(2015, 10, 30))
Пример #47
0
 def test_negative_period3(self):
     result = relative_date_to_date('-1b')
     self.assertEqual(result, date(2015, 11, 5))
Пример #48
0
 def test_one_day(self):
     result = relative_date_to_date('1d')
     self.assertEqual(result, self.tomorrow)
Пример #49
0
 def test_negative_period2(self):
     result = relative_date_to_date('-0d')
     self.assertTrue(result, self.today)
Пример #50
0
 def test_one_bweek(self):
     result = relative_date_to_date('5b')
     self.assertEqual(result, self.friday)
Пример #51
0
 def test_offset1(self):
     result = relative_date_to_date('1d', self.tomorrow)
     self.assertEqual(result, date(2015, 11, 8))
Пример #52
0
 def test_one_month(self):
     test_date = date(2015, 1, 10)
     result = relative_date_to_date('1m', test_date)
     self.assertEqual(result, date(2015, 2, 10))
Пример #53
0
 def test_today2(self):
     result = relative_date_to_date('tod')
     self.assertEqual(result, self.today)
Пример #54
0
 def test_one_year(self):
     test_date = date(2015, 1, 10)
     result = relative_date_to_date('1y', test_date)
     self.assertEqual(result, date(2016, 1, 10))
Пример #55
0
 def test_tomorrow2(self):
     result = relative_date_to_date('tom')
     self.assertEqual(result, self.tomorrow)
Пример #56
0
 def test_zero_months(self):
     result = relative_date_to_date('0m')
     self.assertEqual(result, self.today)
Пример #57
0
 def test_yesterday2(self):
     result = relative_date_to_date('yes')
     self.assertEqual(result, self.yesterday)
Пример #58
0
 def test_monday3(self):
     result = relative_date_to_date('mon')
     self.assertEqual(result, self.monday)
Пример #59
0
 def test_zero_months(self):
     result = relative_date_to_date('0m')
     self.assertEqual(result, self.today)