Source code for pyam.cmd.write_csv

"""Implementation of write-csv command"""
import argparse
from pathlib import Path
import csv
import openpyxl
from pyam.cohort import get_cohort
from pyam.cmd.args import add_common_args
from pyam.files import set_csv_column, PathGlob

[docs]def main(args=None): """Read marks from a set of mark spreadsheets and write them into csv files""" if args is None: parser = argparse.ArgumentParser(description=__doc__) add_args(parser) args = parser.parse_args() cohort = get_cohort(args.cohort) students = cohort.students(args.students) cohort.start_log_section(f"Collating marks into csv files") marks = get_marks(cohort, students, args.prefix, args.mark_sheets) def get_value(student_id): match = None for student in marks: if student.student_id in student_id or student.username in student_id: match = student break if match: return marks.pop(match) cohort.log.warning("No mark found for %s", student_id) return None if args.output: # create a new csv file write_mark_csv(args.output, marks) else: # fill in already existing csv files - warn if students not included for path in args.csv_files: set_csv_column(path, cohort.get("mark-column.mark"), cohort.get("mark-column.studentid"), get_value) for student in marks: cohort.log.warning("No CSV record for %s", student.name())
[docs]def get_id_and_mark(path): """Returns student id and mark from spreadsheet at path""" wbook = openpyxl.load_workbook(path, data_only=True) student_id = None mark = None for title, coord in wbook.defined_names["student_id"].destinations: student_id = wbook[title][coord].value for title, coord in wbook.defined_names["mark"].destinations: mark = wbook[title][coord].value return (student_id, mark)
[docs]def get_marks(cohort, students, prefix, paths) -> dict: """Sets marks for a set of students from spreadsheets Given a list of paths, or a cohort name and prefix Returns a dictionary mapping student_id to marks. Will warn if there are missing marks or missing students.""" if not paths: paths = list(cohort.report_path.glob(f"{prefix}*.xlsx")) marks = {} for path in paths: if path.suffix != ".xlsx": cohort.log.warning("File %s is not a spreadsheet", path) continue if path.stem.endswith("template"): continue try: (student_id, mark) = get_id_and_mark(path) except KeyError: continue for student in students: if student.student_id == student_id: marks[student] = mark break return marks
[docs]def write_mark_csv(filename, marks): """Write out student marks to a new csv file""" with open(filename, 'w', newline='') as csvfile: writer = csv.writer(csvfile,dialect="excel") writer.writerow(("Student ID", "Last Name", "First Name", "Mark")) for student, mark in sorted(marks.items()): writer.writerow((student.student_id, student.last_name, student.first_name, mark))
[docs]def add_args(parser=argparse.ArgumentParser(description=__doc__)): """Add and parse args for this script""" add_common_args(parser) parser.add_argument( '--mark-sheets', nargs="*", action=PathGlob, default=None, help="list of mark sheets to be processed. " "Defaults to those in report directory with matching prefix") parser.add_argument( '--csv-files', nargs="*", action=PathGlob, default=None, help="List of csv files to be modified. " "Default is those starting with prefix in report directory.") parser.add_argument( '-o','--output', type=Path, help="Output path to create new CSV file in. Incompatible with --csv-files " ) parser.add_argument( '--mark-col', help="Name of column in csv file where marks are to be written.") parser.add_argument('--student-col', help="Name of student id column in CSV files")