Commit d7d40205 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Apply strict recurrence when rec: expression starts with +.

Insprired from the Simpletask client for Android.

https://github.com/mpcjanssen/simpletask-android
parent 5d62f8fc
...@@ -18,7 +18,7 @@ from datetime import date, timedelta ...@@ -18,7 +18,7 @@ from datetime import date, timedelta
import unittest import unittest
from topydo.lib.Config import config from topydo.lib.Config import config
from topydo.lib.Recurrence import advance_recurring_todo, strict_advance_recurring_todo, NoRecurrenceException from topydo.lib.Recurrence import advance_recurring_todo, NoRecurrenceException
from topydo.lib.Todo import Todo from topydo.lib.Todo import Todo
from test.TopydoTest import TopydoTest from test.TopydoTest import TopydoTest
...@@ -26,6 +26,7 @@ class RecurrenceTest(TopydoTest): ...@@ -26,6 +26,7 @@ class RecurrenceTest(TopydoTest):
def setUp(self): def setUp(self):
super(RecurrenceTest, self).setUp() super(RecurrenceTest, self).setUp()
self.todo = Todo("Test rec:1w") self.todo = Todo("Test rec:1w")
self.stricttodo = Todo("Test rec:+1w")
def test_duedate1(self): def test_duedate1(self):
""" Where due date is in the future. """ """ Where due date is in the future. """
...@@ -63,7 +64,7 @@ class RecurrenceTest(TopydoTest): ...@@ -63,7 +64,7 @@ class RecurrenceTest(TopydoTest):
new_due = date.today() - timedelta(1) new_due = date.today() - timedelta(1)
self.todo.set_tag(config().tag_due(), past.isoformat()) self.todo.set_tag(config().tag_due(), past.isoformat())
new_todo = strict_advance_recurring_todo(self.todo) new_todo = advance_recurring_todo(self.todo, p_strict=True)
self.assertEqual(new_todo.due_date(), new_due) self.assertEqual(new_todo.due_date(), new_due)
...@@ -73,7 +74,7 @@ class RecurrenceTest(TopydoTest): ...@@ -73,7 +74,7 @@ class RecurrenceTest(TopydoTest):
new_due = date.today() + timedelta(8) new_due = date.today() + timedelta(8)
self.todo.set_tag(config().tag_due(), future.isoformat()) self.todo.set_tag(config().tag_due(), future.isoformat())
new_todo = strict_advance_recurring_todo(self.todo) new_todo = advance_recurring_todo(self.todo, p_strict=True)
self.assertEqual(new_todo.due_date(), new_due) self.assertEqual(new_todo.due_date(), new_due)
...@@ -83,7 +84,7 @@ class RecurrenceTest(TopydoTest): ...@@ -83,7 +84,7 @@ class RecurrenceTest(TopydoTest):
new_due = date.today() + timedelta(7) new_due = date.today() + timedelta(7)
self.todo.set_tag(config().tag_due(), today.isoformat()) self.todo.set_tag(config().tag_due(), today.isoformat())
new_todo = strict_advance_recurring_todo(self.todo) new_todo = advance_recurring_todo(self.todo, p_strict=True)
self.assertEqual(new_todo.due_date(), new_due) self.assertEqual(new_todo.due_date(), new_due)
...@@ -96,7 +97,7 @@ class RecurrenceTest(TopydoTest): ...@@ -96,7 +97,7 @@ class RecurrenceTest(TopydoTest):
def test_noduedate2(self): def test_noduedate2(self):
new_due = date.today() + timedelta(7) new_due = date.today() + timedelta(7)
new_todo = strict_advance_recurring_todo(self.todo) new_todo = advance_recurring_todo(self.todo, p_strict=True)
self.assertTrue(new_todo.has_tag(config().tag_due())) self.assertTrue(new_todo.has_tag(config().tag_due()))
self.assertEqual(new_todo.due_date(), new_due) self.assertEqual(new_todo.due_date(), new_due)
...@@ -121,7 +122,7 @@ class RecurrenceTest(TopydoTest): ...@@ -121,7 +122,7 @@ class RecurrenceTest(TopydoTest):
self.todo.set_tag(config().tag_start(), yesterday.isoformat()) self.todo.set_tag(config().tag_start(), yesterday.isoformat())
new_start = date.today() + timedelta(5) new_start = date.today() + timedelta(5)
new_todo = strict_advance_recurring_todo(self.todo) new_todo = advance_recurring_todo(self.todo, p_strict=True)
self.assertEqual(new_todo.start_date(), new_start) self.assertEqual(new_todo.start_date(), new_start)
...@@ -135,6 +136,32 @@ class RecurrenceTest(TopydoTest): ...@@ -135,6 +136,32 @@ class RecurrenceTest(TopydoTest):
self.assertEqual(new_todo.start_date(), new_start) self.assertEqual(new_todo.start_date(), new_start)
def test_strict_recurrence1(self):
"""
Strict recurrence where due date is in the past, using + notation in
expression.
"""
past = date.today() - timedelta(8)
new_due = date.today() - timedelta(1)
self.stricttodo.set_tag(config().tag_due(), past.isoformat())
new_todo = advance_recurring_todo(self.stricttodo, p_strict=True)
self.assertEqual(new_todo.due_date(), new_due)
def test_strict_recurrence2(self):
"""
Strict recurrence where due date is in the future, using + notation in
expression.
"""
future = date.today() + timedelta(1)
new_due = date.today() + timedelta(8)
self.stricttodo.set_tag(config().tag_due(), future.isoformat())
new_todo = advance_recurring_todo(self.stricttodo, p_strict=True)
self.assertEqual(new_todo.due_date(), new_due)
def test_no_recurrence(self): def test_no_recurrence(self):
self.todo.remove_tag('rec') self.todo.remove_tag('rec')
self.assertRaises(NoRecurrenceException, advance_recurring_todo, self.todo) self.assertRaises(NoRecurrenceException, advance_recurring_todo, self.todo)
......
...@@ -19,7 +19,7 @@ from datetime import date ...@@ -19,7 +19,7 @@ from datetime import date
from topydo.lib.DCommand import DCommand from topydo.lib.DCommand import DCommand
from topydo.lib.PrettyPrinter import PrettyPrinter from topydo.lib.PrettyPrinter import PrettyPrinter
from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers
from topydo.lib.Recurrence import advance_recurring_todo, strict_advance_recurring_todo, NoRecurrenceException from topydo.lib.Recurrence import advance_recurring_todo, NoRecurrenceException
from topydo.lib.Utils import date_string_to_date from topydo.lib.Utils import date_string_to_date
class DoCommand(DCommand): class DoCommand(DCommand):
...@@ -54,12 +54,11 @@ class DoCommand(DCommand): ...@@ -54,12 +54,11 @@ class DoCommand(DCommand):
def _handle_recurrence(self, p_todo): def _handle_recurrence(self, p_todo):
if p_todo.has_tag('rec'): if p_todo.has_tag('rec'):
try: try:
if self.strict_recurrence: new_todo = advance_recurring_todo(
new_todo = strict_advance_recurring_todo(p_todo, p_todo,
self.completion_date) p_offset=self.completion_date,
else: p_strict=self.strict_recurrence
new_todo = advance_recurring_todo(p_todo, )
self.completion_date)
self.todolist.add_todo(new_todo) self.todolist.add_todo(new_todo)
......
...@@ -25,24 +25,36 @@ from topydo.lib.Todo import Todo ...@@ -25,24 +25,36 @@ from topydo.lib.Todo import Todo
class NoRecurrenceException(Exception): class NoRecurrenceException(Exception):
pass pass
def _advance_recurring_todo_helper(p_todo, p_offset): 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 Given a Todo item, return a new instance of a Todo item with the dates
shifted according to the recurrence rule. shifted according to the recurrence rule.
The new date is calculated from the given p_offset value. 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. When no recurrence tag is present, an exception is raised.
""" """
todo = Todo(p_todo.source()) todo = Todo(p_todo.source())
pattern = todo.tag_value('rec') pattern = todo.tag_value('rec')
if not pattern: if not pattern:
raise NoRecurrenceException() 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() length = todo.length()
new_due = relative_date_to_date(pattern, p_offset) new_due = relative_date_to_date(pattern, offset)
if not new_due: if not new_due:
raise NoRecurrenceException() raise NoRecurrenceException()
...@@ -57,23 +69,3 @@ def _advance_recurring_todo_helper(p_todo, p_offset): ...@@ -57,23 +69,3 @@ def _advance_recurring_todo_helper(p_todo, p_offset):
todo.set_creation_date(date.today()) todo.set_creation_date(date.today())
return todo return todo
def advance_recurring_todo(p_todo, p_offset=None):
p_offset = p_offset or date.today()
return _advance_recurring_todo_helper(p_todo, p_offset)
def strict_advance_recurring_todo(p_todo, p_offset=None):
"""
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.
"""
offset = p_todo.due_date() or p_offset or date.today()
return _advance_recurring_todo_helper(p_todo, offset)
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