Commit ed237733 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Make a base class for DoCommand and DeleteCommand since they're alike.

parent 28532694
...@@ -28,21 +28,39 @@ class DeleteCommandTest(CommandTest.CommandTest): ...@@ -28,21 +28,39 @@ class DeleteCommandTest(CommandTest.CommandTest):
self.todolist = TodoList.TodoList(todos) self.todolist = TodoList.TodoList(todos)
def test_del1(self): def test_del1(self):
command = DeleteCommand.DeleteCommand(["1"], self.todolist, self.out, self.error) command = DeleteCommand.DeleteCommand(["1"], self.todolist, self.out, self.error, lambda p: "n")
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.todolist.todo(1).source(), "Bar") self.assertEquals(self.todolist.todo(1).source(), "Bar")
self.assertEquals(self.output, " 1 Foo id:1\nRemoved.\n") self.assertEquals(self.output, " 2 Bar p:1\nRemoved: Foo id:1\n")
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_del2(self): def test_del2(self):
command = DeleteCommand.DeleteCommand(["1"], self.todolist, self.out, self.error, lambda p: "y")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.todolist.count(), 0)
self.assertEquals(self.output, " 2 Bar p:1\nRemoved: Bar\nRemoved: Foo\n")
self.assertEquals(self.errors, "")
def test_del3(self):
command = DeleteCommand.DeleteCommand(["-f", "1"], self.todolist, self.out, self.error, lambda p: "n")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.todolist.count(), 0)
self.assertEquals(self.output, " 2 Bar p:1\nRemoved: Foo\n")
self.assertEquals(self.errors, "")
def test_del4(self):
command = DeleteCommand.DeleteCommand(["2"], self.todolist, self.out, self.error) command = DeleteCommand.DeleteCommand(["2"], self.todolist, self.out, self.error)
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.todolist.todo(1).source(), "Foo") self.assertEquals(self.todolist.todo(1).source(), "Foo")
self.assertEquals(self.output, " 2 Bar p:1\nRemoved.\n") self.assertEquals(self.output, "Removed: Bar p:1")
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_del3(self): def test_del3(self):
......
# Topydo - A todo.txt client written in Python. # Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 Bram Schoenmakers <me@bramschoenmakers.nl> # Copyright (C) 2014 Bram Schoenmakers <me@bramschoenmakers.nl>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
...@@ -50,14 +50,14 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -50,14 +50,14 @@ class DoCommandTest(CommandTest.CommandTest):
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.todo(3).is_completed()) self.assertTrue(self.todolist.todo(3).is_completed())
self.assertEquals(self.output, "x %s Baz p:1\n" % self.today) self.assertEquals(self.output, "Completed: x %s Baz p:1\n" % self.today)
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_do_children1(self): def test_do_subtasks1(self):
command = DoCommand.DoCommand(["1"], self.todolist, self.out, self.error, _yes_prompt) command = DoCommand.DoCommand(["1"], self.todolist, self.out, self.error, _yes_prompt)
command.execute() command.execute()
result = " 2 Bar p:1\n 3 Baz p:1\nx %s Bar p:1\nx %s Baz p:1\nx %s Foo id:1\n" % (self.today, self.today, self.today) result = " 2 Bar p:1\n 3 Baz p:1\nCompleted: x %s Bar p:1\nCompleted: x %s Baz p:1\nCompleted: x %s Foo id:1\n" % (self.today, self.today, self.today)
for number in [1, 2, 3]: for number in [1, 2, 3]:
self.assertTrue(self.todolist.todo(number).is_completed()) self.assertTrue(self.todolist.todo(number).is_completed())
...@@ -67,11 +67,11 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -67,11 +67,11 @@ class DoCommandTest(CommandTest.CommandTest):
self.assertEquals(self.output, result) self.assertEquals(self.output, result)
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_do_children2(self): def test_do_subtasks2(self):
command = DoCommand.DoCommand(["1"], self.todolist, self.out, self.error, _no_prompt) command = DoCommand.DoCommand(["1"], self.todolist, self.out, self.error, _no_prompt)
command.execute() command.execute()
result = " 2 Bar p:1\n 3 Baz p:1\nx %s Foo id:1\n" % self.today result = " 2 Bar p:1\n 3 Baz p:1\nCompleted: x %s Foo id:1\n" % self.today
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.todo(1).is_completed()) self.assertTrue(self.todolist.todo(1).is_completed())
...@@ -80,7 +80,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -80,7 +80,7 @@ class DoCommandTest(CommandTest.CommandTest):
self.assertEquals(self.output, result) self.assertEquals(self.output, result)
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_do_children_force1(self): def test_do_subtasks_force1(self):
prompt_shown = False prompt_shown = False
def prompt(p_prompt): def prompt(p_prompt):
...@@ -93,7 +93,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -93,7 +93,7 @@ class DoCommandTest(CommandTest.CommandTest):
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
self.assertFalse(self.todolist.todo(2).is_completed()) self.assertFalse(self.todolist.todo(2).is_completed())
def test_do_children_force2(self): def test_do_subtasks_force2(self):
prompt_shown = False prompt_shown = False
def prompt(p_prompt): def prompt(p_prompt):
...@@ -114,7 +114,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -114,7 +114,7 @@ class DoCommandTest(CommandTest.CommandTest):
command.execute() command.execute()
todo = self.todolist.todo(8) todo = self.todolist.todo(8)
result = " 8 %s Recurring! rec:1d due:%s\nx %s Recurring! rec:1d\n" % (self.today, self.tomorrow, self.today) result = " 8 %s Recurring! rec:1d due:%s\nCompleted: x %s Recurring! rec:1d\n" % (self.today, self.tomorrow, self.today)
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, result) self.assertEquals(self.output, result)
...@@ -144,7 +144,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -144,7 +144,7 @@ class DoCommandTest(CommandTest.CommandTest):
command = DoCommand.DoCommand(["2"], self.todolist, self.out, self.error) command = DoCommand.DoCommand(["2"], self.todolist, self.out, self.error)
command.execute() command.execute()
first_output = "x %s Bar p:1\n" % self.today first_output = "Completed: x %s Bar p:1\n" % self.today
self.assertEquals(self.output, first_output) self.assertEquals(self.output, first_output)
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
...@@ -152,14 +152,14 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -152,14 +152,14 @@ class DoCommandTest(CommandTest.CommandTest):
command = DoCommand.DoCommand(["3"], self.todolist, self.out, self.error) command = DoCommand.DoCommand(["3"], self.todolist, self.out, self.error)
command.execute() command.execute()
self.assertEquals(self.output, first_output + "x %s Baz p:1\nThe following todo item(s) became active:\nFoo id:1\n" % self.today) self.assertEquals(self.output, first_output + "Completed: x %s Baz p:1\nThe following todo item(s) became active:\nFoo id:1\n" % self.today)
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_activated_todos2(self): def test_activated_todos2(self):
command = DoCommand.DoCommand(["7"], self.todolist, self.out, self.error) command = DoCommand.DoCommand(["7"], self.todolist, self.out, self.error)
command.execute() command.execute()
self.assertEquals(self.output, "x %s Subtodo of inactive p:2\n" % self.today) self.assertEquals(self.output, "Completed: x %s Subtodo of inactive p:2\n" % self.today)
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_already_complete(self): def test_already_complete(self):
......
# 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 Command import *
from PrettyPrinter import *
from TodoList import InvalidTodoException
from Utils import convert_todo_number, InvalidTodoNumberException
class DCommand(Command):
"""
A common class for the 'do' and 'del' operations, because they're quite
alike.
"""
def __init__(self, p_args, p_todolist,
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(DCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt)
self.number = None
self.force = self.argument_shift("--force") or self.argument_shift("-f")
try:
self.number = convert_todo_number(self.argument(0))
self.todo = self.todolist.todo(self.number)
except (InvalidCommandArgument, InvalidTodoNumberException, InvalidTodoException):
self.todo = None
def _uncompleted_children(self, p_todo):
return sorted([t for t in self.todolist.children(p_todo) if not t.is_completed()])
def _print_list(self, p_todos, p_print_numbers=True):
filters = []
if p_print_numbers:
filters = [self.todolist.pp_number()]
self.out("\n".join(pretty_print_list(p_todos, filters)))
def prompt_text(self):
return "Yes or no? [n] "
def prefix(self):
""" Prefix to use when printing a todo. """
return ""
def _process_subtasks(self):
children = self._uncompleted_children(self.todo)
if children:
self._print_list(children)
if not self.force:
confirmation = self.prompt(self.prompt_text())
if not self.force and re.match('^y(es)?$', confirmation, re.I):
for child in children:
self.execute_specific_core(child)
self.out(self.prefix() + pretty_print(child))
def _print_unlocked_todos(self):
"""
Print the items that became unlocked by marking this subitem
(self.todo) as complete.
"""
parents = [parent for parent in self.todolist.parents(self.todo) if not self._uncompleted_children(parent) and parent.is_active()]
if parents:
self.out("The following todo item(s) became active:")
self._print_list(parents, False)
def condition(self):
""" An additional condition whether execute_specific should be executed. """
return True
def conditionFailedText(self):
return ""
def execute_specific(self):
pass
def execute_specific_core(self, p_todo):
"""
The core operation on the todo itself. Also used to operate on
child/parent tasks.
"""
pass
def execute(self):
if not super(DCommand, self).execute():
return False
if not self.number:
self.error(self.usage())
elif self.todo and self.condition():
self._process_subtasks()
self.execute_specific()
self._print_unlocked_todos()
elif not self.todo:
self.error("Invalid todo number given.")
else:
self.error(self.conditionFailedText())
...@@ -14,41 +14,31 @@ ...@@ -14,41 +14,31 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from Command import * from DCommand import DCommand
from PrettyPrinter import pretty_print from PrettyPrinter import pretty_print
from TodoList import InvalidTodoException
from Utils import convert_todo_number, InvalidTodoNumberException
class DeleteCommand(Command): class DeleteCommand(DCommand):
def __init__(self, p_args, p_todolist, def __init__(self, p_args, p_todolist,
p_out=lambda a: None, p_out=lambda a: None,
p_err=lambda a: None, p_err=lambda a: None,
p_prompt=lambda a: None): p_prompt=lambda a: None):
super(DeleteCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt) super(DeleteCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt)
self.number = None def prompt_text(self):
return "Also remove subtasks? [n] "
try: def prefix(self):
self.number = convert_todo_number(self.argument(0)) return "Removed: "
self.todo = self.todolist.todo(self.number)
except (InvalidCommandArgument, InvalidTodoNumberException, InvalidTodoException):
self.todo = None
def execute(self): def execute_specific_core(self, p_todo):
if not super(DeleteCommand, self).execute(): self.todolist.delete(p_todo)
return False
if not self.number: def execute_specific(self):
self.error(self.usage()) self.out(self.prefix() + pretty_print(self.todo))
elif self.todo: self.execute_specific_core(self.todo)
self.out(pretty_print(self.todo, [self.todolist.pp_number()]))
self.todolist.delete(self.todo)
self.out("Removed.")
else:
self.error("Invalid todo number given.")
def usage(self): def usage(self):
return """Synopsis: del <NUMBER>""" return """Synopsis: del [-f] <NUMBER>"""
def help(self): def help(self):
return """Deletes the todo item with the given number from the list.""" return """Deletes the todo item with the given number from the list."""
# Topydo - A todo.txt client written in Python. # Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 Bram Schoenmakers <me@bramschoenmakers.nl> # Copyright (C) 2014 Bram Schoenmakers <me@bramschoenmakers.nl>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import re import re
from Command import * from DCommand import DCommand
from PrettyPrinter import * from PrettyPrinter import pretty_print
from Recurrence import advance_recurring_todo from Recurrence import advance_recurring_todo
from TodoList import InvalidTodoException
from Utils import convert_todo_number, InvalidTodoNumberException
class DoCommand(Command): class DoCommand(DCommand):
def __init__(self, p_args, p_todolist, def __init__(self, p_args, p_todolist,
p_out=lambda a: None, p_out=lambda a: None,
p_err=lambda a: None, p_err=lambda a: None,
p_prompt=lambda a: None): p_prompt=lambda a: None):
super(DoCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt) super(DoCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt)
self.number = None
self.force = self.argument_shift("--force") or self.argument_shift("-f")
try:
self.number = convert_todo_number(self.argument(0))
self.todo = self.todolist.todo(self.number)
except (InvalidCommandArgument, InvalidTodoNumberException, InvalidTodoException):
self.todo = None
def _uncompleted_children(self, p_todo):
return sorted([t for t in self.todolist.children(p_todo) if not t.is_completed()])
def _print_list(self, p_todos, p_print_numbers=True):
filters = []
if p_print_numbers:
filters = [self.todolist.pp_number()]
self.out("\n".join(pretty_print_list(p_todos, filters)))
def _complete_children(self):
children = self._uncompleted_children(self.todo)
if children:
self._print_list(children)
if not self.force:
confirmation = self.prompt("Also mark subtasks as done? [n] ")
if not self.force and re.match('^y(es)?$', confirmation, re.I):
for child in children:
self.todolist.set_todo_completed(child)
self.out(pretty_print(child))
def _handle_recurrence(self): def _handle_recurrence(self):
if self.todo.has_tag('rec'): if self.todo.has_tag('rec'):
new_todo = advance_recurring_todo(self.todo) new_todo = advance_recurring_todo(self.todo)
self.todolist.add_todo(new_todo) self.todolist.add_todo(new_todo)
self.out(pretty_print(new_todo, [self.todolist.pp_number()])) self.out(pretty_print(new_todo, [self.todolist.pp_number()]))
def _print_unlocked_todos(self): def prompt_text(self):
""" return "Also mark subtasks as done? [n] "
Print the items that became unlocked by marking this subitem
(self.todo) as complete. def prefix(self):
""" return "Completed: "
parents = [parent for parent in self.todolist.parents(self.todo) if not self._uncompleted_children(parent) and parent.is_active()]
if parents: def condition(self):
self.out("The following todo item(s) became active:") """ An additional condition whether execute_specific should be executed. """
self._print_list(parents, False) return not self.todo.is_completed()
def execute(self): def conditionFailedText(self):
if not super(DoCommand, self).execute(): return "Todo has already been completed."
return False
if not self.number: def execute_specific(self):
self.error(self.usage()) """ Actions specific to this command. """
elif self.todo and not self.todo.is_completed(): self._handle_recurrence()
self._complete_children() self.execute_specific_core(self.todo)
self._handle_recurrence() self.out(self.prefix() + pretty_print(self.todo))
self.todolist.set_todo_completed(self.todo)
self.out(pretty_print(self.todo)) def execute_specific_core(self, p_todo):
self._print_unlocked_todos() """
elif not self.todo: The core operation on the todo itself. Also used to operate on
self.error("Invalid todo number given.") child/parent tasks.
else: """
self.error("Todo has already been completed.") self.todolist.set_todo_completed(p_todo)
def usage(self): def usage(self):
return """Synopsis: do [--force] <NUMBER>""" return """Synopsis: do [--force] <NUMBER>"""
......
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