recipes: more complete units.yaml, support parsing of conversions
This commit is contained in:
parent
e950977e05
commit
a2cbbb2068
1 changed files with 70 additions and 15 deletions
85
recipes.py
85
recipes.py
|
@ -10,10 +10,59 @@ class Context:
|
||||||
self.units = Units()
|
self.units = Units()
|
||||||
self.ingredients = Ingredients(self)
|
self.ingredients = Ingredients(self)
|
||||||
|
|
||||||
|
class Conversion:
|
||||||
|
def load(self, units: List["Unit"], dct: Dict[str, Any]) -> None:
|
||||||
|
def find_unit(name: str) -> Optional[Unit]:
|
||||||
|
for unit in units:
|
||||||
|
if unit.name == name:
|
||||||
|
return unit
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert_dict(dct, ["from", "to", "ratio"], [])
|
||||||
|
|
||||||
|
assert_type(dct, "from", str)
|
||||||
|
fromunit = find_unit(dct["from"])
|
||||||
|
if fromunit is None:
|
||||||
|
raise RuntimeError(f"unit {dct['from']} doesn't exist")
|
||||||
|
self.fromunit = fromunit
|
||||||
|
|
||||||
|
assert_type(dct, "to", str)
|
||||||
|
tounit = find_unit(dct["to"])
|
||||||
|
if tounit is None:
|
||||||
|
raise RuntimeError(f"unit {tounit} doesn't exist")
|
||||||
|
self.tounit = tounit
|
||||||
|
|
||||||
|
# TODO: or float
|
||||||
|
assert_type(dct, "ratio", int)
|
||||||
|
self.ratio = dct["ratio"]
|
||||||
|
|
||||||
class Unit:
|
class Unit:
|
||||||
def __init__(self, name: str) -> None:
|
def load(self, units: List["Unit"], dct: Dict[str, Any]) -> None:
|
||||||
self.name = name
|
assert_dict(dct, ["name"], ["conversions", "aliases"])
|
||||||
|
|
||||||
|
assert_type(dct, "name", str)
|
||||||
|
self.name = dct["name"]
|
||||||
|
|
||||||
|
unitsx = units[:]
|
||||||
|
unitsx.append(self)
|
||||||
|
|
||||||
|
self.conversions: List[Conversion] = []
|
||||||
|
if "conversions" in dct:
|
||||||
|
assert_list(dct["conversions"])
|
||||||
|
for convdct in dct["conversions"]:
|
||||||
|
if "from" in dct["conversions"]:
|
||||||
|
raise RuntimeError(f"conversions in units.yaml cannot have a from field, it is automatically assigned from the unit name")
|
||||||
|
convdct["from"] = self.name
|
||||||
|
conversion = Conversion()
|
||||||
|
conversion.load(unitsx, convdct)
|
||||||
|
self.conversions.append(conversion)
|
||||||
|
|
||||||
|
self.aliases: List[str] = []
|
||||||
|
if "aliases" in dct:
|
||||||
|
assert_list(dct["aliases"])
|
||||||
|
for alias in dct["aliases"]:
|
||||||
|
assert_type(alias, "", str)
|
||||||
|
self.aliases.append(alias)
|
||||||
|
|
||||||
|
|
||||||
class Units:
|
class Units:
|
||||||
|
@ -22,9 +71,10 @@ class Units:
|
||||||
|
|
||||||
def load(self, lst: List[Any]) -> List[str]:
|
def load(self, lst: List[Any]) -> List[str]:
|
||||||
assert_list(lst)
|
assert_list(lst)
|
||||||
for unit in lst:
|
for unitdct in lst:
|
||||||
assert_type(unit, "", str)
|
unit = Unit()
|
||||||
self.units.append(Unit(unit))
|
unit.load(self.units, unitdct)
|
||||||
|
self.units.append(unit)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def get(self, name: str) -> Optional[Unit]:
|
def get(self, name: str) -> Optional[Unit]:
|
||||||
|
@ -40,7 +90,7 @@ class Ingredient:
|
||||||
|
|
||||||
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"])
|
assert_dict(dct, ["name"], ["wdid", "pricedb", "aliases", "conversions"])
|
||||||
|
|
||||||
assert_type(dct, "name", str)
|
assert_type(dct, "name", str)
|
||||||
self.name = dct["name"]
|
self.name = dct["name"]
|
||||||
|
@ -63,6 +113,13 @@ class Ingredient:
|
||||||
assert_type(elem, "", str)
|
assert_type(elem, "", str)
|
||||||
self.aliases.append(elem)
|
self.aliases.append(elem)
|
||||||
|
|
||||||
|
self.conversions = []
|
||||||
|
if "conversions" in dct:
|
||||||
|
assert_list(dct["conversions"])
|
||||||
|
for dct in dct["conversions"]:
|
||||||
|
conversion = Conversion()
|
||||||
|
conversion.load(self.ctx.units.units, dct)
|
||||||
|
self.conversions.append(conversion)
|
||||||
return issues
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,7 +165,7 @@ class PriceDB:
|
||||||
|
|
||||||
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"])
|
assert_dict(dct, ["price"], ["amount", "unit"])
|
||||||
|
|
||||||
if isinstance(dct["price"], float):
|
if isinstance(dct["price"], float):
|
||||||
self.price = dct["price"]
|
self.price = dct["price"]
|
||||||
|
@ -146,7 +203,7 @@ class IngredientInstance:
|
||||||
|
|
||||||
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", "or"])
|
assert_dict(dct, ["name"], ["amount", "unit", "note", "or"])
|
||||||
|
|
||||||
assert_type(dct, "name", str)
|
assert_type(dct, "name", str)
|
||||||
self.name = dct["name"]
|
self.name = dct["name"]
|
||||||
|
@ -196,7 +253,7 @@ class RecipePart:
|
||||||
|
|
||||||
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"], [])
|
assert_dict(dct, ["title", "ingredients", "steps"], [])
|
||||||
|
|
||||||
assert_type(dct, "title", str)
|
assert_type(dct, "title", str)
|
||||||
self.title = dct["title"]
|
self.title = dct["title"]
|
||||||
|
@ -227,7 +284,7 @@ class Recipe:
|
||||||
def load(self, dct: Dict[str, Any]) -> List[str]:
|
def load(self, dct: Dict[str, Any]) -> List[str]:
|
||||||
issues: List[str] = []
|
issues: List[str] = []
|
||||||
if "parts" in dct:
|
if "parts" in dct:
|
||||||
assert_dict(dct, ["title"], [])
|
assert_dict(dct, ["title"], ["parts"])
|
||||||
assert_type(dct, "title", str)
|
assert_type(dct, "title", str)
|
||||||
self.title = dct["title"]
|
self.title = dct["title"]
|
||||||
|
|
||||||
|
@ -246,17 +303,15 @@ class Recipe:
|
||||||
|
|
||||||
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]:
|
) -> None:
|
||||||
issues = []
|
|
||||||
if not isinstance(dct, dict):
|
if not isinstance(dct, dict):
|
||||||
raise RuntimeError(f"{dct} has to be a dict")
|
raise RuntimeError(f"{dct} has to be a dict")
|
||||||
for reqkey in required_keys:
|
for reqkey in required_keys:
|
||||||
if reqkey not in dct:
|
if reqkey not in dct:
|
||||||
issues.append(f"{reqkey} is required")
|
raise RuntimeError(f"{reqkey} is required")
|
||||||
extraelems = [x for x in dct.keys() if x not in required_keys + optional_keys]
|
extraelems = [x for x in dct.keys() if x not in required_keys + optional_keys]
|
||||||
if len(extraelems) != 0:
|
if len(extraelems) != 0:
|
||||||
issues.append(f"{extraelems} not allowed")
|
raise RuntimeError(f"{extraelems} not allowed")
|
||||||
return issues
|
|
||||||
|
|
||||||
|
|
||||||
def assert_type(dct: Dict[str, Any], key: str, type: type) -> None:
|
def assert_type(dct: Dict[str, Any], key: str, type: type) -> None:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue