Commit 5bcf70e6 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge pull request #30 from mruwek/add-todos-from-file

Add todos from file with '-f' flag.
parents f31b49f1 4380d872
...@@ -16,7 +16,16 @@ ...@@ -16,7 +16,16 @@
from datetime import date from datetime import date
import unittest import unittest
# We're searching for 'mock'
# pylint: disable=no-name-in-module
try:
from unittest import mock
except ImportError:
import mock
from six import u from six import u
from io import StringIO
from topydo.commands import AddCommand from topydo.commands import AddCommand
from topydo.commands import ListCommand from topydo.commands import ListCommand
...@@ -242,6 +251,21 @@ class AddCommandTest(CommandTest): ...@@ -242,6 +251,21 @@ class AddCommandTest(CommandTest):
self.assertEqual(self.output, utf8(u("| 1| {} Special \u25c4\n").format(self.today))) self.assertEqual(self.output, utf8(u("| 1| {} Special \u25c4\n").format(self.today)))
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
@mock.patch("topydo.commands.AddCommand.stdin", StringIO(u("Fo\u00f3 due:tod id:1\nB\u0105r before:1")))
def test_add_from_stdin(self):
command = AddCommand.AddCommand(["-f", "-"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, utf8(u("| 1| {tod} Fo\u00f3 due:{tod} id:1\n| 2| {tod} B\u0105r p:1\n".format(tod=self.today))))
self.assertEqual(self.errors, "")
def test_add_from_file(self):
command = AddCommand.AddCommand(["-f", "test/data/AddCommandTest-from_file.txt"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, utf8(u("| 1| {tod} Foo @fo\u00f3b\u0105r due:{tod} id:1\n| 2| {tod} Bar +baz t:{tod} p:1\n".format(tod=self.today))))
self.assertEqual(self.errors, "")
def test_help(self): def test_help(self):
command = AddCommand.AddCommand(["help"], self.todolist, self.out, self.error) command = AddCommand.AddCommand(["help"], self.todolist, self.out, self.error)
command.execute() command.execute()
......
Foo @foóbąr due:tod id:1
Bar +baz t:tod before:1
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
from datetime import date from datetime import date
import re import re
from sys import stdin
import codecs
from os.path import expanduser
from topydo.lib.Config import config from topydo.lib.Config import config
from topydo.lib.Command import Command from topydo.lib.Command import Command
...@@ -33,17 +36,40 @@ class AddCommand(Command): ...@@ -33,17 +36,40 @@ class AddCommand(Command):
super(AddCommand, self).__init__( super(AddCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt) p_args, p_todolist, p_out, p_err, p_prompt)
self.text = ' '.join(p_args) self.text = ' '.join(p_args)
self.todo = None self.from_file = None
def _preprocess_input_todo(self): def _process_flags(self):
opts, args = self.getopt('f:')
for opt, value in opts:
if opt == '-f':
self.from_file = expanduser(value)
self.args = args
def get_todos_from_file(self):
if self.from_file == '-':
f = stdin
else:
f = codecs.open(self.from_file, 'r', encoding='utf-8')
todos = f.read().splitlines()
return todos
def _add_todo(self, p_todo_text):
def _preprocess_input_todo(p_todo_text):
""" """
Preprocesses user input when adding a task. Preprocesses user input when adding a task.
It detects a priority mid-sentence and puts it at the start. It detects a priority mid-sentence and puts it at the start.
""" """
self.text = re.sub(r'^(.+) (\([A-Z]\))(.*)$', r'\2 \1\3', self.text) todo_text = re.sub(r'^(.+) (\([A-Z]\))(.*)$', r'\2 \1\3', p_todo_text)
return todo_text
def _postprocess_input_todo(self): def _postprocess_input_todo(p_todo):
""" """
Post-processes a parsed todo when adding it to the list. Post-processes a parsed todo when adding it to the list.
...@@ -53,26 +79,26 @@ class AddCommand(Command): ...@@ -53,26 +79,26 @@ class AddCommand(Command):
after: tags after: tags
""" """
def convert_date(p_tag): def convert_date(p_tag):
value = self.todo.tag_value(p_tag) value = p_todo.tag_value(p_tag)
if value: if value:
dateobj = relative_date_to_date(value) dateobj = relative_date_to_date(value)
if dateobj: if dateobj:
self.todo.set_tag(p_tag, dateobj.isoformat()) p_todo.set_tag(p_tag, dateobj.isoformat())
def add_dependencies(p_tag): def add_dependencies(p_tag):
for value in self.todo.tag_values(p_tag): for value in p_todo.tag_values(p_tag):
try: try:
dep = self.todolist.todo(value) dep = self.todolist.todo(value)
if p_tag == 'after': if p_tag == 'after':
self.todolist.add_dependency(self.todo, dep) self.todolist.add_dependency(p_todo, dep)
elif p_tag == 'before' or p_tag == 'partof': elif p_tag == 'before' or p_tag == 'partof':
self.todolist.add_dependency(dep, self.todo) self.todolist.add_dependency(dep, p_todo)
except InvalidTodoException: except InvalidTodoException:
pass pass
self.todo.remove_tag(p_tag, value) p_todo.remove_tag(p_tag, value)
convert_date(config().tag_start()) convert_date(config().tag_start())
convert_date(config().tag_due()) convert_date(config().tag_due())
...@@ -81,25 +107,38 @@ class AddCommand(Command): ...@@ -81,25 +107,38 @@ class AddCommand(Command):
add_dependencies('before') add_dependencies('before')
add_dependencies('after') add_dependencies('after')
self.todo.set_creation_date(date.today()) p_todo.set_creation_date(date.today())
todo_text = _preprocess_input_todo(p_todo_text)
todo = self.todolist.add(todo_text)
_postprocess_input_todo(todo)
self.out(self.printer.print_todo(todo))
def execute(self): def execute(self):
""" Adds a todo item to the list. """ """ Adds a todo item to the list. """
if not super(AddCommand, self).execute(): if not super(AddCommand, self).execute():
return False return False
if self.text:
self._preprocess_input_todo()
self.todo = self.todolist.add(self.text)
self._postprocess_input_todo()
self.printer.add_filter(PrettyPrinterNumbers(self.todolist)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
self.out(self.printer.print_todo(self.todo)) self._process_flags()
if self.from_file:
new_todos = self.get_todos_from_file()
for todo in new_todos:
self._add_todo(todo)
else:
if self.text:
self._add_todo(self.text)
else: else:
self.error(self.usage()) self.error(self.usage())
def usage(self): def usage(self):
return """Synopsis: add <text>""" return """Synopsis:
add <text>
add -f <file>
add -f -"""
def help(self): def help(self):
return """\ return """\
...@@ -114,4 +153,6 @@ This subcommand automatically adds the creation date to the added item. ...@@ -114,4 +153,6 @@ This subcommand automatically adds the creation date to the added item.
todo number (not the dependency number). todo number (not the dependency number).
Example: add "Subtask partof:1" Example: add "Subtask partof:1"
-f : Add todo items from specified <file> or from standard input.
""" """
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