mirror of
https://github.com/topydo/topydo.git
synced 2024-06-02 18:48:33 +00:00
Add postpone subcommand.
This commit is contained in:
parent
99ca605763
commit
1b7b8412f1
|
@ -39,6 +39,7 @@ Subcommands implemented:
|
|||
* ls
|
||||
* lscon
|
||||
* lsprj
|
||||
* postpone [x]
|
||||
* pri
|
||||
* sort [xx]
|
||||
* tag [x]
|
||||
|
|
|
@ -32,6 +32,7 @@ from DoCommand import DoCommand
|
|||
from ListCommand import ListCommand
|
||||
from ListContextCommand import ListContextCommand
|
||||
from ListProjectCommand import ListProjectCommand
|
||||
from PostponeCommand import PostponeCommand
|
||||
from PrettyPrinter import *
|
||||
from PriorityCommand import PriorityCommand
|
||||
from SortCommand import SortCommand
|
||||
|
@ -119,6 +120,7 @@ class CLIApplication(object):
|
|||
'listproj': ListProjectCommand,
|
||||
'listproject': ListProjectCommand,
|
||||
'listprojects': ListProjectCommand,
|
||||
'postpone': PostponeCommand,
|
||||
'pri': PriorityCommand,
|
||||
'rm': DeleteCommand,
|
||||
'sort': SortCommand,
|
||||
|
|
97
lib/PostponeCommand.py
Normal file
97
lib/PostponeCommand.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
# Topydo - A todo.txt client written in Python.
|
||||
# Copyright (C) 2014 Bram Schoenmakers <me@bramschoenmakers.nl>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from datetime import date, timedelta
|
||||
|
||||
from Command import *
|
||||
from PrettyPrinter import *
|
||||
from RelativeDate import relative_date_to_date
|
||||
from TodoList import InvalidTodoException
|
||||
from Utils import convert_todo_number, InvalidTodoNumberException, date_string_to_date
|
||||
|
||||
class PostponeCommand(Command):
|
||||
def __init__(self, p_args, p_todolist,
|
||||
p_out=lambda a: None,
|
||||
p_err=lambda a: None,
|
||||
p_prompt=lambda a: None):
|
||||
super(PostponeCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt)
|
||||
|
||||
self.move_start_date = False
|
||||
|
||||
def _process_flags(self):
|
||||
opts, args = self.getopt('s')
|
||||
|
||||
for o, a in opts:
|
||||
if o == '-s':
|
||||
self.move_start_date = True
|
||||
|
||||
self.args = args
|
||||
|
||||
def _get_offset(self, 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
|
||||
|
||||
def execute(self):
|
||||
if not super(PostponeCommand, self).execute():
|
||||
return False
|
||||
|
||||
self._process_flags()
|
||||
|
||||
try:
|
||||
number = convert_todo_number(self.argument(0))
|
||||
todo = self.todolist.todo(number)
|
||||
pattern = self.argument(1)
|
||||
|
||||
# pdb.set_trace()
|
||||
offset = self._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.out(pretty_print(todo, [self.todolist.pp_number()]))
|
||||
else:
|
||||
self.error("Invalid date pattern given.")
|
||||
|
||||
except InvalidCommandArgument:
|
||||
self.error(self.usage())
|
||||
except (InvalidTodoNumberException, InvalidTodoException):
|
||||
self.error("Invalid todo number given.")
|
||||
|
||||
def usage(self):
|
||||
return "Synopsis: postpone [-s] <NUMBER> <PATTERN>"
|
||||
|
||||
def help(self):
|
||||
return """Postpone a todo item with the given number and the given pattern.
|
||||
|
||||
Postponing is done by adjusting the due date of the todo, and if the -s flag is
|
||||
given, the start date accordingly.
|
||||
|
||||
The pattern is a relative date, written in the format <COUNT><PERIOD> where
|
||||
count is a number and <PERIOD> is either 'd', 'w', 'm' or 'y', which stands for
|
||||
days, weeks, months and years respectively. Example: 'postpone 1 1w' postpones
|
||||
todo number 1 for 1 week."""
|
161
test/PostponeCommandTest.py
Normal file
161
test/PostponeCommandTest.py
Normal file
|
@ -0,0 +1,161 @@
|
|||
# Topydo - A todo.txt client written in Python.
|
||||
# Copyright (C) 2014 Bram Schoenmakers <me@bramschoenmakers.nl>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from datetime import date, timedelta
|
||||
|
||||
import CommandTest
|
||||
import PostponeCommand
|
||||
import TodoList
|
||||
|
||||
class PostponeCommandTest(CommandTest.CommandTest):
|
||||
def setUp(self):
|
||||
self.today = date.today()
|
||||
self.past = date.today() - timedelta(1)
|
||||
self.future = date.today() + timedelta(1)
|
||||
self.start = date.today() - timedelta(2)
|
||||
self.future_start = self.future - timedelta(2)
|
||||
|
||||
todos = [
|
||||
"Foo",
|
||||
"Bar due:%s" % self.today.isoformat(),
|
||||
"Baz due:%s t:%s" % (self.today.isoformat(), self.start.isoformat()),
|
||||
"Past due:%s" % self.past.isoformat(),
|
||||
"Future due:%s t:%s" % (self.future.isoformat(), self.future_start.isoformat()),
|
||||
]
|
||||
|
||||
self.todolist = TodoList.TodoList(todos)
|
||||
|
||||
def test_postpone1(self):
|
||||
command = PostponeCommand.PostponeCommand(["1", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.today + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 1 Foo due:%s\n" % due.isoformat())
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone2(self):
|
||||
command = PostponeCommand.PostponeCommand(["2", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.today + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 2 Bar due:%s\n" % due.isoformat())
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone3(self):
|
||||
command = PostponeCommand.PostponeCommand(["-s", "2", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.today + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 2 Bar due:%s\n" % due.isoformat())
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone4(self):
|
||||
command = PostponeCommand.PostponeCommand(["3", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.today + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 3 Baz due:%s t:%s\n" % (due.isoformat(), self.start.isoformat()))
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone5(self):
|
||||
command = PostponeCommand.PostponeCommand(["-s", "3", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.today + timedelta(7)
|
||||
start = self.start + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 3 Baz due:%s t:%s\n" % (due.isoformat(), start.isoformat()))
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone6(self):
|
||||
command = PostponeCommand.PostponeCommand(["4", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.today + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 4 Past due:%s\n" % due.isoformat())
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone7(self):
|
||||
command = PostponeCommand.PostponeCommand(["5", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.future + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 5 Future due:%s t:%s\n" % (due.isoformat(), self.future_start.isoformat()))
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone8(self):
|
||||
command = PostponeCommand.PostponeCommand(["-s", "5", "1w"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
due = self.future + timedelta(7)
|
||||
start = self.future_start + timedelta(7)
|
||||
|
||||
self.assertTrue(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, " 5 Future due:%s t:%s\n" % (due.isoformat(), start.isoformat()))
|
||||
self.assertEquals(self.errors, "")
|
||||
|
||||
def test_postpone9(self):
|
||||
command = PostponeCommand.PostponeCommand(["1", "foo"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
self.assertFalse(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, "")
|
||||
self.assertEquals(self.errors, "Invalid date pattern given.\n")
|
||||
|
||||
def test_postpone10(self):
|
||||
command = PostponeCommand.PostponeCommand(["99", "foo"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
self.assertFalse(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, "")
|
||||
self.assertEquals(self.errors, "Invalid todo number given.\n")
|
||||
|
||||
def test_postpone11(self):
|
||||
command = PostponeCommand.PostponeCommand(["A", "foo"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
self.assertFalse(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, "")
|
||||
self.assertEquals(self.errors, "Invalid todo number given.\n")
|
||||
|
||||
def test_postpone12(self):
|
||||
command = PostponeCommand.PostponeCommand(["1"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
self.assertFalse(self.todolist.is_dirty())
|
||||
self.assertEquals(self.output, "")
|
||||
self.assertEquals(self.errors, command.usage() + "\n")
|
||||
|
||||
def test_help(self):
|
||||
command = PostponeCommand.PostponeCommand(["help"], self.todolist, self.out, self.error)
|
||||
command.execute()
|
||||
|
||||
self.assertEquals(self.output, "")
|
||||
self.assertEquals(self.errors, command.usage() + "\n\n" + command.help() + "\n")
|
||||
|
Loading…
Reference in a new issue