diff --git a/coursebuilder/__main__.py b/coursebuilder/__main__.py index eb3f5bf..beedcb5 100644 --- a/coursebuilder/__main__.py +++ b/coursebuilder/__main__.py @@ -18,48 +18,58 @@ import pandas as pd from tablegenerator import TableGenerator from markdowngenerator import MarkdownGenerator from templategenerator import TemplateGenerator -from converter import Converter +from schema import Schema +from query import Query class CourseBuilder: @staticmethod def generate(args): - if args.schema and args.meta and len(args.fields) > 0: + if args.schema and args.meta: # get actual fields - actual_fields = [] + actual_fields = None # use a file instead of list - if os.path.isfile(args.fields[0]): + if args.fields and os.path.isfile(args.fields[0]): with open(args.fields[0]) as ff: actual_fields = yaml.load(ff,Loader=yaml.Loader)['fields'] else: + # seem we have a list or None actual_fields = args.fields - # get schema - actual_schema = None + schema = None with open(args.schema) as f: - actual_schema = yaml.load(f,Loader=yaml.Loader) + schema = Schema(yaml.load(f,Loader=yaml.Loader)) + + # if no fields are given, take all! + if actual_fields == None: + actual_fields = list(schema.keys()) + + # in case we are running query mode + query = Query(args.query) if args.query else None + + result = [] # iterate through meta files for m in args.meta: with open(m) as fm: - - generator = Converter() - generator.set_schema(actual_schema) meta = yaml.load(fm,Loader=yaml.Loader) - table_items = generator.process(meta=meta,fields=actual_fields,lang=args.lang) + table_items = schema.process(meta=meta,fields=actual_fields,lang=args.lang) if query == None else schema.process_raw(meta=meta,fields=actual_fields,lang=args.lang) if args.legacy: - MarkdownGenerator.generate_table_legacy(table_items=table_items,add_pagebreak=args.pagebreak,title_template=args.title,first_colwidth=args.maxcol) + MarkdownGenerator.generate_table_legacy(table_items=table_items,add_pagebreak=args.pagebreak,title_template=args.title,first_colwidth=args.leftcol) + elif query: + query.run(table_items) else: - MarkdownGenerator.generate_table(table_items=table_items,add_pagebreak=args.pagebreak,title_template=args.title,first_colwidth=args.maxcol) + MarkdownGenerator.generate_table(table_items=table_items,add_pagebreak=args.pagebreak,title_template=args.title,first_colwidth=args.leftcol) - # MarkdownGenerator.generate(table_items,pagebreak=args.pagebreak,title=args.title,header_level=args.level) + + @staticmethod def run(): @@ -71,6 +81,8 @@ class CourseBuilder: parser.add_argument('-l','--lang',help="Language to parse from meta file (use de or en)",default='de') parser.add_argument('-f','--fields',help="Fields to be used, the table will be build accordingly",action="extend", nargs="+", type=str) parser.add_argument('-s','--schema',help="using provided schema") + parser.add_argument('-q','--query',help="compound query to select items") + parser.add_argument('-p','--pagebreak',action="store_true",help="add a pagebreak after each module") parser.add_argument('--title',type=str,default=None,help="template for title - use curly brackets (i.e. {}) to mark where the title string is inserted") parser.add_argument('-b','--book',type=str,help="process a whole curriculum book with sections") @@ -81,7 +93,7 @@ class CourseBuilder: parser.add_argument('--legacy',action="store_true",help="use legacy generator mode for compatibility") - parser.add_argument('--maxcol',type=int,default=28,help='maximum size of left column') + parser.add_argument('--leftcol',type=int,default=28,help='maximum size of left column') # get arguments args = parser.parse_args() @@ -96,11 +108,6 @@ class CourseBuilder: # book mode with predefined setting from a book file if args.book and args.schema: - generator = Converter() - - with open(args.schema) as sf: - generator.set_schema(yaml.load(sf,Loader=yaml.Loader)) - with open(args.book) as bf: actual_fields = [] @@ -109,14 +116,19 @@ class CourseBuilder: book_path = os.path.abspath(args.book) for bi in book['book']: + if 'fields' in bi: actual_fields = bi['fields'] + if 'sections' in bi: for section in bi['sections']: + if 'text' in section: print(section['text'][args.lang]) - if 'modules' in section: + if 'modules' in section: + + # override fields args.fields = actual_fields # expand filenames to be relative to the book diff --git a/coursebuilder/markdowngenerator.py b/coursebuilder/markdowngenerator.py index c765dab..6d45baf 100644 --- a/coursebuilder/markdowngenerator.py +++ b/coursebuilder/markdowngenerator.py @@ -2,8 +2,6 @@ import itertools - - class MarkdownGenerator: @staticmethod @@ -32,7 +30,6 @@ class MarkdownGenerator: if add_pagebreak: print('\\pagebreak') - @staticmethod diff --git a/coursebuilder/query.py b/coursebuilder/query.py new file mode 100644 index 0000000..fab883b --- /dev/null +++ b/coursebuilder/query.py @@ -0,0 +1,13 @@ + +class Query: + + def __init__(self,query) -> None: + self.__query = query + + def run(self,table_items): + # print(table_items) + for row in table_items: + print(row) + # print(eval(self.__query,{row:row})) + pass + diff --git a/coursebuilder/converter.py b/coursebuilder/schema.py similarity index 69% rename from coursebuilder/converter.py rename to coursebuilder/schema.py index 668dab8..78e609a 100644 --- a/coursebuilder/converter.py +++ b/coursebuilder/schema.py @@ -1,13 +1,13 @@ import string -class Converter: +class Schema: - def __init__(self) -> None: - self.__schema = None - - def set_schema(self,schema = None): + def __init__(self,schema) -> None: self.__schema = schema + def keys(self): + return self.__schema.keys() + def get_template(self,field,lang='de'): if 'template' in self.__schema[field]: return self.__schema[field]['template'][lang] @@ -62,7 +62,9 @@ class Converter: t = string.Template(self.get_template(field,lang)) return [self.process_label(field,lang),t.substitute({'value' : v})] + def process_multinum(self,meta,field,lang='de'): + """multinums have various values""" v = meta[field]['value'] t = string.Template(self.get_template(field,lang)) if hasattr(v, "__len__"): @@ -104,8 +106,53 @@ class Converter: case 'int' | 'num' : table_items.append(self.process_num(meta,field,lang)) case 'multinum' : table_items.append(self.process_multinum(meta,field,lang)) case 'multikey': table_items.append(self.process_multikey(meta,field,lang)) + case _: raise ValueError except Exception as exp: print(field,' not resolvable in ',self.__schema,exp) # maybe return tableitems as np.Dataframe? - return table_items \ No newline at end of file + return table_items + + def get_str(self,meta,field,lang='de'): + if self.is_translatable(field): + return meta[field][lang] + else: + if not 'value' in meta[field]: + raise AssertionError(field,'incomplete') + return meta[field]['value'] + + def get_enum(self,meta,field,lang): + vv = meta[field]['value'] + return self.__schema[field]['values'][vv][lang] + + # if self.needs_spec(field): + + # t = string.Template(self.get_template(field=field,lang=lang)) + + # spec = meta[field]['spec'][lang] + + # return [self.process_label(field,lang),t.substitute({'value': enum_val,'spec': spec})] + # else: + # return [self.process_label(field,lang),enum_val] + + + + def get_value(self,meta,field,lang): + match self.__schema[field]['type']: + case 'str': return self.get_str(meta,field,lang) + case 'enum': return self.get_enum(meta,field,lang) + + + def process_raw(self,meta,fields,lang): + + items = [{'field' : field, + 'lang' : lang, + 'type' : self.__schema[field]['type'], + 'label' : self.process_label(field,lang), + 'value' : self.get_value(meta,field,lang) + } + for field in fields] + + + # maybe return tableitems as np.Dataframe? + return items \ No newline at end of file diff --git a/test/Makefile b/test/Makefile index 73a600a..c806cc2 100644 --- a/test/Makefile +++ b/test/Makefile @@ -6,7 +6,7 @@ target_de_book := ${build_dir}/curricullum.de.pdf targets := ${target_de} ${target_en} ${target_de_book} -target_flags := --template pandoc-template/eisvogel.latex +target_flags := --template pandoc-template/eisvogel.latex -V table-use-row-colors:true coursebuilder := ../coursebuilder @@ -22,6 +22,8 @@ ${target_de}: mkdir -p ${build_dir} python ${coursebuilder} -s schema.yaml -m mod.cg.yaml -l de -f fields.yaml | pandoc ${target_flags} -o ${target_de} +${target_de_book}: + python ${coursebuilder} -s schema.yaml -b book.yaml -p --title "### {}" -l de --leftcol 36 | pandoc ${target_flags} -V lang:de -o ${target_de_book} clean: rm -f ${targets} @@ -30,9 +32,7 @@ debug: python ${coursebuilder} -s schema.yaml -m mod.cg.yaml mod.interactsys.yaml mod.test.yaml -p --title "## {}" -l de -f name credits goal content # | pandoc ${target_flags} -V lang:de -o ${target_de} - -debug-book: - python ${coursebuilder} -s schema.yaml -b book.yaml -p --title "### {}" -l de --legacy | pandoc ${target_flags} -V lang:de -o ${target_de_book} - +debug-query: + python ${coursebuilder} -s schema.yaml -m mod.cg.yaml mod.interactsys.yaml -q "kind == compulsory" .PHONY: clean \ No newline at end of file diff --git a/test/book.yaml b/test/book.yaml index 38011e9..5dc7188 100644 --- a/test/book.yaml +++ b/test/book.yaml @@ -4,8 +4,9 @@ # book: - - fields: - - name + - fields: + - name + - instructor - id - goal - content @@ -36,3 +37,18 @@ book: - mod.test.yaml +# +# tables +# +query: + list-credits-and-workload: + - fields: + - name + - credits + - workload + +# just for ideas +regulations: + - globals: + - course_name: Applied Computer Science (M.Sc.) + \ No newline at end of file diff --git a/test/fields.yaml b/test/fields.yaml index bede013..28aef14 100644 --- a/test/fields.yaml +++ b/test/fields.yaml @@ -1,5 +1,6 @@ fields: - - name + - name + - instructor - id - goal - content diff --git a/test/mod.cg.yaml b/test/mod.cg.yaml index e5b4201..1b614ab 100644 --- a/test/mod.cg.yaml +++ b/test/mod.cg.yaml @@ -2,6 +2,9 @@ name: de: Computergrafik en: Computer Graphics +instructor: + de: Prof. Hartmut Seichter, PhD + en: Prof. Hartmut Seichter, PhD id: value: CG diff --git a/test/mod.test.yaml b/test/mod.test.yaml index c70d8ca..bdfb4f3 100644 --- a/test/mod.test.yaml +++ b/test/mod.test.yaml @@ -2,6 +2,9 @@ name: de: Test Vorlesung en: Lecture of Test +instructor: + de: Cicero + en: Cicero id: value: Test diff --git a/test/schema.yaml b/test/schema.yaml index e38783c..fde6931 100644 --- a/test/schema.yaml +++ b/test/schema.yaml @@ -15,9 +15,8 @@ name: # instructor: type: str - translatable: false label: - de: "Modulverantwortlicher/Modulverantwortliche" + de: "Modulverantwortlicher / Modulverantwortliche" en: "module instructor" @@ -196,11 +195,11 @@ credits: # Leistungsnachweis # form-of-exam: + type: enum label: { de: "Leistungsnachweis", en: "form of examination" } - type: enum values: { 'written' : { de: "Schriftliche Prüfung", @@ -225,28 +224,28 @@ form-of-exam: # Semester # term: + type: multinum label: { de: "Semester", en: "term" } - type: multinum template: - de: " ${value}. Semester" - en: " ${value}. semester" + de: " ${value}\\. Semester" + en: " ${value}\\. semester" # # Häufigkeit des Angebots # frequency: + type: enum label: { de: "Häufigkeit des Angebots", en: "frequency of Offer" } - type: "enum" values: { 'once_per_term' : { de: "jedes Semester", - en: "every term" + en: "every semester" }, 'once_per_year' : { de: "einmal im Studienjahr", @@ -254,6 +253,9 @@ frequency: } } +# +# Dauer des Angebots +# duration: type: int label: @@ -263,6 +265,9 @@ duration: de: "$value Semester" en: "$value term(s)" +# +# Art der Veranstaltung +# kind: type: enum label: { @@ -280,6 +285,9 @@ kind: } } +# +# Freiform Bemerkungen +# remarks: type: str label: {