WIP
This commit is contained in:
parent
2e1490d98f
commit
1d00963035
4 changed files with 411 additions and 361 deletions
|
@ -10,10 +10,6 @@ import yaml
|
||||||
from coursebuilder.schema import Schema
|
from coursebuilder.schema import Schema
|
||||||
|
|
||||||
|
|
||||||
class LanguageSelector:
|
|
||||||
context_lang: str
|
|
||||||
|
|
||||||
|
|
||||||
class Course:
|
class Course:
|
||||||
i18n_name: str = "lang.{}.yaml"
|
i18n_name: str = "lang.{}.yaml"
|
||||||
mod_name: str = "mod.yaml"
|
mod_name: str = "mod.yaml"
|
||||||
|
@ -28,19 +24,19 @@ class Course:
|
||||||
for p in path.parent.glob(Course.i18n_name.format("*"))
|
for p in path.parent.glob(Course.i18n_name.format("*"))
|
||||||
}
|
}
|
||||||
|
|
||||||
def validate(self, *, schema: Schema, lang: str) -> None:
|
|
||||||
print(self.__data)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __getitem__(self, name: str, /) -> Any:
|
def __getitem__(self, name: str, /) -> Any:
|
||||||
return (
|
"""this overload magic function takes a key and a language code like my_key.en or my_key.de"""
|
||||||
self.__data[name]
|
s = name.split(".")
|
||||||
if name in self.__data.keys()
|
|
||||||
else self.__i18n[LanguageSelector.context_lang][name]
|
|
||||||
)
|
|
||||||
|
|
||||||
def __getattr__(self, name: str, /) -> Any:
|
if len(s) != 2:
|
||||||
return self.__data[name]
|
raise ValueError(
|
||||||
|
"query with item selector requires form ['key.lang'] alternative is ['key.*']"
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
self.__i18n[s[-1]][s[0]]
|
||||||
|
if s[-1] in self.__i18n.keys() and s[0] in self.__i18n[s[-1]].keys()
|
||||||
|
else self.__data[s[0]]
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"data:{self.__data}\ni18n:{self.__i18n}"
|
return f"data:{self.__data}\ni18n:{self.__i18n}"
|
||||||
|
@ -83,22 +79,52 @@ def main():
|
||||||
type=str,
|
type=str,
|
||||||
help="schema to validate against",
|
help="schema to validate against",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--fields",
|
||||||
|
help="Fields to be used, the table will be build accordingly",
|
||||||
|
action="extend",
|
||||||
|
nargs="+",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-c",
|
||||||
|
"--create",
|
||||||
|
help="Fields to be used, the table will be build accordingly",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
|
||||||
# get arguments
|
# get arguments
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# just input
|
# with input
|
||||||
if args.input and args.schema:
|
if args.input and args.schema:
|
||||||
with open(args.schema) as f_schema:
|
with open(args.schema) as f_schema:
|
||||||
schema = Schema(schema=yaml.load(f_schema, Loader=yaml.Loader))
|
schema = Schema(schema=yaml.load(f_schema, Loader=yaml.Loader)) # Schema
|
||||||
sc = StudyCourse(path=(Path(".") / args.input).absolute())
|
sc = StudyCourse(path=(Path(".") / args.input).absolute()) # Database
|
||||||
|
|
||||||
LanguageSelector.context_lang = "de"
|
actual_fields = args.fields if args.fields else schema.keys()
|
||||||
|
|
||||||
for k in schema.keys():
|
for field in actual_fields:
|
||||||
print(k)
|
for lang in sc.languages:
|
||||||
for shortcode, course in sc.courses.items():
|
for shortcode, course in sc.courses.items():
|
||||||
print(course[k])
|
print(
|
||||||
|
field,
|
||||||
|
"@",
|
||||||
|
shortcode,
|
||||||
|
".",
|
||||||
|
lang,
|
||||||
|
"\n",
|
||||||
|
course[f"{field}.{lang}"],
|
||||||
|
)
|
||||||
|
|
||||||
|
elif args.schema and args.create:
|
||||||
|
schema = Schema(
|
||||||
|
schema=yaml.load(open(args.schema), Loader=yaml.Loader)
|
||||||
|
) # Schema
|
||||||
|
print(schema.fields())
|
||||||
|
print(schema.types())
|
||||||
|
print(schema.facets())
|
||||||
|
|
||||||
|
|
||||||
# run as main
|
# run as main
|
||||||
|
|
|
@ -1,142 +1,159 @@
|
||||||
class Schema:
|
class Schema:
|
||||||
|
__yes_vals: list[str] = ["true", "yes", "on"]
|
||||||
|
|
||||||
|
__unique: str = "unique"
|
||||||
|
__spec: str = "spec"
|
||||||
|
__facets: str = "facets"
|
||||||
|
__fields: str = "fields"
|
||||||
|
__type: str = "type"
|
||||||
|
__label: str = "label"
|
||||||
|
|
||||||
def __init__(self, *, schema: dict) -> None:
|
def __init__(self, *, schema: dict) -> None:
|
||||||
self.__schema = schema
|
self.__schema = schema
|
||||||
|
|
||||||
def __getitem__(self, field):
|
def facets(self) -> list[str]:
|
||||||
return self.__schema[field]
|
return list(self.__schema[Schema.__facets])
|
||||||
|
|
||||||
def keys(self):
|
def fields(self) -> list[str]:
|
||||||
return self.__schema.keys()
|
return list(self.__schema[Schema.__fields].keys())
|
||||||
|
|
||||||
def is_translatable(self, field):
|
def types(self) -> dict:
|
||||||
if "translatable" in self.__schema[field]:
|
return {
|
||||||
return self.__schema[field]["translatable"]
|
field: a[Schema.__type]
|
||||||
else:
|
for field, a in self.__schema[Schema.__fields].items()
|
||||||
return True
|
}
|
||||||
|
|
||||||
def needs_spec(self, field):
|
def is_unique(self, field: str) -> bool:
|
||||||
if "spec" in self.__schema[field]:
|
|
||||||
return self.__schema[field]
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_value(self, meta: dict, field: str, lang: str):
|
|
||||||
"""
|
|
||||||
treats receiving the value like a variant,
|
|
||||||
returns values with their language specific representations
|
|
||||||
"""
|
|
||||||
match self.__schema[field]["type"]:
|
|
||||||
case "str":
|
|
||||||
return (
|
return (
|
||||||
meta[field][lang]
|
Schema.__yes_vals in self.__schema[field][Schema.__unique].lower()
|
||||||
if self.is_translatable(field)
|
if Schema.__unique in self.__schema[field].keys()
|
||||||
else meta[field]["value"]
|
else True
|
||||||
)
|
)
|
||||||
case "enum" | "int" | "num" | "multikey":
|
|
||||||
return meta[field]["value"]
|
def needs_spec(self, field: str) -> bool:
|
||||||
case "multinum":
|
|
||||||
return (
|
return (
|
||||||
meta[field]["value"]
|
Schema.__yes_vals in self.__schema[field][Schema.__spec].lower()
|
||||||
if hasattr(meta[field]["value"], "__iter__")
|
if Schema.__spec in self.__schema[field].keys()
|
||||||
else [
|
else False
|
||||||
meta[field]["value"],
|
|
||||||
]
|
|
||||||
) # force list!
|
|
||||||
|
|
||||||
def to_list_of_dict(self, meta, fields, lang):
|
|
||||||
"""
|
|
||||||
generates a list of dict which can easily be converted
|
|
||||||
to a pandas dataframe
|
|
||||||
"""
|
|
||||||
# list comprehension for rows
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
"field": field, # field name
|
|
||||||
"lang": lang, # language shortcode
|
|
||||||
"type": self.__schema[field]["type"], # datatype
|
|
||||||
"label": self.__schema[field]["label"][lang], # label
|
|
||||||
"value": self.get_value(meta, field, lang), # actual value
|
|
||||||
"template": self.__schema[field]["template"][lang]
|
|
||||||
if "template" in self.__schema[field]
|
|
||||||
else None,
|
|
||||||
# getting crazy with nested dict comprehension
|
|
||||||
"enum_values": {
|
|
||||||
k: v[lang] for (k, v) in self.__schema[field]["values"].items()
|
|
||||||
}
|
|
||||||
if "enum" in self.__schema[field]["type"]
|
|
||||||
else None,
|
|
||||||
"key_values": {
|
|
||||||
k: v[lang] for (k, v) in self.__schema[field]["keys"].items()
|
|
||||||
}
|
|
||||||
if "multikey" in self.__schema[field]["type"]
|
|
||||||
else None,
|
|
||||||
"spec": meta[field]["spec"][lang] if "spec" in meta[field] else None,
|
|
||||||
}
|
|
||||||
for field in fields
|
|
||||||
]
|
|
||||||
|
|
||||||
def to_short_dict(self, meta, fields, lang):
|
|
||||||
"""
|
|
||||||
generates a short version of dict which can easily be converted
|
|
||||||
to a pandas dataframe
|
|
||||||
"""
|
|
||||||
# dict comprehension for whole meta part
|
|
||||||
return {field: self.get_value(meta, field, lang) for field in fields}
|
|
||||||
|
|
||||||
def to_list_of_tuple(self, meta, fields, lang):
|
|
||||||
"""
|
|
||||||
generates a list of tuples with a label and value (text)
|
|
||||||
this is usually consumed by a Markdown generator
|
|
||||||
|
|
||||||
todo: needs deuglyfication of free standing loop, templates are possible for all
|
|
||||||
"""
|
|
||||||
list = []
|
|
||||||
for r in self.to_list_of_dict(meta, fields, lang):
|
|
||||||
match r["type"]:
|
|
||||||
case "str":
|
|
||||||
list.append((r["label"], r["value"]))
|
|
||||||
case "int" | "num":
|
|
||||||
list.append(
|
|
||||||
(
|
|
||||||
r["label"],
|
|
||||||
r["template"].format(value=r["value"], spec=r["spec"])
|
|
||||||
if r["template"]
|
|
||||||
else r["value"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
case "enum":
|
|
||||||
list.append(
|
|
||||||
(
|
|
||||||
r["label"],
|
|
||||||
r["template"].format(
|
|
||||||
value=r["enum_values"][r["value"]], spec=r["spec"]
|
|
||||||
)
|
|
||||||
if r["template"]
|
|
||||||
else r["enum_values"][r["value"]],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
case "multikey":
|
|
||||||
list.append(
|
|
||||||
(
|
|
||||||
r["label"],
|
|
||||||
", ".join(
|
|
||||||
[
|
|
||||||
r["template"].format(
|
|
||||||
key=r["key_values"][k], value=v
|
|
||||||
)
|
|
||||||
for k, v in r["value"].items()
|
|
||||||
]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
case "multinum":
|
|
||||||
list.append(
|
|
||||||
(
|
|
||||||
r["label"],
|
|
||||||
", ".join(
|
|
||||||
r["template"].format(value=v) for v in r["value"]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return list
|
# def get_value(self, meta: dict, field: str, lang: str):
|
||||||
|
# """
|
||||||
|
# treats receiving the value like a variant,
|
||||||
|
# returns values with their language specific representations
|
||||||
|
# """
|
||||||
|
# match self.__schema[field]["type"]:
|
||||||
|
# case "str":
|
||||||
|
# return (
|
||||||
|
# meta[field][lang]
|
||||||
|
# if self.is_translatable(field)
|
||||||
|
# else meta[field]["value"]
|
||||||
|
# )
|
||||||
|
# case "enum" | "int" | "num" | "multikey":
|
||||||
|
# return meta[field]["value"]
|
||||||
|
# case "multinum":
|
||||||
|
# return (
|
||||||
|
# meta[field]["value"]
|
||||||
|
# if hasattr(meta[field]["value"], "__iter__")
|
||||||
|
# else [
|
||||||
|
# meta[field]["value"],
|
||||||
|
# ]
|
||||||
|
# ) # force list!
|
||||||
|
|
||||||
|
# def to_list_of_dict(self, meta, fields, lang):
|
||||||
|
# """
|
||||||
|
# generates a list of dict which can easily be converted
|
||||||
|
# to a pandas dataframe
|
||||||
|
# """
|
||||||
|
# # list comprehension for rows
|
||||||
|
# return [
|
||||||
|
# {
|
||||||
|
# "field": field, # field name
|
||||||
|
# "lang": lang, # language shortcode
|
||||||
|
# "type": self.__schema[field]["type"], # datatype
|
||||||
|
# "label": self.__schema[field]["label"][lang], # label
|
||||||
|
# "value": self.get_value(meta, field, lang), # actual value
|
||||||
|
# "template": self.__schema[field]["template"][lang]
|
||||||
|
# if "template" in self.__schema[field]
|
||||||
|
# else None,
|
||||||
|
# # getting crazy with nested dict comprehension
|
||||||
|
# "enum_values": {
|
||||||
|
# k: v[lang] for (k, v) in self.__schema[field]["values"].items()
|
||||||
|
# }
|
||||||
|
# if "enum" in self.__schema[field]["type"]
|
||||||
|
# else None,
|
||||||
|
# "key_values": {
|
||||||
|
# k: v[lang] for (k, v) in self.__schema[field]["keys"].items()
|
||||||
|
# }
|
||||||
|
# if "multikey" in self.__schema[field]["type"]
|
||||||
|
# else None,
|
||||||
|
# "spec": meta[field]["spec"][lang] if "spec" in meta[field] else None,
|
||||||
|
# }
|
||||||
|
# for field in fields
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# def to_short_dict(self, meta, fields, lang):
|
||||||
|
# """
|
||||||
|
# generates a short version of dict which can easily be converted
|
||||||
|
# to a pandas dataframe
|
||||||
|
# """
|
||||||
|
# # dict comprehension for whole meta part
|
||||||
|
# return {field: self.get_value(meta, field, lang) for field in fields}
|
||||||
|
|
||||||
|
# def to_list_of_tuple(self, meta, fields, lang):
|
||||||
|
# """
|
||||||
|
# generates a list of tuples with a label and value (text)
|
||||||
|
# this is usually consumed by a Markdown generator
|
||||||
|
|
||||||
|
# todo: needs deuglyfication of free standing loop, templates are possible for all
|
||||||
|
# """
|
||||||
|
# list = []
|
||||||
|
# for r in self.to_list_of_dict(meta, fields, lang):
|
||||||
|
# match r["type"]:
|
||||||
|
# case "str":
|
||||||
|
# list.append((r["label"], r["value"]))
|
||||||
|
# case "int" | "num":
|
||||||
|
# list.append(
|
||||||
|
# (
|
||||||
|
# r["label"],
|
||||||
|
# r["template"].format(value=r["value"], spec=r["spec"])
|
||||||
|
# if r["template"]
|
||||||
|
# else r["value"],
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# case "enum":
|
||||||
|
# list.append(
|
||||||
|
# (
|
||||||
|
# r["label"],
|
||||||
|
# r["template"].format(
|
||||||
|
# value=r["enum_values"][r["value"]], spec=r["spec"]
|
||||||
|
# )
|
||||||
|
# if r["template"]
|
||||||
|
# else r["enum_values"][r["value"]],
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# case "multikey":
|
||||||
|
# list.append(
|
||||||
|
# (
|
||||||
|
# r["label"],
|
||||||
|
# ", ".join(
|
||||||
|
# [
|
||||||
|
# r["template"].format(
|
||||||
|
# key=r["key_values"][k], value=v
|
||||||
|
# )
|
||||||
|
# for k, v in r["value"].items()
|
||||||
|
# ]
|
||||||
|
# ),
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# case "multinum":
|
||||||
|
# list.append(
|
||||||
|
# (
|
||||||
|
# r["label"],
|
||||||
|
# ", ".join(
|
||||||
|
# r["template"].format(value=v) for v in r["value"]
|
||||||
|
# ),
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
|
# return list
|
||||||
|
|
|
@ -13,8 +13,7 @@ credits: 5
|
||||||
form-of-exam:
|
form-of-exam:
|
||||||
type: alternative
|
type: alternative
|
||||||
|
|
||||||
duration:
|
duration: 1
|
||||||
value: 1
|
|
||||||
|
|
||||||
author-of-indenture:
|
author-of-indenture:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
# fields in curricular description
|
facets: ["de", "en"]
|
||||||
# leaning on methods in OpenAPI 3.0
|
|
||||||
|
|
||||||
|
templates:
|
||||||
|
name:
|
||||||
|
de: Modulname {value}
|
||||||
|
en: name of course {value}
|
||||||
|
|
||||||
|
fields:
|
||||||
|
#
|
||||||
|
# Kürzel / ID
|
||||||
|
#
|
||||||
|
id:
|
||||||
|
type: str
|
||||||
|
translatable: false
|
||||||
|
label: { de: "Kürzel", en: "code" }
|
||||||
#
|
#
|
||||||
# Modulname
|
# Modulname
|
||||||
#
|
#
|
||||||
|
@ -19,14 +31,6 @@ instructor:
|
||||||
de: "Modulverantwortlicher / Modulverantwortliche"
|
de: "Modulverantwortlicher / Modulverantwortliche"
|
||||||
en: "module instructor"
|
en: "module instructor"
|
||||||
|
|
||||||
#
|
|
||||||
# Kürzel / ID
|
|
||||||
#
|
|
||||||
id:
|
|
||||||
type: str
|
|
||||||
translatable: false
|
|
||||||
label: { de: "Kürzel", en: "code" }
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Qualifikationsziele
|
# Qualifikationsziele
|
||||||
#
|
#
|
||||||
|
@ -77,10 +81,14 @@ form-of-instruction:
|
||||||
{
|
{
|
||||||
"lecture": { de: "Vorlesung", en: "lecture" },
|
"lecture": { de: "Vorlesung", en: "lecture" },
|
||||||
"lecture_seminar":
|
"lecture_seminar":
|
||||||
{ de: "Seminaristische Vorlesung", en: "lecture and seminar" },
|
{
|
||||||
|
de: "Seminaristische Vorlesung",
|
||||||
|
en: "lecture and seminar",
|
||||||
|
},
|
||||||
"seminar": { de: "Seminar", en: "seminar" },
|
"seminar": { de: "Seminar", en: "seminar" },
|
||||||
"exersise": { de: "Übung", en: "lab exersise" },
|
"exersise": { de: "Übung", en: "lab exersise" },
|
||||||
"pc_lab": { de: "Rechnergestütztes Praktikum", en: "PC exersise" },
|
"pc_lab":
|
||||||
|
{ de: "Rechnergestütztes Praktikum", en: "PC exersise" },
|
||||||
"project": { de: "Project", en: "project" },
|
"project": { de: "Project", en: "project" },
|
||||||
}
|
}
|
||||||
template:
|
template:
|
||||||
|
@ -210,18 +218,18 @@ form-of-exam:
|
||||||
#
|
#
|
||||||
# Art der Veranstaltung
|
# Art der Veranstaltung
|
||||||
#
|
#
|
||||||
kind:
|
# kind:
|
||||||
type: enum
|
# type: enum
|
||||||
label:
|
# label:
|
||||||
{
|
# {
|
||||||
de: "Art der Veranstaltung (Pflicht, Wahl, etc.)",
|
# de: "Art der Veranstaltung (Pflicht, Wahl, etc.)",
|
||||||
en: "kind of module (compulsory, elective)",
|
# en: "kind of module (compulsory, elective)",
|
||||||
}
|
# }
|
||||||
values:
|
# values:
|
||||||
{
|
# {
|
||||||
"compulsory": { de: "Pflicht", en: "compulsory" },
|
# "compulsory": { de: "Pflicht", en: "compulsory" },
|
||||||
"elective": { de: "Wahl/Wahlpflicht", en: "elective" },
|
# "elective": { de: "Wahl/Wahlpflicht", en: "elective" },
|
||||||
}
|
# }
|
||||||
|
|
||||||
#
|
#
|
||||||
# Freiform Bemerkungen
|
# Freiform Bemerkungen
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue