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 @@
import re
from topydo.lib.Command import Command
from topydo.lib.MultiCommand import MultiCommand
from topydo.lib.PrettyPrinter import PrettyPrinter
from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers
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
alike.
......@@ -38,14 +38,7 @@ class DCommand(Command):
self.process_flags()
self.length = len(self.todolist.todos()) # to determine newly activated todos
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)
self.get_todos(self.args)
def get_flags(self):
""" Default implementation of getting specific flags. """
......@@ -136,27 +129,15 @@ class DCommand(Command):
"""
pass
def execute(self):
if not super(DCommand, self).execute():
return False
if len(self.args) == 0:
self.error(self.usage())
elif len(self.invalid_numbers) > 1 or len(self.invalid_numbers) > 0 and len(self.todos) > 0:
for number in self.invalid_numbers:
self.error("Invalid todo number given: {}.".format(number))
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)
def execute_multi_specific(self):
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)
# 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 @@
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.PrettyPrinterFilter import PrettyPrinterNumbers
from topydo.lib.RelativeDate import relative_date_to_date
from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.Utils import date_string_to_date
class PostponeCommand(Command):
class PostponeCommand(MultiCommand):
def __init__(self, p_args, p_todolist,
p_out=lambda a: None,
p_err=lambda a: None,
......@@ -32,6 +33,8 @@ class PostponeCommand(Command):
p_args, p_todolist, p_out, p_err, p_prompt)
self.move_start_date = False
self._process_flags()
self.get_todos(self.args[:-1])
def _process_flags(self):
opts, args = self.getopt('s')
......@@ -42,7 +45,7 @@ class PostponeCommand(Command):
self.args = args
def execute(self):
def execute_multi_specific(self):
def _get_offset(p_todo):
offset = p_todo.tag_value(
config().tag_due(), date.today().isoformat())
......@@ -53,53 +56,29 @@ class PostponeCommand(Command):
return offset_date
if not super(PostponeCommand, self).execute():
return False
try:
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 = []
invalid_numbers = []
for number in self.args[:-1]:
try:
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())
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())
except (InvalidCommandArgument, IndexError):
self.error(self.usage())
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
except (InvalidCommandArgument, IndexError):
self.error(self.usage())
def usage(self):
return "Synopsis: postpone [-s] <NUMBER> [<NUMBER2> ...] <PATTERN>"
......
......@@ -14,12 +14,12 @@
# 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.MultiCommand import MultiCommand
from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers
from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.Utils import is_valid_priority
class PriorityCommand(Command):
class PriorityCommand(MultiCommand):
def __init__(self, p_args, p_todolist,
p_out=lambda a: None,
p_err=lambda a: None,
......@@ -27,49 +27,31 @@ class PriorityCommand(Command):
super(PriorityCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
def execute(self):
if not super(PriorityCommand, self).execute():
return False
self.get_todos(self.args[:-1])
def execute_multi_specific(self):
priority = None
todos = []
invalid_numbers = []
for number in self.args[:-1]:
try:
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:
priority = self.args[-1]
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
if len(todos) > 0:
if is_valid_priority(priority):
for todo in todos:
old_priority = todo.priority()
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())
try:
priority = self.args[-1]
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
if is_valid_priority(priority):
for todo in self.todos:
old_priority = todo.priority()
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.")
except IndexError:
self.error(self.usage())
def usage(self):
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