コード例 #1
0
ファイル: taskcmd.py プロジェクト: mathstuf/yokadi
    def do_t_filter(self, line):
        """Define permanent keyword filter used by t_list
        Ex.:
            - t_filter @work (filter all task that have the "work" keyword)
            - t_filter none (remove filter)"""
        #TODO: add completion

        if not line:
            raise YokadiException("You must give keyword as argument or 'none' to reset filter")

        if parseutils.simplifySpaces(line).lower() == "none":
            self.kFilters = []
            self.pFilter = ""
            self.prompt = "yokadi> "
        else:
            projectName, keywordFilters = parseutils.extractKeywords(line)
            self.kFilters = keywordFilters
            self.pFilter = projectName
            prompt = "y"
            if self.pFilter:
                prompt += " %s" % projectName
            if self.kFilters:
                parseutils.warnIfKeywordDoesNotExist(self.kFilters)
                prompt += " %s" % (" ".join([str(k) for k in keywordFilters]))
            self.prompt = "%s> " % prompt
コード例 #2
0
ファイル: taskcmd.py プロジェクト: ryanakca/yokadi
    def do_t_add_keywords(self, line):
        """Add keywords to an existing task
        t_add_keyword <id> <keyword1> <keyword2>[=<value>]...
        """
        tokens = line.split(" ", 1)
        if len(tokens) < 2:
            raise YokadiException("You should give at least two arguments: <task id> <keyword>")
        task = dbutils.getTaskFromId(tokens[0])
        remainingText, newKwDict = parseutils.extractKeywords(tokens[1])

        dbutils.createMissingKeywords(newKwDict.keys())

        kwDict = task.getKeywordDict()
        kwDict.update(newKwDict)
        task.setKeywordDict(kwDict)
コード例 #3
0
ファイル: taskcmd.py プロジェクト: mathstuf/yokadi
    def do_t_add_keywords(self, line):
        """Add keywords to an existing task
        t_add_keyword <id> <@keyword1> <@keyword2>[=<value>]...
        """
        tokens = parseutils.simplifySpaces(line).split(" ", 1)
        if len(tokens) < 2:
            raise YokadiException("You should give at least two arguments: <task id> <keyword>")
        task = dbutils.getTaskFromId(tokens[0])
        garbage, keywordFilters = parseutils.extractKeywords(tokens[1])
        newKwDict = parseutils.keywordFiltersToDict(keywordFilters)
        if garbage:
            raise YokadiException("Cannot parse line, got garbage (%s). Maybe you forgot to add @ before keyword ?"
                                   % garbage)

        dbutils.createMissingKeywords(newKwDict.keys())

        kwDict = task.getKeywordDict()
        kwDict.update(newKwDict)
        task.setKeywordDict(kwDict)
