Commit 851e2cdd authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge branch 'master' into dot

Revived the dot subcommand and the dot printer for 'ls'.
parents f2072530 798ed50b
......@@ -14,3 +14,4 @@ exclude_lines =
omit =
topydo/commands/ExitCommand.py
topydo/lib/Version.py
topydo/ui/*
......@@ -8,8 +8,9 @@ python:
install:
- "python -m pip install pip --upgrade"
- "pip install ."
- "pip install .[columns]"
- "pip install .[ical]"
- "pip install .[prompt-toolkit]"
- "pip install .[prompt]"
- "pip install .[test]"
- "pip install pylint"
- "pip install codecov"
......
0.10
----
A major release, introducing a new user interface (TUI). Special thanks go to
@mruwek for helping out to get this UI in its current shape.
* New: A column-based user interface. Each column has its own filters and sort
order, allowing you to build a dashboard with your todo items. Launch with
`topydo columns`.
* New: color blocks that change from green to red (overdue) as time passes by.
Use the %z placeholder to add color blocks to the `ls` output.
* New: color option can be set to 0, 1, 16 or 256 and if needed overridden by
-C on the commandline.
* New: recurrence based on business days. Skips Saturdays and Sundays when
calculating the next date (thanks to @mruwek).
* New: items can be sorted by length (use 'length' as sort field).
* New: parents-of and children-of operators with `add`, `dep` and `append`
subcommands. The todo item receives the same parents/children from the
specified todo item.
* New: `append` understands relative dates and other tags that are special to
`add` (thanks to @rameshg87).
* Fix: dependency ID creation with orphan todo items.
* Fix: crash after completing/deleting an edited item.
* Fix: crash after completing an item that got a new dependency with `dep add`
* Change: a new tag value with an existing key can be added with the tag
subcommand (thanks to @MinchinWeb)
* Change: ~/.config/topydo/config can be used as a configuration file.
* Change: No backups are written for read-only commands (e.g. lsprj)
* Change: topydo is more scalable for large todo.txt files.
* Known issue: color blocks are not shown in `ls` output in the column UI.
0.9
---
* Dropped support for Python 2.7.
* Add ability to filter on creation/completion dates:
topydo ls created:today
topydo ls completed:today
topydo -t done.txt completed:today # if auto-archiving is set
* `ls -F` supports `%P` that expands to a single space when no priority is set,
in contrast to `%p` which expands to an empty string (thanks to @MinchinWeb).
* `ls -N` prints enough todo items such that it fits on one screen (thanks to
@MinchinWeb).
* Aliases can have a `{}` placeholder which is substituted with the alias'
arguments (thanks to @mruwek).
* `pri` accepts priorities in lowercase (thanks to @MinchinWeb).
* Several bugfixes for `dep gc`.
* Various test/CI improvements.
0.8
---
......@@ -21,8 +75,8 @@ for the majority of these new features.
* `ls` output can be customized with a -F flag or a configuration option:
[ls]
list_format = |%I| %x %{(}p{)} %c %s %k %{due:}d %{t:}t
[ls]
list_format = |%I| %x %{(}p{)} %c %s %k %{due:}d %{t:}t
or `ls -F "%{(}p{)} %s %{due:}d"`.
......
......@@ -43,10 +43,6 @@ smoothly into topydo.
exit 1
fi
if ! python2 -m pylint --errors-only topydo test; then
exit 1
fi
if ! python3 -m pylint --errors-only topydo test; then
exit 1
fi
......
......@@ -26,12 +26,26 @@ Simply install with:
pip install topydo
### Optional dependencies
### Dependencies
* [arrow][8] : Used to turn dates into a human readable version.
#### Optional dependencies:
* [icalendar][7] : To print your todo.txt file as an iCalendar file
(not supported for Python 3.2).
(not supported for PyPy3).
* [prompt-toolkit][6] : For topydo's _prompt_ mode, which offers a shell-like
interface with auto-completion.
* [arrow][8] : Used to turn dates into a human readable version.
* [urwid][12] : For topydo's _columns_ mode, a TUI with columns for
your todo items.
* [backports.shutil_get_terminal_size][9] : Used to determine your terminal
window size. This function was
added to the standard library in
Python 3.3 and so is only
required for PyPy3.
* [mock][11] : Used for testing. This was added to the standard
library in Python 3.3.
Demo
----
......@@ -46,3 +60,8 @@ Demo
[5]: https://raw.githubusercontent.com/bram85/topydo/master/doc/topydo.gif
[6]: https://github.com/jonathanslenders/python-prompt-toolkit
[7]: https://github.com/collective/icalendar
[8]: https://github.com/crsmithdev/arrow
[9]: https://github.com/chrippa/backports.shutil_get_terminal_size
[10]: https://dateutil.readthedocs.org/
[11]: https://github.com/testing-cabal/mock
[12]: https://github.com/urwid/urwid
......@@ -33,12 +33,15 @@ setup(
],
extras_require = {
':sys_platform=="win32"': ['colorama>=0.2.5'],
':python_version=="3.2"': ['backports.shutil_get_terminal_size>=1.0.0'],
'columns': ['urwid >= 1.3.0'],
'ical': ['icalendar'],
'prompt-toolkit': ['prompt-toolkit >= 0.53'],
'prompt': ['prompt_toolkit >= 0.53'],
'test': ['coverage', 'freezegun', 'green', ],
'test:python_version=="3.2"': ['mock'],
},
entry_points= {
'console_scripts': ['topydo = topydo.cli.UILoader:main'],
'console_scripts': ['topydo = topydo.ui.UILoader:main'],
},
classifiers = [
"Development Status :: 5 - Production/Stable",
......
......@@ -20,14 +20,19 @@ from topydo.lib.Utils import escape_ansi
class CommandTest(TopydoTest):
def __init__(self, *args, **kwargs):
super(CommandTest, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.output = ""
self.errors = ""
def out(self, p_output):
if p_output:
self.output += escape_ansi(p_output + "\n")
if isinstance(p_output, list) and p_output:
self.output += escape_ansi(
"\n".join([str(s) for s in p_output]) + "\n")
elif p_output:
self.output += str(p_output) + "\n"
def error(self, p_error):
if p_error:
self.errors += escape_ansi(p_error + "\n")
if isinstance(p_error, list) and p_error:
self.errors += escape_ansi(p_error + "\n") + "\n"
elif p_error:
self.errors += str(p_error) + "\n"
[column_keymap]
up = up
<Left> = prev_column
<Esc>d = delete_column
(A) item 1
(B) item 2
(C) item 3
(D) item 4
(E) item 5
(F) item 6
(G) item 7
(H) item 8
(I) item 9
(J) item 10
(K) item 11
(L) item 12
(M) item 13
(N) item 14
(O) item 15
(P) item 16
(Q) item 17
(R) item 18
(S) item 19
(T) item 20
(U) item 21
(V) item 22
(W) item 23
(X) item 24
(Y) item 25
(Z) item 26
(A) item 27
(B) item 28
(C) item 29
(D) item 30
(E) item 31
(F) item 32
(G) item 33
(H) item 34
(I) item 35
(J) item 36
(K) item 37
(L) item 38
(M) item 39
(N) item 40
(O) item 41
(P) item 42
(Q) item 43
(R) item 44
(S) item 45
(T) item 46
(U) item 47
(V) item 48
(W) item 49
(X) item 50
1 No length (zero)
2016-04-25 2 No length (zero)
3 Length of 0 days t:2016-04-25 due:2016-04-25
4 Length of 0 days t:2016-04-25 due:2016-04-25
5 Length of 0 days tomorrow t:2016-04-26 due:2016-04-26
2016-04-25 1 Length of 1 day with creation due:2016-04-26
2 Length of 1 day t:2016-04-25 due:2016-04-26
2016-04-25 Length of 2 days with creation due:2016-04-27
4 Length of 0 days t:2016-04-25 due:2016-04-25
2016-04-25 2 No length (zero)
3 Length of 0 days t:2016-04-25 due:2016-04-25
5 Length of 0 days tomorrow t:2016-04-26 due:2016-04-26
2 Length of 1 day t:2016-04-25 due:2016-04-26
2016-04-25 Length of 2 days with creation due:2016-04-27
2016-04-25 1 Length of 1 day with creation due:2016-04-26
1 No length (zero)
......@@ -3,3 +3,5 @@ foo = rm -f test
baz = FooBar
format = ls -F "|I| x c d {(}p{)} s k" -n 25
smile = ls
star = tag {} star 1
quot = lol'd
......@@ -52,4 +52,4 @@ def todolist_to_string(p_list):
def print_view(p_view):
printer = PrettyPrinter()
return printer.print_list(p_view.todos)
return "\n".join([str(s) for s in printer.print_list(p_view.todos)])
......@@ -33,7 +33,7 @@ except ImportError:
class AddCommandTest(CommandTest):
def setUp(self):
super(AddCommandTest, self).setUp()
super().setUp()
self.todolist = TodoList.TodoList([])
self.today = date.today().isoformat()
......@@ -268,6 +268,61 @@ class AddCommandTest(CommandTest):
self.assertEqual(self.output, "|wb3| {today} Bar p:1 @Context\n|wb3| {today} Bar @Context\n".format(today=self.today))
def add_parentsof_helper(self, p_tag):
command = AddCommand.AddCommand(["Foo"], self.todolist, self.out,
self.error)
command.execute()
command = AddCommand.AddCommand(["Bar before:1"], self.todolist,
self.out, self.error)
command.execute()
command = AddCommand.AddCommand(["Baz {}:2".format(p_tag)],
self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.todo(3).has_tag('p', '1'))
def test_add_dep_parentsof01(self):
self.add_parentsof_helper('parentsof')
def test_add_dep_parentsof02(self):
self.add_parentsof_helper('parentof')
def test_add_dep_parentsof03(self):
self.add_parentsof_helper('parents-of')
def test_add_dep_parentsof04(self):
self.add_parentsof_helper('parent-of')
def add_childrenof_helper(self, p_tag):
command = AddCommand.AddCommand(["Foo"], self.todolist, self.out,
self.error)
command.execute()
command = AddCommand.AddCommand(["Bar before:1"], self.todolist,
self.out, self.error)
command.execute()
command = AddCommand.AddCommand(["Baz {}:1".format(p_tag)],
self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.todo(3).has_tag('id', '2'))
self.assertTrue(self.todolist.todo(2).has_tag('p', '2'))
def test_add_dep_childrenof01(self):
self.add_childrenof_helper('childrenof')
def test_add_dep_childrenof02(self):
self.add_childrenof_helper('childof')
def test_add_dep_childrenof03(self):
self.add_childrenof_helper('children-of')
def test_add_dep_childrenof04(self):
self.add_childrenof_helper('child-of')
def test_add_reldate1(self):
command = AddCommand.AddCommand(["Foo due:today"], self.todolist,
self.out, self.error)
......
......@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
from datetime import date
from test.command_testcase import CommandTest
from topydo.commands.AppendCommand import AppendCommand
......@@ -23,9 +24,10 @@ from topydo.lib.TodoList import TodoList
class AppendCommandTest(CommandTest):
def setUp(self):
super(AppendCommandTest, self).setUp()
super().setUp()
self.todolist = TodoList([])
self.todolist.add("Foo")
self.today = date.today().isoformat()
def test_append1(self):
command = AppendCommand([1, "Bar"], self.todolist, self.out,
......@@ -79,6 +81,27 @@ class AppendCommandTest(CommandTest):
self.assertEqual(self.output, "")
self.assertEqual(self.errors, command.usage() + "\n")
def test_append8(self):
command = AppendCommand([1, "due:today t:today"], self.todolist,
self.out, self.error)
command.execute()
self.assertEqual(self.output,
"| 1| Foo due:%s t:%s\n" % (self.today, self.today))
self.assertEqual(self.errors, "")
def test_append9(self):
self.todolist.add("Qux due:2015-12-21 t:2015-12-21 before:1")
self.todolist.add("Baz")
command = AppendCommand([2, "due:today t:today before:3"], self.todolist,
self.out, self.error)
command.execute()
self.assertEqual(
self.output,
"| 2| Qux due:%s t:%s p:1 p:2\n" % (self.today, self.today))
self.assertEqual(self.errors, "")
def test_help(self):
command = AppendCommand(["help"], self.todolist, self.out, self.error)
command.execute()
......
......@@ -30,8 +30,8 @@ class ArchiveCommandTest(CommandTest):
command = ArchiveCommand(todolist, archive)
command.execute()
self.assertTrue(todolist.is_dirty())
self.assertTrue(archive.is_dirty())
self.assertTrue(todolist.dirty)
self.assertTrue(archive.dirty)
self.assertEqual(todolist.print_todos(), "x Not complete\n(C) Active")
self.assertEqual(archive.print_todos(), "x 2014-10-19 Complete\nx 2014-10-20 Another one complete")
......
This diff is collapsed.
......@@ -45,8 +45,7 @@ class ConfigTest(TopydoTest):
""" Bad colour switch value. """
# boolean settings must first be typecast to integers, because all
# strings evaulate to 'True'
self.assertEqual(config("test/data/ConfigTest4.conf").colors(),
bool(int(config().defaults["topydo"]["colors"])))
self.assertEqual(config("test/data/ConfigTest4.conf").colors(), 16)
def test_config06(self):
""" Bad auto creation date switch value. """
......@@ -83,62 +82,76 @@ class ConfigTest(TopydoTest):
self.assertEqual(config("test/data/ConfigTest4.conf").append_parent_contexts(),
bool(int(config().defaults["dep"]["append_parent_contexts"])))
@skip("Error checking not yet implemented")
def test_config14(self):
""" Bad priority color value. """
self.assertEqual(config("test/data/ConfigTest4.conf").priority_colors(),
config().defaults["colorscheme"]["priority_colors"])
self.assertEqual(config("test/data/ConfigTest4.conf").priority_color('A').color, 6)
self.assertEqual(config("test/data/ConfigTest4.conf").priority_color('B').color, 3)
self.assertEqual(config("test/data/ConfigTest4.conf").priority_color('C').color, 4)
@skip("Error checking not yet implemented")
def test_config15(self):
""" Bad project color value. """
self.assertEqual(config("test/data/ConfigTest4.conf").project_color(),
config().defaults["colorscheme"]["project_color"])
self.assertTrue(config("test/data/ConfigTest4.conf").project_color().is_neutral())
@skip("Error checking not yet implemented")
def test_config16(self):
""" Bad context color value. """
self.assertEqual(config("test/data/ConfigTest4.conf").context_color(),
config().defaults["colorscheme"]["context_color"])
self.assertTrue(config("test/data/ConfigTest4.conf").context_color().is_neutral())
@skip("Error checking not yet implemented")
def test_config17(self):
""" Bad metadata color value. """
self.assertEqual(config("test/data/ConfigTest4.conf").metadata_color(),
config().defaults["colorscheme"]["metadata_color"])
self.assertTrue(config("test/data/ConfigTest4.conf").metadata_color().is_neutral())
@skip("Error checking not yet implemented")
def test_config18(self):
""" Bad link color value. """
self.assertEqual(config("test/data/ConfigTest4.conf").link_color(),
config().defaults["colorscheme"]["link_color"])
self.assertTrue(config("test/data/ConfigTest4.conf").link_color().is_neutral())
@skip("Test not yet implemented")
# the test needs to be of the internal function _str_to_dict
def test_config19(self):
""" No priority color value. """
self.assertEqual(config("test/data/ConfigTest4.conf").priority_colors(),
config().defaults["colorscheme"]["priority_colors"])
self.assertEqual(config("test/data/ConfigTest4.conf").priority_color('A').color, 6)
self.assertEqual(config("test/data/ConfigTest4.conf").priority_color('B').color, 3)
self.assertEqual(config("test/data/ConfigTest4.conf").priority_color('C').color, 4)
def test_config20(self):
""" No project color value. """
self.assertEqual(config("test/data/ConfigTest5.conf").project_color(),
config().defaults["colorscheme"]["project_color"])
self.assertEqual(config("test/data/ConfigTest5.conf").project_color().color, 1)
def test_config21(self):
""" No context color value. """
self.assertEqual(config("test/data/ConfigTest5.conf").context_color(),
config().defaults["colorscheme"]["context_color"])
self.assertEqual(config("test/data/ConfigTest5.conf").context_color().color, 5)
def test_config22(self):
""" No metadata color value. """
self.assertEqual(config("test/data/ConfigTest5.conf").metadata_color(),
config().defaults["colorscheme"]["metadata_color"])
self.assertEqual(config("test/data/ConfigTest5.conf").metadata_color().color, 2)
def test_config23(self):
""" No link color value. """
self.assertEqual(config("test/data/ConfigTest5.conf").link_color(),
config().defaults["colorscheme"]["link_color"])
self.assertEqual(config("test/data/ConfigTest5.conf").link_color().color, 6)
def test_config24(self):
""" column_keymap test. """
keymap, keystates = config("test/data/ConfigTest6.conf").column_keymap()
self.assertEqual(keymap['pp'], 'postpone')
self.assertEqual(keymap['ps'], 'postpone_s')
self.assertEqual(keymap['pr'], 'pri')
self.assertEqual(keymap['pra'], 'cmd pri {} a')
self.assertIn('p', keystates)
self.assertIn('g', keystates)
self.assertIn('pp', keystates)
self.assertIn('ps', keystates)
self.assertIn('pr', keystates)
self.assertEqual(keymap['up'], 'up')
self.assertIn('u', keystates)
self.assertEqual(keymap['<Left>'], 'prev_column')
self.assertNotIn('<Lef', keystates)
self.assertEqual(keymap['<Esc>d'], 'delete_column')
self.assertNotIn('<Esc', keystates)
self.assertIn('<Esc>', keystates)
if __name__ == '__main__':
unittest.main()
......@@ -33,7 +33,7 @@ def _no_prompt(self):
class DeleteCommandTest(CommandTest):
def setUp(self):
super(DeleteCommandTest, self).setUp()
super().setUp()
todos = [
"Foo id:1",
"Bar p:1",
......@@ -48,7 +48,7 @@ class DeleteCommandTest(CommandTest):
_no_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.todo(1).source(), "Bar")
self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Foo id:1\n")
self.assertEqual(self.errors, "")
......@@ -58,7 +58,7 @@ class DeleteCommandTest(CommandTest):
_no_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.todo(1).source(), "Bar")
self.assertEqual(self.output, "| 2| Bar p:1\nRemoved: Foo id:1\n")
self.assertEqual(self.errors, "")
......@@ -68,7 +68,7 @@ class DeleteCommandTest(CommandTest):
_yes_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.count(), 2)
self.assertEqual(self.output,
"| 2| Bar p:1\nRemoved: Bar\nRemoved: Foo\n")
......@@ -79,7 +79,7 @@ class DeleteCommandTest(CommandTest):
self.error, _yes_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
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.errors, "")
......@@ -89,7 +89,7 @@ class DeleteCommandTest(CommandTest):
self.error, _yes_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
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.errors, "")
......@@ -98,7 +98,7 @@ class DeleteCommandTest(CommandTest):
command = DeleteCommand(["2"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.todo(1).source(), "Foo")
self.assertEqual(self.output, "Removed: Bar p:1\nThe following todo item(s) became active:\n| 1| Foo\n")
self.assertEqual(self.errors, "")
......@@ -107,7 +107,7 @@ class DeleteCommandTest(CommandTest):
command = DeleteCommand(["99"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -115,7 +115,7 @@ class DeleteCommandTest(CommandTest):
command = DeleteCommand(["A"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -159,7 +159,7 @@ class DeleteCommandTest(CommandTest):
self.error, _yes_prompt)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given: 99.\n")
......@@ -169,7 +169,7 @@ class DeleteCommandTest(CommandTest):
self.error, _yes_prompt)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given: 99.\nInvalid todo number given: A.\n")
......@@ -181,7 +181,7 @@ class DeleteCommandTest(CommandTest):
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors,
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
......@@ -193,7 +193,7 @@ class DeleteCommandTest(CommandTest):
result = "Removed: a @test with due:2015-06-03\nRemoved: a @test with +project\n"
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.count(), 2)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -203,7 +203,7 @@ class DeleteCommandTest(CommandTest):
self.todolist, self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "Removed: a @test with due:2015-06-03\n")
self.assertEqual(self.errors, "")
......@@ -212,7 +212,7 @@ class DeleteCommandTest(CommandTest):
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_del4(self):
""" Remove only relevant todo items. """
......@@ -222,7 +222,7 @@ class DeleteCommandTest(CommandTest):
result = "Foo"
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.count(), 1)
self.assertEqual(self.todolist.print_todos(), result)
......@@ -232,14 +232,14 @@ class DeleteCommandTest(CommandTest):
self.error, _yes_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.count(), 0)
def test_empty(self):
command = DeleteCommand([], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, command.usage() + "\n")
......
This diff is collapsed.
......@@ -23,7 +23,7 @@ from topydo.lib.TodoList import TodoList
class DepriCommandTest(CommandTest):
def setUp(self):
super(DepriCommandTest, self).setUp()
super().setUp()
todos = [
"(A) Foo",
"Bar",
......@@ -39,7 +39,7 @@ class DepriCommandTest(CommandTest):
command = DepriCommand(["1"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.todo(1).priority(), None)
self.assertEqual(self.output, "Priority removed.\n| 1| Foo\n")
self.assertEqual(self.errors, "")
......@@ -48,7 +48,7 @@ class DepriCommandTest(CommandTest):
command = DepriCommand(["2"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.todolist.todo(2).priority(), None)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "")
......@@ -57,7 +57,7 @@ class DepriCommandTest(CommandTest):
command = DepriCommand(["Foo"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.todo(1).priority(), None)
self.assertEqual(self.output, "Priority removed.\n| 1| Foo\n")
self.assertEqual(self.errors, "")
......@@ -67,7 +67,7 @@ class DepriCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.todo(1).priority(), None)
self.assertEqual(self.todolist.todo(3).priority(), None)
self.assertEqual(self.output, "Priority removed.\n| 1| Foo\nPriority removed.\n| 3| Baz\n")
......@@ -80,7 +80,7 @@ class DepriCommandTest(CommandTest):
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.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -91,7 +91,7 @@ class DepriCommandTest(CommandTest):
result = "Priority removed.\n| 4| a @test with due:2015-06-03\n"
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -100,7 +100,7 @@ class DepriCommandTest(CommandTest):
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_depri4(self):
""" Don't remove priority from unrelevant todo items. """
......@@ -108,7 +108,7 @@ class DepriCommandTest(CommandTest):
self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_depri5(self):
""" Force unprioritizing unrelevant items with additional -x flag. """
......@@ -116,7 +116,7 @@ class DepriCommandTest(CommandTest):
self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "Priority removed.\n| 6| Bax id:1\n")
self.assertEqual(self.errors, "")
......@@ -124,7 +124,7 @@ class DepriCommandTest(CommandTest):
command = DepriCommand(["99"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -133,7 +133,7 @@ class DepriCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given: 99.\n")
......@@ -142,7 +142,7 @@ class DepriCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given: 99.\nInvalid todo number given: FooBar.\n")
......@@ -154,7 +154,7 @@ class DepriCommandTest(CommandTest):
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors,
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
......@@ -163,7 +163,7 @@ class DepriCommandTest(CommandTest):
command = DepriCommand([], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, command.usage() + "\n")
......
......@@ -32,7 +32,7 @@ def _no_prompt(self):
class DoCommandTest(CommandTest):
def setUp(self):
super(DoCommandTest, self).setUp()
super().setUp()
todos = [
"Foo id:1",
"Bar p:1",
......@@ -61,7 +61,7 @@ class DoCommandTest(CommandTest):
_no_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertTrue(self.todolist.todo(3).is_completed())
self.assertEqual(self.output,
"Completed: x {} Baz p:1\n".format(self.today))
......@@ -77,7 +77,7 @@ class DoCommandTest(CommandTest):
for number in [1, 2, 3]:
self.assertTrue(self.todolist.todo(number).is_completed())
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertFalse(self.todolist.todo(4).is_completed())
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -89,7 +89,7 @@ class DoCommandTest(CommandTest):
result = "| 2| Bar p:1\n| 3| Baz p:1\nCompleted: x {} Foo id:1\n".format(self.today)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertTrue(self.todolist.todo(1).is_completed())
self.assertFalse(self.todolist.todo(2).is_completed())
self.assertFalse(self.todolist.todo(3).is_completed())
......@@ -130,7 +130,7 @@ class DoCommandTest(CommandTest):
command = DoCommand(p_flags, self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.count(), 12)
......@@ -162,7 +162,7 @@ class DoCommandTest(CommandTest):
command = DoCommand(["99"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -170,7 +170,7 @@ class DoCommandTest(CommandTest):
command = DoCommand(["AAA"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -179,7 +179,7 @@ class DoCommandTest(CommandTest):
_yes_prompt)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -209,7 +209,7 @@ class DoCommandTest(CommandTest):
command = DoCommand(["5"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.todolist.todo(5).completion_date(),
date(2014, 10, 18))
self.assertFalse(self.output)
......@@ -219,7 +219,7 @@ class DoCommandTest(CommandTest):
command = DoCommand(["baz"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertTrue(self.todolist.todo(3).is_completed())
self.assertEqual(self.output,
"Completed: x {} Baz p:1\n".format(self.today))
......@@ -230,7 +230,7 @@ class DoCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "Completed: x 2014-11-18 Baz p:1\n")
self.assertEqual(self.errors, "")
......@@ -239,7 +239,7 @@ class DoCommandTest(CommandTest):
self.error, _yes_prompt)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 2| Bar p:1\n| 3| Baz p:1\nCompleted: x 2014-11-18 Bar p:1\nCompleted: x 2014-11-18 Baz p:1\nCompleted: x 2014-11-18 Foo id:1\n")
self.assertEqual(self.errors, "")
......@@ -248,7 +248,7 @@ class DoCommandTest(CommandTest):
self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "Completed: x 2014-11-18 Baz p:1\n")
self.assertEqual(self.errors, "")
......@@ -257,7 +257,7 @@ class DoCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"Completed: x {} Baz p:1\n".format(self.today))
self.assertEqual(self.errors, "")
......@@ -271,7 +271,7 @@ class DoCommandTest(CommandTest):
self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
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, "")
......@@ -285,7 +285,7 @@ class DoCommandTest(CommandTest):
self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
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, "")
......@@ -298,7 +298,7 @@ class DoCommandTest(CommandTest):
self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
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, "")
......@@ -310,7 +310,7 @@ class DoCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"Completed: x {} Baz p:1\n".format(self.yesterday))
self.assertEqual(self.errors, "")
......@@ -323,7 +323,7 @@ class DoCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"Completed: x {} Baz p:1\n".format(self.yesterday))
self.assertEqual(self.errors, "")
......@@ -385,7 +385,7 @@ class DoCommandTest(CommandTest):
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.errors,
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
......@@ -394,7 +394,7 @@ class DoCommandTest(CommandTest):
self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.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, "")
......@@ -403,7 +403,7 @@ class DoCommandTest(CommandTest):
self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "Completed: x {} a @test with due:2015-06-03\n".format(self.today))
self.assertEqual(self.errors, "")
......@@ -412,7 +412,7 @@ class DoCommandTest(CommandTest):
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_do4(self):
""" Don't do anything with unrelevant todo items. """
......@@ -420,7 +420,7 @@ class DoCommandTest(CommandTest):
None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_do5(self):
""" Force marking unrelevant items as done with additional -x flag. """
......@@ -430,7 +430,7 @@ class DoCommandTest(CommandTest):
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.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -450,7 +450,7 @@ class DoCommandTest(CommandTest):
command = DoCommand([], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, command.usage() + "\n")
......
......@@ -33,7 +33,7 @@ except ImportError:
class EditCommandTest(CommandTest):
def setUp(self):
super(EditCommandTest, self).setUp()
super().setUp()
todos = [
"Foo id:1",
"Bar p:1 @test",
......@@ -56,7 +56,7 @@ class EditCommandTest(CommandTest):
command.execute()
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.print_todos(), u"Bar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a\nFoo id:1")
@mock.patch('topydo.commands.EditCommand._is_edited')
......@@ -72,7 +72,7 @@ class EditCommandTest(CommandTest):
None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nBaz @test\nFo\u00f3B\u0105\u017a\nLazy Cat")
......@@ -82,7 +82,7 @@ class EditCommandTest(CommandTest):
None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.errors, "Invalid todo number given.\n")
def test_edit04(self):
......@@ -91,7 +91,7 @@ class EditCommandTest(CommandTest):
self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.errors, "Invalid todo number given: 5.\n")
def test_edit05(self):
......@@ -102,7 +102,7 @@ class EditCommandTest(CommandTest):
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.errors,
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
......@@ -119,7 +119,7 @@ class EditCommandTest(CommandTest):
self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.print_todos(),
u"Foo id:1\nBar p:1 @test\nBaz @test\nLazy Cat")
......@@ -137,7 +137,7 @@ class EditCommandTest(CommandTest):
self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.errors, "Editing aborted. Nothing to do.\n")
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nBar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a")
......@@ -158,7 +158,7 @@ class EditCommandTest(CommandTest):
expected = u"| 3| Lazy Cat\n| 4| Lazy Dog\n"
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, expected)
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nFo\u00f3B\u0105\u017a\nLazy Cat\nLazy Dog")
......
......@@ -301,7 +301,7 @@ class FilterTest(TopydoTest):
class OrdinalTagFilterTest(TopydoTest):
def setUp(self):
super(OrdinalTagFilterTest, self).setUp()
super().setUp()
today = date.today()
tomorrow = today + timedelta(1)
......@@ -379,9 +379,87 @@ class OrdinalTagFilterTest(TopydoTest):
self.assertEqual(result[0].source(), self.todo3)
class CreationFilterTest(TopydoTest):
def setUp(self):
super().setUp()
self.todo1 = "2015-12-19 With creation date."
self.todo2 = "Without creation date."
self.todos = [Todo(self.todo1), Todo(self.todo2)]
def test_filter1(self):
cf = Filter.CreationFilter('create:2015-12-19')
result = cf.filter(self.todos)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].source(), self.todo1)
def test_filter2(self):
cf = Filter.CreationFilter('creation:2015-12-19')
result = cf.filter(self.todos)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].source(), self.todo1)
def test_filter3(self):
cf = Filter.CreationFilter('created:2015-12-19')
result = cf.filter(self.todos)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].source(), self.todo1)
class CompletionFilterTest(TopydoTest):
def setUp(self):
super().setUp()
self.todo1 = "2015-12-19 With creation date."
self.todo2 = "x 2015-12-19 2015-12-18 Without creation date."
self.todo3 = "x 2015-12-18 Without creation date."
self.todos = [Todo(self.todo1), Todo(self.todo2), Todo(self.todo3)]
def test_filter1(self):
cf = Filter.CompletionFilter('complete:2015-12-19')
result = cf.filter(self.todos)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].source(), self.todo2)
def test_filter2(self):
cf = Filter.CompletionFilter('completed:2015-12-19')
result = cf.filter(self.todos)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].source(), self.todo2)
def test_filter3(self):
cf = Filter.CompletionFilter('completion:2015-12-19')
result = cf.filter(self.todos)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].source(), self.todo2)
def test_filter4(self):
cf = Filter.CompletionFilter('completion:<=2015-12-19')
result = cf.filter(self.todos)
self.assertEqual(len(result), 2)
self.assertEqual(result[0].source(), self.todo2)
self.assertEqual(result[1].source(), self.todo3)
class PriorityFilterTest(TopydoTest):
def setUp(self):
super(PriorityFilterTest, self).setUp()
super().setUp()
self.todo1 = "(A) Foo"
self.todo2 = "(B) Bar"
......
......@@ -21,8 +21,8 @@ from topydo.Commands import get_subcommand
from topydo.commands.AddCommand import AddCommand
from topydo.commands.DeleteCommand import DeleteCommand
from topydo.commands.ListCommand import ListCommand
from topydo.commands.ListProjectCommand import ListProjectCommand
from topydo.lib.Config import config
from topydo.commands.TagCommand import TagCommand
from topydo.lib.Config import config, ConfigError
class GetSubcommandTest(TopydoTest):
def test_normal_cmd(self):
......@@ -60,6 +60,14 @@ class GetSubcommandTest(TopydoTest):
self.assertTrue(issubclass(real_cmd, ListCommand))
self.assertEqual(final_args, [u"\u263b"])
def test_alias04(self):
config("test/data/aliases.conf")
args = ["star", "foo"]
real_cmd, final_args = get_subcommand(args)
self.assertTrue(issubclass(real_cmd, TagCommand))
self.assertEqual(final_args, ["foo", "star", "1"])
def test_default_cmd01(self):
args = ["bar"]
real_cmd, final_args = get_subcommand(args)
......@@ -111,6 +119,15 @@ class GetSubcommandTest(TopydoTest):
real_cmd, final_args = get_subcommand(args)
self.assertEqual(real_cmd, None)
def test_alias_quotation(self):
config("test/data/aliases.conf")
args = ["quot"]
with self.assertRaises(ConfigError) as ce:
get_subcommand(args)
self.assertEqual(str(ce.exception), 'No closing quotation')
def test_help(self):
real_cmd, final_args = get_subcommand(['help', 'nonexisting'])
self.assertFalse(real_cmd)
......
......@@ -22,7 +22,7 @@ from topydo.lib.Graph import DirectedGraph
class GraphTest(TopydoTest):
def setUp(self):
super(GraphTest, self).setUp()
super().setUp()
self.graph = DirectedGraph()
......
This diff is collapsed.
This diff is collapsed.
......@@ -24,7 +24,7 @@ from topydo.lib.TodoList import TodoList
class PostponeCommandTest(CommandTest):
def setUp(self):
super(PostponeCommandTest, self).setUp()
super().setUp()
self.today = date.today()
self.past = date.today() - timedelta(1)
self.future = date.today() + timedelta(1)
......@@ -49,7 +49,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"| 1| Foo due:{}\n".format(due.isoformat()))
self.assertEqual(self.errors, "")
......@@ -61,7 +61,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"| 2| Bar due:{}\n".format(due.isoformat()))
self.assertEqual(self.errors, "")
......@@ -73,7 +73,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"| 2| Bar due:{}\n".format(due.isoformat()))
self.assertEqual(self.errors, "")
......@@ -85,7 +85,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 3| Baz due:{} t:{}\n".format(due.isoformat(), self.start.isoformat()))
self.assertEqual(self.errors, "")
......@@ -97,7 +97,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
start = self.start + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
# pylint: disable=E1103
self.assertEqual(self.output, "| 3| Baz due:{} t:{}\n".format(due.isoformat(), start.isoformat()))
self.assertEqual(self.errors, "")
......@@ -109,7 +109,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"| 4| Past due:{}\n".format(due.isoformat()))
self.assertEqual(self.errors, "")
......@@ -121,7 +121,7 @@ class PostponeCommandTest(CommandTest):
due = self.future + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
# pylint: disable=E1103
self.assertEqual(self.output, "| 5| Future due:{} t:{}\n".format(due.isoformat(), self.future_start.isoformat()))
self.assertEqual(self.errors, "")
......@@ -134,7 +134,7 @@ class PostponeCommandTest(CommandTest):
due = self.future + timedelta(7)
start = self.future_start + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
# pylint: disable=E1103
self.assertEqual(self.output, "| 5| Future due:{} t:{}\n".format(due.isoformat(), start.isoformat()))
self.assertEqual(self.errors, "")
......@@ -144,7 +144,7 @@ class PostponeCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid date pattern given.\n")
......@@ -153,7 +153,7 @@ class PostponeCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -162,7 +162,7 @@ class PostponeCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -170,7 +170,7 @@ class PostponeCommandTest(CommandTest):
command = PostponeCommand(["1"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, command.usage() + "\n")
......@@ -181,7 +181,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"| 1| Foo due:{}\n".format(due.isoformat()))
self.assertEqual(self.errors, "")
......@@ -193,7 +193,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 1| Foo due:{}\n| 2| Bar due:{}\n".format(due.isoformat(), due.isoformat()))
self.assertEqual(self.errors, "")
......@@ -204,7 +204,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 1| Foo due:{}\n| 2| Bar due:{}\n".format(due.isoformat(), due.isoformat()))
self.assertEqual(self.errors, "")
......@@ -216,7 +216,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
start = self.start + timedelta(7)
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
# pylint: disable=E1103
self.assertEqual(self.output, "| 2| Bar due:{}\n| 3| Baz due:{} t:{}\n".format(due.isoformat(), due.isoformat(), start.isoformat()))
self.assertEqual(self.errors, "")
......@@ -226,7 +226,7 @@ class PostponeCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid date pattern given.\n")
......@@ -235,7 +235,7 @@ class PostponeCommandTest(CommandTest):
self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given: 99.\nInvalid todo number given: 123.\n")
......@@ -244,7 +244,7 @@ class PostponeCommandTest(CommandTest):
self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given: Zoo.\nInvalid todo number given: 99.\nInvalid todo number given: 123.\n")
......@@ -254,7 +254,7 @@ class PostponeCommandTest(CommandTest):
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors,
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
......@@ -267,7 +267,7 @@ class PostponeCommandTest(CommandTest):
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.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -282,7 +282,7 @@ class PostponeCommandTest(CommandTest):
result = "| 3| Baz due:{} t:{}\n".format(due.isoformat(),
self.start.isoformat())
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -291,7 +291,7 @@ class PostponeCommandTest(CommandTest):
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_postpone4(self):
""" Don't postpone unrelevant todo items. """
......@@ -299,7 +299,7 @@ class PostponeCommandTest(CommandTest):
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_postpone5(self):
""" Force postponing unrelevant items with additional -x flag. """
......@@ -310,7 +310,7 @@ class PostponeCommandTest(CommandTest):
due = self.today + timedelta(7)
result = "| 6| FutureStart t:{} due:{}\n".format(self.future.isoformat(), due.isoformat())
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......
......@@ -23,7 +23,7 @@ from topydo.lib.TodoList import TodoList
class PriorityCommandTest(CommandTest):
def setUp(self):
super(PriorityCommandTest, self).setUp()
super().setUp()
todos = [
"(A) Foo",
"Bar",
......@@ -39,7 +39,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"Priority changed from A to B\n| 1| (B) Foo\n")
self.assertEqual(self.errors, "")
......@@ -49,7 +49,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "Priority set to Z.\n| 2| (Z) Bar\n")
self.assertEqual(self.errors, "")
......@@ -58,7 +58,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"Priority changed from A to B\n| 1| (B) Foo\n")
self.assertEqual(self.errors, "")
......@@ -68,7 +68,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "| 1| (A) Foo\n")
self.assertEqual(self.errors, "")
......@@ -77,7 +77,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
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, "")
......@@ -87,7 +87,17 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
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, "")
def test_set_prio7(self):
""" Allow lowercase priority to be set. """
command = PriorityCommand(["Foo", "2", "c"], self.todolist, self.out,
self.error)
command.execute()
self.assertTrue(self.todolist.dirty)
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, "")
......@@ -98,7 +108,7 @@ class PriorityCommandTest(CommandTest):
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.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -109,7 +119,7 @@ class PriorityCommandTest(CommandTest):
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.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, result)
self.assertEqual(self.errors, "")
......@@ -119,7 +129,7 @@ class PriorityCommandTest(CommandTest):
None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_prio4(self):
""" Don't prioritize unrelevant todo items. """
......@@ -127,7 +137,7 @@ class PriorityCommandTest(CommandTest):
self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
def test_expr_prio5(self):
""" Force prioritizing unrelevant items with additional -x flag. """
......@@ -135,7 +145,7 @@ class PriorityCommandTest(CommandTest):
self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"Priority set to D.\n| 5| (D) Baz id:1\n")
self.assertEqual(self.errors, "")
......@@ -145,7 +155,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given.\n")
......@@ -154,7 +164,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given: 99.\n")
......@@ -163,7 +173,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number given: 98.\nInvalid todo number given: 99.\n")
......@@ -172,7 +182,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid priority given.\n")
......@@ -180,7 +190,7 @@ class PriorityCommandTest(CommandTest):
command = PriorityCommand(["A"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, command.usage() + "\n")
......@@ -188,7 +198,7 @@ class PriorityCommandTest(CommandTest):
command = PriorityCommand(["1"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, command.usage() + "\n")
......@@ -200,7 +210,7 @@ class PriorityCommandTest(CommandTest):
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors,
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
......@@ -214,7 +224,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid priority given.\n")
......@@ -227,7 +237,7 @@ class PriorityCommandTest(CommandTest):
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid priority given.\n")
......@@ -235,7 +245,7 @@ class PriorityCommandTest(CommandTest):
command = PriorityCommand([], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, command.usage() + "\n")
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2016 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 freezegun import freeze_time
import unittest
from test.topydo_testcase import TopydoTest
from topydo.lib.Config import config
from topydo.lib.ProgressColor import progress_color
from topydo.lib.Todo import Todo
def set_256_colors():
config(p_overrides={('topydo', 'colors'): '256'})
@freeze_time('2016, 01, 01')
class ProgressColorTest(TopydoTest):
def test_progress1(self):
""" Test progress of task with no length """
color = progress_color(Todo('Foo'))
self.assertEqual(color.color, 2)
def test_progress2(self):
""" Test progress of task with no length (but with creation date). """
color = progress_color(Todo('2016-02-11 Foo'))
self.assertEqual(color.color, 2)
def test_progress3(self):
""" Test progress of task with no length """
set_256_colors()
color = progress_color(Todo('Foo'))
self.assertEqual(color.color, 22)
def test_progress4(self):
""" Test progress of task with no length (but with creation date). """
set_256_colors()
color = progress_color(Todo('2016-02-11 Foo'))
self.assertEqual(color.color, 22)
def test_progress5(self):
""" Test overdue tasks """
color = progress_color(Todo('Foo due:2015-12-31'))
self.assertEqual(color.color, 1)
def test_progress6(self):
""" Test overdue tasks """
set_256_colors()
color = progress_color(Todo('Foo due:2015-12-31'))
self.assertEqual(color.color, 196)
def test_progress7(self):
""" Due today """
color = progress_color(Todo('Foo due:2016-01-01'))
self.assertEqual(color.color, 3)
def test_progress8(self):
""" Due today (256) """
set_256_colors()
color = progress_color(Todo('Foo due:2016-01-01'))
self.assertEqual(color.color, 202)
def test_progress9(self):
""" Due tomorrow """
color = progress_color(Todo('Foo due:2016-01-02'))
# a length of 14 days is assumed
self.assertEqual(color.color, 3)
def test_progress10(self):
set_256_colors()
color = progress_color(Todo('Foo due:2016-01-02'))
# a length of 14 days is assumed
self.assertEqual(color.color, 208)
def test_progress11(self):
""" Due tomorrow (creation date) """
color = progress_color(Todo('2016-01-01 Foo due:2016-01-02'))
# a length of 14 days is assumed
self.assertEqual(color.color, 2)
def test_progress12(self):
""" Due tomorrow (creation date) """
set_256_colors()
color = progress_color(Todo('2016-01-01 Foo due:2016-01-02'))
self.assertEqual(color.color, 22)
def test_progress13(self):
""" Due tomorrow (recurrence) """
color = progress_color(Todo('Foo due:2016-01-02 rec:1d'))
self.assertEqual(color.color, 2)
def test_progress14(self):
""" Due tomorrow (recurrence) """
set_256_colors()
color = progress_color(Todo('Foo due:2016-01-02 rec:1d'))
self.assertEqual(color.color, 22)
def test_progress15(self):
""" Due tomorrow (creation date + recurrence) """
color = progress_color(Todo('2016-12-01 Foo due:2016-01-02 rec:1d'))
self.assertEqual(color.color, 2)
def test_progress16(self):
""" Due tomorrow (creation date + recurrence) """
set_256_colors()
color = progress_color(Todo('2015-12-01 Foo due:2016-01-02 rec:1d'))
self.assertEqual(color.color, 22)
def test_progress17(self):
""" Due tomorrow (creation date + recurrence + start date) """
color = progress_color(Todo('2016-12-01 Foo due:2016-01-02 rec:1d t:2016-01-02'))
self.assertEqual(color.color, 2)
def test_progress18(self):
""" Due tomorrow (creation date + recurrence + start date) """
set_256_colors()
color = progress_color(Todo('2015-12-01 Foo due:2016-01-02 rec:1d t:2016-01-02'))
self.assertEqual(color.color, 22)
def test_progress19(self):
""" Due tomorrow (creation date + strict recurrence + start date) """
color = progress_color(Todo('2016-12-01 Foo due:2016-01-02 rec:+1d t:2016-01-02'))
self.assertEqual(color.color, 2)
def test_progress20(self):
""" Due tomorrow (creation date + strict recurrence + start date) """
set_256_colors()
color = progress_color(Todo('2015-12-01 Foo due:2016-01-02 rec:+1d t:2016-01-02'))
self.assertEqual(color.color, 22)
def test_progress21(self):
""" Due tomorrow (creation date + start date) """
color = progress_color(Todo('2016-12-01 Foo due:2016-01-02 t:2016-01-02'))
self.assertEqual(color.color, 2)
def test_progress22(self):
""" Due tomorrow (creation date + start date) """
set_256_colors()
color = progress_color(Todo('2015-12-01 Foo due:2016-01-02 t:2016-01-02'))
self.assertEqual(color.color, 22)
def test_progress23(self):
""" Due tomorrow (creation date + start date) """
color = progress_color(Todo('2016-12-01 Foo due:2016-01-02 t:2015-12-31'))
self.assertEqual(color.color, 10)
def test_progress24(self):
""" Due tomorrow (creation date + start date) """
set_256_colors()
color = progress_color(Todo('2015-12-01 Foo due:2016-01-02 t:2015-12-31'))
self.assertEqual(color.color, 118)
def test_progress25(self):
""" Start date after due date """
color = progress_color(Todo('Foo due:2016-01-02 t:2016-01-03'))
# a length of 14 days is assumed
self.assertEqual(color.color, 3)
def test_progress26(self):
""" Start date after due date """
set_256_colors()
color = progress_color(Todo('Foo due:2016-01-02 t:2016-01-03'))
# a length of 14 days is assumed
self.assertEqual(color.color, 208)
def test_progress27(self):
""" Creation date after due date """
set_256_colors()
color = progress_color(Todo('2016-01-03 Foo due:2016-01-02'))
# a length of 14 days is assumed
self.assertEqual(color.color, 208)
if __name__ == '__main__':
unittest.main()
......@@ -25,7 +25,7 @@ from topydo.lib.Todo import Todo
class RecurrenceTest(TopydoTest):
def setUp(self):
super(RecurrenceTest, self).setUp()
super().setUp()
self.todo = Todo("Test rec:1w")
self.stricttodo = Todo("Test rec:+1w")
......
......@@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
from datetime import date, timedelta
from datetime import date
from freezegun import freeze_time
from test.topydo_testcase import TopydoTest
......@@ -25,7 +25,7 @@ from topydo.lib.RelativeDate import relative_date_to_date
@freeze_time('2015, 11, 06')
class RelativeDateTester(TopydoTest):
def setUp(self):
super(RelativeDateTester, self).setUp()
super().setUp()
self.yesterday = date(2015, 11, 5)
self.today = date(2015, 11, 6)
self.tomorrow = date(2015, 11, 7)
......@@ -40,6 +40,18 @@ class RelativeDateTester(TopydoTest):
result = relative_date_to_date('1d')
self.assertEqual(result, self.tomorrow)
def test_zero_bdays(self):
result = relative_date_to_date('0b')
self.assertEqual(result, self.today)
def test_one_bday(self):
result = relative_date_to_date('1b')
self.assertEqual(result, self.monday)
def test_one_bweek(self):
result = relative_date_to_date('5b')
self.assertEqual(result, self.friday)
def test_one_week(self):
result = relative_date_to_date('1w')
self.assertEqual(result, date(2015, 11, 13))
......@@ -152,6 +164,14 @@ class RelativeDateTester(TopydoTest):
result = relative_date_to_date('-0d')
self.assertTrue(result, self.today)
def test_negative_period3(self):
result = relative_date_to_date('-1b')
self.assertEqual(result, date(2015, 11, 5))
def test_negative_period4(self):
result = relative_date_to_date('-5b')
self.assertEqual(result, date(2015, 10, 30))
def test_weekday_next_week(self):
"""
When entering "Friday" on a Friday, return next week Friday instead of
......
......@@ -35,7 +35,7 @@ from topydo.lib.TodoList import TodoList
class RevertCommandTest(CommandTest):
def setUp(self):
super(RevertCommandTest, self).setUp()
super().setUp()
todos = [
"Foo",
"Bar",
......
......@@ -24,7 +24,7 @@ from topydo.lib.Config import config
class SortCommandTest(CommandTest):
def setUp(self):
super(SortCommandTest, self).setUp()
super().setUp()
self.todolist = load_file_to_todolist("test/data/SorterTest1.txt")
def test_sort1(self):
......
......@@ -14,6 +14,7 @@
# 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 freezegun import freeze_time
import unittest
from test.facilities import (load_file, load_file_to_todolist, print_view,
......@@ -23,6 +24,7 @@ from topydo.lib.Config import config
from topydo.lib.Sorter import Sorter
@freeze_time("2016, 04, 25")
class SorterTest(TopydoTest):
def sort_file(self, p_filename, p_filename_ref, p_sorter):
"""
......@@ -189,5 +191,14 @@ class SorterTest(TopydoTest):
'test/data/SorterTest13-result-context.txt', sorter)
def test_sort19(self):
"""
Check sorting by length.
"""
sorter = Sorter('length,text')
self.sort_file('test/data/SorterTest14.txt',
'test/data/SorterTest14-result.txt', sorter)
if __name__ == '__main__':
unittest.main()
......@@ -24,7 +24,7 @@ from topydo.lib.TodoList import TodoList
class TagCommandTest(CommandTest):
def setUp(self):
super(TagCommandTest, self).setUp()
super().setUp()
todos = [
"Foo",
"Bar due:2014-10-22",
......@@ -42,7 +42,7 @@ class TagCommandTest(CommandTest):
self.assertEqual(self.todolist.todo(1).source(), "Foo due:2014-10-22")
self.assertEqual(self.output, "| 1| Foo due:2014-10-22\n")
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
def test_add_tag2(self):
command = TagCommand(["Foo", "due", "2014-10-22"], self.todolist,
......@@ -52,7 +52,7 @@ class TagCommandTest(CommandTest):
self.assertEqual(self.todolist.todo(1).source(), "Foo due:2014-10-22")
self.assertEqual(self.output, "| 1| Foo due:2014-10-22\n")
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
def test_add_tag3(self):
command = TagCommand(["-a", "2", "due", "2014-10-19"], self.todolist,
......@@ -64,23 +64,34 @@ class TagCommandTest(CommandTest):
self.assertEqual(self.output,
"| 2| Bar due:2014-10-22 due:2014-10-19\n")
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
def test_add_tag4(self):
command = TagCommand(["Foox", "due", "2014-10-22"], self.todolist,
self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertFalse(self.output)
self.assertEqual(self.errors, "Invalid todo number.\n")
def test_force_add_tag01(self):
'''Tries to different values to a tag for the same name 3 times.'''
for letter in ['a', 'b', 'c']:
command = TagCommand(['-a', '1', 'k', letter], self.todolist,
self.out, self.error)
command.execute()
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.todo(1).source(), "Foo k:a k:b k:c")
def test_set_tag04(self):
command = TagCommand(["3", "due", "2014-10-20"], self.todolist,
self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "| 3| Baz due:2014-10-20\n")
self.assertEqual(self.errors, "")
......@@ -89,7 +100,7 @@ class TagCommandTest(CommandTest):
self.out, self.error, lambda t: "all")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-20 due:2014-10-20\n")
self.assertEqual(self.errors, "")
......@@ -98,7 +109,7 @@ class TagCommandTest(CommandTest):
self.out, self.error, lambda t: "1")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEqual(self.errors, "")
......@@ -107,7 +118,7 @@ class TagCommandTest(CommandTest):
self.out, self.error, lambda t: "2")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-20 due:2014-10-20\n")
self.assertEqual(self.errors, "")
......@@ -116,7 +127,7 @@ class TagCommandTest(CommandTest):
self.out, self.error, lambda t: "")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEqual(self.errors, "")
......@@ -125,7 +136,7 @@ class TagCommandTest(CommandTest):
self.out, self.error, lambda t: "99")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEqual(self.errors, "")
......@@ -134,7 +145,7 @@ class TagCommandTest(CommandTest):
self.out, self.error, lambda t: "99")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
"| 4| Fnord due:2014-10-20 due:2014-10-20\n")
self.assertEqual(self.errors, "")
......@@ -145,7 +156,7 @@ class TagCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 3| Baz due:2015-11-19\n")
self.assertEqual(self.errors, "")
......@@ -158,7 +169,7 @@ class TagCommandTest(CommandTest):
self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 3| Baz due:2014-10-20 foo:today\n")
self.assertEqual(self.errors, "")
......@@ -166,7 +177,7 @@ class TagCommandTest(CommandTest):
command = TagCommand(["1", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "| 1| Foo\n")
self.assertEqual(self.errors, "")
......@@ -174,7 +185,7 @@ class TagCommandTest(CommandTest):
command = TagCommand(["2", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 2| Bar\n")
self.assertEqual(self.errors, "")
......@@ -183,7 +194,7 @@ class TagCommandTest(CommandTest):
self.error, lambda t: "all")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output,
" 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord\n")
self.assertEqual(self.errors, "")
......@@ -193,7 +204,7 @@ class TagCommandTest(CommandTest):
lambda t: "1")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-22\n")
self.assertEqual(self.errors, "")
......@@ -202,7 +213,7 @@ class TagCommandTest(CommandTest):
lambda t: "99")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEqual(self.errors, "")
......@@ -211,7 +222,7 @@ class TagCommandTest(CommandTest):
lambda t: "A")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n| 4| Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEqual(self.errors, "")
......@@ -219,7 +230,7 @@ class TagCommandTest(CommandTest):
command = TagCommand(["5", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number.\n")
......@@ -227,7 +238,7 @@ class TagCommandTest(CommandTest):
command = TagCommand(["A", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number.\n")
......@@ -236,7 +247,7 @@ class TagCommandTest(CommandTest):
self.error, lambda t: "A")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, "| 4| Fnord\n")
self.assertEqual(self.errors, "")
......@@ -244,7 +255,7 @@ class TagCommandTest(CommandTest):
command = TagCommand(["4"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, command.usage() + "\n")
......
This diff is collapsed.
# 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/>.
import unittest
from test.topydo_testcase import TopydoTest
from topydo.lib.Utils import translate_key_to_config
class UtilsTest(TopydoTest):
def test_key_to_cfg(self):
ctrl_s = translate_key_to_config('ctrl s')
meta_d = translate_key_to_config('meta d')
esc = translate_key_to_config('esc')
f4 = translate_key_to_config('f4')
self.assertEqual(ctrl_s, '<C-s>')
self.assertEqual(meta_d, '<M-d>')
self.assertEqual(esc, '<Esc>')
self.assertEqual(f4, '<F4>')
if __name__ == '__main__':
unittest.main()
......@@ -4,7 +4,7 @@
default_command = ls
; filename = todo.txt
; archive_filename = done.txt
colors = 1
colors = auto
; identifiers can be 'linenumber' or 'text'
identifiers = linenumber
backup_count = 5
......@@ -42,6 +42,8 @@ append_parent_contexts = 0
; [light-]gray, darkgray or numbers from 0 to 255. When number is specified color
; is matched from Xterm color chart available here:
; http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
; When using values between 16 and 256, make sure to set colors = 256 in the
; [topydo] section.
; priority_colors = A:cyan,B:yellow,C:blue
; project_color = red
......@@ -52,7 +54,9 @@ append_parent_contexts = 0
[aliases]
;showall = ls -x
;next = ls -n 1
;top = ls -F '|%I| %x %p %S %k %{(}H{)}'
;top = ls -F '%I %x %P %S %k %{(}H{)}' -N
;star = tag {} star 1
;unstar = tag {} star
;lsproj = lsprj
;listprj = lsprj
;listproj = lsprj
......@@ -61,3 +65,35 @@ append_parent_contexts = 0
;listcon = lscon
;listcontext = lscon
;listcontexts = lscon
[columns]
column_width = 40
[column_keymap]
; Keymap configuration for column-mode
gg = home
G = end
j = down
k = up
d = cmd del {}
e = cmd edit {}
u = cmd revert
x = cmd do {}
pp = postpone
ps = postpone_s
pr = pri
m = mark
0 = first_column
$ = last_column
h = prev_column
l = next_column
A = append_column
I = insert_column
E = edit_column
D = delete_column
Y = copy_column
L = swap_left
R = swap_right
<Left> = prev_column
<Right> = next_column
<Esc> = reset
......@@ -21,7 +21,7 @@ instance based on an argument list.
import sys
from topydo.lib.Config import config
from topydo.lib.Config import config, ConfigError
_SUBCOMMAND_MAP = {
'add': 'AddCommand',
......@@ -71,6 +71,18 @@ def get_subcommand(p_args):
__import__(modulename, globals(), locals(), [classname], 0)
return getattr(sys.modules[modulename], classname)
def join_args(p_cli_args, p_alias_args):
"""
Returns properly joined args from alias definition and from user input.
"""
if '{}' in p_alias_args:
pos = p_alias_args.index('{}')
args = p_alias_args[:pos] + p_cli_args + p_alias_args[pos+1:]
else:
args = p_alias_args + p_cli_args
return args
def resolve_alias(p_alias, p_args):
"""
Resolves a subcommand alias and returns a tuple (Command, args).
......@@ -78,10 +90,14 @@ def get_subcommand(p_args):
If alias resolves to non-existent command, main help message is
returned.
"""
real_subcommand, alias_args = alias_map[p_alias]
try:
real_subcommand, alias_args = alias_map[p_alias]
except ValueError as ve:
raise ConfigError(alias_map[p_alias]) from ve
try:
result = import_subcommand(real_subcommand)
args = alias_args + p_args
args = join_args(p_args, alias_args)
return (result, args)
except KeyError:
return get_subcommand(['help'])
......
......@@ -22,19 +22,17 @@ from datetime import date
from os.path import expanduser
from sys import stdin
from topydo.lib.Command import Command
from topydo.lib.WriteCommand import WriteCommand
from topydo.lib.Config import config
from topydo.lib.prettyprinters.Numbers import PrettyPrinterNumbers
from topydo.lib.RelativeDate import relative_date_to_date
from topydo.lib.TodoListBase import InvalidTodoException
class AddCommand(Command):
class AddCommand(WriteCommand):
def __init__(self, p_args, p_todolist, # pragma: no branch
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(AddCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.text = ' '.join(p_args)
self.from_file = None
......@@ -70,56 +68,18 @@ class AddCommand(Command):
return todo_text
def _postprocess_input_todo(p_todo):
"""
Post-processes a parsed todo when adding it to the list.
* It converts relative dates to absolute ones.
* Automatically inserts a creation date if not present.
* Handles more user-friendly dependencies with before:, partof: and
after: tags
"""
def convert_date(p_tag):
value = p_todo.tag_value(p_tag)
if value:
dateobj = relative_date_to_date(value)
if dateobj:
p_todo.set_tag(p_tag, dateobj.isoformat())
def add_dependencies(p_tag):
for value in p_todo.tag_values(p_tag):
try:
dep = self.todolist.todo(value)
if p_tag == 'after':
self.todolist.add_dependency(p_todo, dep)
elif p_tag == 'before' or p_tag == 'partof':
self.todolist.add_dependency(dep, p_todo)
except InvalidTodoException:
pass
p_todo.remove_tag(p_tag, value)
convert_date(config().tag_start())
convert_date(config().tag_due())
add_dependencies('partof')
add_dependencies('before')
add_dependencies('after')
if config().auto_creation_date():
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.postprocess_input_todo(todo)
if config().auto_creation_date():
todo.set_creation_date(date.today())
self.out(self.printer.print_todo(todo))
def execute(self):
""" Adds a todo item to the list. """
if not super(AddCommand, self).execute():
if not super().execute():
return False
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
......@@ -138,23 +98,22 @@ class AddCommand(Command):
def usage(self):
return """Synopsis:
add <text>
add -f <file>
add -f -"""
add <TEXT>
add -f <FILE> | -"""
def help(self):
return """\
This subcommand automatically adds the creation date to the added item.
<text> may contain:
TEXT may contain:
* Priorities mid-sentence. Example: add "Water flowers (C)"
* Dependencies using before, after and partof tags. They are translated to the
corresponding 'id' and 'p' tags. The values of these tags correspond to the
todo number (not the dependency number).
* Dependencies using before, after, partof, parents-of and children-of tags.
These are translated to the corresponding 'id' and 'p' tags. The values of
these tags correspond to the todo number (not the dependency number).
Example: add "Subtask partof:1"
-f : Add todo items from specified <file> or from standard input.
-f : Add todo items from specified FILE or from standard input.\
"""
......@@ -14,21 +14,23 @@
# 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, InvalidCommandArgument
from topydo.lib.Config import config
from topydo.lib.Command import InvalidCommandArgument
from topydo.lib.WriteCommand import WriteCommand
from topydo.lib.prettyprinters.Numbers import PrettyPrinterNumbers
from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.TodoParser import parse_line
class AppendCommand(Command):
class AppendCommand(WriteCommand):
def __init__(self, p_args, p_todolist, #pragma: no branch
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(AppendCommand, self).__init__(p_args, p_todolist, p_out, p_err,
super().__init__(p_args, p_todolist, p_out, p_err,
p_prompt)
def execute(self):
if not super(AppendCommand, self).execute():
if not super().execute():
return False
try:
......@@ -37,7 +39,13 @@ class AppendCommand(Command):
if text:
todo = self.todolist.todo(number)
new_text_parsed = parse_line(text)
new_tags = new_text_parsed['tags']
for tag in (config().tag_start(), config().tag_due()):
if tag in new_tags:
todo.remove_tag(tag)
self.todolist.append(todo, text)
self.postprocess_input_todo(todo)
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
self.out(self.printer.print_todo(todo))
......@@ -49,9 +57,9 @@ class AppendCommand(Command):
self.error("Invalid todo number given.")
def usage(self):
return """Synopsis: append <number> <text>"""
return """Synopsis: append <NUMBER> <TEXT>"""
def help(self):
return """\
Adds the given <text> to the end of the todo indicated by <number>.
Adds the given TEXT to the end of the todo indicated by NUMBER.\
"""
......@@ -27,7 +27,7 @@ class ArchiveCommand(Command):
TodoListBase class which does no dependency checking, so a better
choice for huge done.txt files.
"""
super(ArchiveCommand, self).__init__([], p_todolist)
super().__init__([], p_todolist)
self.archive = p_archive_list
def execute(self):
......
......@@ -22,7 +22,7 @@ class DeleteCommand(DCommand):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(DeleteCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
def prompt_text(self):
......@@ -40,15 +40,15 @@ class DeleteCommand(DCommand):
def usage(self):
return """\
Synopsis: del [-f] <NUMBER1> [<NUMBER2> ...]
del [-x] -e <EXPRESSION>
Synopsis: del [-f] <NUMBER 1> [<NUMBER 2> ...]
del [-x] -e <EXPRESSION>\
"""
def help(self):
return """\
Deletes the todo item(s) with the given number(s) from the list.
It is also possible to delete items as complete with an expression using
the -e flag. Use -x to also process todo items that are normally invisible
(with the 'ls' subcommand).
It is also possible to delete items that match EXPRESSION using the -e flag.
Use -x to also process todo items that are normally invisible (as with the 'ls'
subcommand).\
"""
......@@ -29,7 +29,7 @@ class DepCommand(Command):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(DepCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
try:
......@@ -40,44 +40,66 @@ class DepCommand(Command):
self.printer = pretty_printer_factory(self.todolist)
def _handle_add(self):
(from_todo, to_todo) = self._get_todos()
if from_todo and to_todo:
for from_todo, to_todo in self._get_todos():
self.todolist.add_dependency(from_todo, to_todo)
def _handle_rm(self):
(from_todo, to_todo) = self._get_todos()
if from_todo and to_todo:
for from_todo, to_todo in self._get_todos():
self.todolist.remove_dependency(from_todo, to_todo)
def _get_todos(self):
from_todo = None
to_todo = None
result = []
def get_parent_dependencies():
child_todo = first_todo
sibling_todo = second_todo
return [(parent, child_todo) for parent in self.todolist.parents(sibling_todo)]
def get_child_dependencies():
parent_todo = first_todo
sibling_todo = second_todo
return [(parent_todo, child) for child in self.todolist.children(sibling_todo)]
get_before_dependency = lambda: [(second_todo, first_todo)]
get_after_dependency = lambda: [(first_todo, second_todo)]
operators = {
"after": get_after_dependency,
"before": get_before_dependency,
"child-of": get_child_dependencies,
"childof": get_child_dependencies,
"children-of": get_child_dependencies,
"childrenof": get_child_dependencies,
"parent-of": get_parent_dependencies,
"parentof": get_parent_dependencies,
"parents-of": get_parent_dependencies,
"parentsof": get_parent_dependencies,
"partof": get_before_dependency,
"to": get_after_dependency,
}
try:
first_todo_nr = self.argument(1)
operator = self.argument(2)
if operator == 'before' or operator == 'partof':
from_todo_nr = self.argument(3)
to_todo_nr = self.argument(1)
elif operator == 'to' or operator == 'after':
from_todo_nr = self.argument(1)
to_todo_nr = self.argument(3)
if operator in operators:
second_todo_nr = self.argument(3)
else:
# the operator was omitted, assume 2nd argument is target task
# default to 'to' behavior
from_todo_nr = self.argument(1)
to_todo_nr = self.argument(2)
second_todo_nr = self.argument(2)
operator = "to"
first_todo = self.todolist.todo(first_todo_nr)
second_todo = self.todolist.todo(second_todo_nr)
from_todo = self.todolist.todo(from_todo_nr)
to_todo = self.todolist.todo(to_todo_nr)
result = operators[operator]()
except (InvalidTodoException):
self.error("Invalid todo number given.")
except InvalidCommandArgument:
self.error(self.usage())
return (from_todo, to_todo)
return result
def _handle_ls(self):
""" Handles the ls subsubcommand. """
......@@ -127,7 +149,7 @@ class DepCommand(Command):
def execute(self):
if not super(DepCommand, self).execute():
if not super().execute():
return False
dispatch = {
......@@ -148,7 +170,7 @@ class DepCommand(Command):
def usage(self):
return """Synopsis:
dep <add|rm> <NUMBER> [to] <NUMBER>
dep add <NUMBER> <before|partof|after> <NUMBER>
dep add <NUMBER> <before|partof|after|parents-of|children-of> <NUMBER>
dep ls <NUMBER> to
dep ls to <NUMBER>
dep dot <NUMBER>
......@@ -156,10 +178,11 @@ class DepCommand(Command):
def help(self):
return """\
* add : Adds a dependency. Using 1 before 2 creates a dependency
from todo item 2 to 1.
* add : Adds a dependency. `dep add 1 2` denotes that todo item 1
is dependant on todo item 2, i.e. item 2 is a subitem of
item 1.
* rm (alias: del) : Removes a dependency.
* ls : Lists all dependencies to or from a certain todo.
* dot : Prints a dependency tree as a Dot graph.
* clean (alias: gc) : Removes redundant id or p tags.
* clean (alias: gc) : Removes redundant id or p tags.\
"""
......@@ -23,7 +23,7 @@ class DepriCommand(MultiCommand):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(DepriCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
def _execute_multi_specific(self):
......@@ -37,14 +37,14 @@ class DepriCommand(MultiCommand):
def usage(self):
return """\
Synopsis: depri <NUMBER1> [<NUMBER2> ...]
depri [-x] -e <EXPRESSION>
Synopsis: depri <NUMBER 1> [<NUMBER 2> ...]
depri [-x] -e <EXPRESSION>\
"""
def help(self):
return """Removes the priority of the given todo item(s).
It is also possible to deprioritize items as complete with an expression using
the -e flag. Use -x to also process todo items that are normally invisible
(with the 'ls' subcommand).
It is also possible to deprioritize items as complete with an EXPRESSION using
the -e flag. Use -x to also process todo items that are normally invisible (as
with the 'ls' subcommand).\
"""
......@@ -33,17 +33,17 @@ class DoCommand(DCommand):
self.strict_recurrence = False
self.completion_date = date.today()
super(DoCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
def get_flags(self):
""" Additional flags. """
opts, long_opts = super(DoCommand, self).get_flags()
opts, long_opts = super().get_flags()
return ("d:s" + opts, ["date=", "strict"] + long_opts)
def process_flag(self, p_opt, p_value):
super(DoCommand, self).process_flag(p_opt, p_value)
super().process_flag(p_opt, p_value)
if p_opt == "-s" or p_opt == "--strict":
self.strict_recurrence = True
......@@ -105,28 +105,28 @@ class DoCommand(DCommand):
def usage(self):
return """\
Synopsis: do [--date] [--force] [--strict] <NUMBER1> [<NUMBER2> ...]
do [-x] -e <EXPRESSION>
Synopsis: do [--date <DATE>] [--force] [--strict] <NUMBER 1> [<NUMBER 2> ...]
do [-x] -e <EXPRESSION>\
"""
def help(self):
return """Marks the todo(s) with given number(s) as complete.
return """Marks the todo(s) with given NUMBER(s) as complete.
It is also possible to mark todo items as complete with an expression using the
-e flag. Use -x to also process todo items that are normally invisible (with
It is also possible to mark todo items as complete with an EXPRESSION using the
-e flag. Use -x to also process todo items that are normally invisible (as with
the 'ls' subcommand).
In case a todo has subitems, a question is asked whether the subitems should be
marked as completed as well. When --force is given, no interaction is required
and the subitems are not marked completed.
In case a todo has subitems (dependencies), a question is asked whether the
subitems should be marked as completed as well. When --force is given, no
interaction is required and the subitems are not marked completed.
In case a completed todo is recurring, a new todo will be added to the list,
while the given todo item is marked as complete. The new date is calculated
based on the todo item's due date. If the due date is in the past, today's date
is used to calculate the new recurrence date. Using --strict prevents this,
is used to calculate the new recurrence date. Using --strict prevents this, and
then the actual due date of the todo item is used to calculate the new
recurrence date. Note that a future due date is always used as such to
calculate the new due date.
Use --date to set a custom completion date.
Use --date to set a custom completion date.\
"""
......@@ -27,10 +27,6 @@ from topydo.lib.TodoList import TodoList
# the true and only editor
DEFAULT_EDITOR = 'vi'
# Access the base class of the TodoList instance kept inside EditCommand. We
# cannot use super() inside the class itself
BASE_TODOLIST = lambda tl: super(TodoList, tl)
def _get_file_mtime(p_file):
return os.stat(p_file.name).st_mtime
......@@ -39,7 +35,7 @@ def _is_edited(p_orig_mtime, p_file):
class EditCommand(MultiCommand):
def __init__(self, p_args, p_todolist, p_output, p_error, p_input):
super(EditCommand, self).__init__(p_args, p_todolist, p_output,
super().__init__(p_args, p_todolist, p_output,
p_error, p_input)
if len(self.args) == 0:
......@@ -115,7 +111,7 @@ class EditCommand(MultiCommand):
if _is_edited(orig_mtime, temp_todos):
for todo in self.todos:
BASE_TODOLIST(self.todolist).delete(todo)
self.todolist.delete(todo, p_leave_tags=True)
for todo in new_todos:
self.todolist.add_todo(todo)
......@@ -138,8 +134,8 @@ class EditCommand(MultiCommand):
def usage(self):
return """Synopsis:
edit
edit <NUMBER1> [<NUMBER2> ...]
edit -e [-x] [expression]
edit <NUMBER 1> [<NUMBER 2> ...]
edit -e [-x] [EXPRESSION]
edit -d"""
def help(self):
......@@ -147,15 +143,15 @@ class EditCommand(MultiCommand):
Launches a text editor to edit todos.
Without any arguments it will just open the todo.txt file. Alternatively it can
edit todo item(s) with the given number(s) or edit relevant todos matching
the given expression. See `topydo help ls` for more information on relevant
edit todo item(s) with the given NUMBER(s) or edit relevant todos matching
the given EXPRESSION. See `topydo help ls` for more information on relevant
todo items. It is also possible to open the archive file.
By default it will use $EDITOR in your environment, otherwise it will fall back
to 'vi'.
By default it will look to your environment variable $EDITOR, otherwise it will
fall back to 'vi'.
-e : Treat the subsequent arguments as an expression.
-x : Edit *all* todos matching the expression (i.e. do not filter on
-e : Treat the subsequent arguments as an EXPRESSION.
-x : Edit *all* todos matching the EXPRESSION (i.e. do not filter on
dependencies or relevance).
-d : Open the archive file.
-d : Open the archive file.\
"""
......@@ -26,11 +26,11 @@ class ExitCommand(Command):
"""
def __init__(self, p_args, p_todolist, p_output, p_error, p_input):
super(ExitCommand, self).__init__(p_args, p_todolist, p_output, p_error,
super().__init__(p_args, p_todolist, p_output, p_error,
p_input)
def execute(self):
if not super(ExitCommand, self).execute():
if not super().execute():
return False
sys.exit(0)
......@@ -20,6 +20,7 @@ from topydo.lib.Filter import InstanceFilter
from topydo.lib.printers.PrettyPrinter import pretty_printer_factory
from topydo.lib.prettyprinters.Format import PrettyPrinterFormatFilter
from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.Utils import get_terminal_size
class ListCommand(ExpressionCommand):
......@@ -27,7 +28,7 @@ class ListCommand(ExpressionCommand):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(ListCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.printer = None
......@@ -50,7 +51,7 @@ class ListCommand(ExpressionCommand):
return True
def _process_flags(self):
opts, args = self.getopt('f:F:i:n:s:x')
opts, args = self.getopt('f:F:i:n:Ns:x')
for opt, value in opts:
if opt == '-x':
......@@ -65,22 +66,26 @@ class ListCommand(ExpressionCommand):
if self._poke_icalendar():
from topydo.lib.printers.Ical import IcalPrinter
self.printer = IcalPrinter(self.todolist)
# a graph without dependencies is not so useful, hence
# show all
self.show_all = True
elif value == 'dot':
from topydo.lib.printers.Dot import DotPrinter
self.printer = DotPrinter(self.todolist)
# a graph without dependencies is not so useful, hence
# show all
self.show_all = True
else:
self.printer = None
elif opt == '-F':
self.format = value
elif opt == '-N':
# 2 lines are assumed to be taken up by printing the next prompt
# display at least one item
self.limit = max(get_terminal_size().lines - 2, 1)
elif opt == '-n':
try:
self.limit = int(value)
except ValueError:
pass # use default value in configuration
pass # use default value in configuration
elif opt == '-i':
self.ids = value.split(',')
......@@ -94,7 +99,7 @@ class ListCommand(ExpressionCommand):
Additional filters to select particular todo items given with the -i
flag.
"""
filters = super(ListCommand, self)._filters()
filters = super()._filters()
if self.ids:
def get_todo(p_id):
......@@ -124,7 +129,6 @@ class ListCommand(ExpressionCommand):
# create a standard printer with some filters
indent = config().list_indent()
final_format = ' ' * indent + self.format
hidden_tags = config().hidden_tags()
filters = []
filters.append(PrettyPrinterFormatFilter(self.todolist, final_format))
......@@ -134,7 +138,7 @@ class ListCommand(ExpressionCommand):
self.out(self.printer.print_list(self._view().todos))
def execute(self):
if not super(ListCommand, self).execute():
if not super().execute():
return False
try:
......@@ -148,20 +152,21 @@ class ListCommand(ExpressionCommand):
return True
def usage(self):
return """Synopsis: ls [-x] [-s <sort_expression>] [-f <output format>]
[-F <format string>] [expression]"""
return """Synopsis: ls [-x] [-s <SORT EXPRESSION>] [-f <OUTPUT FORMAT>]
[-F <FORMAT STRING>] [-i <NUMBER 1>[,<NUMBER 2> ...]] [-N | -n <INTEGER>]
[EXPRESSION]"""
def help(self):
return """\
Lists all relevant todos. A todo is relevant when:
* has not been completed yet;
* the start date (if present) has passed;
* has not been completed yet,
* the start date (if present) has passed, and
* there are no subitems that need to be completed.
When an expression is given, only the todos matching that expression are shown.
When an EXPRESSION is given, only the todos matching that EXPRESSION are shown.
-f : Specify the output format, being 'text' (default), 'dot' or 'ical' or
-f : Specify the OUTPUT format, being 'text' (default), 'dot' or 'ical' or
'json'.
* 'text' - Text output with colors and indentation if applicable.
......@@ -172,6 +177,7 @@ When an expression is given, only the todos matching that expression are shown.
an 'ical' tag with a unique ID. Completed todo items may be
archived.
* 'json' - Javascript Object Notation (JSON)
-F : Specify the format of the text ('text' format), which may contain
placeholders that may be expanded if the todo has such attribute. If such
attribute does not exist, then it expands to an empty string.
......@@ -187,6 +193,7 @@ When an expression is given, only the todos matching that expression are shown.
%k: List of tags separated by spaces (excluding hidden tags).
%K: List of all tags separated by spaces.
%p: Priority.
%P: Priority or placeholder space if no priority.
%s: Todo text.
%S: Todo text, truncated such that an item fits on one line.
%t: Absolute creation date.
......@@ -198,12 +205,14 @@ When an expression is given, only the todos matching that expression are shown.
Conditional characters can be added with blocks surrounded by curly
braces, they will only appear when a placeholder expanded to a value.
E.g. %{(}p{)} will print (C) when the todo item has priority C, or ''
E.g. %{(}p{)} will print '(C)' when the todo item has priority C, or ''
(empty string) when an item has no priority set.
A tab character serves as a marker to start right alignment.
-i : Comma separated list of todo IDs to print.
-s : Sort the list according to a sort expression. Defaults to the expression
-n : Number of items to display. Defaults to the value in the configuration.
-N : Limit number of items displayed such that they fit on the terminal.
-s : Sort the list according to a SORT EXPRESSION. Defaults to the expression
in the configuration.
-x : Show all todos (i.e. do not filter on dependencies or relevance).
-x : Show all todos (i.e. do not filter on dependencies or relevance).\
"""
......@@ -22,11 +22,11 @@ class ListContextCommand(Command):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(ListContextCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
def execute(self):
if not super(ListContextCommand, self).execute():
if not super().execute():
return False
for context in sorted(self.todolist.contexts(), key=lambda s: s.lower()):
......
......@@ -22,11 +22,11 @@ class ListProjectCommand(Command):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(ListProjectCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
def execute(self):
if not super(ListProjectCommand, self).execute():
if not super().execute():
return False
for project in sorted(self.todolist.projects(), key=lambda s: s.lower()):
......
......@@ -28,7 +28,7 @@ class PostponeCommand(MultiCommand):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(PostponeCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.move_start_date = False
......@@ -69,7 +69,7 @@ class PostponeCommand(MultiCommand):
# pylint: disable=E1103
todo.set_tag(config().tag_due(), new_due.isoformat())
self.todolist.set_dirty()
self.todolist.dirty = True
self.out(self.printer.print_todo(todo))
else:
self.error("Invalid date pattern given.")
......@@ -77,23 +77,23 @@ class PostponeCommand(MultiCommand):
def usage(self):
return """\
Synopsis: postpone [-s] <NUMBER> [<NUMBER2> ...] <PATTERN>"
postpone [-x] -e <EXPRESSION>
Synopsis: postpone [-s] <NUMBER> [<NUMBER2> ...] <PATTERN>
postpone [-x] -e <EXPRESSION>\
"""
def help(self):
return """\
Postpone the todo item(s) with the given number(s) and the given pattern.
Postpone the todo item(s) with the given NUMBER(s) and the given PATTERN.
Postponing is done by adjusting the due date(s) of the todo(s), and if the -s
flag is given, the start date accordingly.
It is also possible to postpone items as complete with an expression using
the -e flag. Use -x to also process todo items that are normally invisible
(with the 'ls' subcommand).
It is also possible to postpone items as complete with an EXPRESSION using
the -e flag. Use -x to also process todo items that are normally invisible (as
with the 'ls' subcommand).
The pattern is a relative date, written in the format <COUNT><PERIOD> where
count is a number and <PERIOD> is either 'd', 'w', 'm' or 'y', which stands for
days, weeks, months and years respectively. Example: 'postpone 1 1w' postpones
todo number 1 for 1 week.
The PATTERN is a relative date, written in the format <COUNT> <PERIOD> where
COUNT is a number and PERIOD is either 'd', 'w', 'm' or 'y', which stands for
days, weeks, months and years respectively. Example: 'postpone 1 2w' postpones
todo number 1 for 2 weeks.\
"""
......@@ -22,18 +22,18 @@ from topydo.lib.Utils import is_valid_priority
class PriorityCommand(MultiCommand):
def __init__(self, p_args, p_todolist, #pragma: no branch
def __init__(self, p_args, p_todolist, # pragma: no branch
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(PriorityCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.last_argument = True
def _execute_multi_specific(self):
def normalize_priority(p_priority):
match = re.search(r'\b([A-Z])\b', p_priority)
match = re.search(r'\b([A-Z])\b', p_priority.upper())
return match.group(1) if match else p_priority
priority = normalize_priority(self.args[-1])
......@@ -56,15 +56,15 @@ class PriorityCommand(MultiCommand):
def usage(self):
return """\
Synopsis: pri <NUMBER1> [<NUMBER2> ...] <PRIORITY>
pri [-x] -e <EXPRESSION>
Synopsis: pri <NUMBER 1> [<NUMBER 2> ...] <PRIORITY>
pri [-x] -e <EXPRESSION>\
"""
def help(self):
return """\
Sets the priority of todo(s) the given number(s) to the given priority.
Sets the priority of todo(s) the given NUMBER(s) to the given PRIORITY.
It is also possible to prioritize items as complete with an expression using
the -e flag. Use -x to also process todo items that are normally invisible
(with the 'ls' subcommand).
It is also possible to prioritize items with an EXPRESSION using the -e flag.
Use -x to also process todo items that are normally invisible (as with the 'ls'
subcommand).\
"""
......@@ -25,11 +25,11 @@ class RevertCommand(Command):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(RevertCommand, self).__init__(p_args, p_todolist, p_out, p_err,
super().__init__(p_args, p_todolist, p_out, p_err,
p_prompt)
def execute(self):
if not super(RevertCommand, self).execute():
if not super().execute():
return False
archive_file = TodoFile.TodoFile(config().archive())
......@@ -54,6 +54,4 @@ class RevertCommand(Command):
return """Synopsis: revert"""
def help(self):
return """\
Reverts the last command.
"""
return """Reverts the last command."""
......@@ -24,11 +24,11 @@ class SortCommand(Command):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(SortCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
def execute(self):
if not super(SortCommand, self).execute():
if not super().execute():
return False
try:
......@@ -42,14 +42,14 @@ class SortCommand(Command):
self.todolist.replace(sorted_todos)
def usage(self):
return """Synopsis: sort [expression]"""
return """Synopsis: sort [<EXPRESSION>]"""
def help(self):
return """\
Sorts the file according to the expression. If no expression is given, the
Sorts the todo file according to the EXPRESSION. If no EXPRESSION is given, the
expression in the configuration is used.
The expression is a comma separated list of attributes to sort on. The list is
The EXPRESSION is a comma separated list of attributes to sort on. The list is
evaluated in order, which means that the first attribute takes higher
precedence, then the second, etc.
......@@ -61,12 +61,12 @@ The following sort attributes are supported:
* importance - Sort by importance
* importance-avg - Sort by average importance (based on parent items)
* text - Sort by text
* <tag> - Sort by values of the given tag
* <TAG> - Sort by values of the given TAG
Each item can optionally be prefixed with asc: and desc: to specify ascending
or descending sort respectively. If not specified, ascending sort is assumed.
Example:
desc:importance,due,desc:priority
desc:importance,due,desc:priority\
"""
......@@ -26,7 +26,7 @@ class TagCommand(Command):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(TagCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.force = False
......@@ -106,10 +106,10 @@ class TagCommand(Command):
self.todo.set_tag(self.tag, self.value, self.force_add, p_old_value)
if old_src != self.todo.source():
self.todolist.set_dirty()
self.todolist.dirty = True
def _set(self):
if len(self.current_values) > 1:
if len(self.current_values) > 1 and not self.force_add:
answer = self._choose()
if answer == "all":
......@@ -124,7 +124,7 @@ class TagCommand(Command):
self._print()
def execute(self):
if not super(TagCommand, self).execute():
if not super().execute():
return False
self._process_args()
......@@ -133,15 +133,15 @@ class TagCommand(Command):
self._set()
def usage(self):
return """Synopsis: tag [-a] [-f] <NUMBER> <tag> [<value>]"""
return """Synopsis: tag [-a] [-f] <NUMBER> <TAG> [<VALUE>]"""
def help(self):
return """\
Sets the given tag to the given todo number with the given value. If the value
is omitted, the tag is removed from the todo item.
Sets the given TAG on the given todo NUMBER with the given VALUE. If the VALUE
is omitted, the TAG is removed from the todo item.
-a : Do not change the current value of the tag if it exists, but add a new
value.
-f : Force setting/removing all values of the tag. Prevents interaction with
the user.
-a : Do not change the current value of the TAG if it exists, but add a new
VALUE for the given TAG.
-f : Force setting/removing all values of the TAG. Prevents interaction with
the user.\
"""
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2016 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/>.
""" This module provides a class that represents a color. """
class AbstractColor:
NEUTRAL = 0
PROJECT = 1
CONTEXT = 2
META = 3
LINK = 4
class Color:
color_names_dict = {
'black': 0,
'red': 1,
'green': 2,
'yellow': 3,
'blue': 4,
'magenta': 5,
'cyan': 6,
'gray': 7,
'darkgray': 8,
'light-red': 9,
'light-green': 10,
'light-yellow': 11,
'light-blue': 12,
'light-magenta': 13,
'light-cyan': 14,
'white': 15,
}
# Source: https://gist.github.com/jasonm23/2868981
html_color_dict = {
0: "#000000", 1: "#800000", 2: "#008000", 3: "#808000", 4: "#000080",
5: "#800080", 6: "#008080", 7: "#c0c0c0", 8: "#808080", 9: "#ff0000",
10: "#00ff00", 11: "#ffff00", 12: "#0000ff", 13: "#ff00ff", 14: "#00ffff",
15: "#ffffff", 16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af",
20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f", 24: "#005f87",
25: "#005faf", 26: "#005fd7", 27: "#005fff", 28: "#008700", 29: "#00875f",
30: "#008787", 31: "#0087af", 32: "#0087d7", 33: "#0087ff", 34: "#00af00",
35: "#00af5f", 36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff",
40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af", 44: "#00d7d7",
45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f", 48: "#00ff87", 49: "#00ffaf",
50: "#00ffd7", 51: "#00ffff", 52: "#5f0000", 53: "#5f005f", 54: "#5f0087",
55: "#5f00af", 56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f",
60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff", 64: "#5f8700",
65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7", 69: "#5f87ff",
70: "#5faf00", 71: "#5faf5f", 72: "#5faf87", 73: "#5fafaf", 74: "#5fafd7",
75: "#5fafff", 76: "#5fd700", 77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af",
80: "#5fd7d7", 81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87",
85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000", 89: "#87005f",
90: "#870087", 91: "#8700af", 92: "#8700d7", 93: "#8700ff", 94: "#875f00",
95: "#875f5f", 96: "#875f87", 97: "#875faf", 98: "#875fd7", 99: "#875fff",
100: "#878700", 101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7",
105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87", 109: "#87afaf",
110: "#87afd7", 111: "#87afff", 112: "#87d700", 113: "#87d75f", 114: "#87d787",
115: "#87d7af", 116: "#87d7d7", 117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f",
120: "#87ff87", 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000",
125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7", 129: "#af00ff",
130: "#af5f00", 131: "#af5f5f", 132: "#af5f87", 133: "#af5faf", 134: "#af5fd7",
135: "#af5fff", 136: "#af8700", 137: "#af875f", 138: "#af8787", 139: "#af87af",
140: "#af87d7", 141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87",
145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700", 149: "#afd75f",
150: "#afd787", 151: "#afd7af", 152: "#afd7d7", 153: "#afd7ff", 154: "#afff00",
155: "#afff5f", 156: "#afff87", 157: "#afffaf", 158: "#afffd7", 159: "#afffff",
160: "#d70000", 161: "#d7005f", 162: "#d70087", 163: "#d700af", 164: "#d700d7",
165: "#d700ff", 166: "#d75f00", 167: "#d75f5f", 168: "#d75f87", 169: "#d75faf",
170: "#d75fd7", 171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787",
175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#dfaf00", 179: "#dfaf5f",
180: "#dfaf87", 181: "#dfafaf", 182: "#dfafdf", 183: "#dfafff", 184: "#dfdf00",
185: "#dfdf5f", 186: "#dfdf87", 187: "#dfdfaf", 188: "#dfdfdf", 189: "#dfdfff",
190: "#dfff00", 191: "#dfff5f", 192: "#dfff87", 193: "#dfffaf", 194: "#dfffdf",
195: "#dfffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087", 199: "#ff00af",
200: "#ff00df", 201: "#ff00ff", 202: "#ff5f00", 203: "#ff5f5f", 204: "#ff5f87",
205: "#ff5faf", 206: "#ff5fdf", 207: "#ff5fff", 208: "#ff8700", 209: "#ff875f",
210: "#ff8787", 211: "#ff87af", 212: "#ff87df", 213: "#ff87ff", 214: "#ffaf00",
215: "#ffaf5f", 216: "#ffaf87", 217: "#ffafaf", 218: "#ffafdf", 219: "#ffafff",
220: "#ffdf00", 221: "#ffdf5f", 222: "#ffdf87", 223: "#ffdfaf", 224: "#ffdfdf",
225: "#ffdfff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87", 229: "#ffffaf",
230: "#ffffdf", 231: "#ffffff", 232: "#080808", 233: "#121212", 234: "#1c1c1c",
235: "#262626", 236: "#303030", 237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e",
240: "#585858", 241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080",
245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8", 249: "#b2b2b2",
250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0", 253: "#dadada", 254: "#e4e4e4",
255: "#eeeeee",
}
def __init__(self, p_value=None):
""" p_value is user input, be it a word color or an xterm code """
self._value = None
self.color = p_value
@property
def color(self):
return self._value
@color.setter
def color(self, p_value):
try:
if not p_value:
self._value = None
elif p_value in Color.color_names_dict:
self._value = Color.color_names_dict[p_value]
else:
self._value = int(p_value)
# values not in the 256 range are normalized to be neutral
if not 0 <= self._value < 256:
raise ValueError
except ValueError:
# garbage was entered, make it neutral, so at least some
# highlighting may take place
self._value = -1
def is_neutral(self):
"""
A neutral color is the default color on the shell, setting this color
will reset all other attributes (background, foreground, decoration).
"""
return self._value == -1
def is_valid(self):
"""
Whether the color is a valid color.
"""
return self._value is not None
def as_ansi(self, p_decoration='normal', p_background=False):
if not self.is_valid():
return ''
elif self.is_neutral():
return '\033[0m'
is_high_color = 8 <= self._value < 16
is_256 = 16 <= self._value < 255
decoration_dict = {
'normal': '0',
'bold': '1',
'faint': '2',
'italic': '3',
'underline': '4',
}
decoration = decoration_dict[p_decoration]
base = 40 if p_background else 30
if is_high_color:
color = '1;{}'.format(base + self._value - 8)
elif is_256:
color = '{};5;{}'.format(base + 8, self._value)
else:
# it's a low color
color = str(base + self._value)
return '\033[{};{}m'.format(
decoration,
color
)
def as_html(self):
try:
return Color.html_color_dict[self.color]
except KeyError:
return '#ffffff'
# 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/>.
""" This module serves for managing output colors. """
from topydo.lib.Config import config
NEUTRAL_COLOR = '\033[0m'
def int_to_ansi(p_int, p_decorator='normal', p_safe=True, p_background=''):
"""
Returns ansi code for color based on xterm color id (0-255) and
decoration, where decoration can be one of: normal, bold, faint,
italic, or underline. When p_safe is True, resulting ansi code is
constructed in most compatible way, but with support for only base 16
colors.
"""
decoration_dict = {
'normal': '0',
'bold': '1',
'faint': '2',
'italic': '3',
'underline': '4'
}
decoration = decoration_dict[p_decorator]
try:
if p_safe:
if p_background:
p_background = ';4{}'.format(p_background)
if 8 > int(p_int) >= 0:
return '\033[{};3{}{}m'.format(decoration, str(p_int), p_background)
elif 16 > int(p_int):
p_int = int(p_int) - 8
return '\033[{};1;3{}{}m'.format(decoration, str(p_int), p_background)
if 256 > int(p_int) >= 0:
if p_background:
p_background = ';48;5;{}'.format(str(p_int))
return '\033[{};38;5;{}{}m'.format(decoration, str(p_int), p_background)
else:
return NEUTRAL_COLOR
except ValueError:
return None
def _name_to_int(p_color_name):
""" Returns xterm color id from color name. """
color_names_dict = {
'black': 0,
'red': 1,
'green': 2,
'yellow': 3,
'blue': 4,
'magenta': 5,
'cyan': 6,
'gray': 7,
'darkgray': 8,
'light-red': 9,
'light-green': 10,
'light-yellow': 11,
'light-blue': 12,
'light-magenta': 13,
'light-cyan': 14,
'white': 15,
}
try:
return color_names_dict[p_color_name]
except KeyError:
return 404
def _name_to_ansi(p_color_name, p_decorator):
""" Returns ansi color code from color name. """
number = _name_to_int(p_color_name)
return int_to_ansi(number, p_decorator)
def _get_ansi(p_color, p_decorator):
""" Returns ansi color code from color name or xterm color id. """
if p_color == '':
ansi = ''
else:
ansi = int_to_ansi(p_color, p_decorator, False)
if not ansi:
ansi = _name_to_ansi(p_color, p_decorator)
return ansi
def _get_priority_colors():
pri_ansi_colors = dict()
pri_colors = config().priority_colors()
for pri in pri_colors:
color = _get_ansi(pri_colors[pri], 'normal')
if color == '':
color = NEUTRAL_COLOR
pri_ansi_colors[pri] = color
return pri_ansi_colors
class Colors(object):
def __init__(self):
self.priority_colors = _get_priority_colors()
self.project_color = config().project_color()
self.context_color = config().context_color()
self.metadata_color = config().metadata_color()
self.link_color = config().link_color()
def get_project_color(self):
return _get_ansi(self.project_color, 'bold')
def get_context_color(self):
return _get_ansi(self.context_color, 'bold')
def get_metadata_color(self):
return _get_ansi(self.metadata_color, 'bold')
def get_link_color(self):
return _get_ansi(self.link_color, 'underline')
def get_priority_color(self, p_priority):
try:
priority_color = self.priority_colors[p_priority]
except KeyError:
priority_color = NEUTRAL_COLOR
return priority_color
......@@ -71,8 +71,8 @@ class Command(object):
""" Retrieves a value from the argument list at the given position. """
try:
return self.args[p_number]
except IndexError:
raise InvalidCommandArgument
except IndexError as ie:
raise InvalidCommandArgument from ie
def getopt(self, p_flags, p_long=None):
p_long = p_long or []
......
This diff is collapsed.
......@@ -31,7 +31,7 @@ class DCommand(MultiCommand):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(DCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.force = False
......
......@@ -32,7 +32,7 @@ class ExpressionCommand(Command):
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(ExpressionCommand, self).__init__(
super().__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.sort_expression = config().sort_string()
......@@ -45,38 +45,12 @@ class ExpressionCommand(Command):
def _filters(self):
filters = []
def arg_filters():
result = []
if self.last_argument:
args = self.args[:-1]
else:
args = self.args
for arg in args:
# when a word starts with -, it should be negated
is_negated = len(arg) > 1 and arg[0] == '-'
arg = arg[1:] if is_negated else arg
if re.match(Filter.ORDINAL_TAG_MATCH, arg):
argfilter = Filter.OrdinalTagFilter(arg)
elif re.match(Filter.PRIORITY_MATCH, arg):
argfilter = Filter.PriorityFilter(arg)
else:
argfilter = Filter.GrepFilter(arg)
if is_negated:
argfilter = Filter.NegationFilter(argfilter)
result.append(argfilter)
return result
if not self.show_all:
filters.append(Filter.DependencyFilter(self.todolist))
filters.append(Filter.RelevanceFilter())
filters += arg_filters()
args = self.args[:-1] if self.last_argument else self.args
filters += Filter.get_filter_list(args)
if not self.show_all:
filters.append(Filter.LimitFilter(self.limit))
......
This diff is collapsed.
......@@ -83,12 +83,14 @@ def average_importance(p_todo, p_ignore_weekend=config().ignore_weekends()):
average = 0
parents = []
if 'parents' in p_todo.attributes:
try:
sum_importance = own_importance
parents = p_todo.attributes['parents']
parents = p_todo.parents()
for parent in parents:
sum_importance += importance(parent, p_ignore_weekend)
average = float(sum_importance) / float(1 + len(parents))
except AttributeError:
pass
return max(own_importance, average)
This diff is collapsed.
This diff is collapsed.
......@@ -29,4 +29,3 @@ class PrettyPrinterFilter(object):
Applies a filter to p_todo_str and returns a modified version of it.
"""
raise NotImplementedError
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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