Exemple #1
0
def readLineWithSpecificContents(f, specificContents, nbLinesRead, isEOF_OK):
    """
    Reads file f waiting to read string specificContents.

    Reads file f until it finds a non-empty line.
    If this non-empty line is specificContents (differences in number of spaces 
    are accepted), it returns it. Otherwise, it displays an error message 
    mentioning filename and nbLinesRead.
    If it finds EOF during its search
        If isEOF_OK is True, just returns "".
        Otherwise displays an error message and stops.

    Parameters
    ----------
    f : file
        File descriptor to read
    specificContents : str
        String which should be read.
    nbLinesRead : list containing one int
        Number of lines read until now in the file. This number is incremented during execution
    isEOF_OK : bool
        If true, if EOF is detected, returns False. Otherwise, generates an error.

    Returns
    -------
    str
        String containing specificContents or "" if EOF
    """
    line = lookForNonBlankLine(f, nbLinesRead, isEOF_OK, specificContents)
    if line == "":
        if isEOF_OK:
            return ""
        sys.exit(
            """ERREUR: Dans le fichier "{}", à la ligne {}, le programme s'attendait à la ligne "{}" et est arrivé à la fin du fichier."""
            .format(f.name, nbLinesRead[0], specificContents))
    if line.replace(" ", "") != specificContents.replace(" ", ""):
        sys.exit(
            """ERREUR: Dans le fichier "{}", à la ligne {}, le programme s'attendait à la ligne "{}" et a lu la ligne "{}"."""
            .format(f.name, nbLinesRead[0], specificContents, line))
    return line
Exemple #2
0
    def __init__(self, filename):
        """Opens file named filename and reads all configuration data"""
        self.confData = {}

        # We read all of the configuration data (without taking care of the type)
        f = openWithErrorManagement(filename, "r", encoding="utf8")
        nbLinesRead = [0]

        confKeys = floatConfKeys + intConfKeys + strConfKeys

        line = lookForNonBlankLine(
            f, nbLinesRead, True, """Une ligne de la forme "Cle = Valeur" """)
        while (line != ""):
            pos = line.find("=")
            if pos < 0:
                sys.exit(
                    """ERREUR: Dans le fichier "{}", à la ligne {}, cette ligne contient "{}" qui ne respecte pas le format "Clé = Valeur" """
                    .format(f.name, nbLinesRead[0], line))
            key = line[:pos].strip(" \t\n")
            value = line[pos + 1:].strip(" \t\n")

            if key not in confKeys:
                sys.exit(
                    """ERREUR: Dans le fichier "{}", à la ligne {}, cette ligne contient "{}" qui définit la clé "{}" qui est inconnue (problème d'orthographe ?)"""
                    .format(f.name, nbLinesRead[0], line, key))

            self.confData[key] = value

            line = lookForNonBlankLine(
                f, nbLinesRead, True,
                """Une ligne de la forme "Cle = Valeur" """)

        f.close()

        # We check that we found all keys in file
        for key in confKeys:
            try:
                self.confData[key]
            except KeyError:
                sys.exit(
                    """ERREUR: Il manque la clé "{}" dans le fichier de configuration "{}"."""
                    .format(key, filename))

        # We take care of float data
        for key in floatConfKeys:
            try:
                result = float(self.confData[key])
            except ValueError:
                sys.exit(
                    """ERREUR: Dans le fichier "{}", la clé "{}" a pour valeur "{}" qui n'est pas un flottant."""
                    .format(f.name, key, confData[key]))
            self.confData[key] = result

        # We take care of int data
        for key in intConfKeys:
            try:
                result = int(self.confData[key])
            except ValueError:
                sys.exit(
                    """ERREUR: Dans le fichier "{}", la clé "{}" a pour valeur "{}" qui n'est pas un entier."""
                    .format(f.name, key, confData[key]))
            self.confData[key] = result

        # Initialize opinionType2CommentBound
        self.opinionType2CommentBound = (
            self.confData["negativeCommentBound"],
            "Erreur (Valeur non utilisée dans self.opinionType2CommentBound)",
            self.confData["positiveCommentBound"])

        # If necessary, we add a '/' at the end of self.confData["rootDirectory"]
        rootDir = self.confData["rootDirectory"]
        if rootDir != "":
            if rootDir[len(rootDir) - 1] != '/':
                self.confData["rootDirectory"] += '/'
