def _parseListLine(self, parser, line): """ Parse line with parser, returns a tuple of the form (options, projectList, filters) """ args = parser.parse_args(line) if len(args.filter) > 0: projectName, keywordFilters = parseutils.extractKeywords(u" ".join( args.filter)) else: projectName = "" keywordFilters = [] if self.kFilters: # Add keyword filter keywordFilters.extend(self.kFilters) if not projectName: if self.pFilter: # If a project filter is defined, use it as none was provided projectName = self.pFilter else: # Take all project if none provided projectName = "%" if projectName.startswith("!"): projectName = self._realProjectName(projectName[1:]) projectList = Project.select(NOT(LIKE(Project.q.name, projectName))) else: projectName = self._realProjectName(projectName) projectList = Project.select(LIKE(Project.q.name, projectName)) if projectList.count() == 0: raise YokadiException("Found no project matching '%s'" % projectName) # Check keywords exist parseutils.warnIfKeywordDoesNotExist(keywordFilters) # Filtering and sorting according to parameters filters = [] # Filter on keywords for keywordFilter in keywordFilters: filters.append(keywordFilter.filter()) # Search if args.search: for word in args.search: if word.startswith("@"): tui.warning( "Maybe you want keyword search (without -s option) " "instead of plain text search?") filters.append( OR(LIKE(Task.q.title, "%" + word + "%"), LIKE(Task.q.description, "%" + word + "%"))) return args, projectList, filters
def testProjectCompleter(self): self.session.add_all([Project(name="foo"), Project(name="foo2"), Project(name="bar")]) expected = ["foo ", "foo2 "] completer = completers.ProjectCompleter(1) result = completer("f", "t_add f", 6, 8) self.assertEqual(result, expected)
def testProjectCompleter(self): Project(name=u"foo") Project(name=u"foo2") Project(name=u"bar") expected = [u"foo ", u"foo2 "] completer = completers.ProjectCompleter(1) result = completer("f", "t_add f", 6, 8) self.assertEqual(result, expected)
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 _parseListLine(self, parser, line): """ Parse line with parser, returns a tuple of the form (options, projectList, filters) """ args = parser.parse_args(line) if len(args.filter) > 0: projectName, keywordFilters = parseutils.extractKeywords(u" ".join(args.filter)) else: projectName = "" keywordFilters = [] if self.kFilters: # Add keyword filter keywordFilters.extend(self.kFilters) if not projectName: if self.pFilter: # If a project filter is defined, use it as none was provided projectName = self.pFilter else: # Take all project if none provided projectName = "%" if projectName.startswith("!"): projectName = self._realProjectName(projectName[1:]) projectList = Project.select(NOT(LIKE(Project.q.name, projectName))) else: projectName = self._realProjectName(projectName) projectList = Project.select(LIKE(Project.q.name, projectName)) if projectList.count() == 0: raise YokadiException("Found no project matching '%s'" % projectName) # Check keywords exist parseutils.warnIfKeywordDoesNotExist(keywordFilters) # Filtering and sorting according to parameters filters = [] # Filter on keywords for keywordFilter in keywordFilters: filters.append(keywordFilter.filter()) # Search if args.search: for word in args.search: if word.startswith("@"): tui.warning("Maybe you want keyword search (without -s option) " "instead of plain text search?") filters.append(OR(LIKE(Task.q.title, "%" + word + "%"), LIKE(Task.q.description, "%" + word + "%"))) return args, projectList, filters
def testAdd(self): tui.addInputAnswers("y") self.cmd.do_p_add("p1") tui.addInputAnswers("y", "y") self.cmd.do_p_add("p2 @kw1 @kw2=12") projects = list(Project.select()) result = [x.name for x in projects] expected = [u"p1", u"p2"] self.assertEqual(result, expected) kwDict = Project.get(2).getKeywordDict() self.assertEqual(kwDict, dict(kw1=None, kw2=12))
def do_t_remove(self, line): parser = self.parser_t_remove() args = parser.parse_args(line) task = self.getTaskFromId(args.id) if not args.force: if not tui.confirm("Remove task '%s'" % task.title): return projectId = task.project.id task.destroySelf() print "Task '%s' removed" % (task.title) # Delete project with no associated tasks if Task.select(Task.q.projectID == projectId).count() == 0: Project.delete(projectId)
def do_t_reorder(self, line): """Reorder tasks of a project. It works by starting an editor with the task list: you can then change the order of the lines and save the list. The urgency field will be updated to match the order. t_reorder <project_name>""" try: project = Project.byName(line) except SQLObjectNotFound: raise BadUsageException("You must provide a valid project name") taskList = Task.select(AND(Task.q.projectID == project.id, Task.q.status != 'done'), orderBy=-Task.q.urgency) lines = ["%d,%s" % (x.id, x.title) for x in taskList] text = tui.editText("\n".join(lines)) ids = [] for line in text.split("\n"): line = line.strip() if not "," in line: continue id = int(line.split(",")[0]) ids.append(id) ids.reverse() for urgency, id in enumerate(ids): task = Task.get(id) task.urgency = urgency
def __init__(self, name, filter_string): self.name = name project_name, keyword_filters = parseutils.extractKeywords( filter_string) q_filters = [x.filter() for x in keyword_filters] project_list = Project.select(LIKE(Project.q.name, project_name)) q_filters.append(IN(Task.q.project, project_list)) # Skip notes q_filters.append( parseutils.KeywordFilter("!@" + NOTE_KEYWORD).filter()) # Only list done tasks if they were done after min_date min_date = compute_min_date() q_filters.append( OR(Task.q.status != 'done', Task.q.doneDate >= min_date)) self.tasks = Task.select(AND(*q_filters), orderBy=Task.q.id, distinct=True, join=LEFTJOINOn( Task, TaskKeyword, Task.q.id == TaskKeyword.q.taskID))
def do_p_add(self, line): """Add new project. Will prompt to create keywords if they do not exist. p_add <projectName> [@<keyword1>] [@<keyword2>]""" if not line: print "Give at least a project name !" return projectName, garbage, keywordDict = parseutils.parseLine(line) if garbage: raise BadUsageException("Cannot parse line, got garbage (%s)" % garbage) try: project = Project(name=projectName) except DuplicateEntryError: raise YokadiException("A project named %s already exists. Please find another name" % projectName) print "Added project '%s'" % projectName if not dbutils.createMissingKeywords(keywordDict.keys()): return None project.setKeywordDict(keywordDict)
def do_p_list(self, line): """List all projects.""" for project in Project.select(): if project.active: active = "" else: active = "(inactive)" print "%s %s %s %s" % (project.name.ljust(20), project.getKeywordsAsString().ljust(20), str(Task.select(Task.q.project == project).count()).rjust(4), active)
def testEdit(self): # Create project p1 and rename it to p2 self.cmd.do_p_add("p1") project = Project.get(1) self.assertEqual(project.name, "p1") tui.addInputAnswers("p2") self.cmd.do_p_edit("p1") self.assertEqual(project.name, "p2") # Create project p3 and try to rename it to p2 self.cmd.do_p_add("p3") project = Project.get(2) self.assertEqual(project.name, "p3") tui.addInputAnswers("p2") self.assertRaises(YokadiException, self.cmd.do_p_edit, "p3") self.assertEqual(project.name, "p3")
def do_p_add(self, line): """Add new project. Will prompt to create keywords if they do not exist. p_add <projectName> [@<keyword1>] [@<keyword2>]""" if not line: print "Give at least a project name !" return projectName, garbage, keywordDict = parseutils.parseLine(line) if garbage: raise BadUsageException("Cannot parse line, got garbage (%s)" % garbage) try: project = Project(name=projectName) except DuplicateEntryError: raise YokadiException( "A project named %s already exists. Please find another name" % projectName) print "Added project '%s'" % projectName if not dbutils.createMissingKeywords(keywordDict.keys()): return None project.setKeywordDict(keywordDict)
def do_p_list(self, line): """List all projects.""" for project in Project.select(): if project.active: active = "" else: active = "(inactive)" print "%s %s %s %s" % ( project.name.ljust(20), project.getKeywordsAsString().ljust(20), str(Task.select(Task.q.project == project).count()).rjust(4), active)
def getProjectFromName(name, parameterName="project_name"): """ Helper function which returns a project given its name, or raise a YokadiException if it does not exist. """ name = name.strip() if len(name) == 0: raise BadUsageException("Missing <%s> parameter" % parameterName) try: return Project.byName(name) except SQLObjectNotFound: raise YokadiException("Project '%s' not found. Use p_list to see all projects." % name)
def getOrCreateProject(projectName, interactive=True, createIfNeeded=True): """Get a project by its name. Create it if needed @param projectName: project name as a string @param interactive: Ask user before creating project (this is the default) @type interactive: Bool @param createIfNeeded: create project if it does not exist (this is the default) @type createIfNeeded: Bool @return: Project instance or None if user cancel creation or createIfNeeded is False""" result = Project.selectBy(name=projectName) result = list(result) if len(result): return result[0] if not createIfNeeded: return None if interactive and not tui.confirm("Project '%s' does not exist, create it" % projectName): return None project = Project(name=projectName) print "Added project '%s'" % projectName return project
def do_p_add(self, line): """Add new project. Will prompt to create keywords if they do not exist. p_add <projectName> [@<keyword1>] [@<keyword2>]""" if not line: print("Give at least a project name !") return projectName, garbage, keywordDict = parseutils.parseLine(line) session = db.getSession() if garbage: raise BadUsageException("Cannot parse line, got garbage (%s)" % garbage) try: project = Project(name=projectName) session.add(project) session.commit() except IntegrityError: session.rollback() raise YokadiException("A project named %s already exists. Please find another name" % projectName) print("Added project '%s'" % projectName) if not dbutils.createMissingKeywords(list(keywordDict.keys())): return None project.setKeywordDict(keywordDict) session.merge(project) session.commit()
def getProjectFromName(name, parameterName="project_name"): """ Helper function which returns a project given its name, or raise a YokadiException if it does not exist. """ name = name.strip() if len(name) == 0: raise BadUsageException("Missing <%s> parameter" % parameterName) try: return Project.byName(name) except SQLObjectNotFound: raise YokadiException( "Project '%s' not found. Use p_list to see all projects." % name)
def testTlistUrgency0(self): # Given a project with two tasks, one with a negative urgency prj = Project(name="prj") self.session.add(prj) t1 = Task(project=prj, title="t1") self.session.add(t1) t2 = Task(project=prj, title="t2", urgency=-1) self.session.add(t2) self.session.flush() # When I list tasks with -u 0 renderer = testutils.TestRenderer() self.cmd.do_t_list("-u 0", renderer=renderer) # Then the task with a negative urgency is not listed self.assertEqual(renderer.tasks, [t1])
def testRenderListSectionOrder(self): projectNames = "ccc", "aaa", "UPPER_CASE", "zzz", "mmm" projectList = [] for name in projectNames: prj = Project(name=name) task = Task(project=prj, title="Hello") self.session.add(prj) self.session.add(task) projectList.append(prj) self.session.flush() renderer = testutils.TestRenderer() self.cmd._renderList(renderer, projectList, filters=[], order=[]) self.assertEqual(list(renderer.taskDict.keys()), sorted(projectNames, key=lambda x: x.lower()))
def do_p_add(self, line): """Add new project. p_add <projectName>""" if not line: print("Missing project name.") return projectName = parseutils.parseOneWordName(line) session = db.getSession() try: project = Project(name=projectName) session.add(project) session.commit() except IntegrityError: session.rollback() raise YokadiException("A project named %s already exists. Please find another name" % projectName) print("Added project '%s'" % projectName)
def testRenderListSectionOrderKeywords(self): prj = Project(name="prj") keywordNames = ["kw_" + x for x in ("ccc", "aaa", "UPPER_CASE", "zzz", "mmm")] keywordList = [] for name in keywordNames: keyword = Keyword(name=name) task = Task(project=prj, title="Hello") TaskKeyword(task=task, keyword=keyword) self.session.add(task) keywordList.append(prj) self.session.flush() renderer = testutils.TestRenderer() self.cmd._renderList(renderer, [prj], filters=[], order=[], groupKeyword="kw_%") self.assertEqual(list(renderer.taskDict.keys()), sorted(keywordNames, key=lambda x: x.lower()))
def generateCal(): """Generate an ical calendar from yokadi database @return: icalendar.Calendar object""" cal = icalendar.Calendar() cal.add("prodid", '-//Yokadi calendar //yokadi.github.com//') cal.add("version", "2.0") # Add projects for project in Project.select(Project.q.active == True): vTodo = icalendar.Todo() vTodo.add("summary", project.name) vTodo["uid"] = PROJECT_UID % project.id cal.add_component(vTodo) # Add tasks for task in Task.select(Task.q.status != "done"): vTodo = createVTodoFromTask(task) cal.add_component(vTodo) return cal
def generateCal(): """Generate an ical calendar from yokadi database @return: icalendar.Calendar object""" cal = icalendar.Calendar() cal.add("prodid", "-//Yokadi calendar //yokadi.github.com//") cal.add("version", "2.0") # Add projects for project in Project.select(Project.q.active == True): vTodo = icalendar.Todo() vTodo.add("summary", project.name) vTodo["uid"] = PROJECT_UID % project.id cal.add_component(vTodo) # Add tasks for task in Task.select(Task.q.status != "done"): vTodo = createVTodoFromTask(task) cal.add_component(vTodo) return cal
def getOrCreateProject(projectName, interactive=True, createIfNeeded=True): """Get a project by its name. Create it if needed @param projectName: project name as a string @param interactive: Ask user before creating project (this is the default) @type interactive: Bool @param createIfNeeded: create project if it does not exist (this is the default) @type createIfNeeded: Bool @return: Project instance or None if user cancel creation or createIfNeeded is False""" session = db.getSession() result = session.query(Project).filter_by(name=projectName).all() if len(result): return result[0] if not createIfNeeded: return None if interactive and not tui.confirm( "Project '%s' does not exist, create it" % projectName): return None project = Project(name=projectName) session.add(project) print("Added project '%s'" % projectName) return project
def testMergeItselfFails(self): project = Project(name="p1") self.assertRaises(YokadiException, project.merge, self.session, project)