def tSheets(schoolyear, manager, date): courses = CourseTables(schoolyear) tidmap = {} for k in courses.classes(): klass = Klass(k) sid2tids = courses.filterText(klass) for sid, tids in sid2tids.items(): if tids.TEXT: if not tids: tids = [_nn] for tid in tids: try: tmap = tidmap[tid] except: tidmap[tid] = {klass.klass: {sid}} continue try: tmap[klass.klass].add(sid) except: tmap[klass.klass] = {sid} noreports = [] teachers = [] for tid in courses.teacherData: lines = [] tname = courses.teacherData.getTeacherName(tid) try: tmap = tidmap[tid] except: noreports.append(tname) continue for k in sorted(tmap): for sid in tmap[k]: sname = courses.subjectName(sid) lines.append((k, sname)) teachers.append((tname, lines)) tpdir = Paths.getUserPath('DIR_TEXT_REPORT_TEMPLATES') templateLoader = jinja2.FileSystemLoader(searchpath=tpdir) templateEnv = jinja2.Environment(loader=templateLoader, autoescape=True) tpfile = 'summary-teachers.html' try: template = templateEnv.get_template(tpfile) except: REPORT.Fail(_NOTEMPLATE, path=os.path.join(tpdir, tpfile)) source = template.render(year=printSchoolYear(schoolyear), manager=manager, date=Dates.dateConv(date), teachers=teachers, noreports=noreports) html = HTML(string=source) pdfBytes = html.write_pdf() return pdfBytes
def choiceTable(schoolyear, klass): """Build a subject choice table for the given school-class. <klass> is a <Klass> instance. """ template = Paths.getUserPath('FILE_SUBJECT_CHOICE_TEMPLATE') table = KlassMatrix(template) # Title already set in template: #table.setTitle("Kurswahl") # "Translation" of info items: kmap = CONF.TABLES.COURSE_PUPIL_FIELDNAMES info = ( (kmap['SCHOOLYEAR'], str(schoolyear)), (kmap['CLASS'], klass.klass), ) table.setInfo(info) ### Manage subjects courses = CourseTables(schoolyear) sid2tlist = courses.classSubjects(klass) # <table.headers> is a list of cell values in the header row. rsid = table.rowindex - 1 # row tag for sid rsname = table.rowindex # row tag for subject name # Go through the template columns and check if they are needed: for sid in sid2tlist: if sid[0] != '_': sname = courses.subjectName(sid) # Add subject col = table.nextcol() table.write(rsid, col, sid) table.write(rsname, col, sname) # Delete excess columns table.delEndCols(col + 1) ### Add pupils pupils = Pupils(schoolyear) for pdata in pupils.classPupils(klass): row = table.nextrow() table.write(row, 0, pdata['PID']) table.write(row, 1, pdata.name()) table.write(row, 2, pdata['STREAM']) # Delete excess rows table.delEndRows(row + 1) ### Save file table.protectSheet() return table.save()
def ksSheets(schoolyear, manager, date): courses = CourseTables(schoolyear) tidmap = { tid: courses.teacherData.getTeacherName(tid) for tid in courses.teacherData } klasses = [] for k in courses.classes(): klass = Klass(k) sidmap = {} sid2tids = courses.filterText(klass) for sid, tids in sid2tids.items(): if tids.TEXT: if not tids: tids = [_nn] for tid in tids: try: sidmap[sid].add(tid) except: sidmap[sid] = {tid} lines = [] for sid, tids in sidmap.items(): sname = courses.subjectName(sid) for tid in tids: lines.append((sname, tidmap[tid])) klasses.append((klass.klass, lines)) tpdir = Paths.getUserPath('DIR_TEXT_REPORT_TEMPLATES') templateLoader = jinja2.FileSystemLoader(searchpath=tpdir) templateEnv = jinja2.Environment(loader=templateLoader, autoescape=True) tpfile = 'summary-classes.html' try: template = templateEnv.get_template(tpfile) except: REPORT.Fail(_NOTEMPLATE, path=os.path.join(tpdir, tpfile)) source = template.render(year=printSchoolYear(schoolyear), manager=manager, date=Dates.dateConv(date), klasses=klasses) html = HTML(string=source) pdfBytes = html.write_pdf() return pdfBytes
def stripTable(schoolyear, term, klass, title): """Build a basic pupil/subject table for entering grades. <klass> is a <Klass> instance. <term> is a string. """ # Info concerning grade tables: gtinfo = CONF.GRADES.GRADE_TABLE_INFO ### Determine table template (output) t = klass.match_map(gtinfo.GRADE_INPUT_TEMPLATE) if not t: REPORT.Fail(_NO_ITEMPLATE, ks=klass) template = Paths.getUserPath('FILE_GRADE_TABLE_TEMPLATE').replace('*', t) table = KlassMatrix(template) table.setTitle(title) table.setInfo([]) ### Read input table template (for determining subjects and order) # Determine table template (input) t = klass.match_map(gtinfo.GRADE_TABLE_TEMPLATE) if not t: REPORT.Fail(_NO_TEMPLATE, ks=klass) template0 = Paths.getUserPath('FILE_GRADE_TABLE_TEMPLATE').replace('*', t) table0 = KlassMatrix(template0) i, x = 0, 0 for row0 in table0.rows: i += 1 if row0[0] and row0[0] != '#': # The subject key line break # <row0> is the title row. ### Manage subjects courses = CourseTables(schoolyear) sid2tlist = courses.classSubjects(klass) # print ("???1", list(sid2tlist)) # Set klass cell rowix = table.rowindex - 1 table.write(rowix, 0, table.headers[0].replace('*', klass.klass)) # Go through the template columns and check if they are needed: col = 0 for sid in row0: if sid and sid[0] != '_' and sid in sid2tlist: sname = courses.subjectName(sid) # Add subject col = table.nextcol() table.write(rowix, col, sname) # Delete excess columns table.delEndCols(col + 1) ### Add pupils pupils = Pupils(schoolyear) for pdata in pupils.classPupils(klass): row = table.nextrow() table.write(row, 0, pdata.name()) table.write(row, 1, pdata['STREAM']) # Delete excess rows table.delEndRows(row + 1) ### Save file table.protectSheet() return table.save()
class GradeReportData: """Manage data connected with a school-class, stream and report type. When referring to old report data, bear in mind that a pupil's stream, or even school-class, may have changed. The grade data includes the class and stream associated with the data. """ def __init__(self, schoolyear, rtype, klass): """<rtype> is the report type, a key to the mapping GRADE.REPORT_TEMPLATES. <klass> is a <Klass> object, which may include stream tags. All streams passed in must map to the same template. """ self.schoolyear = schoolyear self.klassdata = klass ### Set up categorized, ordered lists of grade fields for insertion ### in a report template. # If there is a list of streams in <klass> this will probably # only match '*' in the template mapping: self.template = getGradeTemplate(rtype, klass) self.alltags = getTemplateTags(self.template) # Extract grade-entry tags, i.e. those matching <str>_<int>: gtags = {} # {subject group -> [(unsorted) index<int>, ...]} for tag in self.alltags: try: _group, index = tag.split('_') group = _group.split('.')[-1] i = int(index) except: continue try: gtags[group].append(i) except: gtags[group] = [i] # Build a sorted mapping of index lists: # {subject group -> [(reverse sorted) index<int>, ...]} # The reversal is for popping in correct order. self.sgroup2indexes = {group: sorted(gtags[group], reverse=True) for group in gtags} # print("\n??? self.alltags", self.alltags) # print("\n??? self.sgroup2indexes", self.sgroup2indexes) ### Sort the subject tags into ordered groups self.courses = CourseTables(schoolyear) subjects = self.courses.filterGrades(klass) # Build a mapping: {subject group -> [(ordered) sid, ...]} self.sgroup2sids = {} for group in self.sgroup2indexes: sidlist = [] self.sgroup2sids[group] = sidlist # CONF.GRADES.ORDERING: {subject group -> [(ordered) sid, ...]} for sid in CONF.GRADES.ORDERING[group]: # Include only sids relevant for the klass. try: del(subjects[sid]) sidlist.append(sid) except: pass # Entries remaining in <subjects> are not covered in ORDERING. for sid in subjects: REPORT.Error(_UNGROUPED_SID, sid=sid, tfile=self.template.filename) def getTagmap(self, grades, pname, grademap='GRADES'): """Prepare tag mapping for substitution in the report template, for the pupil <pname>. <grades> is a mapping {sid -> grade}, or something similar which can be handled by <dict(grades)>. <grademap> is the name of a configuration file (in 'GRADES') providing a grade -> text mapping. Grouped subjects expected by the template get two entries: one for the subject name and one for the grade. They are allocated according to the numbered slots defined for the predefined ordering (config: GRADES/ORDERING). "Grade" entries whose tag begins with '_' and which are not covered by the data in GRADES/ORDERING are copied directly to the output mapping. Return a mapping {template tag -> replacement text}. """ tagmap = {} # for the result g2text = CONF.GRADES[grademap] # grade -> text representation # Copy the grade mapping, because it will be modified to keep # track of unused grade entries: gmap = dict(grades) # this accepts a variety of input types for group, sidlist in self.sgroup2sids.items(): # Copy the indexes because the list is modified here (<pop()>) indexes = self.sgroup2indexes[group].copy() for sid in sidlist: try: g = gmap.pop(sid) except: REPORT.Error(_MISSING_GRADE, pname=pname, sid=sid) g = '?' if g == _INVALID: continue try: i = indexes.pop() except: REPORT.Fail(_TOO_MANY_SUBJECTS, group=group, pname=pname, sids=repr(sidlist), template=self.template.filename) sname = self.courses.subjectName(sid).split('|')[0].rstrip() tagmap["%s_%d_N" % (group, i)] = sname g1 = g2text.get(g) if not g1: REPORT.Error(_NO_MAPPED_GRADE, grade=g) g1 = '?' tagmap["%s_%d" % (group, i)] = g1 # Process superfluous indexes for i in indexes: tagmap["%s_%d_N" % (group, i)] = g2text.NONE tagmap["%s_%d" % (group, i)] = g2text.NONE # Report unused grade entries unused = [] for sid, g in gmap.items(): if g == _INVALID: continue if sid[0] == '_': tagmap[sid] = g else: unused.append("%s: %s" % (sid, g)) if unused: REPORT.Error(_UNUSED_GRADES, pname=pname, grades="; ".join(unused)) return tagmap