Commit ebbf3954 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge pull request #44 from mruwek/expressions-in-multicommand

Expression-mode for del, depri, do, pri, postpone.
parents 9d33afef a842cb2c
...@@ -35,6 +35,8 @@ class DeleteCommandTest(CommandTest): ...@@ -35,6 +35,8 @@ class DeleteCommandTest(CommandTest):
todos = [ todos = [
"Foo id:1", "Foo id:1",
"Bar p:1", "Bar p:1",
"a @test with due:2015-06-03",
"a @test with +project",
] ]
self.todolist = TodoList(todos) self.todolist = TodoList(todos)
...@@ -62,7 +64,7 @@ class DeleteCommandTest(CommandTest): ...@@ -62,7 +64,7 @@ class DeleteCommandTest(CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.todolist.count(), 0) self.assertEqual(self.todolist.count(), 2)
self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Bar\nRemoved: Foo\n") self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Bar\nRemoved: Foo\n")
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
...@@ -71,7 +73,7 @@ class DeleteCommandTest(CommandTest): ...@@ -71,7 +73,7 @@ class DeleteCommandTest(CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.todolist.count(), 1) # force won't delete subtasks self.assertEqual(self.todolist.count(), 3) # force won't delete subtasks
self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Foo id:1\n") self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Foo id:1\n")
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
...@@ -80,7 +82,7 @@ class DeleteCommandTest(CommandTest): ...@@ -80,7 +82,7 @@ class DeleteCommandTest(CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.todolist.count(), 1) # force won't delete subtasks self.assertEqual(self.todolist.count(), 3) # force won't delete subtasks
self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Foo id:1\n") self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Foo id:1\n")
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
...@@ -116,7 +118,9 @@ class DeleteCommandTest(CommandTest): ...@@ -116,7 +118,9 @@ class DeleteCommandTest(CommandTest):
command = DeleteCommand(["8to"], self.todolist, self.out, self.error) command = DeleteCommand(["8to"], self.todolist, self.out, self.error)
command.execute() command.execute()
self.assertEqual(self.todolist.print_todos(), "Foo") result = "Foo\na @test with due:2015-06-03\na @test with +project"
self.assertEqual(self.todolist.print_todos(), result)
self.assertRaises(InvalidTodoException, self.todolist.todo, 'b0n') self.assertRaises(InvalidTodoException, self.todolist.todo, 'b0n')
def test_multi_del1(self): def test_multi_del1(self):
...@@ -124,14 +128,20 @@ class DeleteCommandTest(CommandTest): ...@@ -124,14 +128,20 @@ class DeleteCommandTest(CommandTest):
command = DeleteCommand(["1", "2"], self.todolist, self.out, self.error, _no_prompt) command = DeleteCommand(["1", "2"], self.todolist, self.out, self.error, _no_prompt)
command.execute() command.execute()
self.assertEqual(self.todolist.count(), 0) result = "a @test with due:2015-06-03\na @test with +project"
self.assertEqual(self.todolist.count(), 2)
self.assertEqual(self.todolist.print_todos(), result)
def test_multi_del2(self): def test_multi_del2(self):
""" Test deletion of multiple items. """ """ Test deletion of multiple items. """
command = DeleteCommand(["1", "2"], self.todolist, self.out, self.error, _yes_prompt) command = DeleteCommand(["1", "2"], self.todolist, self.out, self.error, _yes_prompt)
command.execute() command.execute()
self.assertEqual(self.todolist.count(), 0) result = "a @test with due:2015-06-03\na @test with +project"
self.assertEqual(self.todolist.count(), 2)
self.assertEqual(self.todolist.print_todos(), result)
def test_multi_del3(self): def test_multi_del3(self):
""" Fail if any of supplied todo numbers is invalid. """ """ Fail if any of supplied todo numbers is invalid. """
...@@ -160,6 +170,50 @@ class DeleteCommandTest(CommandTest): ...@@ -160,6 +170,50 @@ class DeleteCommandTest(CommandTest):
self.assertEqual(self.output, "") self.assertEqual(self.output, "")
self.assertEqual(self.errors, u("Invalid todo number given: Fo\u00d3B\u0105r.\n")) self.assertEqual(self.errors, u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
def test_expr_del1(self):
command = DeleteCommand(["-e", "@test"], self.todolist, self.out, self.error, None)
command.execute()
result = "Removed: a @test with due:2015-06-03\nRemoved: a @test with +project\n"
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.todolist.count(), 2)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_expr_del2(self):
command = DeleteCommand(["-e", "@test", "due:2015-06-03"], self.todolist, self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "Removed: a @test with due:2015-06-03\n")
self.assertEqual(self.errors, "")
def test_expr_del3(self):
command = DeleteCommand(["-e", "@test", "due:2015-06-03", "+project"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_del4(self):
""" Remove only relevant todo items. """
command = DeleteCommand(["-e", ""], self.todolist, self.out, self.error, None)
command.execute()
result = "Foo"
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.todolist.count(), 1)
self.assertEqual(self.todolist.print_todos(), result)
def test_expr_del5(self):
""" Force deleting unrelevant items with additional -x flag. """
command = DeleteCommand(["-xe", ""], self.todolist, self.out, self.error, _yes_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.todolist.count(), 0)
def test_empty(self): def test_empty(self):
command = DeleteCommand([], self.todolist, self.out, self.error) command = DeleteCommand([], self.todolist, self.out, self.error)
command.execute() command.execute()
......
...@@ -28,6 +28,9 @@ class DepriCommandTest(CommandTest): ...@@ -28,6 +28,9 @@ class DepriCommandTest(CommandTest):
"(A) Foo", "(A) Foo",
"Bar", "Bar",
"(B) Baz", "(B) Baz",
"(E) a @test with due:2015-06-03",
"(Z) a @test with +project p:1",
"(D) Bax id:1",
] ]
self.todolist = TodoList(todos) self.todolist = TodoList(todos)
...@@ -69,6 +72,50 @@ class DepriCommandTest(CommandTest): ...@@ -69,6 +72,50 @@ class DepriCommandTest(CommandTest):
self.assertEqual(self.output, "Priority removed.\n| 1| Foo\nPriority removed.\n| 3| Baz\n") self.assertEqual(self.output, "Priority removed.\n| 1| Foo\nPriority removed.\n| 3| Baz\n")
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
def test_expr_depri1(self):
command = DepriCommand(["-e", "@test"], self.todolist, self.out, self.error, None)
command.execute()
result = "Priority removed.\n| 4| a @test with due:2015-06-03\nPriority removed.\n| 5| a @test with +project p:1\n"
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_expr_depri2(self):
command = DepriCommand(["-e", "@test", "due:2015-06-03"], self.todolist, self.out, self.error, None)
command.execute()
result = "Priority removed.\n| 4| a @test with due:2015-06-03\n"
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_expr_depri3(self):
command = DepriCommand(["-e", "@test", "due:2015-06-03", "+project"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_depri4(self):
""" Don't remove priority from unrelevant todo items. """
command = DepriCommand(["-e", "Bax"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_depri5(self):
""" Force unprioritizing unrelevant items with additional -x flag. """
command = DepriCommand(["-xe", "Bax"], self.todolist, self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "Priority removed.\n| 6| Bax id:1\n")
self.assertEqual(self.errors, "")
def test_invalid1(self): def test_invalid1(self):
command = DepriCommand(["99"], self.todolist, self.out, self.error) command = DepriCommand(["99"], self.todolist, self.out, self.error)
......
...@@ -41,6 +41,8 @@ class DoCommandTest(CommandTest): ...@@ -41,6 +41,8 @@ class DoCommandTest(CommandTest):
"Subtodo of inactive p:2", "Subtodo of inactive p:2",
"Strict due:2014-01-01 rec:1d", "Strict due:2014-01-01 rec:1d",
"Invalid rec:1", "Invalid rec:1",
"a @test with due:2015-06-03",
"a @test with +project",
] ]
self.todolist = TodoList(todos) self.todolist = TodoList(todos)
...@@ -123,7 +125,7 @@ class DoCommandTest(CommandTest): ...@@ -123,7 +125,7 @@ class DoCommandTest(CommandTest):
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.count(), 10) self.assertEqual(self.todolist.count(), 12)
def test_recurrence(self): def test_recurrence(self):
self.assertFalse(self.todolist.todo(4).has_tag('due')) self.assertFalse(self.todolist.todo(4).has_tag('due'))
...@@ -131,7 +133,7 @@ class DoCommandTest(CommandTest): ...@@ -131,7 +133,7 @@ class DoCommandTest(CommandTest):
self._recurrence_helper(["4"]) self._recurrence_helper(["4"])
self.assertTrue(self.todolist.todo(4).is_completed()) self.assertTrue(self.todolist.todo(4).is_completed())
result = "| 10| {today} Recurring! rec:1d due:{tomorrow}\nCompleted: x {today} Recurring! rec:1d\n".format(today=self.today, tomorrow=self.tomorrow) result = "| 12| {today} Recurring! rec:1d due:{tomorrow}\nCompleted: x {today} Recurring! rec:1d\n".format(today=self.today, tomorrow=self.tomorrow)
self.assertEqual(self.output, result) self.assertEqual(self.output, result)
todo = self.todolist.todo(10) todo = self.todolist.todo(10)
...@@ -140,13 +142,13 @@ class DoCommandTest(CommandTest): ...@@ -140,13 +142,13 @@ class DoCommandTest(CommandTest):
def test_strict_recurrence1(self): def test_strict_recurrence1(self):
self._recurrence_helper(["-s", "8"]) self._recurrence_helper(["-s", "8"])
result = "| 10| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today) result = "| 12| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today)
self.assertEqual(self.output, result) self.assertEqual(self.output, result)
def test_strict_recurrence2(self): def test_strict_recurrence2(self):
self._recurrence_helper(["--strict", "8"]) self._recurrence_helper(["--strict", "8"])
result = "| 10| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today) result = "| 12| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today)
self.assertEqual(self.output, result) self.assertEqual(self.output, result)
def test_invalid1(self): def test_invalid1(self):
...@@ -254,7 +256,7 @@ class DoCommandTest(CommandTest): ...@@ -254,7 +256,7 @@ class DoCommandTest(CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "| 10| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday)) self.assertEqual(self.output, "| 12| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday))
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
def test_do_custom_date6(self): def test_do_custom_date6(self):
...@@ -267,7 +269,7 @@ class DoCommandTest(CommandTest): ...@@ -267,7 +269,7 @@ class DoCommandTest(CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "| 10| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday)) self.assertEqual(self.output, "| 12| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday))
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
def test_do_custom_date7(self): def test_do_custom_date7(self):
...@@ -279,7 +281,7 @@ class DoCommandTest(CommandTest): ...@@ -279,7 +281,7 @@ class DoCommandTest(CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "| 10| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {yesterday} Strict due:2014-01-01 rec:1d\n".format(today=self.today, yesterday=self.yesterday)) self.assertEqual(self.output, "| 12| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {yesterday} Strict due:2014-01-01 rec:1d\n".format(today=self.today, yesterday=self.yesterday))
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
def test_multi_do1(self): def test_multi_do1(self):
...@@ -320,10 +322,10 @@ class DoCommandTest(CommandTest): ...@@ -320,10 +322,10 @@ class DoCommandTest(CommandTest):
""" """
Check output when all supplied todo numbers are invalid. Check output when all supplied todo numbers are invalid.
""" """
command = DoCommand(["99", "10"], self.todolist, self.out, self.error, _no_prompt) command = DoCommand(["99", "15"], self.todolist, self.out, self.error, _no_prompt)
command.execute() command.execute()
self.assertEqual(self.errors, "Invalid todo number given: 99.\nInvalid todo number given: 10.\n") self.assertEqual(self.errors, "Invalid todo number given: 99.\nInvalid todo number given: 15.\n")
def test_multi_do6(self): def test_multi_do6(self):
""" Throw an error with invalid argument containing special characters. """ """ Throw an error with invalid argument containing special characters. """
...@@ -333,6 +335,46 @@ class DoCommandTest(CommandTest): ...@@ -333,6 +335,46 @@ class DoCommandTest(CommandTest):
self.assertFalse(self.todolist.is_dirty()) self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.errors, u("Invalid todo number given: Fo\u00d3B\u0105r.\n")) self.assertEqual(self.errors, u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
def test_expr_do1(self):
command = DoCommand(["-e", "@test"], self.todolist, self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "Completed: x {t} a @test with due:2015-06-03\nCompleted: x {t} a @test with +project\n".format(t=self.today))
self.assertEqual(self.errors, "")
def test_expr_do2(self):
command = DoCommand(["-e", "@test", "due:2015-06-03"], self.todolist, self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "Completed: x {} a @test with due:2015-06-03\n".format(self.today))
self.assertEqual(self.errors, "")
def test_expr_do3(self):
command = DoCommand(["-e", "@test", "due:2015-06-03", "+project"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_do4(self):
""" Don't do anything with unrelevant todo items. """
command = DoCommand(["-e", "Foo"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_do5(self):
""" Force marking unrelevant items as done with additional -x flag. """
command = DoCommand(["-xe", "Foo"], self.todolist, self.out, self.error, _yes_prompt)
command.execute()
result = "| 2| Bar p:1\n| 3| Baz p:1\nCompleted: x {t} Bar p:1\nCompleted: x {t} Baz p:1\nCompleted: x {t} Foo id:1\n".format(t=self.today)
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_invalid_recurrence(self): def test_invalid_recurrence(self):
""" Show error message when an item has an invalid recurrence pattern. """ """ Show error message when an item has an invalid recurrence pattern. """
command = DoCommand(["9"], self.todolist, self.out, self.error, _no_prompt) command = DoCommand(["9"], self.todolist, self.out, self.error, _no_prompt)
......
...@@ -139,7 +139,7 @@ class EditCommandTest(CommandTest): ...@@ -139,7 +139,7 @@ class EditCommandTest(CommandTest):
self.assertEqual(self.output, expected) self.assertEqual(self.output, expected)
self.assertEqual(self.todolist.print_todos(), u("Foo id:1\nFo\u00f3B\u0105\u017a\nLazy Cat\nLazy Dog")) self.assertEqual(self.todolist.print_todos(), u("Foo id:1\nFo\u00f3B\u0105\u017a\nLazy Cat\nLazy Dog"))
@mock.patch('topydo.commands.EditCommand.call') @mock.patch('topydo.commands.EditCommand.check_call')
def test_edit_archive(self, mock_call): def test_edit_archive(self, mock_call):
""" Edit archive file. """ """ Edit archive file. """
mock_call.return_value = 0 mock_call.return_value = 0
...@@ -148,11 +148,29 @@ class EditCommandTest(CommandTest): ...@@ -148,11 +148,29 @@ class EditCommandTest(CommandTest):
os.environ['EDITOR'] = editor os.environ['EDITOR'] = editor
archive = config().archive() archive = config().archive()
command = EditCommand([u("-d")], self.todolist, self.out, self.error, None) command = EditCommand(["-d"], self.todolist, self.out, self.error, None)
command.execute() command.execute()
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
mock_call.assert_called_once_with([editor, archive]) mock_call.assert_called_once_with([editor, archive])
@mock.patch('topydo.commands.EditCommand.check_call')
def test_edit_todotxt(self, mock_call):
""" Edit todo file. """
mock_call.return_value = 0
editor = 'vi'
os.environ['EDITOR'] = editor
todotxt = config().todotxt()
result = self.todolist.print_todos() # copy TodoList content *before* executing command
command = EditCommand([], self.todolist, self.out, self.error, None)
command.execute()
self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.print_todos(), result)
mock_call.assert_called_once_with([editor, todotxt])
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -37,6 +37,7 @@ class PostponeCommandTest(CommandTest): ...@@ -37,6 +37,7 @@ class PostponeCommandTest(CommandTest):
"Baz due:{} t:{}".format(self.today.isoformat(), self.start.isoformat()), "Baz due:{} t:{}".format(self.today.isoformat(), self.start.isoformat()),
"Past due:{}".format(self.past.isoformat()), "Past due:{}".format(self.past.isoformat()),
"Future due:{} t:{}".format(self.future.isoformat(), self.future_start.isoformat()), "Future due:{} t:{}".format(self.future.isoformat(), self.future_start.isoformat()),
"FutureStart t:{}".format(self.future.isoformat())
] ]
self.todolist = TodoList(todos) self.todolist = TodoList(todos)
...@@ -233,6 +234,55 @@ class PostponeCommandTest(CommandTest): ...@@ -233,6 +234,55 @@ class PostponeCommandTest(CommandTest):
self.assertEqual(self.output, "") self.assertEqual(self.output, "")
self.assertEqual(self.errors, u("Invalid todo number given: Fo\u00d3B\u0105r.\n")) self.assertEqual(self.errors, u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
def test_expr_postpone1(self):
command = PostponeCommand(["-e", "due:tod", "2w"], self.todolist, self.out, self.error, None)
command.execute()
due = self.today + timedelta(14)
result = "| 2| Bar due:{d}\n| 3| Baz due:{d} t:{s}\n".format(d=due.isoformat(), s=self.start.isoformat())
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_expr_postpone2(self):
cmd_args = ["-e", "t:{}".format(self.start.isoformat()), "due:tod", "1w"]
command = PostponeCommand(cmd_args, self.todolist, self.out, self.error, None)
command.execute()
due = self.today + timedelta(7)
result = "| 3| Baz due:{} t:{}\n".format(due.isoformat(), self.start.isoformat())
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_expr_postpone3(self):
command = PostponeCommand(["-e", "@test", "due:tod", "+project", "C"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_postpone4(self):
""" Don't postpone unrelevant todo items. """
command = PostponeCommand(["-e", "FutureStart", "1w"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_postpone5(self):
""" Force postponing unrelevant items with additional -x flag. """
command = PostponeCommand(["-xe", "FutureStart", "1w"], self.todolist, self.out, self.error, None)
command.execute()
due = self.today + timedelta(7)
result = "| 6| FutureStart t:{} due:{}\n".format(self.future.isoformat(), due.isoformat())
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_help(self): def test_help(self):
command = PostponeCommand(["help"], self.todolist, self.out, self.error) command = PostponeCommand(["help"], self.todolist, self.out, self.error)
command.execute() command.execute()
......
...@@ -27,6 +27,9 @@ class PriorityCommandTest(CommandTest): ...@@ -27,6 +27,9 @@ class PriorityCommandTest(CommandTest):
todos = [ todos = [
"(A) Foo", "(A) Foo",
"Bar", "Bar",
"(B) a @test with due:2015-06-03",
"a @test with +project p:1",
"Baz id:1",
] ]
self.todolist = TodoList(todos) self.todolist = TodoList(todos)
...@@ -71,6 +74,49 @@ class PriorityCommandTest(CommandTest): ...@@ -71,6 +74,49 @@ class PriorityCommandTest(CommandTest):
self.assertEqual(self.output, "Priority changed from A to C\n| 1| (C) Foo\nPriority set to C.\n| 2| (C) Bar\n") self.assertEqual(self.output, "Priority changed from A to C\n| 1| (C) Foo\nPriority set to C.\n| 2| (C) Bar\n")
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
def test_expr_prio1(self):
command = PriorityCommand(["-e", "@test", "C"], self.todolist, self.out, self.error, None)
command.execute()
result = "Priority changed from B to C\n| 3| (C) a @test with due:2015-06-03\nPriority set to C.\n| 4| (C) a @test with +project p:1\n"
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_expr_prio2(self):
command = PriorityCommand(["-e", "@test", "due:2015-06-03", "C"], self.todolist, self.out, self.error, None)
command.execute()
result = "Priority changed from B to C\n| 3| (C) a @test with due:2015-06-03\n"
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
def test_expr_prio3(self):
command = PriorityCommand(["-e", "@test", "due:2015-06-03", "+project", "C"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_prio4(self):
""" Don't prioritize unrelevant todo items. """
command = PriorityCommand(["-e", "Baz", "C"], self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
def test_expr_prio5(self):
""" Force prioritizing unrelevant items with additional -x flag. """
command = PriorityCommand(["-xe", "Baz", "D"], self.todolist, self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, "Priority set to D.\n| 5| (D) Baz id:1\n")
self.assertEqual(self.errors, "")
def test_invalid1(self): def test_invalid1(self):
command = PriorityCommand(["99", "A"], self.todolist, self.out, self.error) command = PriorityCommand(["99", "A"], self.todolist, self.out, self.error)
command.execute() command.execute()
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# 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 topydo.commands.DCommand import DCommand from topydo.lib.DCommand import DCommand
class DeleteCommand(DCommand): class DeleteCommand(DCommand):
def __init__(self, p_args, p_todolist, def __init__(self, p_args, p_todolist,
......
...@@ -25,10 +25,7 @@ class DepriCommand(MultiCommand): ...@@ -25,10 +25,7 @@ class DepriCommand(MultiCommand):
super(DepriCommand, self).__init__( super(DepriCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt) p_args, p_todolist, p_out, p_err, p_prompt)
self.get_todos(self.args) def _execute_multi_specific(self):
def execute_multi_specific(self):
try:
self.printer.add_filter(PrettyPrinterNumbers(self.todolist)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
for todo in self.todos: for todo in self.todos:
...@@ -37,9 +34,6 @@ class DepriCommand(MultiCommand): ...@@ -37,9 +34,6 @@ class DepriCommand(MultiCommand):
self.out("Priority removed.") self.out("Priority removed.")
self.out(self.printer.print_todo(todo)) self.out(self.printer.print_todo(todo))
except IndexError:
self.error(self.usage())
def usage(self): def usage(self):
return """Synopsis: depri <NUMBER1> [<NUMBER2> ...]""" return """Synopsis: depri <NUMBER1> [<NUMBER2> ...]"""
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
from datetime import date from datetime import date
from topydo.commands.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, strict_advance_recurring_todo, NoRecurrenceException
...@@ -36,9 +36,13 @@ class DoCommand(DCommand): ...@@ -36,9 +36,13 @@ class DoCommand(DCommand):
def get_flags(self): def get_flags(self):
""" Additional flags. """ """ Additional flags. """
return ("d:s", ["date=", "strict"]) opts, long_opts = super(DoCommand, self).get_flags()
return ("d:s" + opts, ["date=", "strict"] + long_opts)
def process_flag(self, p_opt, p_value): def process_flag(self, p_opt, p_value):
super(DoCommand, self).process_flag(p_opt, p_value)
if p_opt == "-s" or p_opt == "--strict": if p_opt == "-s" or p_opt == "--strict":
self.strict_recurrence = True self.strict_recurrence = True
elif p_opt == "-d" or p_opt == "--date": elif p_opt == "-d" or p_opt == "--date":
......
...@@ -34,26 +34,25 @@ DEFAULT_EDITOR = 'vi' ...@@ -34,26 +34,25 @@ DEFAULT_EDITOR = 'vi'
# cannot use super() inside the class itself # cannot use super() inside the class itself
BASE_TODOLIST = lambda tl: super(TodoList, tl) BASE_TODOLIST = lambda tl: super(TodoList, tl)
class EditCommand(MultiCommand, ExpressionCommand): class EditCommand(MultiCommand):
def __init__(self, p_args, p_todolist, p_output, p_error, p_input): def __init__(self, p_args, p_todolist, p_output, p_error, p_input):
super(EditCommand, self).__init__(p_args, p_todolist, p_output, super(EditCommand, self).__init__(p_args, p_todolist, p_output,
p_error, p_input) p_error, p_input)
if len(self.args) == 0:
self.multi_mode = False
self.is_expression = False self.is_expression = False
self.edit_archive = False self.edit_archive = False
self.last_argument = False
def _process_flags(self): def get_flags(self):
opts, args = self.getopt('xed') return ("d", [])
for opt, value in opts: def process_flag(self, p_opt, p_value):
if opt == '-d': if p_opt == '-d':
self.edit_archive = True self.edit_archive = True
elif opt == '-x': self.multi_mode = False
self.show_all = True
elif opt == '-e':
self.is_expression = True
self.args = args
def _todos_to_temp(self): def _todos_to_temp(self):
f = tempfile.NamedTemporaryFile() f = tempfile.NamedTemporaryFile()
...@@ -73,12 +72,20 @@ class EditCommand(MultiCommand, ExpressionCommand): ...@@ -73,12 +72,20 @@ class EditCommand(MultiCommand, ExpressionCommand):
return todo_objs return todo_objs
def _open_in_editor(self, p_temp_file, p_editor): def _open_in_editor(self, p_file):
try: try:
return check_call([p_editor, p_temp_file.name]) editor = os.environ['EDITOR'] or DEFAULT_EDITOR
except(KeyError):
editor = DEFAULT_EDITOR
try:
return check_call([editor, p_file])
except CalledProcessError: except CalledProcessError:
self.error('Something went wrong in the editor...') self.error('Something went wrong in the editor...')
return 1 return 1
except(OSError):
self.error('There is no such editor as: ' + editor + '. '
'Check your $EDITOR and/or $PATH')
def _catch_todo_errors(self): def _catch_todo_errors(self):
errors = [] errors = []
...@@ -94,40 +101,12 @@ class EditCommand(MultiCommand, ExpressionCommand): ...@@ -94,40 +101,12 @@ class EditCommand(MultiCommand, ExpressionCommand):
else: else:
return None return None
def execute(self): def _execute_multi_specific(self):
if not super(EditCommand, self).execute():
return False
self.printer.add_filter(PrettyPrinterNumbers(self.todolist)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
try:
editor = os.environ['EDITOR'] or DEFAULT_EDITOR
except(KeyError):
editor = DEFAULT_EDITOR
try:
if len(self.args) < 1:
todo = config().todotxt()
return call([editor, todo]) == 0
else:
self._process_flags()
if self.edit_archive:
archive = config().archive()
return call([editor, archive]) == 0
if self.is_expression:
self.todos = self._view().todos
else:
self.get_todos(self.args)
todo_errors = self._catch_todo_errors()
if not todo_errors:
temp_todos = self._todos_to_temp() temp_todos = self._todos_to_temp()
if not self._open_in_editor(temp_todos, editor): if not self._open_in_editor(temp_todos.name):
new_todos = self._todos_from_temp(temp_todos) new_todos = self._todos_from_temp(temp_todos)
if len(new_todos) == len(self.todos): if len(new_todos) == len(self.todos):
for todo in self.todos: for todo in self.todos:
...@@ -141,12 +120,16 @@ class EditCommand(MultiCommand, ExpressionCommand): ...@@ -141,12 +120,16 @@ class EditCommand(MultiCommand, ExpressionCommand):
'number of supplied todo IDs.') 'number of supplied todo IDs.')
else: else:
self.error(self.usage()) self.error(self.usage())
def _execute_not_multi(self):
if self.edit_archive:
archive = config().archive()
return self._open_in_editor(archive) == 0
else: else:
for error in todo_errors: todo = config().todotxt()
self.error(error)
except(OSError): return self._open_in_editor(todo) == 0
self.error('There is no such editor as: ' + editor + '. '
'Check your $EDITOR and/or $PATH')
def usage(self): def usage(self):
return """Synopsis: return """Synopsis:
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
from datetime import date, timedelta from datetime import date, timedelta
from topydo.lib.MultiCommand import MultiCommand from topydo.lib.MultiCommand import MultiCommand
from topydo.lib.Command import InvalidCommandArgument
from topydo.lib.Config import config from topydo.lib.Config import config
from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers
from topydo.lib.RelativeDate import relative_date_to_date from topydo.lib.RelativeDate import relative_date_to_date
...@@ -32,19 +31,16 @@ class PostponeCommand(MultiCommand): ...@@ -32,19 +31,16 @@ class PostponeCommand(MultiCommand):
p_args, p_todolist, p_out, p_err, p_prompt) p_args, p_todolist, p_out, p_err, p_prompt)
self.move_start_date = False self.move_start_date = False
self._process_flags() self.last_argument = True
self.get_todos(self.args[:-1])
def _process_flags(self): def get_flags(self):
opts, args = self.getopt('s') return("s", [])
for opt, _ in opts: def process_flag(self, p_opt, p_value):
if opt == '-s': if p_opt == '-s':
self.move_start_date = True self.move_start_date = True
self.args = args def _execute_multi_specific(self):
def execute_multi_specific(self):
def _get_offset(p_todo): def _get_offset(p_todo):
offset = p_todo.tag_value( offset = p_todo.tag_value(
config().tag_due(), date.today().isoformat()) config().tag_due(), date.today().isoformat())
...@@ -55,7 +51,6 @@ class PostponeCommand(MultiCommand): ...@@ -55,7 +51,6 @@ class PostponeCommand(MultiCommand):
return offset_date return offset_date
try:
pattern = self.args[-1] pattern = self.args[-1]
self.printer.add_filter(PrettyPrinterNumbers(self.todolist)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
...@@ -78,8 +73,6 @@ class PostponeCommand(MultiCommand): ...@@ -78,8 +73,6 @@ class PostponeCommand(MultiCommand):
else: else:
self.error("Invalid date pattern given.") self.error("Invalid date pattern given.")
break break
except (InvalidCommandArgument, IndexError):
self.error(self.usage())
def usage(self): def usage(self):
return "Synopsis: postpone [-s] <NUMBER> [<NUMBER2> ...] <PATTERN>" return "Synopsis: postpone [-s] <NUMBER> [<NUMBER2> ...] <PATTERN>"
......
...@@ -26,12 +26,11 @@ class PriorityCommand(MultiCommand): ...@@ -26,12 +26,11 @@ class PriorityCommand(MultiCommand):
super(PriorityCommand, self).__init__( super(PriorityCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt) p_args, p_todolist, p_out, p_err, p_prompt)
self.get_todos(self.args[:-1]) self.last_argument = True
def execute_multi_specific(self): def _execute_multi_specific(self):
priority = None priority = None
try:
priority = self.args[-1] priority = self.args[-1]
self.printer.add_filter(PrettyPrinterNumbers(self.todolist)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
...@@ -49,8 +48,6 @@ class PriorityCommand(MultiCommand): ...@@ -49,8 +48,6 @@ class PriorityCommand(MultiCommand):
self.out(self.printer.print_todo(todo)) self.out(self.printer.print_todo(todo))
else: else:
self.error("Invalid priority given.") self.error("Invalid priority given.")
except IndexError:
self.error(self.usage())
def usage(self): def usage(self):
return """Synopsis: pri <NUMBER1> [<NUMBER2> ...] <PRIORITY>""" return """Synopsis: pri <NUMBER1> [<NUMBER2> ...] <PRIORITY>"""
......
...@@ -35,29 +35,14 @@ class DCommand(MultiCommand): ...@@ -35,29 +35,14 @@ class DCommand(MultiCommand):
self.force = False self.force = False
self.process_flags()
self.length = len(self.todolist.todos()) # to determine newly activated todos self.length = len(self.todolist.todos()) # to determine newly activated todos
self.get_todos(self.args)
def get_flags(self): def get_flags(self):
""" Default implementation of getting specific flags. """ return ("f", ["force"])
return ("", [])
def process_flag(self, p_option, p_value): def process_flag(self, p_opt, p_value):
""" Default implementation of processing specific flags. """ if p_opt == "-f" or p_opt == "--force":
pass
def process_flags(self):
opts, args = self.get_flags()
opts, args = self.getopt("f" + opts, ["force"] + args)
for opt, value in opts:
if opt == "-f" or opt == "--force":
self.force = True self.force = True
else:
self.process_flag(opt, value)
self.args = args
def _uncompleted_children(self, p_todo): def _uncompleted_children(self, p_todo):
return sorted( return sorted(
...@@ -128,7 +113,7 @@ class DCommand(MultiCommand): ...@@ -128,7 +113,7 @@ class DCommand(MultiCommand):
""" """
pass pass
def execute_multi_specific(self): def _execute_multi_specific(self):
old_active = self._active_todos() old_active = self._active_todos()
for todo in self.todos: for todo in self.todos:
......
...@@ -35,13 +35,22 @@ class ExpressionCommand(Command): ...@@ -35,13 +35,22 @@ class ExpressionCommand(Command):
self.sort_expression = config().sort_string() self.sort_expression = config().sort_string()
self.show_all = False self.show_all = False
# Commands using last argument differently (i.e as something other than
# todo ID/expression) have to set attribute below to True.
self.last_argument = False
def _filters(self): def _filters(self):
filters = [] filters = []
def arg_filters(): def arg_filters():
result = [] result = []
for arg in self.args:
if self.last_argument:
args = self.args[:-1]
else:
args = self.args
for arg in args:
if re.match(Filter.ORDINAL_TAG_MATCH, arg): if re.match(Filter.ORDINAL_TAG_MATCH, arg):
argfilter = Filter.OrdinalTagFilter(arg) argfilter = Filter.OrdinalTagFilter(arg)
elif len(arg) > 1 and arg[0] == '-': elif len(arg) > 1 and arg[0] == '-':
......
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
from six import u from six import u
from topydo.lib.Command import Command from topydo.lib.ExpressionCommand import ExpressionCommand
from topydo.lib.TodoListBase import InvalidTodoException from topydo.lib.TodoListBase import InvalidTodoException
class MultiCommand(Command): class MultiCommand(ExpressionCommand):
""" """
A common class for operations that can work with multiple todo IDs. A common class for operations that can work with multiple todo IDs.
""" """
...@@ -33,10 +33,45 @@ class MultiCommand(Command): ...@@ -33,10 +33,45 @@ class MultiCommand(Command):
self.todos = [] self.todos = []
self.invalid_numbers = [] self.invalid_numbers = []
self.is_expression = False
self.multi_mode = True
def get_todos(self, p_numbers): def get_flags(self):
""" Default implementation of getting specific flags. """
return ("", [])
def process_flag(self, p_option, p_value):
""" Default implementation of processing specific flags. """
pass
def _process_flags(self):
opts, long_opts = self.get_flags()
opts, args = self.getopt("xe" + opts, long_opts)
for opt, value in opts:
if opt == '-x':
self.show_all = True
elif opt == '-e':
self.is_expression = True
else:
self.process_flag(opt, value)
self.args = args
def get_todos_from_expr(self):
self.todos = self._view().todos
def get_todos(self):
""" Gets todo objects from supplied todo IDs """ """ Gets todo objects from supplied todo IDs """
for number in p_numbers: if self.is_expression:
self.get_todos_from_expr()
else:
if self.last_argument:
numbers = self.args[:-1]
else:
numbers = self.args
for number in numbers:
try: try:
self.todos.append(self.todolist.todo(number)) self.todos.append(self.todolist.todo(number))
except InvalidTodoException: except InvalidTodoException:
...@@ -65,21 +100,34 @@ class MultiCommand(Command): ...@@ -65,21 +100,34 @@ class MultiCommand(Command):
else: else:
return None return None
def execute_multi_specific(self): def _execute_multi_specific(self):
""" """
Operations specific for particular command dealing with multiple todo Operations specific for particular command dealing with multiple todo
IDs. IDs.
""" """
pass pass
def _execute_not_multi(self):
"""
Some commands can do something else besides operating on multiple todo
IDs. This method is a wrapper for those other operations.
"""
pass
def execute(self): def execute(self):
if not super(MultiCommand, self).execute(): if not super(MultiCommand, self).execute():
return False return False
self._process_flags()
if not self.multi_mode:
self._execute_not_multi()
else:
self.get_todos()
todo_errors = self._catch_todo_errors() todo_errors = self._catch_todo_errors()
if not todo_errors: if not todo_errors:
self.execute_multi_specific() self._execute_multi_specific()
else: else:
for error in todo_errors: for error in todo_errors:
self.error(error) self.error(error)
......
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