Example #1
0
def getDates(module_code, assignment_name):
    """get the assignment dates"""
    params_filepath = const.get_params_file_path(module_code, assignment_name)
    definitions_filepath = const.get_definitions_file_path(module_code)
    definitions_dates = None

    with open(params_filepath, 'r') as stream:
        data = yaml.safe_load(stream)

    weekNumber = data['weekNumber']

    if os.path.isfile(definitions_filepath):
        with open(definitions_filepath, 'r') as stream:
            definitions_loaded = yaml.safe_load(stream)
        definitions_dates = definitions.calculate_dates(
            weekNumber, definitions_loaded)

    startDay = getDate('startDay', definitions_dates, data)
    endDay = getDate('endDay', definitions_dates, data)
    cutoffDay = getDate('cutoffDay', definitions_dates, data)

    if startDay is None or endDay is None or cutoffDay is None:
        return None
    else:
        return startDay, endDay, cutoffDay
def getCutoffDay(module_code, week_number):
    """get cutoff day for a module"""
    params_filepath = const.get_params_file_path(module_code, week_number)
    with open(params_filepath, 'r') as stream:
        data = yaml.safe_load(stream)
    if data.get("cutoffDay"):
        return str(data.get("cutoffDay"))
    else:
        print("ERROR: cutoffDay doesn't exist!!!")
        return "False"
Example #3
0
def get_total_attempts(module_code, assignment_name, student_id) -> int:
    exceptions = getStudentExceptions(module_code, assignment_name, student_id)

    if exceptions is None or 'totalAttempts' not in exceptions:
        """read /**weekNum**/params.yaml file to get totalAttempts value"""
        path = const.get_params_file_path(module_code, assignment_name)
        with open(path, 'r') as stream:
            data: dict = yaml.safe_load(stream)
        return data.get("totalAttempts")
    else:
        return exceptions['totalAttempts']
Example #4
0
def getPenaltyPerDay(module_code, assignment_name, end_day, now):
    """get penalty per day for a module"""
    params_filepath = const.get_params_file_path(module_code, assignment_name)
    with open(params_filepath, 'r') as stream:
        data = yaml.safe_load(stream)
    if data.get("penaltyPerDay"):
        penalty = calculate_penalty(int(data.get("penaltyPerDay")), end_day,
                                    now)

        return str(penalty)
    else:
        print("ERROR: penaltyPerDay doesn't exist!!!")
        return "False"
def checkCollectionFilename(name, sock):
    """check if the submitted filename matches the required filename"""
    sock.sendall(b"OK")
    filename = sock.recv(1024).decode()
    module_code = sock.recv(1024).decode()
    week_number = sock.recv(1024).decode()

    params_filepath = const.get_params_file_path(module_code, week_number)
    with open(params_filepath, 'r') as stream:
        data = yaml.safe_load(stream)
    if data.get("collectionFilename") and str(data.get("collectionFilename")) == filename:
        sock.sendall(b"True")
    else:
        sock.sendall((str(data.get("collectionFilename")) + " is required!").encode('utf-8'))
    RetrCommand(name, sock)
Example #6
0
def checkCollectionFilename(name, sock):
    """check if the submitted filename matches the required filename"""
    send_message("OK", sock)
    filename = recv_message(sock)
    module_code = recv_message(sock)
    assignment_name = recv_message(sock)

    params_filepath = const.get_params_file_path(module_code, assignment_name)
    with open(params_filepath, 'r') as stream:
        data = yaml.safe_load(stream)
    if data.get("collectionFilename") and str(
            data.get("collectionFilename")) == filename:
        send_message("True", sock)
    else:
        send_message(
            str(data.get("collectionFilename")) + " is required!", sock)
    RetrCommand(name, sock)
Example #7
0
    def generate_assignment_csv(self, module, assignment_path, data_path,
                                students: list, reports_path):
        assignment = os.path.basename(assignment_path)
        params_file_path = const.get_params_file_path(module, assignment)
        report_file_path = os.path.join(reports_path,
                                        f"{assignment}-grades.csv")

        if os.path.isfile(report_file_path):
            shutil.move(report_file_path, report_file_path + ".old")

        with open(params_file_path, 'r') as file:
            params: dict = yaml.safe_load(file)

        if "tests" in params and len(students) > 0:
            with open(report_file_path, 'w+') as report_file:
                report_writer = csv.writer(report_file,
                                           delimiter=',',
                                           quotechar='"',
                                           quoting=csv.QUOTE_NONNUMERIC)
                columns = ["Student ID"]

                tests = params["tests"]

                for key in tests.keys():
                    columns.append(key)

                columns.append("marks")
                columns.append("Submission Date")

                report_writer.writerow(columns)

                rows = []
                for student in students:
                    self.write_student_marks(data_path, assignment, student,
                                             columns[1:len(columns) - 1], rows)

                if len(rows) == 0:
                    # there were no grades for this assignment, so remove the report file
                    os.remove(report_file_path)
                else:
                    for row in rows:
                        report_writer.writerow(row)
