summaryrefslogtreecommitdiffstats
path: root/mark.py
blob: 2630be1a09b5bad99b669c7b7de7f6dcddbe9680 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from dataclasses import dataclass
import jinja_helpers
import configparser
import argparse
import tempfile
import zipfile
import reflect
import jinja2
import shutil
import yaml
import json
import os

@dataclass
class FileDependencies:
    assessment_struct:dict

    def __enter__(self):
        try:
            for file_dep in self.assessment_struct["dependencies"]["files"]:
                if os.path.isfile(file_dep):
                    shutil.copy(file_dep, os.path.split(file_dep)[-1])
                else:
                    shutil.copytree(file_dep, os.path.split(file_dep)[-1])
                # print("%s --> %s" % (file_dep, os.path.join(os.getcwd(), os.path.split(file_dep)[-1])))
        except KeyError:
            pass

    def __exit__(self, type, value, traceback):
        try:
            for file_dep in self.assessment_struct["dependencies"]["files"]:
                if os.path.isfile(os.path.split(file_dep)[-1]):
                    os.remove(os.path.split(file_dep)[-1])
                else:
                    shutil.rmtree(os.path.split(file_dep)[-1])
        except KeyError:
            pass

def main(**kwargs):
    student_no = os.path.splitext(os.path.split(args["submission"])[-1])[0]

    with tempfile.TemporaryDirectory() as tempdir:
        with zipfile.ZipFile(args["submission"]) as z:
            z.extractall(tempdir)

        # some zipping applications make a folder inside the zip with the files in that folder.
        # try to deal with this here.
        submission_files = tempdir
        if os.path.isdir(
            os.path.join(submission_files, os.listdir(submission_files)[0])
        ) and len(os.listdir(submission_files)) == 1:
            submission_files = os.path.join(submission_files, os.listdir(submission_files)[0])

        with open(kwargs["assessment"], "r") as f:
            assessment_struct = yaml.safe_load(f)

        with FileDependencies(assessment_struct):
            output = reflect.gen_reflection_report(submission_files, assessment_struct, student_no, kwargs)
        output_file = kwargs["out"]
        
        if kwargs["format"] == "yaml":
            strout = yaml.dump(output)
        elif kwargs["format"] == "json":
            strout = json.dumps(output, indent = 4)
        else:
            with open(os.path.join("templates", "%s.jinja2" % kwargs["format"]), "r") as f:
                jinja_template = jinja2.Template(f.read())

            strout = jinja_template.render(**output, **jinja_helpers._get_helpers(), **kwargs)

        if output_file == "stdout":
            print(strout)
            # input("\n\n[tempdir: %s] Press any key to close..." % tempdir)
            exit()

        if output_file == "auto":
            output_file = "%s_report.%s" % (student_no, kwargs["format"])

        with open(output_file, "w") as f:
            f.write(strout)

        # input("\n\n[tempdir: %s] Press any key to close..." % tempdir)

if __name__ == "__main__":
    config = configparser.ConfigParser()
    config.read("smarker.conf")

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-a", "--assessment",
        help = "Path to an assessment .yml file",
        type = os.path.abspath,
        required = True
    )
    parser.add_argument(
        "-s", "--submission",
        help = "Path to a zip of a student's code",
        type = os.path.abspath,
        required = True
    )
    parser.add_argument(
        "-f", "--format",
        help = "Output format type",
        type = str,
        choices = ["yaml", "json"] + [os.path.splitext(f)[0] for f in os.listdir("templates")],
        default = "txt"
    )
    parser.add_argument(
        "-o", "--out",
        help = "Path to write the output to, or, by default write to stdout. 'auto' automatically generates a file name.",
        default = "stdout",
    )

    for section in config.sections():
        for option in config.options(section):
            parser.add_argument(
                "--%s_%s" % (section, option),
                default = config.get(section, option),
                help = "Optional argument inherited from config file. Read smarker.conf for details."
            )

    args = vars(parser.parse_args())
    main(**args)