supplements.py 5.97 KB
Newer Older
1
2
3
4
#!/usr/bin/env python

"""Prepare supplement material

5
This script copies and renames supplementary material (such as exam sheet or
6
7
sample solution) with file names following the exam scan naming convention.

8
9
This information is either taken from the filenames of exam scan PDFs or from
the Moodle grading CSV file.
10
11

Attention: Contents in output folder will be overwritten in the following!
12
13
"""

14
15
16
17
__author__ = "Amrita Deb (deb@itc.rwth-aachen.de), " +\
    "Christian Rohlfing (rohlfing@ient.rwth-aachen.de)"


18
19
20
21
22
23
import sys  # get arguments from command line
import os  # path listing/manipulation/...
import time  # keep track of time
import argparse  # handle command line arguments
import shutil  # copy

24
import utils.matnum as matnum_utils
25
import utils.moodle as moodle
26
27


28
def copy_supplements(supp_dir, supp_files, prefixes, output_dir, dry=False):
29
30
31
32
33
    """Copy supplement files

    Args:
        supp_dir (str): path to supplement folder
        output_dir (str): path to output folder
34
        prefixes (list): list of prefixes
35
36
37
38
39
40
        dry (bool): indicate dry run
    """

    dryout = []
    if dry:
        print("Dry run\n")
41
42
    else:
        print("Start renaming...", sep='', end='', flush=True)
43
44
45

    # Iterate over supplement files
    cnt = 0
46
    num_files = len(supp_files)*len(prefixes)
47
48
49
50
51
52
    copied_files = []
    for supp_file in supp_files:
        supp_filefull = os.path.join(supp_dir, supp_file)
        supp_stem = os.path.splitext(supp_file)[0]  # filename without .pdf

        # Iterate over scanned PDF files
53
        for prefix in prefixes:
54
55
56
57
58
59
60
            new_file = prefix + "_" + supp_stem + ".pdf"
            new_filefull = os.path.join(output_dir, new_file)

            # Copy
            if not dry:
                shutil.copyfile(supp_filefull, new_filefull)
            else:
Christian Rohlfing's avatar
Christian Rohlfing committed
61
62
63
                dryout.append(
                    "- {old} -> {new}"
                    .format(old=supp_file, new=new_file))
64
65
66
67
68
69
70
71
72
73
74
            copied_files.append(new_file)

            # Print progress
            if not (cnt % max(1, round(num_files/10))):
                print(".", sep=' ', end='', flush=True)
            cnt += 1

    # Display dry run results
    if dry:
        dryout.sort()
        print("\nDry run results:\n{}".format("\n".join(dryout)))
75
76
    else:
        print("done")
77
78
79
80

    return copied_files


81
82
83
84
85
def _make_parser():
    csv_parser = moodle.get_moodle_csv_parser()

    parser = argparse.ArgumentParser(
        parents=[csv_parser],
Christian Rohlfing's avatar
bugfix    
Christian Rohlfing committed
86
        description=__doc__, prog='supplements.py',
87
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
88

89
    parser.add_argument(
90
        "infolder", help="Folder with supplements.")
91
    parser.add_argument(
92
93
        "prefix", help="Provides information to construct prefixes. Either " +
        "folder with scanned PDFs or Moodle grading CSV file.")
94
    parser.add_argument(
95
96
        "outfolder",
        help="Output folder with supplements per student.")
97

98
99
100
101
102
103
104
    parser.add_argument(
        "--filenameformat", default="{matnum}_{fullname[0]}",
        help="File name format. Available keywords: " +
        "{{matnum}}, {{fullname}}, {{lastname}}, {{firstname}}. " +
        "Default: '{{matnum}}_{{fullname[0]}}'")
    parser.add_argument(
        "-d", "--dry", action='store_true', help="Flag for dry run")
105

106
107
108
109
    return parser


# Create argument parser with default values
Christian Rohlfing's avatar
Christian Rohlfing committed
110
_parser = _make_parser()
111
112
113
114
115
116
117


def main(args):
    """Main routine
    """

    # Argument handling
Christian Rohlfing's avatar
Christian Rohlfing committed
118
    args = _parser.parse_args(args)
119
120
    supp_dir = args.infolder
    prefixinfo = args.prefix
121
    prefixformat = args.filenameformat
122
    output_dir = args.outfolder
Christian Rohlfing's avatar
Christian Rohlfing committed
123
124
125
    csv_enc = args.csvenc
    csv_delim = args.csvdelim
    csv_quote = args.csvquote
126
127
    dry = args.dry

Deb's avatar
Deb committed
128
129
130
131
    # Check folders
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

132
133
134
135
136
137
138
139
140
141
142
143
144
145
    # Decide whether PDF folder or CSV file was given
    csvfilename = pdf_dir = ""
    ext = os.path.splitext(prefixinfo)[1].lower()
    if ext == '.csv':  # CSV file
        csvfilename = prefixinfo
        if not os.path.isfile(csvfilename):
            raise Exception("File {} does not exist.".format(csvfilename))
    elif ext == '':  # Folder
        pdf_dir = prefixinfo
        if not os.path.isdir(pdf_dir):
            raise Exception("Folder {} does not exist.".format(pdf_dir))
    else:
        raise Exception("{} neither CSV file nor folder.".format(prefixinfo))

146
147
    # Print status
    starttime = time.time()
148
    supp_folder = os.listdir(supp_dir)
149
    supp_files = [_ for _ in supp_folder if _.lower().endswith(".pdf")]
150
151
152
153
154
155
156
157
    print("""
Available supplement PDFs to be copied:
- {}

Files in output folder {} will be overwritten during this process.
    """.format("\n- ".join(supp_files),  output_dir))

    # Create prefixes
Amrita's avatar
Amrita committed
158
    print(pdf_dir)
159
160
161
    if pdf_dir != "":  # Take prefixes from pdf directory
        pdf_folder = os.listdir(pdf_dir)
        pdf_files = [_ for _ in pdf_folder
162
                     if _.lower().endswith(".pdf") and
163
                     matnum_utils.starts_with_matnum(_)]
164
165
166
167
168
169
        prefixes = []
        for pdf_file in pdf_files:
            prefix = os.path.splitext(pdf_file)[0]  # take file name as prefix
            prefixes.append(prefix)
    else:  # Take prefixes from CSV file
        prefixes = []
Christian Rohlfing's avatar
Christian Rohlfing committed
170
171
        infos = moodle.extract_info(sheet_csv=csvfilename, csv_delim=csv_delim,
                                    csv_quote=csv_quote, csv_enc=csv_enc)
172
        for info in infos:
173
174
175
            prefix = prefixformat.format(
                matnum=info['matnum'], fullname=info['fullname'],
                lastname=info['lastname'], firstname=info['firstname'])
176
            prefixes.append(prefix)  # save prefix
177
178
179
180

    # Copy supplements to output dir and prepend prefixes
    copied_files = copy_supplements(supp_dir, supp_files, prefixes,
                                    output_dir, dry)
181
182
183

    # Print status
    endtime = time.time()
184
185
    print("""
All PDFs are renamed and can be found in {} folder.
186
187
188
189
190
191
192
193
Time taken: {:.2f}s
    """.format(output_dir, endtime-starttime))

    return copied_files


if __name__ == '__main__':
    main(sys.argv[1:])