Example #1
0
def connectDatabase(dbFileName, createIfNeeded=True):
    """Connect to database and create it if needed
    @param dbFileName: path to database file
    @type dbFileName: str
    @param createIfNeeded: Indicate if database must be created if it does not exists (default True)
    @type createIfNeeded: bool"""

    dbFileName=os.path.abspath(dbFileName)

    if sys.platform == 'win32':
        connectionString = 'sqlite:/'+ dbFileName[0] +'|' + dbFileName[2:]
    else:
        connectionString = 'sqlite:' + dbFileName
        
    connection = connectionForURI(connectionString)
    sqlhub.processConnection = connection

    if not os.path.exists(dbFileName):
        if createIfNeeded:
            print "Creating database"
            createTables()
            # Set database version according to current yokadi release
            Config(name=DB_VERSION_KEY, value=str(DB_VERSION), system=True, desc="Database schema release number")
        else:
            print "Database file (%s) does not exist or is not readable. Exiting" % dbFileName
            sys.exit(1)

    # Check version
    version = getVersion()
    if version != DB_VERSION:
        tui.error("Your database version is %d but Yokadi wants version %d." \
            % (version, DB_VERSION))
        print "Please, run the %s/update.py script to migrate your database prior to running Yokadi" % \
                os.path.abspath(utils.shareDirPath())
        sys.exit(1)
Example #2
0
 def do_a_remove(self, line):
     """Remove an alias"""
     if line in self.aliases:
         del self.aliases[line]
         aliases = Config.selectBy(name="ALIASES")[0]
         aliases.value = repr(self.aliases)
     else:
         tui.error("No alias with that name. Use a_list to display all aliases")
Example #3
0
 def __init__(self):
     try:
         self.aliases = eval(Config.byName("ALIASES").value)
     except SQLObjectNotFound:
         self.aliases = {}
     except Exception, e:
         tui.error("Aliases syntax error. Ignored")
         self.aliases = {}
Example #4
0
def warnIfKeywordDoesNotExist(keywordFilters):
    """Warn user is keyword does not exist
    @return: True if at least one keyword does not exist, else False"""
    doesNotExist = False
    for keyword in [k.name for k in keywordFilters]:
            if Keyword.select(LIKE(Keyword.q.name, keyword)).count() == 0:
                tui.error("Keyword %s is unknown." % keyword)
                doesNotExist = True
    return doesNotExist
Example #5
0
 def onecmd(self, line):
     """This method is subclassed just to be
     able to encapsulate it with a try/except bloc"""
     try:
         # Decode user input
         line=line.decode(tui.ENCODING)
         return Cmd.onecmd(self, line)
     except YokadiOptionParserNormalExitException:
         pass
     except YokadiException, e:
         tui.error("*** Yokadi error ***\n\t%s" % e)
Example #6
0
 def onecmd(self, line):
     """This method is subclassed just to be
     able to encapsulate it with a try/except bloc"""
     try:
         # Decode user input
         line = line.decode(tui.ENCODING)
         return Cmd.onecmd(self, line)
     except YokadiOptionParserNormalExitException:
         pass
     except UnicodeDecodeError, e:
         tui.error("Unicode decoding error. Please check you locale and terminal settings (%s)." % e)
Example #7
0
def run():
    athlete_data = read_data("athlete_events.csv")
    # keeps repeating unless break
    while True:
        selection = tui.menu()
        if selection == "years":
            process.list_years(athlete_data)
        elif selection == "tally":
            process.tally_medals(athlete_data)
        elif selection == "team":
            process.tally_team_medals(athlete_data)
        elif selection == "exit":
            break
        else:
            tui.error("Invalid Selection!")
Example #8
0
def run():
    data = read_data("athlete_events.csv")          # Data variable is the result of the call to function 'read_data'

    while True:                                     # Menu selection
        selection = tui.menu()
        if selection == "years":
            process.list_years(data)
        elif selection == "tally":
            process.tally_medals(data)
        elif selection == "ctally":
            process.tally_team_medals(data)
        elif selection == "exit":
            break                                   # Exits (or breaks) the run of the program
        else:
            tui.error("Invalid Selection!")
Example #9
0
 def do_c_set(self, line):
     """Set a configuration key to value : c_set <key> <value>"""
     line = line.split()
     if len(line) < 2:
         raise YokadiException("You should provide two arguments : the parameter key and the value")
     name = line[0]
     value = " ".join(line[1:])
     p = Config.select(AND(Config.q.name == name, Config.q.system == False))
     if p.count() == 0:
         tui.error("Sorry, no parameter match")
     else:
         if self.checkParameterValue(name, value):
             p[0].value = value
             tui.info("Parameter updated")
         else:
             tui.error("Parameter value is incorrect")
Example #10
0
def run():
    athlete_data = read_data("athlete_events.csv")
    # The run function also contains the keywords pass.
    # These should be replaced with appropriate calls to the functions in the module process once this has been implemented

    while True:
        selection = tui.menu()
        if selection == "years":
            process.list_years(athlete_data)
        elif selection == "tally":
            process.tally_medals(athlete_data)
        elif selection == "team":
            process.tally_team_medals(athlete_data)
        elif selection == "exit":
            break
        else:
            tui.error("Invalid Selection!")
