Commit 1139c19f authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge pull request #15 from mruwek/multi-todos-cmds-refactoring

Introduce MultiCommand class for cmds operating on multiple todos.
parents 92489d1f 96cca8b6
...@@ -16,12 +16,12 @@ ...@@ -16,12 +16,12 @@
import re import re
from topydo.lib.Command import Command from topydo.lib.MultiCommand import MultiCommand
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.TodoListBase import InvalidTodoException from topydo.lib.TodoListBase import InvalidTodoException
class DCommand(Command): class DCommand(MultiCommand):
""" """
A common class for the 'do' and 'del' operations, because they're quite A common class for the 'do' and 'del' operations, because they're quite
alike. alike.
...@@ -38,14 +38,7 @@ class DCommand(Command): ...@@ -38,14 +38,7 @@ class DCommand(Command):
self.process_flags() 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)
self.todos = []
self.invalid_numbers = []
for number in self.args:
try:
self.todos.append(self.todolist.todo(number))
except InvalidTodoException:
self.invalid_numbers.append(number)
def get_flags(self): def get_flags(self):
""" Default implementation of getting specific flags. """ """ Default implementation of getting specific flags. """
...@@ -136,27 +129,15 @@ class DCommand(Command): ...@@ -136,27 +129,15 @@ class DCommand(Command):
""" """
pass pass
def execute(self): def execute_multi_specific(self):
if not super(DCommand, self).execute(): old_active = self._active_todos()
return False
for todo in self.todos:
if len(self.args) == 0: if todo and self.condition(todo):
self.error(self.usage()) self._process_subtasks(todo)
elif len(self.invalid_numbers) > 1 or len(self.invalid_numbers) > 0 and len(self.todos) > 0: self.execute_specific(todo)
for number in self.invalid_numbers: else:
self.error("Invalid todo number given: {}.".format(number)) self.error(self.condition_failed_text())
elif len(self.invalid_numbers) == 1 and len(self.todos) == 0:
self.error("Invalid todo number given.")
else:
old_active = self._active_todos()
for todo in self.todos:
if todo and self.condition(todo):
self._process_subtasks(todo)
self.execute_specific(todo)
else:
self.error(self.condition_failed_text())
current_active = self._active_todos()
self._print_unlocked_todos(old_active, current_active)
current_active = self._active_todos()
self._print_unlocked_todos(old_active, current_active)
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 - 2015 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 topydo.lib.Command import Command
from topydo.lib.TodoListBase import InvalidTodoException
class MultiCommand(Command):
"""
A common class for operations that can work with multiple todo IDs.
"""
def __init__(self, p_args, p_todolist,
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(MultiCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.todos = []
self.invalid_numbers = []
def get_todos(self, p_numbers):
""" Gets todo objects from supplied todo IDs """
for number in p_numbers:
try:
self.todos.append(self.todolist.todo(number))
except InvalidTodoException:
self.invalid_numbers.append(number)
def _catch_todo_errors(self):
"""
Returns None or list of error messages depending on number of valid todo
objects and number of invalid todo IDs.
In case of multiple invalid todo IDs we generate separate error message for each
one of them with information about supplied ID.
"""
errors = []
if len(self.invalid_numbers) > 1 or len(self.invalid_numbers) > 0 and len(self.todos) > 0:
for number in self.invalid_numbers:
errors.append("Invalid todo number given: {}.".format(number))
elif len(self.invalid_numbers) == 1 and len(self.todos) == 0:
errors.append("Invalid todo number given.")
elif len(self.todos) == 0 and len(self.invalid_numbers) == 0:
errors.append(self.usage())
if len(errors) > 0:
return errors
else:
return None
def execute_multi_specific(self):
"""
Operations specific for particular command dealing with multiple todo
IDs.
"""
pass
def execute(self):
if not super(MultiCommand, self).execute():
return False
todo_errors = self._catch_todo_errors()
if not todo_errors:
self.execute_multi_specific()
else:
for error in todo_errors:
self.error(error)
...@@ -16,14 +16,15 @@ ...@@ -16,14 +16,15 @@
from datetime import date, timedelta from datetime import date, timedelta
from topydo.lib.Command import Command, InvalidCommandArgument 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
from topydo.lib.TodoListBase import InvalidTodoException from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.Utils import date_string_to_date from topydo.lib.Utils import date_string_to_date
class PostponeCommand(Command): class PostponeCommand(MultiCommand):
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,
...@@ -32,6 +33,8 @@ class PostponeCommand(Command): ...@@ -32,6 +33,8 @@ class PostponeCommand(Command):
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.get_todos(self.args[:-1])
def _process_flags(self): def _process_flags(self):
opts, args = self.getopt('s') opts, args = self.getopt('s')
...@@ -42,7 +45,7 @@ class PostponeCommand(Command): ...@@ -42,7 +45,7 @@ class PostponeCommand(Command):
self.args = args self.args = args
def execute(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())
...@@ -53,53 +56,29 @@ class PostponeCommand(Command): ...@@ -53,53 +56,29 @@ class PostponeCommand(Command):
return offset_date return offset_date
if not super(PostponeCommand, self).execute(): try:
return False pattern = self.args[-1]
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
self._process_flags() for todo in self.todos:
offset = _get_offset(todo)
new_due = relative_date_to_date(pattern, offset)
todos = [] if new_due:
invalid_numbers = [] if self.move_start_date and todo.has_tag(config().tag_start()):
length = todo.length()
for number in self.args[:-1]: new_start = new_due - timedelta(length)
try: todo.set_tag(config().tag_start(), new_start.isoformat())
todos.append(self.todolist.todo(number))
except InvalidTodoException:
invalid_numbers.append(number)
if len(invalid_numbers) > 1 or len(invalid_numbers) > 0 and len(todos) > 0:
for number in invalid_numbers:
self.error("Invalid todo number given: {}.".format(number))
elif len(invalid_numbers) == 1 and len(todos) == 0:
self.error("Invalid todo number given.")
else:
try:
pattern = self.args[-1]
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
if len(todos) > 0:
for todo in todos:
offset = _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(self.printer.print_todo(todo))
else:
self.error("Invalid date pattern given.")
break
else:
self.error(self.usage())
except (InvalidCommandArgument, IndexError): todo.set_tag(config().tag_due(), new_due.isoformat())
self.error(self.usage())
self.todolist.set_dirty()
self.out(self.printer.print_todo(todo))
else:
self.error("Invalid date pattern given.")
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>"
......
...@@ -14,12 +14,12 @@ ...@@ -14,12 +14,12 @@
# 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.lib.Command import Command from topydo.lib.MultiCommand import MultiCommand
from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers
from topydo.lib.TodoListBase import InvalidTodoException from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.Utils import is_valid_priority from topydo.lib.Utils import is_valid_priority
class PriorityCommand(Command): class PriorityCommand(MultiCommand):
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,
...@@ -27,49 +27,31 @@ class PriorityCommand(Command): ...@@ -27,49 +27,31 @@ class PriorityCommand(Command):
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)
def execute(self): self.get_todos(self.args[:-1])
if not super(PriorityCommand, self).execute():
return False
def execute_multi_specific(self):
priority = None priority = None
todos = []
invalid_numbers = []
for number in self.args[:-1]: try:
try: priority = self.args[-1]
todos.append(self.todolist.todo(number)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
except InvalidTodoException:
invalid_numbers.append(number) if is_valid_priority(priority):
for todo in self.todos:
if len(invalid_numbers) > 1 or len(invalid_numbers) > 0 and len(todos) > 0: old_priority = todo.priority()
for number in invalid_numbers: self.todolist.set_priority(todo, priority)
self.error("Invalid todo number given: {}.".format(number))
elif len(invalid_numbers) == 1 and len(todos) == 0: if old_priority and priority and old_priority != priority:
self.error("Invalid todo number given.") self.out("Priority changed from {} to {}".format(
else: old_priority, priority))
try: elif not old_priority:
priority = self.args[-1] self.out("Priority set to {}.".format(priority))
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
self.out(self.printer.print_todo(todo))
if len(todos) > 0: else:
if is_valid_priority(priority): self.error("Invalid priority given.")
for todo in todos: except IndexError:
old_priority = todo.priority() self.error(self.usage())
self.todolist.set_priority(todo, priority)
if old_priority and priority and old_priority != priority:
self.out("Priority changed from {} to {}".format(
old_priority, priority))
elif not old_priority:
self.out("Priority set to {}.".format(priority))
self.out(self.printer.print_todo(todo))
else:
self.error("Invalid priority given.")
else:
self.error(self.usage())
except IndexError:
self.error(self.usage())
def usage(self): def usage(self):
return """Synopsis: pri <NUMBER1> [<NUMBER2> ...] <PRIORITY>""" return """Synopsis: pri <NUMBER1> [<NUMBER2> ...] <PRIORITY>"""
......
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