Exemple #3
0
def main():
    """Main entry point of the application"""

    #
    # Call parameter analysis
    #
    if len(sys.argv) != 3:
        print("ERREUR: Pas assez de parametres")
        usage()
        return

    if sys.argv[1][0] != '-':
        print(
            """ERREUR: Le premier parametre devrait etre "-1" ou "-2" (sans les guillemets)"""
        )
        usage()
        return

    if len(sys.argv[1]) == 1 or sys.argv[1][1] not in "13":
        print(
            """ERREUR: Le premier parametre devrait etre "-1" ou "-3" (sans les guillemets)"""
        )
        usage()
        return

    #
    # We display cos version before starting the processing
    #
    print()
    print("cos version 2.0.2")
    print()

    #
    # Read all configuration data
    #
    conf = Conf(sys.argv[2])

    #
    # Read the list of defenses
    #
    defenses = []
    f = openWithErrorManagement(key2inputFileName("defensesFilename", conf),
                                "r",
                                encoding=conf.get("encoding"))
    nbLinesRead = [0]
    name = lookForNonBlankLine(f, nbLinesRead, True, "Nom soutenance")
    while name != "":
        defenses.append(Defense(name))
        name = lookForNonBlankLine(f, nbLinesRead, True, "Nom soutenance")
    f.close()

    #
    # Read the list of students and the title of their defense
    #
    students = []
    f = openWithErrorManagement(key2inputFileName("studentsFilename", conf),
                                "r",
                                encoding=conf.get("encoding"))
    nbLinesRead = [0]

    lookForNonBlankLine(
        f, nbLinesRead, True,
        "Nom soutenance")  # We ignore the line giving the title of the columns
    studentLine = lookForNonBlankLine(f, nbLinesRead, True, "Nom soutenance")
    while studentLine != "":
        info = splitCsvLine(studentLine, conf.get("csvSeparator"))
        # We look for info in the list of defense names
        found = False
        for defense in defenses:
            if info[1] == defense.name:
                # OK, this defense name is known
                students.append(Student(info[0], defense, defenses))
                found = True
                break
        if not found:
            sys.exit(
                """ERREUR: Dans le fichier "{}", la ligne {} ("{}") fait référence à une soutenance intitulée "{}" qui n'apparaît pas dans le fichier "{}"."""
                .format(conf.get("studentsFilename"), nbLinesRead[0],
                        studentLine, info[1], conf.get("defensesFilename")))
        studentLine = lookForNonBlankLine(f, nbLinesRead, True,
                                          "Nom soutenance")
    f.close()

    #
    # Read the list of criteria types
    #
    criteriaTypes = []
    f = openWithErrorManagement(key2inputFileName("criteriaTypesFilename",
                                                  conf),
                                "r",
                                encoding=conf.get("encoding"))
    nbLinesRead = [0]
    criteriaType = lookForNonBlankLine(f, nbLinesRead, True, "Type de critère")
    while criteriaType != "":
        criteriaTypes.append(criteriaType)
        criteriaType = lookForNonBlankLine(f, nbLinesRead, True,
                                           "Type de critère")
    f.close()

    #
    # Read the list of criterias
    #
    criterias = []
    f = openWithErrorManagement(key2inputFileName("criteriasFilename", conf),
                                "r",
                                encoding=conf.get("encoding"))
    nbLinesRead = [0]

    lookForNonBlankLine(
        f, nbLinesRead, True,
        "Nom critère")  # We ignore the line giving the title of the columns
    criteriaLine = lookForNonBlankLine(f, nbLinesRead, True, "Nom critère")
    while criteriaLine != "":
        info = splitCsvLine(criteriaLine, conf.get("csvSeparator"))
        # We look for info[0] in the list of criteria types
        found = False
        for criteriaType in criteriaTypes:
            if info[0] == criteriaType:
                found = True
                break
        if not found:
            sys.exit(
                """ERREUR: Dans fichier "{}", la ligne {} ("{}") fait référence à un type de critère intitulée "{}" qui n'apparaît pas dans le fichier "{}"."""
                .format(f.name, nbLinesRead[0], criteriaLine, info[0],
                        conf.get("criteriaTypesFilename")))
        # OK, this citeriaType is known
        try:
            floatValue = float(info[2])
        except ValueError:
            sys.exit(
                """ERREUR: Dans fichier "{}", la ligne {} ("{}") a son 3ème champ ("{}") qui n'est pas un flottant."""
                .format(f.name, nbLinesRead[0], criteriaLine, info[2]))
        criterias.append(
            Criteria(info[0], info[1], floatValue, conf.get("ratioCriteriaKO"),
                     conf.get("ratioCriteriaOK")))
        criteriaLine = lookForNonBlankLine(f, nbLinesRead, True, "Nom critère")
    f.close()

    #
    # Prepare dateTime string which may be used for names of output files
    #
    date = datetime.datetime.now()
    s = str(date)
    dateTime = s[:s.find('.')]

    #
    # Remaining work depends on what the user asks for
    #
    if sys.argv[1][1] == '1':
        generateModels(conf, defenses, students, criteriaTypes, criterias,
                       dateTime)
    else:
        analyzeTeacherData(conf, defenses, criteriaTypes, criterias)
        analyzeStudentsData(conf, defenses, students, criteriaTypes, criterias)
        generateResults(conf, defenses, students, criteriaTypes, criterias,
                        dateTime)

    #
    # We display an end of execution message
    #
    if sys.argv[1][1] == '1':
        print(
            """OK, exécution de la phase {} terminée : les fichiers "{}", "{}" et "{}" ont été générés."""
            .format(
                sys.argv[1][1],
                key2ouputFileName("nominativeSheetsFilename", conf, dateTime),
                key2ouputFileName("genericSheetFilename", conf, dateTime),
                key2ouputFileName("genericTeacherMarksFilename", conf,
                                  dateTime)))
    else:
        print(
            """OK, exécution de la phase {} terminée : les fichiers "{}", "{}" et "{}" ont été générés."""
            .format(
                sys.argv[1][1],
                key2ouputFileName("synthesisCommentsFilename", conf, dateTime),
                key2ouputFileName("evaluationCommentsFilename", conf,
                                  dateTime),
                key2ouputFileName("studentsMarksSheetFilename", conf,
                                  dateTime)))
    print()

    return
Exemple #4
0
def analyzeStudentsData(conf, defenses, students, criteriaTypes, criterias):
    """
    Enrich students information with the contents of conf.get("filledNominativeSheetsFilename")

    Parameters
    ----------
    conf : Conf
        Configuration information
    f : file
        File on which to write
    defenses : list of Defense
        List of defenses
    students : liste of Student
        List of students
    criteriaTypes : liste of str
        List of criteria types
    criterias : liste of Criteria
        List of criterias

    Returns
    -------
    void
    """
    #
    # Analyze the contents of conf.get("filledNominativeSheetsFilename"),
    #
    f = openWithErrorManagement(key2inputFileName(
        "filledNominativeSheetsFilename", conf),
                                "r",
                                encoding=conf.get("encoding"))
    nbLinesRead = [0]
    while readLineWithSpecificContents(f, conf.get("studentBound"),
                                       nbLinesRead, True) != "":
        # Determine student index in students
        studentLine = lookForNonBlankLine(f, nbLinesRead, False,
                                          "Ligne contenant un nom d'etudiant")
        studentLine = studentLine[:studentLine.rfind(
            "("
        )]  # To suppress the name of the defense which is between parenthesis at the end of the line
        studentIndex = findName(studentLine, students, nbLinesRead, f,
                                conf.get("studentsFilename"))
        if students[studentIndex].alreadyProcessed:
            sys.exit(
                """ERREUR: Dans le fichier "{}", derriere la ligne {}, l'etudiant ("{}") apparaît pour la deuxième fois."""
                .format(conf.get("filledNominativeSheetsFilename"),
                        nbLinesRead[0], studentLine))
        students[studentIndex].alreadyProcessed = True

        # Skip delimiter of student name
        readLineWithSpecificContents(f, conf.get("studentBound"), nbLinesRead,
                                     False)

        # Analyze answers for the different defenses evaluated by the student
        # NB: There is one less defense evaluated by the student, as he does not
        #     evalkuate his own defense.
        for unusedIndex in list(range(len(defenses) - 1)):
            # Skip delimiter of defense name
            readLineWithSpecificContents(f, conf.get("defenseBound"),
                                         nbLinesRead, False)
            # Determine defense index in defenses
            defenseLine = lookForNonBlankLine(
                f, nbLinesRead, False, "Ligne contenant un nom de projet")
            defenseIndex = findName(defenseLine, defenses, nbLinesRead, f,
                                    conf.get("defensesFilename"))
            if defenses[defenseIndex] == students[studentIndex].defense:
                sys.exit(
                    """ERREUR: Dans le fichier "{}", derriere la ligne {}, l'étudiant "{}"a un commentaire de son propre projet "{}" : tentative de triche ?."""
                    .format(conf.get("filledNominativeSheetsFilename"),
                            nbLinesRead[0], students[studentIndex].name,
                            defenses[defenseIndex].name))
            # Skip delimiter of defense name
            readLineWithSpecificContents(f, conf.get("defenseBound"),
                                         nbLinesRead, False)
            # For each criteria type
            for criteriaType in criteriaTypes:
                # Skip criteria type
                readLineWithSpecificContents(f, criteriaType, nbLinesRead,
                                             False)
                # Handle each critera in this criteria type
                for criteria in criterias:
                    if criteria.criteriaType == criteriaType:
                        criteriaLine = lookForNonBlankLine(
                            f, nbLinesRead, False,
                            "Ligne contenant un critère")
                        if criteriaLine[0] in "+-":
                            # We skip '+' or '-' sign which is at the beginning of the line
                            criteriaIndex = findName(
                                criteriaLine[1:].strip(" \t"), criterias,
                                nbLinesRead, f, conf.get("criteriasFilename"))
                        elif criteriaLine[-1] in "+-":
                            # We skip '+' or '-' sign which is at the end of the line
                            criteriaIndex = findName(
                                criteriaLine[:-1].strip(" \t"), criterias,
                                nbLinesRead, f, conf.get("criteriasFilename"))
                        else:
                            criteriaIndex = findName(
                                criteriaLine, criterias, nbLinesRead, f,
                                conf.get("criteriasFilename"))
                        if criteriaLine[0] == '+' or criteriaLine[-1] == '+':
                            students[studentIndex].opinionsPerDefense[
                                defenseIndex][
                                    POSITIVE_OPINION].criteriaIndex = criteriaIndex
                            students[studentIndex].opinionsPerDefense[
                                defenseIndex][
                                    POSITIVE_OPINION].nbCriteriaIndex += 1
                        elif criteriaLine[0] == '-' or criteriaLine[-1] == '-':
                            students[studentIndex].opinionsPerDefense[
                                defenseIndex][
                                    NEGATIVE_OPINION].criteriaIndex = criteriaIndex
                            students[studentIndex].opinionsPerDefense[
                                defenseIndex][
                                    NEGATIVE_OPINION].nbCriteriaIndex += 1
            # We now take care of opinion comments
            for opinionType in list_opinions:
                # Skip line introducing comment
                readLineWithSpecificContents(f,
                                             conf.getCommentBound(opinionType),
                                             nbLinesRead, False)
                # Take care of comment
                s = f.readline()
                nbLinesRead[0] += 1
                if s == "":
                    sys.exit(
                        """ERREUR: Dans le fichier "{}", derriere la ligne {}, il devrait y avoir un commentaire {} et non la fin du fichier."""
                        .format(conf.get("filledNominativeSheetsFilename"),
                                nbLinesRead[0], opinionType2str[opinionType]))
                s = removeComment(s)
                s = s.strip(" \t\n")
                if s == "":
                    # It may happen that a student fills up the second line of the comment instead of the first line.
                    # If the first line is empty, we read the second line in case.
                    s = f.readline()
                    nbLinesRead[0] += 1
                    if s == "":
                        sys.exit(
                            """ERREUR: Dans le fichier "{}", derriere la ligne {}, il devrait y avoir un commentaire {} et non la fin du fichier."""
                            .format(conf.get("filledNominativeSheetsFilename"),
                                    nbLinesRead[0],
                                    opinionType2str[opinionType]))
                    s = removeComment(s)
                    s = s.strip(" \t\n")
                students[studentIndex].opinionsPerDefense[defenseIndex][
                    opinionType].comment = s
                # Compute bonus for comment
                if students[studentIndex].opinionsPerDefense[defenseIndex][
                        opinionType].nbCriteriaIndex > 1:
                    # Student has given a "+" (or a "-") to several criteras ==>
                    # We cannot say for which criteria is this comment ==>
                    # We ignore this comment.
                    print(
                        """ATTENTION: Pour la soutenance "{}", l'étudiant "{}" a mis le commentaire ({})\n"{}"\nMais, il a mis le signe "{}" sur plusieurs critères\n==> COS ne peut donc pas prendre en compte ce commentaire\n==> Regardez si vous pouvez ne garder qu'un "{}" dans "{}" qui correspondrait à ce commentaire.\n"""
                        .format(
                            defenses[defenseIndex].name, studentLine,
                            opinionType2str[opinionType],
                            students[studentIndex].opinionsPerDefense[
                                defenseIndex][opinionType].comment,
                            opinionType2sign[opinionType],
                            opinionType2sign[opinionType], f.name))
                    students[studentIndex].opinionsPerDefense[defenseIndex][
                        opinionType].comment = ""
                if students[studentIndex].opinionsPerDefense[defenseIndex][
                        opinionType].comment != "":
                    criteriaIndex = students[studentIndex].opinionsPerDefense[
                        defenseIndex][opinionType].criteriaIndex
                    if criteriaIndex < 0:
                        print(
                            """ATTENTION: Pour la soutenance "{}", l'étudiant "{}" a mis un commentaire {} sans sélectionner de critère {}\n==> Regardez si vous pouvez mettre un "{}" dans "{}" qui correspondrait à ce commentaire.\n"""
                            .format(defenses[defenseIndex].name, studentLine,
                                    opinionType2str[opinionType],
                                    opinionType2str[opinionType],
                                    opinionType2sign[opinionType], f.name))
                        students[studentIndex].opinionsPerDefense[
                            defenseIndex][opinionType].comment = ""
                    elif defenses[defenseIndex].teacherOpinionsPerCriteria[
                            criteriaIndex].opinionType == opinionType:
                        # Student gave the same mak as the teacher ==> bonus
                        students[studentIndex].bonus += conf.get(
                            "bonusCriteriaOK")
                    elif (((opinionType == POSITIVE_OPINION
                            and defenses[defenseIndex].teacherBestOpinionType
                            == AVERAGE_OPINION) or
                           (opinionType == NEGATIVE_OPINION
                            and defenses[defenseIndex].teacherWorstOpinionType
                            == AVERAGE_OPINION)) and defenses[defenseIndex].
                          teacherOpinionsPerCriteria[criteriaIndex].opinionType
                          == AVERAGE_OPINION):
                        # The teacher found no criteria with opinionType and, for this criteria which index is criteriaIndex,
                        # the teacher gave a mark signifying AVERAGE_OPINION. As the student cannot give an average opinion,
                        # we consider that this is a good answer.
                        students[studentIndex].bonus += conf.get(
                            "bonusCriteriaOK")
    f.close()
