Initial import
This commit is contained in:
commit
62889999fe
89
process-gradescope-grades.py
Executable file
89
process-gradescope-grades.py
Executable file
|
@ -0,0 +1,89 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Script to ...
|
||||||
|
#
|
||||||
|
# Minimally tested. Seems to work. Use at your own risk.
|
||||||
|
#
|
||||||
|
# By James Eagan <james.eagan@telecom-paris.fr>
|
||||||
|
# https://james.eagan.fr
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import re
|
||||||
|
|
||||||
|
skipCols = ['SID', 'Email', 'Submission ID', 'Submission Time',
|
||||||
|
'Lateness (H:M:S)', 'View Count', 'Submission Count',
|
||||||
|
]
|
||||||
|
|
||||||
|
def readCSV(fileName):
|
||||||
|
cols = list(pd.read_csv(fileName, nrows=1))
|
||||||
|
keepCols = [col for col in cols if col not in skipCols]
|
||||||
|
|
||||||
|
df = pd.read_csv(fileName, usecols=keepCols)
|
||||||
|
df = df.sort_values(by='Nom')
|
||||||
|
return df
|
||||||
|
|
||||||
|
pattern = re.compile(r'(\d+\.?\d*): (.+) \((\d+\.\d*) pts\)')
|
||||||
|
def massageHeaders(df, args):
|
||||||
|
multiHeaders = [[], [], []]
|
||||||
|
|
||||||
|
for header in df.columns:
|
||||||
|
match = pattern.match(header)
|
||||||
|
if match:
|
||||||
|
# Question in the form: '11.4: types d'attributs (variables) (1.0 pts)'
|
||||||
|
multiHeaders[0].append('Q' + match.group(1)) # Q1, Q2, Q3.1, Q3.2, etc
|
||||||
|
multiHeaders[1].append(match.group(2)) # Question label
|
||||||
|
multiHeaders[2].append(float(match.group(3))) # Question points (e.g. 1, 2, 1.5)
|
||||||
|
else:
|
||||||
|
multiHeaders[0].append('')
|
||||||
|
multiHeaders[1].append('')
|
||||||
|
multiHeaders[2].append(header)
|
||||||
|
|
||||||
|
df.columns = pd.MultiIndex.from_arrays(multiHeaders)
|
||||||
|
return df
|
||||||
|
|
||||||
|
def writeExcel(df, fileName):
|
||||||
|
with pd.ExcelWriter(fileName) as writer:
|
||||||
|
df.to_excel(writer)
|
||||||
|
# with open(basename + "-out.csv", 'w') as writer:
|
||||||
|
# writer.write(df.to_csv())
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(description="Massage Gradescope data")
|
||||||
|
parser.add_argument("csv", help="csv file as exported from Gradescope")
|
||||||
|
parser.add_argument("-o", "--out", help="file to write output")
|
||||||
|
group = parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument("-,", "--commas", help="use commas for decimal separator", action="store_true")
|
||||||
|
group.add_argument("-.", "--dots", help="use dots for decimal separator", action="store_true")
|
||||||
|
group.add_argument("-d", "--decimal-separator", help="decimal separator for real numbers", default=",")
|
||||||
|
parser.add_argument("-s", "--sep", help="csv column separator (default: ',' when decimal separator is '.' and ';' for ',')")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.commas:
|
||||||
|
args.decimal_separator = ","
|
||||||
|
elif args.dots:
|
||||||
|
args.decimal_separator = "."
|
||||||
|
|
||||||
|
if not args.sep:
|
||||||
|
args.sep = ';' if args.decimal_separator == ',' else ','
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
|
def writeOutput(df, args):
|
||||||
|
if args.out:
|
||||||
|
writeExcel(df, args.out)
|
||||||
|
else :
|
||||||
|
df.to_csv(sys.stdout, sep=args.sep, decimal=args.decimal_separator)
|
||||||
|
|
||||||
|
def nowDoIt():
|
||||||
|
args = parse_args()
|
||||||
|
df = readCSV(args.csv)
|
||||||
|
massageHeaders(df, args)
|
||||||
|
writeOutput(df, args)
|
||||||
|
|
||||||
|
nowDoIt()
|
||||||
|
|
Loading…
Reference in a new issue