use context to hold commonly used instances

This commit is contained in:
Emi Vasilek 2023-11-05 11:05:23 +01:00
parent 2e12ab77a5
commit 2bb9aed4a3

View file

@ -4,6 +4,11 @@ import os
import yaml import yaml
import jinja2 import jinja2
class Context:
def __init__(self) -> None:
self.units = Units()
self.ingredients = Ingredients(self)
class Unit: class Unit:
def __init__(self, name: str) -> None: def __init__(self, name: str) -> None:
@ -29,6 +34,8 @@ class Units:
class Ingredient: class Ingredient:
def __init__(self, ctx: Context) -> None:
self.ctx = ctx
def load(self, dct: Dict[str, Any]) -> List[str]: def load(self, dct: Dict[str, Any]) -> List[str]:
issues = [] issues = []
issues += assert_dict(dct, ["name"], ["wdid", "pricedb", "aliases"]) issues += assert_dict(dct, ["name"], ["wdid", "pricedb", "aliases"])
@ -44,7 +51,7 @@ class Ingredient:
self.pricedb = None self.pricedb = None
if "pricedb" in dct: if "pricedb" in dct:
assert_list(dct["pricedb"]) assert_list(dct["pricedb"])
self.pricedb = PriceDBs() self.pricedb = PriceDBs(self.ctx)
issues += self.pricedb.load(dct["pricedb"]) issues += self.pricedb.load(dct["pricedb"])
self.aliases = [] self.aliases = []
@ -58,14 +65,15 @@ class Ingredient:
class Ingredients: class Ingredients:
def __init__(self) -> None: def __init__(self, ctx: Context) -> None:
self.ctx = ctx
self.ingredients: List[Ingredient] = [] self.ingredients: List[Ingredient] = []
def load(self, lst: List[Any]) -> List[str]: def load(self, lst: List[Any]) -> List[str]:
issues = [] issues = []
assert_list(lst) assert_list(lst)
for ingdct in lst: for ingdct in lst:
ing = Ingredient() ing = Ingredient(self.ctx)
issues += ing.load(ingdct) issues += ing.load(ingdct)
self.ingredients.append(ing) self.ingredients.append(ing)
return issues return issues
@ -78,20 +86,24 @@ class Ingredients:
class PriceDBs: class PriceDBs:
def __init__(self) -> None: def __init__(self, ctx: Context) -> None:
self.ctx = ctx
self.pricedbs: List[PriceDB] = [] self.pricedbs: List[PriceDB] = []
def load(self, lst: List[Any]) -> List[str]: def load(self, lst: List[Any]) -> List[str]:
issues = [] issues = []
assert_list(lst) assert_list(lst)
for elem in lst: for elem in lst:
pricedb = PriceDB() pricedb = PriceDB(self.ctx)
issues += pricedb.load(elem) issues += pricedb.load(elem)
self.pricedbs.append(pricedb) self.pricedbs.append(pricedb)
return issues return issues
class PriceDB: class PriceDB:
def __init__(self, ctx: Context) -> None:
self.ctx = ctx
def load(self, dct: Dict[str, Any]) -> List[str]: def load(self, dct: Dict[str, Any]) -> List[str]:
issues = [] issues = []
issues += assert_dict(dct, ["price"], ["amount", "unit"]) issues += assert_dict(dct, ["price"], ["amount", "unit"])
@ -116,13 +128,16 @@ class PriceDB:
if "unit" in dct: if "unit" in dct:
assert_type(dct, "unit", str) assert_type(dct, "unit", str)
try: try:
self.unit = units.get(dct["unit"]) self.unit = self.ctx.units.get(dct["unit"])
except RuntimeError as e: except RuntimeError as e:
issues.append(str(e)) issues.append(str(e))
return issues return issues
class IngredientInstance: class IngredientInstance:
def __init__(self, ctx: Context) -> None:
self.ctx = ctx
def load(self, dct: Dict[str, Any]) -> List[str]: def load(self, dct: Dict[str, Any]) -> List[str]:
issues = [] issues = []
issues += assert_dict(dct, ["name"], ["amount", "unit", "note"]) issues += assert_dict(dct, ["name"], ["amount", "unit", "note"])
@ -131,7 +146,7 @@ class IngredientInstance:
self.name = dct["name"] self.name = dct["name"]
try: try:
self.ingredient = ingredients.get(self.name) self.ingredient = self.ctx.ingredients.get(self.name)
except RuntimeError as e: except RuntimeError as e:
issues.append(str(e)) issues.append(str(e))
@ -148,7 +163,7 @@ class IngredientInstance:
if "unit" in dct: if "unit" in dct:
assert_type(dct, "unit", str) assert_type(dct, "unit", str)
try: try:
self.unit = units.get(dct["unit"]) self.unit = self.ctx.units.get(dct["unit"])
except RuntimeError as e: except RuntimeError as e:
issues.append(str(e)) issues.append(str(e))
@ -161,6 +176,8 @@ class IngredientInstance:
class RecipePart: class RecipePart:
def __init__(self, ctx: Context) -> None:
self.ctx = ctx
def load(self, dct: Dict[str, Any]) -> List[str]: def load(self, dct: Dict[str, Any]) -> List[str]:
issues = [] issues = []
issues += assert_dict(dct, ["title", "ingredients", "steps"], []) issues += assert_dict(dct, ["title", "ingredients", "steps"], [])
@ -171,7 +188,7 @@ class RecipePart:
assert_type(dct, "ingredients", list) assert_type(dct, "ingredients", list)
self.ingredients: List[IngredientInstance] = [] self.ingredients: List[IngredientInstance] = []
for ing in dct["ingredients"]: for ing in dct["ingredients"]:
ingredient = IngredientInstance() ingredient = IngredientInstance(self.ctx)
issues += ingredient.load(ing) issues += ingredient.load(ing)
self.ingredients.append(ingredient) self.ingredients.append(ingredient)
@ -184,7 +201,8 @@ class RecipePart:
class Recipe: class Recipe:
def __init__(self) -> None: def __init__(self, ctx: Context) -> None:
self.ctx = ctx
self.parts: List[RecipePart] = [] self.parts: List[RecipePart] = []
self.srcpath = "" self.srcpath = ""
self.outpath = "" self.outpath = ""
@ -199,24 +217,17 @@ class Recipe:
assert_list(dct["parts"]) assert_list(dct["parts"])
for partdct in dct["parts"]: for partdct in dct["parts"]:
rp = RecipePart() rp = RecipePart(self.ctx)
issues += rp.load(partdct) issues += rp.load(partdct)
self.parts.append(rp) self.parts.append(rp)
else: else:
rp = RecipePart() rp = RecipePart(self.ctx)
issues = rp.load(dct) issues = rp.load(dct)
self.parts = [rp] self.parts = [rp]
self.title = rp.title self.title = rp.title
return issues return issues
def load_file(file: str) -> Any:
print(f"loading {file}")
with open(file, encoding="utf-8") as f:
ymltxt = f.read()
return yaml.safe_load(ymltxt)
def assert_dict( def assert_dict(
dct: Dict[str, Any], required_keys: List[str], optional_keys: List[str] dct: Dict[str, Any], required_keys: List[str], optional_keys: List[str]
) -> List[str]: ) -> List[str]:
@ -245,9 +256,24 @@ def assert_list(lst: List[Any]) -> None:
raise RuntimeError(f"{lst} has to be a {list}") raise RuntimeError(f"{lst} has to be a {list}")
def rendertemplate( class Builder:
template: jinja2.Template, format: str, file: str, args: Any def __init__(self) -> None:
) -> None: self.jinjaenv = jinja2.Environment(
loader=jinja2.FileSystemLoader("templates"),
autoescape=jinja2.select_autoescape(),
)
self.ctx = Context()
def load_file(self, file: str) -> Any:
print(f"loading {file}")
with open(file, encoding="utf-8") as f:
ymltxt = f.read()
return yaml.safe_load(ymltxt)
def rendertemplate(
self, templatepath: str, format: str, file: str, args: Any
) -> None:
template = self.jinjaenv.get_template(templatepath)
print(f"rendering {file}") print(f"rendering {file}")
outstr = template.render(args) outstr = template.render(args)
@ -256,25 +282,22 @@ def rendertemplate(
with open(f"out/{format}/{file}", "w", encoding="utf-8") as f: with open(f"out/{format}/{file}", "w", encoding="utf-8") as f:
f.write(outstr) f.write(outstr)
def load(self) -> None:
units = Units()
ingredients = Ingredients()
def main() -> None:
issues: List[str] = [] issues: List[str] = []
unitsdct = load_file("recipes/units.yaml") unitsdct = self.load_file("recipes/units.yaml")
issues += units.load(unitsdct) issues += self.ctx.units.load(unitsdct)
ingredientsdct = load_file("recipes/ingredients.yaml") ingredientsdct = self.load_file("recipes/ingredients.yaml")
issues += ingredients.load(ingredientsdct) issues += self.ctx.ingredients.load(ingredientsdct)
if len(issues) != 0: if len(issues) != 0:
for issue in issues: for issue in issues:
print("ERROR", issue) print("ERROR", issue)
return return
def run(self) -> None:
issues = []
files = [] files = []
for _, _, filesx in os.walk("recipes/recipes"): for _, _, filesx in os.walk("recipes/recipes"):
files = filesx files = filesx
@ -285,8 +308,8 @@ def main() -> None:
if not file.endswith(".yaml"): if not file.endswith(".yaml"):
print(f"unknown extension of {file}") print(f"unknown extension of {file}")
continue continue
recipe = Recipe() recipe = Recipe(self.ctx)
recipedct = load_file("recipes/recipes/" + file) recipedct = self.load_file("recipes/recipes/" + file)
issues += recipe.load(recipedct) issues += recipe.load(recipedct)
recipe.srcpath = file recipe.srcpath = file
recipe.outpath = file[:-5] + ".html" recipe.outpath = file[:-5] + ".html"
@ -297,18 +320,12 @@ def main() -> None:
print("ERROR", issue) print("ERROR", issue)
return return
env = jinja2.Environment( self.rendertemplate("index.html", "html", "index.html", {"recipes": recipes})
loader=jinja2.FileSystemLoader("templates"),
autoescape=jinja2.select_autoescape(),
)
indextemplate = env.get_template("index.html")
rendertemplate(indextemplate, "html", "index.html", {"recipes": recipes})
recipetemplate = env.get_template("recipe.html")
for recipe in recipes: for recipe in recipes:
rendertemplate(recipetemplate, "html", recipe.outpath, {"recipe": recipe}) self.rendertemplate( "recipe.html", "html", recipe.outpath, {"recipe": recipe})
if __name__ == "__main__": if __name__ == "__main__":
main() builder = Builder()
builder.load()
builder.run()