Commit 486e995b authored by Bram Schoenmakers's avatar Bram Schoenmakers

Add support for recurrences using the 'rec' tag.

(C) A weekly recurring todo due:1w rec:1w
parent 46f10988
""" This module deals with recurring tasks. """
from datetime import date, timedelta
import Config
from RelativeDate import relative_date_to_date
import Todo
class NoRecurrenceException(Exception):
pass
def _get_due_date(p_todo):
"""
Gets the due date of a todo as a date object. Defaults to today when the
todo has no due date, or when the due date was in the past.
"""
due = p_todo.due_date()
if not due or due < date.today():
due = date.today()
return due
def advance_recurring_todo(p_todo):
"""
Given a Todo item, return a new instance of a Todo item with the dates
shifted according to the recurrence rule.
When no recurrence tag is present, an exception is raised.
"""
todo = Todo.Todo(p_todo.source())
pattern = todo.tag_value('rec')
if not pattern:
raise NoRecurrenceException()
due = _get_due_date(todo)
length = todo.length()
new_due = relative_date_to_date(pattern, due)
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())
return todo
from datetime import date, timedelta
import unittest
import Config
from Recurrence import advance_recurring_todo, NoRecurrenceException
import Todo
class RelativeDateTester(unittest.TestCase):
def setUp(self):
self.todo = Todo.Todo("Test rec:1w")
def test_duedate1(self):
""" Where due date is in the future. """
future = date.today() + timedelta(1)
new_due = date.today() + timedelta(8)
self.todo.set_tag(Config.TAG_DUE, future.isoformat())
new_todo = advance_recurring_todo(self.todo)
self.assertEquals(new_todo.due_date(), new_due)
def test_duedate2(self):
""" Where due date is today. """
todo = date.today()
new_due = date.today() + timedelta(7)
self.todo.set_tag(Config.TAG_DUE, todo.isoformat())
new_todo = advance_recurring_todo(self.todo)
self.assertEquals(new_todo.due_date(), new_due)
def test_duedate3(self):
""" Where due date is in the past. """
past = date.today() - timedelta(8)
new_due = date.today() + timedelta(7)
self.todo.set_tag(Config.TAG_DUE, past.isoformat())
new_todo = advance_recurring_todo(self.todo)
self.assertEquals(new_todo.due_date(), new_due)
def test_noduedate(self):
new_due = date.today() + timedelta(7)
new_todo = advance_recurring_todo(self.todo)
self.assertTrue(new_todo.has_tag(Config.TAG_DUE))
self.assertEquals(new_todo.due_date(), new_due)
def test_startdate(self):
""" Start date is before due date. """
self.todo.set_tag(Config.TAG_DUE, date.today().isoformat())
yesterday = date.today() - timedelta(1)
self.todo.set_tag(Config.TAG_START, yesterday.isoformat())
new_start = date.today() + timedelta(6)
new_todo = advance_recurring_todo(self.todo)
self.assertEquals(new_todo.start_date(), new_start)
def test_startdate2(self):
""" Start date equals due date. """
self.todo.set_tag(Config.TAG_DUE, date.today().isoformat())
self.todo.set_tag(Config.TAG_START, date.today().isoformat())
new_start = date.today() + timedelta(7)
new_todo = advance_recurring_todo(self.todo)
self.assertEquals(new_todo.start_date(), new_start)
def test_no_recurrence(self):
self.todo.remove_tag('rec')
self.assertRaises(NoRecurrenceException,advance_recurring_todo,self.todo)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment