def testFullRendering(self): dbutils.getOrCreateProject("x", interactive=False) dbutils.getOrCreateKeyword("k1", interactive=False) dbutils.getOrCreateKeyword("k2", interactive=False) t1 = dbutils.addTask("x", "t1", {}) t2 = dbutils.addTask("x", "t2", {"k1": None, "k2": 12}) longTask = dbutils.addTask("x", "A longer task name", {}) longTask.description = "And it has a description" out = StringIO() renderer = TextListRenderer(out, termWidth=80, cryptoMgr=YokadiCryptoManager()) renderer.addTaskList("Foo", [t2, longTask]) self.assertEqual(renderer.maxTitleWidth, len(longTask.title) + 1) renderer.end() out = stripColor(out.getvalue()) expected = \ " Foo \n" \ + "ID│Title │U │S│Age │Due date\n" \ + "──┼───────────────────┼───┼─┼────────┼────────\n" \ + "2 │t2 (k1, k2) │0 │N│0m │ \n" \ + "3 │A longer task name*│0 │N│0m │ \n" self.assertMultiLineEqual(out, expected)
def testTitleFormater(self): dbutils.getOrCreateProject("x", interactive=False) dbutils.getOrCreateKeyword("key1", interactive=False) dbutils.getOrCreateKeyword("key2", interactive=False) task = dbutils.addTask("x", "t1", {}) taskWithKeywords = dbutils.addTask("x", "t2", { "key1": None, "key2": 12 }) longTask = dbutils.addTask("x", "01234567890123456789", {}) longTask.description = "And it has a description" TEST_DATA = ( (task, 20, "t1"), (taskWithKeywords, 20, "t2 (key1, key2)"), (taskWithKeywords, 4, "t2 >"), (longTask, 10, longTask.title[:8] + ">*"), (longTask, len(longTask.title), longTask.title[:-2] + ">*"), (longTask, len(longTask.title) + 1, longTask.title + "*"), (longTask, 40, longTask.title.ljust(39) + "*"), ) for task, width, expected in TEST_DATA: with self.subTest(task=task, width=width): formater = TitleFormater(width, StubCryptoMgr()) out = formater(task)[0] out = stripColor(out) expected = expected.ljust(width) self.assertEqual(out, expected)
def testTitleFormater(self): dbutils.getOrCreateProject("x", interactive=False) dbutils.getOrCreateKeyword("key1", interactive=False) dbutils.getOrCreateKeyword("key2", interactive=False) task = dbutils.addTask("x", "t1", {}) taskWithKeywords = dbutils.addTask("x", "t2", {"key1": None, "key2": 12}) longTask = dbutils.addTask("x", "01234567890123456789", {}) longTask.description = "And it has a description" TEST_DATA = ( (task, 20, "t1"), (taskWithKeywords, 20, "t2 (key1, key2)"), (taskWithKeywords, 4, "t2 >"), (longTask, 10, longTask.title[:8] + ">*"), (longTask, len(longTask.title), longTask.title[:-2] + ">*"), (longTask, len(longTask.title) + 1, longTask.title + "*"), (longTask, 40, longTask.title.ljust(39) + "*"), ) for task, width, expected in TEST_DATA: with self.subTest(task=task, width=width): formater = TitleFormater(width) out = formater(task)[0] out = stripColor(out) expected = expected.ljust(width) self.assertEqual(out, expected)
def testGetOrCreateProject(self): # interactive tui.addInputAnswers("y") dbutils.getOrCreateProject("p1") self.session.query(Project).filter_by(name="p1").one() # !interactive dbutils.getOrCreateProject("p2", interactive=False) self.session.query(Project).filter_by(name="p2").one()
def testGetOrCreateProject(self): # interactive tui.addInputAnswers("y") dbutils.getOrCreateProject("p1") self._assertOneObject(Project.selectBy(name="p1")) # !interactive dbutils.getOrCreateProject("p2", interactive=False) self._assertOneObject(Project.selectBy(name="p2"))
def testTitleFormater(self): dbutils.getOrCreateProject("x", interactive=False) dbutils.getOrCreateKeyword("k1", interactive=False) dbutils.getOrCreateKeyword("k2", interactive=False) t1 = dbutils.addTask("x", "t1", {}) t2 = dbutils.addTask("x", "t2", {"k1": None, "k2": 12}) longerTask = dbutils.addTask("x", "A longer task name", {}) longerTask.description = "And it has a description" out = StringIO() renderer = TextListRenderer(out, termWidth=80, cryptoMgr=YokadiCryptoManager()) renderer.addTaskList("Foo", [t1]) self.assertEquals(renderer.maxTitleWidth, 5) renderer.end() expected = unicode(\ "%(CYAN)s Foo %(RESET)s\n" \ + "%(BOLD)sID|Title|U |S|Age |Due date%(RESET)s\n" \ + "--------------------------------\n" \ + "1 |t1 %(RESET)s|0 |N|0m | \n" \ ) % dict(CYAN=C.CYAN, RESET=C.RESET, BOLD=C.BOLD) testutils.multiLinesAssertEqual(self, out.getvalue(), expected) out = StringIO() renderer = TextListRenderer(out, termWidth=80, cryptoMgr=YokadiCryptoManager()) renderer.addTaskList("Foo", [t1, t2]) self.assertEquals(renderer.maxTitleWidth, 11) renderer.end() expected = unicode(\ "%(CYAN)s Foo %(RESET)s\n" \ + "%(BOLD)sID|Title |U |S|Age |Due date%(RESET)s\n" \ + "--------------------------------------\n" \ + "1 |t1 %(RESET)s|0 |N|0m | \n" \ + "2 |t2 (%(BOLD)sk1, k2)%(RESET)s|0 |N|0m | \n" \ ) % dict(CYAN=C.CYAN, RESET=C.RESET, BOLD=C.BOLD) testutils.multiLinesAssertEqual(self, out.getvalue(), expected) out = StringIO() renderer = TextListRenderer(out, termWidth=80, cryptoMgr=YokadiCryptoManager()) renderer.addTaskList("Foo", [t2, longerTask]) self.assertEquals(renderer.maxTitleWidth, len(longerTask.title) + 1) renderer.end() expected = unicode(\ "%(CYAN)s Foo %(RESET)s\n" \ + "%(BOLD)sID|Title |U |S|Age |Due date%(RESET)s\n" \ + "----------------------------------------------\n" \ + "2 |t2 (%(BOLD)sk1, k2) %(RESET)s|0 |N|0m | \n" \ + "3 |A longer task name%(RESET)s*|0 |N|0m | \n" \ ) % dict(CYAN=C.CYAN, RESET=C.RESET, BOLD=C.BOLD) testutils.multiLinesAssertEqual(self, out.getvalue(), expected)
def testTitleFormater(self): dbutils.getOrCreateProject("x", interactive=False) dbutils.getOrCreateKeyword("k1", interactive=False) dbutils.getOrCreateKeyword("k2", interactive=False) t1 = dbutils.addTask("x", "t1", {}) t2 = dbutils.addTask("x", "t2", {"k1": None, "k2": 12}) longerTask = dbutils.addTask("x", "A longer task name", {}) longerTask.description = "And it has a description" out = StringIO() renderer = TextListRenderer(out, termWidth=80, cryptoMgr=YokadiCryptoManager()) renderer.addTaskList("Foo", [t1]) self.assertEqual(renderer.maxTitleWidth, 5) renderer.end() expected = str(\ "%(CYAN)s Foo %(RESET)s\n" \ + "%(BOLD)sID|Title|U |S|Age |Due date%(RESET)s\n" \ + "--------------------------------\n" \ + "1 |t1 %(RESET)s|0 |N|0m | \n" \ ) % dict(CYAN=C.CYAN, RESET=C.RESET, BOLD=C.BOLD) testutils.multiLinesAssertEqual(self, out.getvalue(), expected) out = StringIO() renderer = TextListRenderer(out, termWidth=80, cryptoMgr=YokadiCryptoManager()) renderer.addTaskList("Foo", [t1, t2]) self.assertEqual(renderer.maxTitleWidth, 11) renderer.end() expected = str(\ "%(CYAN)s Foo %(RESET)s\n" \ + "%(BOLD)sID|Title |U |S|Age |Due date%(RESET)s\n" \ + "--------------------------------------\n" \ + "1 |t1 %(RESET)s|0 |N|0m | \n" \ + "2 |t2 (%(BOLD)sk1, k2)%(RESET)s|0 |N|0m | \n" \ ) % dict(CYAN=C.CYAN, RESET=C.RESET, BOLD=C.BOLD) testutils.multiLinesAssertEqual(self, out.getvalue(), expected) out = StringIO() renderer = TextListRenderer(out, termWidth=80, cryptoMgr=YokadiCryptoManager()) renderer.addTaskList("Foo", [t2, longerTask]) self.assertEqual(renderer.maxTitleWidth, len(longerTask.title) + 1) renderer.end() expected = str(\ "%(CYAN)s Foo %(RESET)s\n" \ + "%(BOLD)sID|Title |U |S|Age |Due date%(RESET)s\n" \ + "----------------------------------------------\n" \ + "2 |t2 (%(BOLD)sk1, k2) %(RESET)s|0 |N|0m | \n" \ + "3 |A longer task name%(RESET)s*|0 |N|0m | \n" \ ) % dict(CYAN=C.CYAN, RESET=C.RESET, BOLD=C.BOLD) testutils.multiLinesAssertEqual(self, out.getvalue(), expected)
def do_p_edit(self, line): """Edit a project. p_edit <project name>""" session = db.getSession() project = dbutils.getOrCreateProject(line, createIfNeeded=False) if not project: raise YokadiException("Project does not exist.") # Create project line projectLine = parseutils.createLine(project.name, "", project.getKeywordDict()) # Edit line = tui.editLine(projectLine) # Update project projectName, garbage, keywordDict = parseutils.parseLine(line) if garbage: raise BadUsageException("Cannot parse line, got garbage (%s)" % garbage) if not dbutils.createMissingKeywords(list(keywordDict.keys())): return try: project.name = projectName project.setKeywordDict(keywordDict) session.merge(project) session.commit() except IntegrityError: session.rollback() raise YokadiException("A project named %s already exists. Please find another name" % projectName)
def testOnlyListTasks(self): prj = dbutils.getOrCreateProject("p1", interactive=False) t1 = dbutils.addTask("p1", "Task", {}) t2 = dbutils.addTask("p1", "Note", {NOTE_KEYWORD: None}) oldList = massedit.createEntriesForProject(prj) self.assertEqual(len(oldList), 1)
def do_p_edit(self, line): """Edit a project. p_edit <project name>""" project = dbutils.getOrCreateProject(line, createIfNeeded=False) if not project: raise YokadiException("Project does not exist.") # Create project line projectLine = parseutils.createLine(project.name, "", project.getKeywordDict()) # Edit line = tui.editLine(projectLine) # Update project projectName, garbage, keywordDict = parseutils.parseLine(line) if garbage: raise BadUsageException("Cannot parse line, got garbage (%s)" % garbage) if not dbutils.createMissingKeywords(keywordDict.keys()): return try: project.name = projectName except DuplicateEntryError: raise YokadiException( "A project named %s already exists. Please find another name" % projectName) project.setKeywordDict(keywordDict)
def testApplyMEditChangesUnknownIds(self): prj = dbutils.getOrCreateProject("p1", interactive=False) t1 = dbutils.addTask("p1", "Foo", {}) t2 = dbutils.addTask("p1", "Bar", {}) oldList = massedit.createEntriesForProject(prj) newList = [ MEditEntry(t1.id, "new", t1.title, {}), MEditEntry(t2.id + 1, "new", t2.title, {}), ] self.assertRaises(YokadiException, massedit.applyChanges, prj, oldList, newList, interactive=False)
def do_t_project(self, line): """Set task's project. t_project <id> <project>""" tokens = parseutils.simplifySpaces(line).split(" ") if len(tokens) != 2: raise YokadiException("You should give two arguments: <task id> <project>") task = self.getTaskFromId(tokens[0]) projectName = tokens[1] projectName = self._realProjectName(projectName) task.project = dbutils.getOrCreateProject(projectName) if task.project: print "Moved task '%s' to project '%s'" % (task.title, projectName)
def do_t_project(self, line): """Set task's project. t_project <id> <project>""" tokens = parseutils.simplifySpaces(line).split(" ") if len(tokens) != 2: raise YokadiException( "You should give two arguments: <task id> <project>") task = self.getTaskFromId(tokens[0]) projectName = tokens[1] projectName = self._realProjectName(projectName) task.project = dbutils.getOrCreateProject(projectName) if task.project: print "Moved task '%s' to project '%s'" % (task.title, projectName)
def do_t_medit(self, line): """Mass edit tasks of a project. t_medit <project_name> Starts a text editor with the task list, you can then: - edit tasks text and keywords - mark tasks as done or started - add new tasks - adjust urgency - delete tasks """ if not line: raise BadUsageException("Missing parameters") projectName = parseOneWordName(line) projectName = self._realProjectName(projectName) project = dbutils.getOrCreateProject(projectName) if not project: return oldList = massedit.createEntriesForProject(project) oldText = massedit.createMEditText(oldList) newText = oldText while True: newText = tui.editText(newText, suffix=".medit") if newText == oldText: print("No changes") return try: newList = massedit.parseMEditText(newText) except massedit.ParseError as exc: print(exc) print() if tui.confirm("Modify text and try again"): lst = newText.splitlines() lst.insert(exc.lineNumber, "# ^ " + exc.message) newText = "\n".join(lst) continue else: return try: massedit.applyChanges(project, oldList, newList) self.session.commit() break except YokadiException as exc: print(exc) print() if not tui.confirm("Modify text and try again"): return
def do_t_medit(self, line): """Mass edit tasks of a project. t_medit <project_name> Starts a text editor with the task list, you can then: - edit tasks text and keywords - mark tasks as done or started - add new tasks - adjust urgency - delete tasks """ if not line: raise BadUsageException("Missing parameters") projectName = parseutils.parseOneWordName(line) projectName = self._realProjectName(projectName) project = dbutils.getOrCreateProject(projectName) if not project: return oldList = massedit.createEntriesForProject(project) oldText = massedit.createMEditText(oldList) newText = oldText while True: newText = tui.editText(newText, suffix=".medit") if newText == oldText: print("No changes") return try: newList = massedit.parseMEditText(newText) except massedit.ParseError as exc: print(exc) print() if tui.confirm("Modify text and try again"): lst = newText.splitlines() lst.insert(exc.lineNumber, "# ^ " + exc.message) newText = "\n".join(lst) continue else: return try: massedit.applyChanges(project, oldList, newList) self.session.commit() break except YokadiException as exc: print(exc) print() if not tui.confirm("Modify text and try again"): return
def testFullRendering(self): dbutils.getOrCreateProject("x", interactive=False) dbutils.getOrCreateKeyword("k1", interactive=False) dbutils.getOrCreateKeyword("k2", interactive=False) dbutils.addTask("x", "t1", {}) t2 = dbutils.addTask("x", "t2", {"k1": None, "k2": 12}) longTask = dbutils.addTask("x", "A longer task name", {}) longTask.description = "And it has a description" out = StringIO() renderer = TextListRenderer(out, termWidth=80) renderer.addTaskList("Foo", [t2, longTask]) self.assertEqual(renderer.maxTitleWidth, len(longTask.title) + 1) renderer.end() out = stripColor(out.getvalue()) expected = \ " Foo \n" \ "ID│Title │U │S│Age │Due date\n" \ "──┼───────────────────┼───┼─┼────────┼────────\n" \ "2 │t2 (k1, k2) │0 │N│0m │ \n" \ "3 │A longer task name*│0 │N│0m │ \n" self.assertMultiLineEqual(out, expected)
def do_p_edit(self, line): """Edit a project. p_edit <project name>""" session = db.getSession() project = dbutils.getOrCreateProject(line, createIfNeeded=False) if not project: raise YokadiException("Project does not exist.") # Edit line = tui.editLine(project.name) # Update project projectName = parseutils.parseOneWordName(line) try: project.name = projectName session.commit() except IntegrityError: session.rollback() raise YokadiException("A project named %s already exists. Please find another name" % projectName)
def testApplyMEditChanges(self): prj = dbutils.getOrCreateProject("p1", interactive=False) t1 = dbutils.addTask("p1", "Change text", {}) tui.addInputAnswers("y", "y") t2 = dbutils.addTask("p1", "Change keywords", {"k1": None, "k2": 1}) t3 = dbutils.addTask("p1", "Done", {}) t3.status = "started" self.session.merge(t3) t4 = dbutils.addTask("p1", "Deleted", {}) t5 = dbutils.addTask("p1", "Moved", {}) self.session.commit() deletedId = t4.id oldList = massedit.createEntriesForProject(prj) newList = [ MEditEntry(None, "new", u"Added", {}), MEditEntry(t1.id, "new", u"New text", {}), MEditEntry(t2.id, "new", u"Change keywords", { "k2": 2, "k3": None }), MEditEntry(t5.id, "new", u"Moved", {}), MEditEntry(t3.id, "done", u"Done", {}), ] massedit.applyChanges(prj, oldList, newList, interactive=False) self.session.commit() newTask = self.session.query(db.Task).filter_by(title=u"Added").one() self.assertEqual(t1.title, u"New text") self.assertEqual(t2.getKeywordDict(), {"k2": 2, "k3": None}) self.assertEqual(t3.status, "done") self.assertTrue(t3.doneDate) self.assertRaises(YokadiException, dbutils.getTaskFromId, deletedId) self.assertEqual(newTask.urgency, 5) self.assertEqual(t1.urgency, 4) self.assertEqual(t2.urgency, 3) self.assertEqual(t5.urgency, 2) self.assertEqual(t3.urgency, 1)
def testApplyMEditChanges(self): prj = dbutils.getOrCreateProject("p1", interactive=False) t1 = dbutils.addTask("p1", "Change text", {}) tui.addInputAnswers("y", "y") t2 = dbutils.addTask("p1", "Change keywords", {"k1": None, "k2": 1}) t3 = dbutils.addTask("p1", "Done", {}) t3.status = "started" self.session.merge(t3) t4 = dbutils.addTask("p1", "Deleted", {}) t5 = dbutils.addTask("p1", "Moved", {}) self.session.commit() deletedId = t4.id oldList = massedit.createEntriesForProject(prj) newList = [ MEditEntry(None, "new", u"Added", {}), MEditEntry(t1.id, "new", u"New text", {}), MEditEntry(t2.id, "new", u"Change keywords", {"k2": 2, "k3": None}), MEditEntry(t5.id, "new", u"Moved", {}), MEditEntry(t3.id, "done", u"Done", {}), ] massedit.applyChanges(prj, oldList, newList, interactive=False) self.session.commit() newTask = self.session.query(db.Task).filter_by(title=u"Added").one() self.assertEqual(t1.title, u"New text") self.assertEqual(t2.getKeywordDict(), {"k2": 2, "k3": None}) self.assertEqual(t3.status, "done") self.assertTrue(t3.doneDate) self.assertRaises(YokadiException, dbutils.getTaskFromId, deletedId) self.assertEqual(newTask.urgency, 5) self.assertEqual(t1.urgency, 4) self.assertEqual(t2.urgency, 3) self.assertEqual(t5.urgency, 2) self.assertEqual(t3.urgency, 1)