Repository: pimutils/todoman
Pull request #196 (2017-03-19 18:29:51)

Fix crash when running "todo new"
Fixes  #195


Patch:
diff --git a/todoman/cli.py b/todoman/cli.py
index e54f968..6bf5c7e 100644
--- a/todoman/cli.py
+++ b/todoman/cli.py
@@ -241,7 +241,7 @@ def new(ctx, summary, list, todo_properties, interactive):
     Create a new task with SUMMARY.
     '''
 
-    todo = Todo(new=True)
+    todo = Todo(new=True, list=list)
 
     default_due = ctx.config['main']['default_due']
     if default_due:
@@ -261,8 +261,7 @@ def new(ctx, summary, list, todo_properties, interactive):
     if not todo.summary:
         raise click.UsageError('No SUMMARY specified')
 
-    todo.list = list
-    ctx.db.save(todo, list)
+    ctx.db.save(todo)
     click.echo(ctx.formatter.detailed(todo))
 
 
diff --git a/todoman/interactive.py b/todoman/interactive.py
index 84650c1..f5808c5 100644
--- a/todoman/interactive.py
+++ b/todoman/interactive.py
@@ -88,7 +88,7 @@ class TodoEditor:
             urwid.RadioButton(
                 list_selector,
                 _list.name,
-                state=_list.name == self.current_list.name,
+                state=_list == self.current_list,
                 on_state_change=self._change_current_list,
                 user_data=_list,
             )
diff --git a/todoman/model.py b/todoman/model.py
index 078429f..a4e6a7d 100644
--- a/todoman/model.py
+++ b/todoman/model.py
@@ -76,7 +76,7 @@ class Todo:
     the local system's one.
     """
 
-    def __init__(self, filename=None, mtime=None, new=False):
+    def __init__(self, filename=None, mtime=None, new=False, list=None):
         """
         Creates a new todo using `todo` as a source.
 
@@ -87,7 +87,7 @@ class Todo:
         :param bool new: Indicate that a new Todo is being created and should
         be populated with default values.
         """
-
+        self.list = list
         now = datetime.now(LOCAL_TIMEZONE)
         self.uid = '{}@{}'.format(uuid4().hex, socket.gethostname())
 
@@ -761,6 +761,11 @@ class List:
         if rv:
             return '\33[38;2;{!s};{!s};{!s}m'.format(*rv)
 
+    def __eq__(self, other):
+        if isinstance(other, List):
+            return self.name == other.name
+        return object.__eq__(self, other)
+
     def __str__(self):
         return self.name
 
@@ -850,7 +855,8 @@ class Database:
         self.cache.clear()
         self.cache = None
 
-    def save(self, todo, list_):
+    def save(self, todo, list_=None):
+        list_ = list_ or todo.list
         vtodo = todo.save(list_)
         path = os.path.join(list_.path, todo.filename)
         self.cache.expire_file(path)


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 1151e0f..071014f 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -1,5 +1,6 @@
 import datetime
 from os.path import isdir
+from unittest.mock import patch
 
 import hypothesis.strategies as st
 import pytest
@@ -534,3 +535,16 @@ def test_multiple_todos_in_file(runner, create):
     assert not result.exception
     result = runner.invoke(cli, ['show', '2'])
     assert not result.exception
+
+
+def test_todo_new(runner, default_database):
+    # This isn't a very thurough test, but at least catches obvious regressions
+    # like startup crashes or typos.
+
+    with patch('urwid.MainLoop'):
+        result = runner.invoke(cli, ['new', '-l', 'default'])
+
+    # Unsaved exit
+    assert isinstance(result.exception, SystemExit)
+    assert result.exception.args == (1,)
+    assert result.output == ''
diff --git a/tests/test_model.py b/tests/test_model.py
index 75e4ee0..477474b 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -238,3 +238,13 @@ def test_todo_filename_absolute_path():
     Todo(filename='test.ics')
     with pytest.raises(ValueError):
         Todo(filename='/test.ics')
+
+
+def test_list_equality(tmpdir):
+    list1 = List(path=str(tmpdir), name='test list')
+    list2 = List(path=str(tmpdir), name='test list')
+    list3 = List(path=str(tmpdir), name='yet another test list')
+
+    assert list1 == list2
+    assert list1 != list3
+    assert list1 != 'test list'