Example #8
0
def initVarsFile(name, sock):
    """init vars.yaml file"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    student_id = recv_message(sock)
    assignment_name = recv_message(sock)
    vars_filepath = const.get_vars_file_path(module_code, assignment_name,
                                             student_id)
    params_filepath = const.get_params_file_path(module_code, assignment_name)
    vars_directory = os.path.dirname(vars_filepath)

    if os.path.isfile(vars_directory + "/reinit.attempts"):
        print("Re-initialising attempts to excepted attempts")
        os.remove(vars_directory + "/reinit.attempts")
        re_initialise_attempts(vars_filepath, module_code, assignment_name,
                               student_id)
    else:
        with open(params_filepath, 'r') as stream:
            params: dict = yaml.safe_load(stream)

        data = {
            "attemptsLeft":
            get_total_attempts(module_code, assignment_name, student_id),
            "marks":
            0,
        }

        if 'attendance' in params:
            data['attendance'] = 0

        if 'compilation' in params:
            data['compilation'] = 0

        with open(vars_filepath, 'w') as f:
            yaml.dump(data, f, default_flow_style=False)

    RetrCommand(name, sock)
Example #9
0
def getExecResult(name, sock):
    """Exec the program and get exec result"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    assignment_name = recv_message(sock)
    student_id = recv_message(sock)
    file_suffix = recv_message(sock)
    penalty = recv_message(sock)
    curr_marks: int = 0
    result_msg: str = ""

    required_code_filename = get_required_code_filename(
        module_code, assignment_name)
    code_filepath = const.get_program_file_path(module_code, assignment_name,
                                                student_id,
                                                required_code_filename)
    params_filepath = const.get_params_file_path(module_code, assignment_name)
    vars_filepath = const.get_vars_file_path(module_code, assignment_name,
                                             student_id)
    vars_directory = os.path.dirname(vars_filepath)
    with open(params_filepath, 'r') as stream:
        data: dict = yaml.safe_load(stream)
    with open(vars_filepath, 'r') as stream:
        vars_data: dict = yaml.safe_load(stream)

    attempts_left = _checkAttemptsLeft(module_code, assignment_name,
                                       student_id)

    # check if attempts left
    if attempts_left != "False" and int(attempts_left) > 0:
        if "tests" in data and data["tests"]:
            tests = data["tests"]
            # if attendance exists, check attendance, assign marks
            if "attendance" in tests:
                attendance = tests["attendance"]
                attendance_marks = int(attendance["marks"])
                attendance_tag = attendance["tag"]
                curr_marks = curr_marks + attendance_marks
                result_msg += "%s: %d/%d\n" % (
                    attendance_tag, attendance_marks, attendance_marks)
                vars_data["attendance"] = attendance_marks
            """Execute the program specified by test"""
            # if compilation exists, check compilation, assign marks

            with handinexecutor.start() as executor:
                compilation_successful = True
                if "compilation" in tests:
                    compilation = tests["compilation"]
                    compilation_marks = int(compilation["marks"])
                    compilation_tag = compilation["tag"]
                    compilation_command = compilation["command"]

                    compile_proc = executor.compile(
                        path_to_file=code_filepath,
                        compile_command=compilation_command,
                        language=None)
                    compilation_successful = compile_proc.exit_code == 0

                    if compilation_successful:
                        vars_data["compilation"] = compilation_marks
                        result_msg += "%s: %d/%d\n" % (compilation_tag,
                                                       compilation_marks,
                                                       compilation_marks)
                        curr_marks += compilation_marks
                    else:
                        # compilation failed
                        result_msg += "%s: %d/%d\n" % (compilation_tag, 0,
                                                       compilation_marks)
                        vars_data["compilation"] = 0
                        test_output(vars_directory, "compilation",
                                    compile_proc.stderr, False)
                        with open(vars_filepath, 'w') as f:
                            yaml.dump(vars_data, f)

                if compilation_successful:
                    for key in tests.keys():
                        if key.startswith("test"):
                            test_marks = int(tests[key]["marks"])
                            test_tag = tests[key]["tag"]
                            test_command = tests[key]["command"]
                            input_data_file_path, answer_file_path, filter_file_path = get_file_paths(
                                tests[key])
                            filter_command = tests[key]["filterCommand"]

                            stdin_input = None
                            if input_data_file_path is not None and input_data_file_path != '':
                                input_data_file = open(input_data_file_path,
                                                       'r')
                                stdin_input = input_data_file.read()
                                input_data_file.close()

                            # change working directory
                            os.chdir(os.path.dirname(code_filepath))
                            exec1 = executor.run(path_to_file=code_filepath,
                                                 run_command=test_command,
                                                 language=None,
                                                 stdin=stdin_input)

                            if exec1.exit_code != 0:
                                # custom test failed
                                result_msg += "%s: %d/%d</br> " % (test_tag, 0,
                                                                   test_marks)
                                test_marks = 0
                                test_output(vars_directory, key,
                                            "Stderr: " + exec1.stderr, False)
                            else:
                                if exec1.timeout:
                                    # custom test failed
                                    result_msg += "%s: %d/%d</br> " % (
                                        test_tag, 0, test_marks)
                                    test_marks = 0
                                    test_output(vars_directory, key,
                                                "Test execution timed out",
                                                False)
                                else:
                                    if const.PROGRAM_SYSCALL_MONITORING and not executor.copy_syscall_log(
                                            vars_directory, key):
                                        print(
                                            "Warning: failed to copy syscall_monitor log"
                                        )

                                    output = exec1.stdout
                                    if answer_file_path is not None and answer_file_path != '':
                                        answer_file = open(
                                            answer_file_path, 'rb')
                                        answer = answer_file.read()

                                        # use stdout and answer as two argv of filter file, then perform filtering
                                        # TODO: may need to be changed ...
                                        if (filter_file_path is not None and filter_file_path != '') and \
                                                (filter_command is not None and filter_command != ''):
                                            try:
                                                # copy filter file to student dir
                                                filter_filename = os.path.basename(
                                                    filter_file_path)
                                                filter_file_path_dst = os.path.join(
                                                    os.path.dirname(
                                                        code_filepath),
                                                    filter_filename)
                                                with open(
                                                        filter_file_path_dst,
                                                        'w'):
                                                    pass
                                                shutil.copyfile(
                                                    filter_file_path,
                                                    filter_file_path_dst)

                                                os.chdir(
                                                    os.path.dirname(
                                                        filter_file_path_dst))
                                                output = replace_whitespace_with_underscore(
                                                    output.decode('utf-8')
                                                ).encode('utf-8')
                                                answer = replace_whitespace_with_underscore(
                                                    answer.decode('utf-8')
                                                ).encode('utf-8')
                                                command: str = (
                                                    filter_command + " %s %s"
                                                ) % (output.decode('utf-8'),
                                                     answer.decode('utf-8'))
                                                filter_proc = Popen(
                                                    command,
                                                    stdin=PIPE,
                                                    stdout=PIPE,
                                                    stderr=PIPE,
                                                    shell=True)
                                                stdout, stderr = filter_proc.communicate(
                                                )
                                                output, answer = stdout.decode(
                                                    'utf-8').split(' ')
                                            except Exception as e:
                                                print(e)
                                        else:
                                            answer = answer.decode()

                                        if compare_output_with_answer(
                                                output, answer):
                                            # custom test success
                                            curr_marks = curr_marks + test_marks
                                            result_msg += "%s: %d/%d</br> " % (
                                                test_tag, test_marks,
                                                test_marks)
                                            test_output(
                                                vars_directory, key, output,
                                                True)
                                        else:
                                            # custom test failed
                                            result_msg += "%s: %d/%d</br> " % (
                                                test_tag, 0, test_marks)
                                            test_marks = 0
                                            test_output(
                                                vars_directory, key, output,
                                                False)
                                            test_output(
                                                vars_directory, key, answer,
                                                None, "Answer File")
                                    else:
                                        # custom test success
                                        curr_marks = curr_marks + test_marks
                                        result_msg += "%s: %d/%d</br> " % (
                                            test_tag, test_marks, test_marks)
                                        test_output(vars_directory, key,
                                                    output, True)

                            vars_data[key] = test_marks

        # check assignment attempts left and update attempts left
        if "attemptsLeft" in vars_data and vars_data["attemptsLeft"]:
            attemptsLeft = vars_data["attemptsLeft"]
            vars_data["attemptsLeft"] = attemptsLeft - 1
            attemptsLeft -= 1
            if attemptsLeft <= 0:
                vars_data["attemptsLeft"] = 0
                attemptsLeft = 0
            with open(vars_filepath, 'w') as f:
                yaml.dump(vars_data, f)
            result_msg += "</br>You have %s attempts left</br> " % str(
                attemptsLeft)

            # apply penalty
            curr_marks = int(
                round(curr_marks - (curr_marks * (int(penalty) / 100))))
            result_msg += f"</br>Penalty: {penalty}%</br> "

            if curr_marks < 0:
                curr_marks = 0

            # update student marks
            with open(vars_filepath, 'r') as stream:
                vars_data2: dict = yaml.safe_load(stream)
            if "marks" in vars_data2.keys():
                vars_data2["marks"] = curr_marks
            with open(vars_filepath, 'w') as f:
                yaml.dump(vars_data2, f)
            result_msg += f"</br>Total marks: {curr_marks}</br> "
            submissions_archive.cull_old_archives(
            )  # this is a successful submission so, you are free to remove old ones
    else:
        result_msg = "Sorry, you have no attempts left for this assignment!"
        submissions_archive.undo_archive(
        )  # unsuccessful submission, remove newest archive and don't remove any old ones

    send_message(result_msg, sock)
    RetrCommand(name, sock)
