| 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
 | from dataclasses import dataclass
import argparse
import tempfile
import zipfile
import shutil
import jinja2
import os
latex_jinja_env = jinja2.Environment(
	block_start_string = '((*',
	block_end_string = '*))',
	variable_start_string = '(((',
	variable_end_string = ')))',
	comment_start_string = "((#",
	comment_end_string = '#))',
	line_statement_prefix = '%%',
	line_comment_prefix = '%#',
	trim_blocks = True,
	autoescape = False,
	loader = jinja2.FileSystemLoader(os.path.abspath(os.path.join(os.path.split(__file__)[0], "templates")))
)
# https://stackoverflow.com/questions/10551117/setting-options-from-environment-variables-when-using-argparse
class EnvDefault(argparse.Action):
    def __init__(self, envvar, required=True, default=None, **kwargs):
        # if not default and envvar:
        #     if envvar in os.environ:
        #         default = os.environ[envvar]
        if envvar in os.environ:
            default = os.environ[envvar]
        if required and default:
            required = False
        super(EnvDefault, self).__init__(default=default, required=required, 
                                         **kwargs)
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values)
@dataclass
class ExtractZipToTempDir(tempfile.TemporaryDirectory):
    zip_file:str
    def __post_init__(self):
        super().__init__()
    def __enter__(self):
        return self.extract()
    def __exit__(self, exc, value, tb):
        self.cleanup()
    def extract(self):
        with zipfile.ZipFile(self.zip_file) as z:
            z.extractall(self.name)
        # some zipping applications make a folder inside the zip with the files in that folder.
        # try to deal with this here.
        submission_files = self.name
        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])
        return submission_files
@dataclass
class FileDependencies:
    assessment_struct:dict
    to_:str=str(os.getcwd())
    def __enter__(self):
        self.get_deps()
    def __exit__(self, type, value, traceback):
        self.rm_deps()
    def get_deps(self):
        try:
            for file_dep in self.assessment_struct["dependencies"]["files"]:
                if os.path.isfile(file_dep):
                    shutil.copy(file_dep, os.path.join(self.to_, os.path.split(file_dep)[-1]))
                else:
                    shutil.copytree(file_dep, os.path.join(self.to_, os.path.split(file_dep)[-1]))
        except KeyError:
            pass
    def rm_deps(self):
        stuff_to_remove = []
        try:
            stuff_to_remove += [os.path.split(f)[-1] for f in self.assessment_struct["dependencies"]["files"]]
        except KeyError:
            pass
        try:
            stuff_to_remove += self.assessment_struct["produced_files"]
        except KeyError:
            pass
        for file_dep in stuff_to_remove:
            file_dep = os.path.join(self.to_, file_dep)
            # print("rm: ", file_dep)
            if os.path.exists(file_dep):
                if os.path.isfile(file_dep):
                    os.remove(file_dep)
                else:
                    shutil.rmtree(file_dep)
@dataclass
class ChangeDirectory:
    target:str
    cwd:str=str(os.getcwd())
    def __enter__(self):
        os.chdir(self.target)
    def __exit__(self, type, value, traceback):
        os.chdir(self.cwd)
 |