def makeAbiReports (schoolyear, klass): """Build abitur grade reports using the grade tables defined by the configuration path FILE_ABITABLE. A template is used to construct the report files. The results – odt files – are placed according to the configuration path FILE_ABIREPORT, first removing any existing files in this folder. odt files are created from a template. Return a tuple: the output folder and a list of odt-file-names (without folder path). """ sheetname = CONF.TABLES.ABITUR_RESULTS.GRADE_TABLE_SHEET infile = Paths.getYearPath (schoolyear, 'FILE_ABITABLE', klass=klass) filepath = Paths.getYearPath (schoolyear, 'FILE_ABIREPORT', klass=klass, make=-1) outdir = os.path.dirname (filepath) if os.path.isdir (outdir): shutil.rmtree (outdir) files = [] for f in sorted (glob (infile)): # Extract pupil info from file-name try: _, index, pid, pname = f.rsplit ('.', 1) [0].rsplit ('-', 3) except: continue data = readTableData (f, table=sheetname) ofile = filepath.replace ('*', '{pnum}-{pid}-{name}'.format ( pnum=index, pid=pid, name=pname)) files.append (os.path.basename (makeAbiReport (ofile, data))) REPORT.Info (_MADENREPORTS, klass=klass, n=len (files), folder=outdir) return outdir, files
def test_01(): filepath = Paths.getYearPath(_year, 'FILE_SP_TEACHERS') REPORT.Test("\n --------------\n%s" % repr(readSPTable(filepath))) filepath = Paths.getYearPath(_year, 'FILE_SP_CLASSES') REPORT.Test("\n --------------\n%s" % repr(readSPTable(filepath))) filepath = Paths.getYearPath(_year, 'FILE_SP_SUBJECTS') REPORT.Test("\n --------------\n%s" % repr(readSPTable(filepath))) filepath = Paths.getYearPath(_year, 'FILE_SP_LESSONS') REPORT.Test("\n --------------\n%s" % repr(readSPTable(filepath)))
def test_01(): pdfBytes = tSheets(_year, _manager, _date) fpath = Paths.getYearPath(_year, 'FILE_TEACHER_REPORT_LISTS') with open(fpath, 'wb') as fh: fh.write(pdfBytes) REPORT.Info("Class and subject lists for each teacher:\n {path}", path=fpath)
def importLatestRaw(schoolyear): allfiles = glob(Paths.getYearPath(schoolyear, 'FILE_PUPILS_RAW')) fpath = sorted(allfiles)[-1] REPORT.Info(_IMPORT_FROM, path=fpath) rpd = readRawPupils(schoolyear, fpath) updateFromRaw(schoolyear, rpd) return rpd
def test_02(): from glob import glob files = glob(Paths.getYearPath(_testyear, 'FILE_GRADE_TABLE', term='*')) for filepath in files: pgrades = readGradeTable(filepath) grades2db(_testyear, pgrades)
def test_01 (): _term = '1' _date = '2016-01-29' for _klass, _pid in ('13', '200301'), ('12.RS', '200403'): klass = Klass(_klass) REPORT.Test("Reading basic grade data for class %s" % klass) #TODO: This might not be the optimal location for this file. filepath = Paths.getYearPath(_testyear, 'FILE_GRADE_TABLE', term=_term).replace('*', str(klass).replace('.', '-')) pgrades = readGradeTable(filepath) REPORT.Test(" ++ INFO: %s" % repr(pgrades.info)) for pid, grades in pgrades.items(): REPORT.Test("\n -- %s: %s\n" % (pid, repr(grades))) REPORT.Test("\nReading template data for class %s" % klass) # Get the report type from the term and klass/stream _rtype = klass.match_map(CONF.GRADES.REPORT_TEMPLATES['_' + _term]) gradedata = GradeReportData(_testyear, _rtype, klass) REPORT.Test(" Indexes:\n %s" % repr(gradedata.sgroup2indexes)) REPORT.Test(" Grade tags:\n %s" % repr(gradedata.sgroup2sids)) grademap = klass.match_map(CONF.MISC.GRADE_SCALE) REPORT.Test("\nTemplate grade map for pupil %s (using %s)" % (_pid, grademap)) tagmap = gradedata.getTagmap(pgrades[_pid], "Pupil_%s" % _pid, grademap) REPORT.Test(" Grade tags:\n %s" % repr(tagmap))
def test_02(): _term = '2' for ks in '10', '11.Gym', '11.RS-HS-_', '12.RS-HS', '12.Gym', '13': klass = Klass(ks) bytefile = makeGradeTable(_testyear, _term, klass, "Noten: 1. Halbjahr") filepath = Paths.getYearPath(_testyear, 'FILE_GRADE_FULL', make=-1, term=_term).replace('*', str(klass).replace('.', '-')) + '.xlsx' with open(filepath, 'wb') as fh: fh.write(bytefile) REPORT.Test(" --> %s" % filepath) bytefile = stripTable(_testyear, _term, klass, "Noten: 1. Halbjahr") filepath = Paths.getYearPath(_testyear, 'FILE_GRADE_INPUT', make=-1, term=_term).replace('*', str(klass).replace('.', '-')) + '.xlsx' with open(filepath, 'wb') as fh: fh.write(bytefile) REPORT.Test(" --> %s" % filepath)
def test_01(): klass = Klass('13') bytefile = choiceTable(_testyear, klass) filepath = Paths.getYearPath(_testyear, 'FILE_SUBJECT_CHOICE_TABLE', make=-1).replace('*', str(klass).replace('.', '-')) + '.xlsx' with open(filepath, 'wb') as fh: fh.write(bytefile) REPORT.Test(" --> %s" % filepath)
def test_04(): """Export pupil data to a spreadsheet table. """ REPORT.Test("Exporting pupil data for school-year %d" % _testyear) fpath = os.path.join(Paths.getYearPath(_testyear, 'DIR_SCHOOLDATA'), '_test', 'export_pupils_0') classes = exportPupils(_testyear, fpath) REPORT.Test("Exported to %s" % fpath)
def __init__(self, schoolyear): l = importLessons(schoolyear) self.newdata = l[1] self.tid2name = l[2] self.badsubjects = l[3] self.filepath = Paths.getYearPath(_year, 'FILE_SUBJECTS') self._wb = load_workbook(self.filepath + '.xlsx') self._ws = self._wb.active self.makeStyle()
def test_03(): """Import pupil data – an old version (to later test updates). The data is in a spreadsheet table. """ fpath = os.path.join(Paths.getYearPath(_testyear, 'DIR_SCHOOLDATA'), '_test', 'import_pupils_0') REPORT.Test("Importing pupil data for school-year %d from %s" % (_testyear, fpath)) classes = importPupils(_testyear, fpath) REPORT.Test("CLASSES/PUPILS: %s" % repr(classes))
def test_06(): """Compare new raw data with saved complete version: Import complete version, then perform update from raw data. """ REPORT.Test("\n --1-----------------\n RESET PUPILS TABLE") fpath = os.path.join(Paths.getYearPath(_testyear, 'DIR_SCHOOLDATA'), '_test', 'Schuelerdaten_1') REPORT.Test("Importing pupil data for school-year %d from %s" % (_testyear, fpath)) REPORT.Test("\n --2-----------------\n COMPARE UPDATES:") importLatestRaw(_testyear)
def __init__(self, schoolyear, filetag, klass=None, **kargs): """<filetag> is an entry in the PATHS config file, which may contain '*' (which will be replaced by the class). If there is already a file with this path, this will be read in using <readDBTable> (which adds a file extension if necessary). """ self.schoolyear = schoolyear self.klass = klass # Configuration info for the options table self.fieldnames = CONF.TABLES.COURSE_PUPIL_FIELDNAMES self.filepath = Paths.getYearPath(schoolyear, filetag, make=-1, **kargs).replace('*', klass)
def test_02(): """ Initialise PUPILS table from "old" raw data (creation from scratch, no pre-existing table). """ db = DB(_testyear, 'RECREATE') fpath = os.path.join(Paths.getYearPath(_testyear, 'DIR_SCHOOLDATA'), '_test', 'pupil_data_0_raw') REPORT.Test( "Initialise with raw pupil data for school-year %d from:\n %s" % (_testyear, fpath)) rpd = readRawPupils(_testyear, fpath) for klass in sorted(rpd): REPORT.Test("\n +++ Class %s" % klass) for row in rpd[klass]: REPORT.Test(" --- %s" % repr(row)) updateFromRaw(_testyear, rpd) db.renameTable('PUPILS', 'PUPILS0') db.deleteIndexes('PUPILS0') REPORT.Test("Saved in table PUPILS0")
def readHols (schoolyear): """Return a <set> of <datetime.date> instances for all valid dates in the holidays file (configuration item "HOLIDAYS"). The dates are in isoformat (YYYY-MM-DD), but also MM-DD is acceptable, in which case the year will be added automatically (from the current school year). """ deltaday = datetime.timedelta (days=1) kalinfo = ConfigFile (Paths.getYearPath (schoolyear, 'FILE_HOLIDAYS')) hols = set () for d0 in kalinfo.SINGLE_DAYS.split ('|'): d = getDate (schoolyear, d0, dateformat=False) if d: hols.add (d) else: raise RuntimeError ("Date Error") for r0 in kalinfo.RANGES.split ('|'): try: d01, d02 = kalinfo [r0].split ('|') except: REPORT.Fail ("Ungültige Ferienzeit: %s" % r0) d1 = getDate (schoolyear, d01, dateformat=False) d2 = getDate (schoolyear, d02, dateformat=False) if (not d1) or (not d2): raise RuntimeError ("Date Error") if d1 >= d2: REPORT.Fail (("Ungültige Ferienangabe: %s" "Startdatum ist nach dem Enddatum") % item) continue while True: hols.add (d1) d1 += deltaday if d1 > d2: break return hols
def save (self): filepath = Paths.getYearPath (self._year, 'FILE_ATTENDANCE_TABLE', make=-1, klass=self._class) self._table.save (filepath)
def importLessons(schoolyear): ### classes class2cid = {} for row in readSPTable(Paths.getYearPath(schoolyear, 'FILE_SP_CLASSES')): #klass = row.CLASS #ctag = row.CTAG #cid = row.CID class2cid[row.CLASS] = row.CID ### subjects stag2sid = {} stag2name = {} for row in readSPTable(Paths.getYearPath(schoolyear, 'FILE_SP_SUBJECTS')): #sname = row.SNAME stag = row.SP #sid = row.SID if row.SID: stag2sid[stag] = row.SID stag2name[stag] = row.SNAME ### teachers tname2tid = {} tid2tname = {} for row in readSPTable(Paths.getYearPath(schoolyear, 'FILE_SP_TEACHERS')): #tname = row.TNAME #tid = row.TID #tclass = row.TCLASS # space-separated list #nz = row.NZ tid = (_TIDX + row.TID) if row.NZ else row.TID tname2tid[row.TNAME] = tid tid2tname[tid] = row.TNAME ### lessons table = {} sidtable = {} badsubjects = {} badclasses = set() badteachers = {} for row in readSPTable(Paths.getYearPath(schoolyear, 'FILE_SP_LESSONS')): # There can be a list of teachers #tnames = row.TNAMES #stag = row.SP #klass = row.CLASS tnames = [t.strip() for t in row.TNAMES.split(',')] stag = row.SP # The class can be a list. classes = [] for c in row.CLASS.split(','): try: klass = class2cid[c.strip()] except KeyError: badclasses.add(c) continue classes.append(klass) if len(classes) == 0: continue try: sid = stag2sid[stag] except KeyError: try: badsubjects[stag2name[stag]].append(klass) except: badsubjects[stag2name[stag]] = [klass] continue for tname in [t.strip() for t in row.TNAMES.split(',')]: try: tid = tname2tid[tname] except KeyError: try: badteachers[tname].append((row.CLASS, stag)) except: badteachers[tname] = [(row.CLASS, stag)] continue for klass in classes: try: t2s = table[klass] except: table[klass] = {tid: {sid}} else: try: t2s[tid].add(sid) except: t2s[tid] = {sid} try: k2c = sidtable[sid] except: sidtable[sid] = {klass: {tid}} else: try: k2c[klass].add(tid) except: k2c[klass] = {tid} if badclasses: REPORT.Warn(_UNKNOWN_CLASSES, cname=badclasses) for t, data in badteachers.items(): REPORT.Warn(_BADTNAME, tname=t, data=data) return table, sidtable, tid2tname, badsubjects
def test_02(): pdfBytes = ksSheets(_year, _manager, _date) fpath = Paths.getYearPath(_year, 'FILE_CLASS_REPORT_LISTS') with open(fpath, 'wb') as fh: fh.write(pdfBytes) REPORT.Info("Fach-Lehrer-Zuordnung der Klassen:\n {path}", path=fpath)
def makeAbiTables (schoolyear, klass, date): """Build grade tables (one for each student) for the final Abitur grades. These tables are used to prepare the grades for (automatic) entry into the certificates. The new tables are placed in a subfolder of the normal folder (see configuration file PATHS: FILE_ABITABLE_NEW). This is to avoid accidentally overwriting existing tables which already contain data. Most of the necessary "cleverness" is built into the template file. """ template = Paths.getUserPath ('FILE_ABITUR_GRADE_TEMPLATE') outpath = Paths.getYearPath (schoolyear, 'FILE_ABITABLE_NEW', klass=klass) for f in glob (os.path.join (os.path.dirname (outpath), '*')): os.remove (f) outpath += '.xlsx' sheetname = CONF.TABLES.ABITUR_RESULTS.GRADE_TABLE_SHEET FrHr = {} for v in CONF.TABLES.ABITUR_RESULTS.P_FrHr: k, v = v.split (':') FrHr [k] = v ncourses = CONF.TABLES.ABITUR_RESULTS.NCOURSES.nat () courseTables = CourseTables (schoolyear) pupils = Pupils (schoolyear).classPupils (klass, date) sid2info = courseTables.filterGrades (klass, realonly=True) subjects = [] for sid, sinfo in sid2info.items (): subjects.append ((sid, sinfo.COURSE_NAME)) teacherMatrix = FormattedMatrix.readMatrix (schoolyear, 'FILE_CLASS_SUBJECTS', klass) i = 0 # pid index for ordering files files = [] # list of created files (full paths) for pdata in pupils: pid = pdata ['PID'] pname = pdata.name () i += 1 filepath = outpath.replace ('*', '{pnum:02d}-{pid}-{name}'.format ( pnum=i, pid=pid, name=Paths.asciify (pname))) fields = {'YEAR': str (schoolyear), 'LASTNAME': pdata ['LASTNAME'], 'FIRSTNAMES': pdata ['FIRSTNAMES'], 'DOB_D': pdata ['DOB_D'], 'POB': pdata ['POB'], 'HOME': pdata ['HOME']} try: fields ['FrHr'] = FrHr [pdata ['SEX']] except: REPORT.Error (_BADSEXFIELD, klass=klass, pname=pname, sex=pdata ['SEX']) fields ['FrHr'] = ' ' f = 0 for sid, sname in subjects: if not teacherMatrix [pid][sid]: continue f += 1 fields ['F' + str (f)] = sname.split ('|') [0].rstrip () if ncourses and f != ncourses: REPORT.Error (_NOTNCOURSES, klass=klass, pname=pname, n=f, nc0=ncourses) continue unused = XLS_template (filepath, template, fields, sheetname=sheetname) files.append (filepath) REPORT.Info (_MADENTABLES, klass=klass, n=len (files)) return files