Example #10
0
def get_required_code_filename(module_code, assignment_name) -> str:
    params_path = const.get_params_file_path(module_code, assignment_name)
    with open(params_path, 'r') as stream:
        data = yaml.safe_load(stream)
    return data.get("collectionFilename") if data.get(
        "collectionFilename") else ""
def getExecResult(name, sock):
    """Exec the program and get exec result"""
    sock.sendall(b"OK")
    module_code = sock.recv(1024).decode()
    week_number = sock.recv(1024).decode()
    student_id = sock.recv(1024).decode()
    file_suffix = sock.recv(1024).decode()
    penalty = sock.recv(1024).decode()

    if file_suffix == "cc" or file_suffix == "cpp":
        lang = "c++"
    elif file_suffix == "java":
        lang = "java"

    curr_marks: int = 0
    result_msg: str = ""
    required_code_filename = get_required_code_filename(module_code, week_number)
    code_filepath = const.get_program_file_path(module_code, week_number, student_id, required_code_filename)
    params_filepath = const.get_params_file_path(module_code, week_number)
    vars_filepath = const.get_vars_file_path(module_code, week_number, student_id)
    with open(params_filepath, 'r') as stream:
        data: dict = yaml.safe_load(stream)
    with open(vars_filepath, 'r') as stream:
        vars_data: dict = yaml.safe_load(stream)

    # check if attempts left
    if vars_data["attemptsLeft"] and vars_data["attemptsLeft"] > 0:
        if data["tests"]:
            # if attendance exists, check attendance, assign marks
            if data["tests"]["attendance"]:
                attendance_marks = int(data["tests"]["attendance"]["marks"])
                attendance_tag = data["tests"]["attendance"]["tag"]
                curr_marks = curr_marks + attendance_marks
                result_msg += "%s: %d/%d\n" % (attendance_tag, attendance_marks, attendance_marks)
                vars_data["attendance"] = attendance_marks

            # if compilation exists, check compilation, assign marks
            if data["tests"]["compilation"]:
                compilation_marks = int(data["tests"]["compilation"]["marks"])
                compilation_tag = data["tests"]["compilation"]["tag"]
                compilation_command = data["tests"]["compilation"]["command"]

                # change working directory
                os.chdir(os.path.dirname(code_filepath))

                p = Popen(compilation_command, stdout=PIPE, shell=True)
                return_code = p.wait()
                if return_code == 0:
                    # compilation successful
                    curr_marks = curr_marks + compilation_marks
                    result_msg += "%s: %d/%d\n" % (compilation_tag, compilation_marks, compilation_marks)
                    vars_data["compilation"] = compilation_marks

                    # execute the rest of custom tests when compilation success
                    for key in data["tests"].keys():
                        if key.startswith("test"):
                            test_marks = int(data["tests"][key]["marks"])
                            test_tag = data["tests"][key]["tag"]
                            test_command = data["tests"][key]["command"]
                            input_data_file_path = data["tests"][key]["inputDataFile"]
                            answer_file_path = data["tests"][key]["answerFile"]
                            filter_file_path = data["tests"][key]["filterFile"]
                            filter_command = data["tests"][key]["filterCommand"]
                            if input_data_file_path is not None and input_data_file_path != '':
                                input_data_file = open(input_data_file_path, 'r')

                                # change working directory
                                os.chdir(os.path.dirname(code_filepath))
                                proc = Popen(test_command, stdin=input_data_file, stdout=PIPE, stderr=PIPE, shell=False)
                                output, stderr = proc.communicate()  # bytes

                                # compare stdout with the answer file
                                if answer_file_path is not None and answer_file_path != '':
                                    answer_file = open(answer_file_path, 'rb')
                                    answer: bytes = answer_file.read()

                                    # use stdout and answer as two argv of filter file, then perform filtering
                                    # TODO: may need to be changed ...
                                    if (filter_file_path is not None and filter_file_path != '') and \
                                            (filter_command is not None and filter_command != ''):
                                        try:
                                            # copy filter file to student dir
                                            filter_filename = os.path.basename(filter_file_path)
                                            filter_file_path_dst = os.path.join(os.path.dirname(code_filepath), filter_filename)
                                            with open(filter_file_path_dst, 'w'):
                                                pass
                                            shutil.copyfile(filter_file_path, filter_file_path_dst)

                                            os.chdir(os.path.dirname(filter_file_path_dst))
                                            output = replace_whitespace_with_underscore(output.decode('utf-8')).encode('utf-8')
                                            answer = replace_whitespace_with_underscore(answer.decode('utf-8')).encode('utf-8')
                                            command: str = (filter_command + " %s %s") % (output.decode('utf-8'), answer.decode('utf-8'))
                                            filter_proc = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
                                            stdout, stderr = filter_proc.communicate()
                                            output, answer = stdout.decode('utf-8').split(' ')
                                        except Exception as e:
                                            print(e)

                                    if compare_output_with_answer(str(output), str(answer)):
                                        # custom test success
                                        curr_marks = curr_marks + test_marks
                                        result_msg += "%s: %d/%d</br>" % (test_tag, test_marks, test_marks)
                                        vars_data[key] = test_marks
                                    else:
                                        # custom test failed
                                        result_msg += "%s: %d/%d</br>" % (test_tag, 0, test_marks)
                                        vars_data[key] = 0

                else:
                    # compilation failed
                    result_msg += "%s: %d/%d\n" % (compilation_tag, 0, compilation_marks)
                    vars_data["compilation"] = 0

                with open(vars_filepath, 'w') as f:
                    yaml.dump(vars_data, f)

            # check assignment attempts left and update attempts left
            vars_filepath = const.get_vars_file_path(module_code, week_number, student_id)
            with open(vars_filepath, 'r') as stream:
                vars_data: dict = yaml.safe_load(stream)
            if vars_data["attemptsLeft"]:
                vars_data["attemptsLeft"] = vars_data["attemptsLeft"] - 1
                if vars_data["attemptsLeft"] <= 0:
                    vars_data["attemptsLeft"] = 0
            with open(vars_filepath, 'w') as f:
                yaml.dump(vars_data, f)
            result_msg += "\n\nYou have %s attempts left\n\n" % str(vars_data["attemptsLeft"])

            # apply penalty
            curr_marks = curr_marks - int(penalty)
            result_msg += "\n\nPenalty: %s\n\n" % str(penalty)

            # update student marks
            with open(vars_filepath, 'r') as stream:
                vars_data2: dict = yaml.safe_load(stream)
            if "marks" in vars_data2.keys():
                vars_data2["marks"] = curr_marks
            with open(vars_filepath, 'w') as f:
                yaml.dump(vars_data2, f)
            result_msg += "\n\nTotal marks: %s\n\n" % str(curr_marks)
    else:
        result_msg = "Sorry, you have no attempts left for this assignment!"

    sock.sendall(result_msg.encode())
    RetrCommand(name, sock)
def get_total_attempts(module_code, week_number) -> int:
    """read /**weekNum**/params.yaml file to get totalAttempts value"""
    path = const.get_params_file_path(module_code, week_number)
    with open(path, 'r') as stream:
        data: dict = yaml.safe_load(stream)
    return data.get("totalAttempts")
Example #13
0
def get_all_test_items(module_code, week_number) -> list:
    params_filepath = const.get_params_file_path(module_code, week_number)
    with open(params_filepath, 'r') as stream:
        data: dict = yaml.safe_load(stream)
    return [item for item in data["tests"].keys()]