Exemple #5
0
def analyzeTeacherData(conf, defenses, criteriaTypes, criterias):
    """
    Enrich defenses information with the contents of conf.get("teacherMarksFilename")

    Parameters
    ----------
    conf : Conf
        Configuration information
    f : file
        File on which to write
    defenses : list of Defense
        List of defenses
    students : liste of Student
        List of students
    criteriaTypes : liste of str
        List of criteria types
    criterias : liste of Criteria
        List of criterias

    Returns
    -------
    void
    """
    #
    # Analyze the contents of conf.get("teacherMarksFilename"),
    #
    f = openWithErrorManagement(key2inputFileName("teacherMarksFilename",
                                                  conf),
                                "r",
                                encoding=conf.get("encoding"))
    nbLinesRead = [0]

    lookForNonBlankLine(f, nbLinesRead, False,
                        "Ligne de titre des colonnesNom soutenance"
                        )  # We ignore the line giving the title of the columns
    # We deal with each criteria
    for criteria in criterias:
        # Read the marks for this criteria
        lineMarks = lookForNonBlankLine(
            f, nbLinesRead, False,
            "Ligne contenant les notes pour un critère donné")
        marks = splitCsvLine(lineMarks, conf.get("csvSeparator"))
        # Read the comments for this criteria
        lineComments = lookForNonBlankLine(
            f, nbLinesRead, False,
            "Ligne contenant les commentaires pour un critère donné")
        comments = splitCsvLine(lineComments, conf.get("csvSeparator"))
        # Add (mark, comment) to each defense
        column = 3  # We set column to 3 in order to skip :
        #   - column 0 which contains title of the line,
        #   - column 1 which contains value for maxCriteriaKO
        #   - column 2 which contains value for minCriteriaOK
        for defense in defenses:
            marks[column] = marks[column].replace(conf.get("decimalSeparator"),
                                                  '.')
            try:
                mark = float(marks[column])
            except ValueError:
                sys.exit(
                    """Dans le fichier "{}", la soutenance "{}" a son critère "{}" qui a reçu la note "{}" qui n'est n'est pas un flottant compris entre 0 et {}."""
                    .format(f.name, defense.name, criteria.name, marks[column],
                            criteria.maxPoints))
            if (mark < 0 or mark > criteria.maxPoints):
                sys.exit(
                    """Dans le fichier "{}", la soutenance "{}" a son critère "{}" qui a reçu la note de {} qui n'est pas comprise entre 0 et {}."""
                    .format(f.name, defense.name, criteria.name, mark,
                            criteria.maxPoints))
            defense.addMarkComment(
                TeacherOpinion(mark, comments[column], criteria))
            column += 1

    lookForNonBlankLine(f, nbLinesRead, False,
                        "Ligne de titre des colonnesNom soutenance"
                        )  # We ignore the line left intentionally blank

    lineGeneralComments = lookForNonBlankLine(
        f, nbLinesRead, False,
        "Ligne contenant les commentaires généraux de chaque projet")
    generalComments = splitCsvLine(lineGeneralComments,
                                   conf.get("csvSeparator"))
    column = 3  # We set column to 3 in order to skip column 0 which contains title of the line,
    # column 1 which contains Note max critere KO, and column 2 which contains
    # Note min critere OK
    for defense in defenses:
        defense.generalComment = generalComments[column]
        column += 1
    f.close()

    #
    # Update each defense, now that we know all the marks given by teacher
    #
    for defense in defenses:
        defense.update()