コード例 #4
0
ファイル: taskcmd.py プロジェクト: ryanakca/yokadi
    def do_t_list(self, line):
        doneRangeList= ["today", "thisweek", "thismonth"]

        def keywordDictIsSubsetOf(taskKeywordDict, wantedKeywordDict):
            # Returns true if taskKeywordDict is a subset of wantedKeywordDict
            # taskKeywordDict is considered a subset of wantedKeywordDict if:
            # 1. All wantedKeywordDict keys are in taskKeywordDict
            # 2. All wantedKeywordDict valued keywords have the same value
            #    in taskKeywordDict
            for wantedKeyword, wantedValue in wantedKeywordDict.items():
                if not wantedKeyword in taskKeywordDict:
                    return False
                if wantedValue and taskKeywordDict[wantedKeyword] != wantedValue:
                    return False
            return True

        def taskHasWantedKeywordDict(task, wantedKeywordDict):
            """
            @param task: task object
            @param wantedKeywordDict: dict of name/value of wanted keyword
            # a task is considered a subset of wantedKeywordDict if:
            # 1. All wantedKeywordDict keys are in task or project keywords
            # 2. All wantedKeywordDict valued keywords have the same value
            #    in task or project keyword"""
            for wantedKeyword, wantedValue in wantedKeywordDict.items():
                taskFilters=[Task.q.id==task.id,
                         TaskKeyword.q.taskID==task.id,
                         TaskKeyword.q.keywordID==Keyword.q.id,
                         LIKE(Keyword.q.name, wantedKeyword)]

                projectFilters=[Project.q.id==task.projectID,
                                ProjectKeyword.q.projectID==Project.q.id,
                                ProjectKeyword.q.keyword==Keyword.q.id,
                                LIKE(Keyword.q.name, wantedKeyword)]

                if wantedValue:
                    taskFilters.append(TaskKeyword.q.value==wantedValue)
                    projectFilters.append(ProjectKeyword.q.value==wantedValue)

                if Task.select(AND(*taskFilters)).count()==0 and Task.select(AND(*projectFilters)).count()==0:
                    return False
            # All critera were met, return ok
            return True

        def createFilterFromRange(_range):
            # Parse the _range string and return an SQLObject filter
            minDate = date.today()
            if _range == "today":
                pass
            elif _range == "thisweek":
                minDate -= timedelta(minDate.weekday())
            elif _range == "thismonth":
                minDate = minDate.replace(day = 1)
            else:
                raise YokadiException("Invalid range value '%s'" % _range)

            return Task.q.doneDate>=minDate

        def selectRendererClass():
            if options.format != "auto":
                return gRendererClassDict[options.format]

            defaultRendererClass = TextListRenderer
            if not options.output:
                return defaultRendererClass

            ext = os.path.splitext(options.output)[1]
            if not ext:
                return defaultRendererClass

            return gRendererClassDict.get(ext[1:], defaultRendererClass)

        #BUG: completion based on parameter position is broken when parameter is given
        parser = self.parser_t_list()
        options, args = parser.parse_args(line)
        if len(args) > 0:
            projectName, keywordDict = parseutils.extractKeywords(u" ".join(args))
        else:
            projectName = ""
            keywordDict = {}

        if not projectName:
            # Take all project if none provided
            projectName="%"

        projectList = Project.select(LIKE(Project.q.name, projectName))

        if projectList.count()==0:
            tui.error("Found no project matching '%s'" % projectName)
            return

        # Check keywords exist
        for keyword in keywordDict.keys():
            if Keyword.select(LIKE(Keyword.q.name, keyword)).count()==0:
                tui.error("Keyword %s is unknown." % keyword)

        # Filtering and sorting according to parameters
        filters=[]
        order=-Task.q.urgency, Task.q.creationDate
        limit=None
        if options.done:
            filters.append(Task.q.status=='done')
            if options.done != "all":
                filters.append(createFilterFromRange(options.done))
        elif not options.all:
            filters.append(Task.q.status!='done')
        if options.topUrgent:
            order=-Task.q.urgency
            limit=5
        if options.topDue:
            filters.append(Task.q.dueDate!=None)
            order=Task.q.dueDate
            limit=5
        if options.search:
            for word in options.search:
                filters.append(OR(LIKE(Task.q.title, "%"+word+"%"),
                                  LIKE(Task.q.description, "%"+word+"%")))

        # Define output
        if options.output:
            out = open(options.output, "w")
        else:
            out = tui.stdout

        # Instantiate renderer
        rendererClass = selectRendererClass()
        renderer = rendererClass(out)

        # Fill the renderer
        if options.keyword:
            if options.keyword.startswith("@"):
                options.keyword = options.keyword[1:]
            for keyword in Keyword.select(LIKE(Keyword.q.name, options.keyword)):
                if unicode(keyword.name).startswith("_") and not options.keyword.startswith("_"):
                    #BUG: cannot filter on db side because sqlobject does not understand ESCAPE needed whith _
                    continue
                taskList = Task.select(AND(TaskKeyword.q.taskID == Task.q.id,
                                           TaskKeyword.q.keywordID == keyword.id,
                                           *filters),
                                        orderBy=order, limit=limit)
                taskList = list(taskList)
                if keywordDict:
                    # FIXME: factorize (see project oriented rendering below)
                    taskList = [x for x in taskList if taskHasWantedKeywordDict(x, keywordDict)]
                if projectList:
                    taskList = [x for x in taskList if x.project in projectList]
                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(keyword), taskList)
            # Call renderer
            renderer.end()
        else:
            hiddenProjectNames = []
            for project in projectList:
                if not project.active:
                    hiddenProjectNames.append(project.name)
                    continue
                taskList = Task.select(AND(Task.q.projectID == project.id, *filters),
                                       orderBy=order, limit=limit)

                if keywordDict:
                    taskList = [x for x in taskList if taskHasWantedKeywordDict(x, keywordDict)]
                else:
                    taskList = list(taskList)
    
                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(project), taskList)
            renderer.end()
    
            if len(hiddenProjectNames) > 0:
                tui.info("hidden projects: %s" % ", ".join(hiddenProjectNames))