Example #11
0
 def _t_add(self, cmd, line):
     """Code shared by t_add and bug_add."""
     line = line.strip()
     if not line:
         tui.error("Missing parameters")
         self.do_help(cmd)
         return None
     projectName, title, keywordDict = parseutils.parseLine(line)
     if not title:
         tui.error("Missing title")
         self.do_help(cmd)
         return None
     task = dbutils.addTask(projectName, title, keywordDict)
     if not task:
         tui.reinjectInRawInput(u"%s %s" % (cmd, line))
         return None
     self.lastTaskId = task.id
     return task
Example #12
0
def main():
    if len(sys.argv) > 1:
        term = sys.argv[1]
    else:
        term = showPrompt(hasTopic=False)
        if term is "":
            return

    while True:
        questions = []
        matches = []
        index = 1
        for source in SOURCES:
            lst = findMatches(source, term)
            for keyword in lst:
                matches.append((source, keyword))
                questions.append((index, "%s (%s)" % (keyword, source)))
                index += 1

        if len(matches) > 0:
            print
            print "# Matching topics:"
            for pos, txt in questions:
                print "%2d: %s" % (pos, txt)
        else:
            tui.error("No match found")
        print

        answer = showPrompt(hasTopic=len(matches) > 0)

        if answer.isdigit():
            index = int(answer) - 1
            if index < 0 or index >= len(matches):
                tui.error("Wrong topic number")
                continue
            source, keyword = matches[index]
            showDoc(source, keyword)
        elif answer == "":
            return
        else:
            term = answer
Example #13
0
def main():
    if len(sys.argv) > 1:
        term = sys.argv[1]
    else:
        term = showPrompt(hasTopic=False)
        if term is "":
            return

    while True:
        questions = []
        matches = []
        index = 1
        for source in SOURCES:
            lst = findMatches(source, term)
            for keyword in lst:
                matches.append((source, keyword))
                questions.append((index, "%s (%s)" % (keyword, source)))
                index += 1

        if len(matches) > 0:
            print
            print "# Matching topics:"
            for pos, txt in questions:
                print "%2d: %s" % (pos, txt)
        else:
            tui.error("No match found")
        print

        answer = showPrompt(hasTopic=len(matches) > 0)

        if answer.isdigit():
            index = int(answer) - 1
            if index < 0 or index >= len(matches):
                tui.error("Wrong topic number")
                continue
            source, keyword = matches[index]
            showDoc(source, keyword)
        elif answer == "":
            return
        else:
            term = answer
Example #14
0
 def parse(self, line):
     """Parse given line to create a keyword filter"""
     operators = ("=<", ">=", "!=", "<", ">", "=")
     if " " in line:
         tui.error("No space in keyword filter !")
         return
     if line.startswith("!"):
         self.negative = True
         line = line[1:]
     if not line.startswith("@"):
         tui.error("Keyword name must be be prefixed with a @")
         return
     line = line[1:] # Squash @
     line = line.replace("==", "=") # Tolerate == syntax
     for operator in operators:
         if operator in line:
             self.name, self.value = line.split(operator, 1)
             self.valueOperator = operator
             try:
                 self.value = int(self.value)
             except ValueError:
                 tui.error("Keyword value must be an integer (got %s)" %
                           (self.value, self.name))
                 return
             break # Exit operator loop
     else:
         # No operator found, only keyword name has been provided
         self.name, self.value = line, None
Example #15
0
def extractKeywords(line):
    """Extract keywords (@k1 @k2=n..) from line
    @param line: line from which keywords are extracted
    @returns: (remaining_text, {keywordDict})"""
    keywordDict = {}
    remainingText=[]
    for token in line.split():
        if token.startswith("@"):
            token=token[1:]
            if "=" in token:
                keyword, value = token.split("=", 1)
                try:
                    value = int(value)
                except ValueError:
                    tui.error("Keyword value must be an integer (got %s). Removing value for %s keyword" %
                              (value, keyword))
                    value = None
            else:
                keyword, value = token, None
            keywordDict[keyword] = value
        else:
            remainingText.append(token)

    return (u" ".join(remainingText), keywordDict)
Example #16
0
    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))
Example #17
0
        try:
            # Decode user input
            line=line.decode(tui.ENCODING)
            return Cmd.onecmd(self, line)
        except YokadiOptionParserNormalExitException:
            pass
        except YokadiException, e:
            tui.error("*** Yokadi error ***\n\t%s" % e)
        except IOError, e:
            # We can get I/O errors when yokadi is piped onto another shell commands
            # that breaks.
            print >>sys.stderr, "*** I/O error ***\n\t%s" % e
        except KeyboardInterrupt:
            print "*** Break ***"
        except Exception, e:
            tui.error("Unhandled exception (oups)\n\t%s" % e)
            print "This is a bug of Yokadi, sorry."
            print "Send the above message by email to Yokadi developers ([email protected]) to help them make Yokadi better."
            cut="---------------------8<----------------------------------------------"
            print cut
            traceback.print_exc()
            print "--"
            print "Python: %s" % sys.version.replace("\n", " ")
            print "SQLObject: %s" % sqlobjectVersion.replace("\n", " ")
            print "OS: %s (%s)" % os.uname()[0:3:2]
            print "Yokadi: %s" % utils.currentVersion()
            print cut
            print

    def loadHistory(self):
        """Tries to load previous history list from disk"""
Example #18
0
    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))