Simplify
This commit is contained in:
parent
353aee80cb
commit
347231f013
2 changed files with 135 additions and 175 deletions
282
recipes.py
282
recipes.py
|
@ -1,3 +1,4 @@
|
||||||
|
from abc import abstractmethod
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict, List, Any, Optional, Set
|
from typing import Dict, List, Any, Optional, Set
|
||||||
import os
|
import os
|
||||||
|
@ -11,103 +12,111 @@ import jsonschema.exceptions
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.units = Units()
|
self.units = Units(self)
|
||||||
self.ingredients = Ingredients(self)
|
self.ingredients = Ingredients(self)
|
||||||
|
self.issues: List[str] = []
|
||||||
|
|
||||||
|
|
||||||
class Conversion:
|
class Element:
|
||||||
def load(self, units: List["Unit"], dct: Dict[str, Any]) -> None:
|
def __init__(self, ctx: Context, dct: Dict[str, Any]) -> None:
|
||||||
|
self.ctx = ctx
|
||||||
|
self.dct = dct
|
||||||
|
self.load(dct)
|
||||||
|
for elem in self.dct.values():
|
||||||
|
if isinstance(elem, dict):
|
||||||
|
raise RuntimeError("Something wasn't processed properly")
|
||||||
|
|
||||||
|
def __contains__(self, item: Any) -> bool:
|
||||||
|
return item in self.dct
|
||||||
|
|
||||||
|
def __getitem__(self, key: str) -> Any:
|
||||||
|
return self.dct[key]
|
||||||
|
|
||||||
|
def __setitem__(self, key: str, val: Any) -> None:
|
||||||
|
self.dct[key] = val
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return self.dct.__repr__()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def load(self, dct: Dict[str, Any]) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Conversion(Element):
|
||||||
|
def load(self, dct: Dict[str, Any]) -> None:
|
||||||
def find_unit(name: str) -> Optional[Unit]:
|
def find_unit(name: str) -> Optional[Unit]:
|
||||||
for unit in units:
|
for unit in self.ctx.units.units:
|
||||||
if unit.name == name:
|
if unit["name"] == name:
|
||||||
return unit
|
return unit
|
||||||
return None
|
return None
|
||||||
|
|
||||||
fromunit = find_unit(dct["from"])
|
fromunit = find_unit(dct["from"])
|
||||||
if fromunit is None:
|
if fromunit is None:
|
||||||
raise RuntimeError(f"unit {dct['from']} doesn't exist")
|
raise RuntimeError(f"unit {fromunit} doesn't exist")
|
||||||
self.fromunit = fromunit
|
self["from"] = fromunit
|
||||||
|
|
||||||
tounit = find_unit(dct["to"])
|
tounit = find_unit(dct["to"])
|
||||||
if tounit is None:
|
if tounit is None:
|
||||||
raise RuntimeError(f"unit {tounit} doesn't exist")
|
raise RuntimeError(f"unit {tounit} doesn't exist")
|
||||||
self.tounit = tounit
|
self["to"] = tounit
|
||||||
|
|
||||||
self.ratio = dct["ratio"]
|
|
||||||
|
|
||||||
|
|
||||||
class Unit:
|
class Unit(Element):
|
||||||
def load(self, units: List["Unit"], dct: Dict[str, Any]) -> None:
|
def load(self, dct: Dict[str, Any]) -> None:
|
||||||
self.name = dct["name"]
|
oldunits = self.ctx.units.units[:]
|
||||||
|
self.ctx.units.units.append(self)
|
||||||
|
|
||||||
unitsx = units[:]
|
conversions: List[Conversion] = []
|
||||||
unitsx.append(self)
|
|
||||||
|
|
||||||
self.conversions: List[Conversion] = []
|
|
||||||
if "conversions" in dct:
|
if "conversions" in dct:
|
||||||
for convdct in dct["conversions"]:
|
for convdct in dct["conversions"]:
|
||||||
if "from" in dct["conversions"]:
|
if "from" in dct["conversions"]:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"conversions in units.yaml cannot have a from field, it is automatically assigned from the unit name"
|
f"conversions in units.yaml cannot have a from field, it is automatically assigned from the unit name"
|
||||||
)
|
)
|
||||||
convdct["from"] = self.name
|
convdct["from"] = self["name"]
|
||||||
conversion = Conversion()
|
conversion = Conversion(self.ctx, convdct)
|
||||||
conversion.load(unitsx, convdct)
|
conversions.append(conversion)
|
||||||
self.conversions.append(conversion)
|
self["conversions"] = conversions
|
||||||
|
|
||||||
self.aliases: List[str] = []
|
aliases: List[str] = []
|
||||||
if "aliases" in dct:
|
if "aliases" in dct:
|
||||||
for alias in dct["aliases"]:
|
for alias in dct["aliases"]:
|
||||||
self.aliases.append(alias)
|
aliases.append(alias)
|
||||||
|
self["aliases"] = aliases
|
||||||
|
self.ctx.units.units = oldunits
|
||||||
|
|
||||||
|
|
||||||
class Units:
|
class Units:
|
||||||
def __init__(self) -> None:
|
def __init__(self, ctx: Context) -> None:
|
||||||
|
self.ctx = ctx
|
||||||
self.units: List[Unit] = []
|
self.units: List[Unit] = []
|
||||||
|
|
||||||
def load(self, lst: List[Any]) -> List[str]:
|
def load(self, lst: List[Any]) -> None:
|
||||||
for unitdct in lst:
|
for unitdct in lst:
|
||||||
unit = Unit()
|
unit = Unit(self.ctx, unitdct)
|
||||||
unit.load(self.units, unitdct)
|
|
||||||
self.units.append(unit)
|
self.units.append(unit)
|
||||||
return []
|
|
||||||
|
|
||||||
def get(self, name: str) -> Optional[Unit]:
|
def get(self, name: str) -> Optional[Unit]:
|
||||||
for unit in self.units:
|
for unit in self.units:
|
||||||
if unit.name == name:
|
if unit["name"] == name:
|
||||||
return unit
|
return unit
|
||||||
raise RuntimeError(f"unit {name} not found")
|
raise RuntimeError(f"unit {name} not found")
|
||||||
|
|
||||||
|
|
||||||
class Ingredient:
|
class Ingredient(Element):
|
||||||
def __init__(self, ctx: Context) -> None:
|
def load(self, dct: Dict[str, Any]) -> None:
|
||||||
self.ctx = ctx
|
|
||||||
|
|
||||||
def load(self, dct: Dict[str, Any]) -> List[str]:
|
|
||||||
issues = []
|
|
||||||
self.name = dct["name"]
|
|
||||||
|
|
||||||
self.wdid = -1
|
|
||||||
if "wdid" in dct:
|
|
||||||
self.wdid = dct["wdid"]
|
|
||||||
|
|
||||||
self.pricedb = None
|
|
||||||
if "pricedb" in dct:
|
if "pricedb" in dct:
|
||||||
self.pricedb = PriceDBs(self.ctx)
|
pricedb = PriceDBs(self.ctx)
|
||||||
issues += self.pricedb.load(dct["pricedb"])
|
self.ctx.issues += pricedb.load(dct["pricedb"])
|
||||||
|
self["pricedb"] = pricedb
|
||||||
|
|
||||||
self.aliases = []
|
conversions = []
|
||||||
if "aliases" in dct:
|
|
||||||
for elem in dct["aliases"]:
|
|
||||||
self.aliases.append(elem)
|
|
||||||
|
|
||||||
self.conversions = []
|
|
||||||
if "conversions" in dct:
|
if "conversions" in dct:
|
||||||
for dct in dct["conversions"]:
|
for convdct in dct["conversions"]:
|
||||||
conversion = Conversion()
|
conversion = Conversion(self.ctx, convdct)
|
||||||
conversion.load(self.ctx.units.units, dct)
|
conversions.append(conversion)
|
||||||
self.conversions.append(conversion)
|
self["conversions"] = conversions
|
||||||
return issues
|
|
||||||
|
|
||||||
|
|
||||||
class Ingredients:
|
class Ingredients:
|
||||||
|
@ -115,17 +124,14 @@ class Ingredients:
|
||||||
self.ctx = ctx
|
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]) -> None:
|
||||||
issues = []
|
|
||||||
for ingdct in lst:
|
for ingdct in lst:
|
||||||
ing = Ingredient(self.ctx)
|
ing = Ingredient(self.ctx, ingdct)
|
||||||
issues += ing.load(ingdct)
|
|
||||||
self.ingredients.append(ing)
|
self.ingredients.append(ing)
|
||||||
return issues
|
|
||||||
|
|
||||||
def get(self, name: str) -> Optional[Ingredient]:
|
def get(self, name: str) -> Optional[Ingredient]:
|
||||||
for ing in self.ingredients:
|
for ing in self.ingredients:
|
||||||
if ing.name == name or name in ing.aliases:
|
if ing["name"] == name or "aliases" in ing and name in ing["aliases"]:
|
||||||
return ing
|
return ing
|
||||||
raise RuntimeError(f"ingredient {name} not found")
|
raise RuntimeError(f"ingredient {name} not found")
|
||||||
|
|
||||||
|
@ -136,120 +142,74 @@ class PriceDBs:
|
||||||
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 = []
|
|
||||||
for elem in lst:
|
for elem in lst:
|
||||||
pricedb = PriceDB(self.ctx)
|
pricedb = PriceDB(self.ctx, elem)
|
||||||
issues += pricedb.load(elem)
|
|
||||||
self.pricedbs.append(pricedb)
|
self.pricedbs.append(pricedb)
|
||||||
return issues
|
return self.ctx.issues
|
||||||
|
|
||||||
|
|
||||||
class PriceDB:
|
class PriceDB(Element):
|
||||||
def __init__(self, ctx: Context) -> None:
|
def load(self, dct: Dict[str, Any]) -> None:
|
||||||
self.ctx = ctx
|
if "amount" not in dct:
|
||||||
|
self["amount"] = 1.0
|
||||||
|
|
||||||
def load(self, dct: Dict[str, Any]) -> List[str]:
|
|
||||||
issues = []
|
|
||||||
self.price = dct["price"]
|
|
||||||
|
|
||||||
self.amount = 1.0
|
|
||||||
if "amount" in dct:
|
|
||||||
self.amount = dct["amount"]
|
|
||||||
|
|
||||||
self.unit = None
|
|
||||||
if "unit" in dct:
|
if "unit" in dct:
|
||||||
try:
|
try:
|
||||||
self.unit = self.ctx.units.get(dct["unit"])
|
self["unit"] = self.ctx.units.get(dct["unit"])
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
issues.append(str(e))
|
self.ctx.issues.append(str(e))
|
||||||
return issues
|
else:
|
||||||
|
self["unit"] = None
|
||||||
|
|
||||||
class IngredientInstance:
|
|
||||||
def __init__(
|
|
||||||
self, ctx: Context, defaultamount: float = 1, defaultunit: Optional[Unit] = None
|
|
||||||
) -> None:
|
|
||||||
self.ctx = ctx
|
|
||||||
self.defaultamount = float(defaultamount)
|
|
||||||
self.defaultunit: Optional[Unit] = defaultunit
|
|
||||||
|
|
||||||
def load(self, dct: Dict[str, Any]) -> List[str]:
|
|
||||||
issues = []
|
|
||||||
self.name = dct["name"]
|
|
||||||
|
|
||||||
|
class IngredientInstance(Element):
|
||||||
|
def load(self, dct: Dict[str, Any]) -> None:
|
||||||
try:
|
try:
|
||||||
self.ingredient = self.ctx.ingredients.get(self.name)
|
self["ingredient"] = self.ctx.ingredients.get(dct["name"])
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
issues.append(str(e))
|
self.ctx.issues.append(str(e))
|
||||||
|
|
||||||
self.amount = self.defaultamount
|
if "amount" not in dct:
|
||||||
if "amount" in dct:
|
self["amount"] = 1.0
|
||||||
self.amount = dct["amount"]
|
|
||||||
|
|
||||||
self.unit = self.defaultunit
|
|
||||||
if "unit" in dct:
|
if "unit" in dct:
|
||||||
try:
|
try:
|
||||||
self.unit = self.ctx.units.get(dct["unit"])
|
self["unit"] = self.ctx.units.get(dct["unit"])
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
issues.append(str(e))
|
self.ctx.issues.append(str(e))
|
||||||
self.note = ""
|
else:
|
||||||
if "note" in dct:
|
self["unit"] = None
|
||||||
self.note = dct["note"]
|
|
||||||
|
|
||||||
self.alternatives = []
|
if "note" not in dct:
|
||||||
|
self["note"] = ""
|
||||||
|
|
||||||
|
alternatives = []
|
||||||
if "or" in dct:
|
if "or" in dct:
|
||||||
for ingdct in dct["or"]:
|
for ingdct in dct["or"]:
|
||||||
ingredient = IngredientInstance(
|
ingredient = IngredientInstance(self.ctx, ingdct)
|
||||||
self.ctx, defaultamount=self.amount, defaultunit=self.unit
|
alternatives.append(ingredient)
|
||||||
)
|
self["alternatives"] = alternatives
|
||||||
ingredient.load(ingdct)
|
|
||||||
self.alternatives.append(ingredient)
|
|
||||||
|
|
||||||
return issues
|
|
||||||
|
|
||||||
|
|
||||||
class Subrecipe:
|
class Recipe(Element):
|
||||||
def __init__(self, ctx: Context) -> None:
|
def __init__(self, ctx: Context, dct: Dict[str, Any]) -> None:
|
||||||
self.ctx = ctx
|
super().__init__(ctx, dct)
|
||||||
|
|
||||||
def load(self, dct: Dict[str, Any]) -> List[str]:
|
|
||||||
issues = []
|
|
||||||
self.title = dct["title"]
|
|
||||||
|
|
||||||
self.ingredients: List[IngredientInstance] = []
|
|
||||||
for ing in dct["ingredients"]:
|
|
||||||
ingredient = IngredientInstance(self.ctx)
|
|
||||||
issues += ingredient.load(ing)
|
|
||||||
self.ingredients.append(ingredient)
|
|
||||||
|
|
||||||
self.steps: List[str] = dct["steps"]
|
|
||||||
|
|
||||||
return issues
|
|
||||||
|
|
||||||
|
|
||||||
class Recipe:
|
|
||||||
def __init__(self, ctx: Context) -> None:
|
|
||||||
self.ctx = ctx
|
|
||||||
self.subrecipes: List[Subrecipe] = []
|
|
||||||
self.srcpath = ""
|
self.srcpath = ""
|
||||||
self.outpath = ""
|
self.outpath = ""
|
||||||
self.title = ""
|
|
||||||
|
|
||||||
def load(self, dct: Dict[str, Any]) -> List[str]:
|
def load(self, dct: Dict[str, Any]) -> None:
|
||||||
issues: List[str] = []
|
ingredients: List[IngredientInstance] = []
|
||||||
|
if "ingredients" in dct:
|
||||||
|
for ing in dct["ingredients"]:
|
||||||
|
ingredient = IngredientInstance(self.ctx, ing)
|
||||||
|
ingredients.append(ingredient)
|
||||||
|
self["ingredients"] = ingredients
|
||||||
|
|
||||||
|
subrecipes: List[Recipe] = []
|
||||||
if "subrecipes" in dct:
|
if "subrecipes" in dct:
|
||||||
self.title = dct["title"]
|
|
||||||
|
|
||||||
for partdct in dct["subrecipes"]:
|
for partdct in dct["subrecipes"]:
|
||||||
rp = Subrecipe(self.ctx)
|
rp = Recipe(self.ctx, partdct)
|
||||||
issues += rp.load(partdct)
|
subrecipes.append(rp)
|
||||||
self.subrecipes.append(rp)
|
self["subrecipes"] = subrecipes
|
||||||
else:
|
|
||||||
rp = Subrecipe(self.ctx)
|
|
||||||
issues = rp.load(dct)
|
|
||||||
self.subrecipes = [rp]
|
|
||||||
self.title = rp.title
|
|
||||||
return issues
|
|
||||||
|
|
||||||
|
|
||||||
class Builder:
|
class Builder:
|
||||||
|
@ -298,30 +258,27 @@ class Builder:
|
||||||
self.outfiles.add(file)
|
self.outfiles.add(file)
|
||||||
|
|
||||||
def load(self, dir: str) -> int:
|
def load(self, dir: str) -> int:
|
||||||
issues: List[str] = []
|
|
||||||
|
|
||||||
unitsdct = self.load_file(dir + "/units.yaml")
|
unitsdct = self.load_file(dir + "/units.yaml")
|
||||||
unitsschema = self.load_file("schemas/units.json")
|
unitsschema = self.load_file("schemas/units.json")
|
||||||
jsonschema.validate(instance=unitsdct, schema=unitsschema)
|
jsonschema.validate(instance=unitsdct, schema=unitsschema)
|
||||||
issues += self.ctx.units.load(unitsdct)
|
self.ctx.units.load(unitsdct)
|
||||||
if len(issues) != 0:
|
if len(self.ctx.issues) != 0:
|
||||||
for issue in issues:
|
for issue in self.ctx.issues:
|
||||||
print("ERROR in units.yaml:", issue)
|
print("ERROR in units.yaml:", issue)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
ingredientsdct = self.load_file(dir + "/ingredients.yaml")
|
ingredientsdct = self.load_file(dir + "/ingredients.yaml")
|
||||||
ingredientsschema = self.load_file("schemas/ingredients.json")
|
ingredientsschema = self.load_file("schemas/ingredients.json")
|
||||||
jsonschema.validate(instance=ingredientsdct, schema=ingredientsschema)
|
jsonschema.validate(instance=ingredientsdct, schema=ingredientsschema)
|
||||||
issues += self.ctx.ingredients.load(ingredientsdct)
|
self.ctx.ingredients.load(ingredientsdct)
|
||||||
if len(issues) != 0:
|
if len(self.ctx.issues) != 0:
|
||||||
for issue in issues:
|
for issue in self.ctx.issues:
|
||||||
print("ERROR in ingredients.yaml:", issue)
|
print("ERROR in ingredients.yaml:", issue)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def run(self, dir: str) -> int:
|
def run(self, dir: str) -> int:
|
||||||
issues = []
|
|
||||||
files = []
|
files = []
|
||||||
for _, _, filesx in os.walk(dir + "/recipes"):
|
for _, _, filesx in os.walk(dir + "/recipes"):
|
||||||
files = filesx
|
files = filesx
|
||||||
|
@ -333,16 +290,15 @@ class Builder:
|
||||||
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(self.ctx)
|
|
||||||
recipedct = self.load_file(dir + "/recipes/" + file)
|
recipedct = self.load_file(dir + "/recipes/" + file)
|
||||||
jsonschema.validate(instance=recipedct, schema=recipeschema)
|
jsonschema.validate(instance=recipedct, schema=recipeschema)
|
||||||
issues += recipe.load(recipedct)
|
recipe = Recipe(self.ctx, recipedct)
|
||||||
recipe.srcpath = file
|
recipe.srcpath = file
|
||||||
recipe.outpath = file[:-5] + ".html"
|
recipe.outpath = file[:-5] + ".html"
|
||||||
recipes.append(recipe)
|
recipes.append(recipe)
|
||||||
|
|
||||||
if len(issues) != 0:
|
if len(self.ctx.issues) != 0:
|
||||||
for issue in issues:
|
for issue in self.ctx.issues:
|
||||||
print("ERROR", issue)
|
print("ERROR", issue)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
@ -359,7 +315,7 @@ class Builder:
|
||||||
format="html",
|
format="html",
|
||||||
file=recipe.outpath,
|
file=recipe.outpath,
|
||||||
dir=dir,
|
dir=dir,
|
||||||
args={"recipe": recipe}
|
args={"recipe": recipe},
|
||||||
)
|
)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% macro ingredientpart(ing) -%}
|
{% macro ingredientpart(ing) -%}
|
||||||
{{ing.amount|numprint}} {{ing.unit.name}} {{ ing.name }}
|
{{ing.amount|numprint}} {{ing["unit"].name}} {{ ing.name }}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro ingredient(ing) -%}
|
{% macro ingredient(ing) -%}
|
||||||
{{ingredientpart(ing)}}
|
{{ingredientpart(ing)}}
|
||||||
{% if ing.alternatives|length != 0 %}
|
{% if ing.alternatives|length != 0 %}
|
||||||
|
@ -10,22 +11,25 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
{%block title%}{{recipe.title}}{%endblock%}
|
|
||||||
{%block body %}
|
{% macro getrecipe(rec) -%}
|
||||||
<a href="index.html">back</a>
|
{% for subrecipe in rec.subrecipes %}
|
||||||
<h1>{{recipe.title}}</h1>
|
{{getrecipe(subrecipe)}}
|
||||||
{% for subrecipe in recipe.subrecipes %}
|
{% endfor %}
|
||||||
{% if recipe.subrecipes|length != 1 %}
|
<h1>{{rec.title}}</h1>
|
||||||
<h2>{{subrecipe.title}}</h2>
|
|
||||||
{% endif %}
|
|
||||||
<h3>Ingredients</h3>
|
<h3>Ingredients</h3>
|
||||||
{% for ing in subrecipe.ingredients %}
|
{% for ing in rec.ingredients %}
|
||||||
<li>{{ingredient(ing)}}</li>
|
<li>{{ingredient(ing)}}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<h3>Steps</h3>
|
<h3>Steps</h3>
|
||||||
{% for step in subrecipe.steps %}
|
{% for step in rec.steps %}
|
||||||
<li>{{ step }}</li>
|
<li>{{ step }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<hr>
|
<hr>
|
||||||
{% endfor %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%block title%}{{recipe.title}}{%endblock%}
|
||||||
|
{%block body %}
|
||||||
|
<a href="index.html">back</a>
|
||||||
|
{{getrecipe(recipe)}}
|
||||||
{%endblock%}
|
{%endblock%}
|
Loading…
Add table
Add a link
Reference in a new issue