コード例 #5
0
ファイル: taskcmd.py プロジェクト: mathstuf/yokadi
    def do_t_list(self, line):

        def selectRendererClass():
            if options.format != "auto":
                return gRendererClassDict[options.format]

            defaultRendererClass = TextListRenderer
            if not options.output:
                return defaultRendererClass

            ext = os.path.splitext(options.output)[1]
            if not ext:
                return defaultRendererClass

            return gRendererClassDict.get(ext[1:], defaultRendererClass)

        #BUG: completion based on parameter position is broken when parameter is given
        parser = self.parser_t_list()
        options, args = parser.parse_args(line)
        if len(args) > 0:
            projectName, keywordFilters = parseutils.extractKeywords(u" ".join(args))
        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 = projectName[1:]
            projectList = Project.select(NOT(LIKE(Project.q.name, projectName)))
        else:
            projectList = Project.select(LIKE(Project.q.name, projectName))

        if projectList.count() == 0:
            tui.error("Found no project matching '%s'" % projectName)
            return

        # Check keywords exist
        parseutils.warnIfKeywordDoesNotExist(keywordFilters)

        # Filtering and sorting according to parameters
        filters = []

        # Filter on keywords
        for keywordFilter in keywordFilters:
            filters.append(keywordFilter.filter())

        order = -Task.q.urgency, Task.q.creationDate
        limit = None
        if options.done:
            filters.append(Task.q.status == 'done')
            if options.done != "all":
                filters.append(parseutils.createFilterFromRange(options.done))
        elif not options.all:
            filters.append(Task.q.status != 'done')
        if options.topUrgent:
            order = -Task.q.urgency
            limit = 5
        if options.topDue:
            filters.append(Task.q.dueDate != None)
            order = Task.q.dueDate
            limit = 5
        if options.overdue:
            filters.append(Task.q.dueDate < datetime.now())
            order = Task.q.dueDate
        if options.search:
            for word in options.search:
                filters.append(OR(LIKE(Task.q.title, "%" + word + "%"),
                                  LIKE(Task.q.description, "%" + word + "%")))

        # Define output
        if options.output:
            out = open(options.output, "w")
        else:
            out = tui.stdout

        # Instantiate renderer
        rendererClass = selectRendererClass()
        renderer = rendererClass(out)

        # Fill the renderer
        if options.keyword:
            if options.keyword.startswith("@"):
                options.keyword = options.keyword[1:]
            for keyword in Keyword.select(LIKE(Keyword.q.name, options.keyword)):
                if unicode(keyword.name).startswith("_") and not options.keyword.startswith("_"):
                    #BUG: cannot filter on db side because sqlobject does not understand ESCAPE needed whith _
                    continue
                taskList = Task.select(AND(TaskKeyword.q.keywordID == keyword.id,
                                           *filters),
                                       orderBy=order, limit=limit, distinct=True,
                                       join=LEFTJOINOn(Task, TaskKeyword, Task.q.id == TaskKeyword.q.taskID))
                taskList = list(taskList)
                if projectList:
                    taskList = [x for x in taskList if x.project in projectList]
                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(keyword), taskList)
            # Call renderer
            renderer.end()
        else:
            hiddenProjectNames = []
            for project in projectList:
                if not project.active:
                    hiddenProjectNames.append(project.name)
                    continue
                taskList = Task.select(AND(Task.q.projectID == project.id, *filters),
                                       orderBy=order, limit=limit, distinct=True,
                                       join=LEFTJOINOn(Task, TaskKeyword, Task.q.id == TaskKeyword.q.taskID))
                taskList = list(taskList)

                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(project), taskList)
            renderer.end()

            if len(hiddenProjectNames) > 0:
                tui.info("hidden projects: %s" % ", ".join(hiddenProjectNames))