rename pricedb to prices

This commit is contained in:
Emi Vasilek 2023-11-11 13:49:00 +01:00
parent 065975d4c2
commit 546ef63289
3 changed files with 80 additions and 30 deletions

View file

@ -47,20 +47,14 @@ class Element:
class Conversion(Element):
def load(self, dct: Dict[str, Any]) -> None:
def find_unit(name: str) -> Optional[Unit]:
for unit in self.ctx.units.units:
if unit["name"] == name:
return unit
return None
fromunit = find_unit(dct["from"])
fromunit = self.ctx.units.get(dct["from"])
if fromunit is None:
raise RuntimeError(f"unit {fromunit} doesn't exist")
raise RuntimeError(f"unit {dct['from']} doesn't exist")
self["from"] = fromunit
tounit = find_unit(dct["to"])
tounit = self.ctx.units.get(dct["to"])
if tounit is None:
raise RuntimeError(f"unit {tounit} doesn't exist")
raise RuntimeError(f"unit {dct['to']} doesn't exist")
self["to"] = tounit
@ -69,10 +63,18 @@ class Unit(Element):
oldunits = self.ctx.units.units[:]
self.ctx.units.units.append(self)
aliases: List[str] = []
if "aliases" in dct:
for alias in dct["aliases"]:
aliases.append(alias)
self["aliases"] = aliases
self.ctx.units.units = oldunits
def finish_load(self) -> None:
conversions: List[Conversion] = []
if "conversions" in dct:
for convdct in dct["conversions"]:
if "from" in dct["conversions"]:
if "conversions" in self.dct:
for convdct in self.dct["conversions"]:
if "from" in self.dct["conversions"]:
raise RuntimeError(
"conversions in units.yaml cannot have a from field, it is automatically assigned from the unit name"
)
@ -81,13 +83,6 @@ class Unit(Element):
conversions.append(conversion)
self["conversions"] = conversions
aliases: List[str] = []
if "aliases" in dct:
for alias in dct["aliases"]:
aliases.append(alias)
self["aliases"] = aliases
self.ctx.units.units = oldunits
class Units:
def __init__(self, ctx: Context) -> None:
@ -98,6 +93,8 @@ class Units:
for unitdct in lst:
unit = Unit(self.ctx, unitdct)
self.units.append(unit)
for unit in self.units:
unit.finish_load()
def get(self, name: str) -> Optional[Unit]:
for unit in self.units:
@ -108,10 +105,10 @@ class Units:
class Ingredient(Element):
def load(self, dct: Dict[str, Any]) -> None:
if "pricedb" in dct:
if "prices" in dct:
pricedb = PriceDBs(self.ctx)
self.ctx.issues += pricedb.load(dct["pricedb"])
self["pricedb"] = pricedb
self.ctx.issues += pricedb.load(dct["prices"])
self["prices"] = pricedb
conversions = []
if "conversions" in dct:
@ -120,6 +117,50 @@ class Ingredient(Element):
conversions.append(conversion)
self["conversions"] = conversions
def convert(
self, amount: float, unitfrom: Unit, unitto: Unit, scannedunits: List[Unit] = []
) -> Optional[float]:
# TODO: this can not solve conversions when we have kg -> g and g -> piece
if unitto == unitfrom:
return amount
conversions = (
self["conversions"] + unitfrom["conversions"] + unitto["conversions"]
)
for conv in conversions:
ratio: float = conv["ratio"]
if (
conv["from"]["name"] == unitfrom["name"]
and conv["to"]["name"] == unitto["name"]
):
return amount * ratio
if (
conv["to"]["name"] == unitfrom["name"]
and conv["from"]["name"] == unitto["name"]
):
return amount / ratio
return None
def getprice(self, amount: float, unit: Unit) -> Optional[float]:
if "prices" not in self.dct:
return None
prices: List[float] = []
pricedbs: PriceDBs = self["prices"]
for entry in pricedbs.pricedbs:
assert isinstance(entry, PriceDB)
entryamount: float = entry["amount"]
entryprice: float = entry["price"]
entryunit: Unit = entry["unit"]
if entryunit == unit:
prices.append((amount / entryamount) * entryprice)
else:
newamount = self.convert(amount, unit, entryunit)
if newamount is not None:
prices.append((newamount / entryamount) * entryprice)
if len(prices) == 0:
return None
assert len(prices) == 1
return prices[0]
class Ingredients:
def __init__(self, ctx: Context) -> None:
@ -166,9 +207,10 @@ class PriceDB(Element):
class IngredientInstance(Element):
def load(self, dct: Dict[str, Any]) -> None:
self["ingredient"] = self.ctx.ingredients.get(dct["name"])
if self["ingredient"] is None:
ingredient = self.ctx.ingredients.get(dct["name"])
if ingredient is None:
self.ctx.issues.append(f"unknown ingredient {dct['name']}")
self["ingredient"] = ingredient
if "amount" not in dct:
self["amount"] = 1.0
@ -187,10 +229,13 @@ class IngredientInstance(Element):
alternatives = []
if "or" in dct:
for ingdct in dct["or"]:
ingredient = IngredientInstance(self.ctx, ingdct)
alternatives.append(ingredient)
ing = IngredientInstance(self.ctx, ingdct)
alternatives.append(ing)
self["alternatives"] = alternatives
if ingredient is not None:
self["price"] = ingredient.getprice(self["amount"], self["unit"])
class Recipe(Element):
def __init__(self, ctx: Context, dct: Dict[str, Any]) -> None:
@ -225,6 +270,10 @@ class Builder:
out = str(input)
if out.endswith(".0"):
return out.split(".", maxsplit=1)[0]
return out
def amountprint(input: int) -> str:
out = numprint(input)
if out == "0.5":
return "1/2"
if out == "0.25":
@ -234,6 +283,7 @@ class Builder:
return out
self.jinjaenv.filters["numprint"] = numprint
self.jinjaenv.filters["amountprint"] = amountprint
self.ctx = Context()
# list of output files that will be built
self.outfiles: Set[str] = set()