From 883f0756f972e89f29e7c6ec54043bad6c6741ac Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Tue, 28 Nov 2023 12:28:52 +0000 Subject: [PATCH 01/18] allow using a single string as an ingredient instead of a dict --- .pylintrc | 2 +- comfyrecipes/builder.py | 3 ++- comfyrecipes/parsing.py | 37 +++++++++++++++++++++++++++--- comfyrecipes/schemas/recipe.json | 27 +++++++++++++--------- comfyrecipes/templates/recipe.html | 7 +++++- 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/.pylintrc b/.pylintrc index 4ff7ab7..6555d60 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,4 +3,4 @@ disable= missing-module-docstring, missing-class-docstring, missing-function-docstring, - too-few-public-methods \ No newline at end of file + too-few-public-methods diff --git a/comfyrecipes/builder.py b/comfyrecipes/builder.py index abdebf5..ba38fae 100644 --- a/comfyrecipes/builder.py +++ b/comfyrecipes/builder.py @@ -139,7 +139,8 @@ class Builder: def collect_unitnames(rec: parsing.Recipe) -> List[str]: results: List[str] = [] for ing in rec.ingredients: - results.append(ing.unit.name) + if ing.unit is not None: + results.append(ing.unit.name) return results unitnamelists = self.foreach_recipe(collect_unitnames) diff --git a/comfyrecipes/parsing.py b/comfyrecipes/parsing.py index 49f6e9f..5968c18 100644 --- a/comfyrecipes/parsing.py +++ b/comfyrecipes/parsing.py @@ -1,5 +1,6 @@ from abc import abstractmethod import collections +import re from typing import Any, Dict, List, Optional, Self import comfyrecipes.settings as settings @@ -178,8 +179,8 @@ class IngredientInstance(Element): self, ctx: Context, name: str, - amount: float, - unit: Unit, + amount: Optional[float], + unit: Optional[Unit], alternatives: List["IngredientInstance"], note: str, price: Optional["PriceDB"], @@ -193,7 +194,37 @@ class IngredientInstance(Element): self.price = price @classmethod - def from_dict(cls, ctx: Context, dct: Dict[str, Any]) -> Self: + def from_dict(cls, ctx: Context, dct: str | Dict[str, Any]) -> Self: + if isinstance(dct, str): + string = dct.strip() + p = re.compile(r"^(?:([0-9\.]+) ([a-zA-Z]+) )?([\w ]+)(?: \((.*)\))?$") + match = p.match(string) + if match is None: + raise RuntimeError( + "ingredient {string} regex not matched, it should be in the format [amount(num) unit(string, one word)] name(string, any number of words) [(note(string))]" + ) + amount = float(match.group(1)) + unitstr = match.group(2) + unit = ctx.default_unit + if unit is not None: + unitx = ctx.units.get(unitstr) + if unitx is None: + ctx.issues.error(issues.ISSUE_UNKNOWN_UNIT, "unknown unit {unitstr}") + else: + unit = unitx + name = match.group(3) + note = match.group(4) + if note is None: + note = "" + return cls( + ctx=ctx, + name=dct, + amount=amount, + unit=unit, + alternatives=[], + note=note, + price=None, + ) name = dct["name"] ingredient = ctx.ingredients.get(name) diff --git a/comfyrecipes/schemas/recipe.json b/comfyrecipes/schemas/recipe.json index 0ca33bd..fc34f3c 100644 --- a/comfyrecipes/schemas/recipe.json +++ b/comfyrecipes/schemas/recipe.json @@ -13,17 +13,22 @@ "ingredients": { "type": "array", "items": { - "$id": "https://example.com/ingredient.json", - "type": "object", - "additionalProperties": false, - "required": [ "name" ], - "properties": { - "name": { "type": "string" }, - "amount": { "type": "number" }, - "unit": { "type": "string" }, - "or": { "items": { "$ref": "/ingredient.json" } }, - "note": { "type": "string" } - } + "oneOf": [ + { "type": "string" }, + { + "$id": "https://example.com/ingredient.json", + "type": "object", + "additionalProperties": false, + "required": [ "name" ], + "properties": { + "name": { "type": "string" }, + "amount": { "type": "number" }, + "unit": { "type": "string" }, + "or": { "items": { "$ref": "/ingredient.json" } }, + "note": { "type": "string" } + } + } + ] } }, "steps": { diff --git a/comfyrecipes/templates/recipe.html b/comfyrecipes/templates/recipe.html index d7824cb..2ffc5b1 100644 --- a/comfyrecipes/templates/recipe.html +++ b/comfyrecipes/templates/recipe.html @@ -1,6 +1,11 @@ {% extends "base.html" %} {% macro ingredientpart(ing) -%} -{% if recipe.price != None %}{{price(ing.price)}} {%endif%}{{ing.amount|amountprint}} {{ing["unit"].name}} {{ ing.name }} {{ing.note}} +{% if recipe.price != None %}{{price(ing.price)}} {%endif%} +{% if ing.amount != None %} {{ing.amount|amountprint}} +{% if ing.unit != None %} {{ing.unit.name}}{% endif %} +{%endif%} + {{ ing.name }} +{% if ing.note != "" %} {{ing.note}}{% endif %} {%- endmacro %} {% macro ingredient(ing) -%} From 69e578dba45e48d0de7605d15be97f3b834d9eb7 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Tue, 28 Nov 2023 12:28:52 +0000 Subject: [PATCH 02/18] allow using a single string as an ingredient instead of a dict --- .pylintrc | 2 +- comfyrecipes/builder.py | 3 ++- comfyrecipes/parsing.py | 37 +++++++++++++++++++++++++++--- comfyrecipes/schemas/recipe.json | 27 +++++++++++++--------- comfyrecipes/templates/recipe.html | 7 +++++- 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/.pylintrc b/.pylintrc index 4ff7ab7..6555d60 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,4 +3,4 @@ disable= missing-module-docstring, missing-class-docstring, missing-function-docstring, - too-few-public-methods \ No newline at end of file + too-few-public-methods diff --git a/comfyrecipes/builder.py b/comfyrecipes/builder.py index abdebf5..ba38fae 100644 --- a/comfyrecipes/builder.py +++ b/comfyrecipes/builder.py @@ -139,7 +139,8 @@ class Builder: def collect_unitnames(rec: parsing.Recipe) -> List[str]: results: List[str] = [] for ing in rec.ingredients: - results.append(ing.unit.name) + if ing.unit is not None: + results.append(ing.unit.name) return results unitnamelists = self.foreach_recipe(collect_unitnames) diff --git a/comfyrecipes/parsing.py b/comfyrecipes/parsing.py index 49f6e9f..65ae589 100644 --- a/comfyrecipes/parsing.py +++ b/comfyrecipes/parsing.py @@ -1,5 +1,6 @@ from abc import abstractmethod import collections +import re from typing import Any, Dict, List, Optional, Self import comfyrecipes.settings as settings @@ -178,8 +179,8 @@ class IngredientInstance(Element): self, ctx: Context, name: str, - amount: float, - unit: Unit, + amount: Optional[float], + unit: Optional[Unit], alternatives: List["IngredientInstance"], note: str, price: Optional["PriceDB"], @@ -193,7 +194,37 @@ class IngredientInstance(Element): self.price = price @classmethod - def from_dict(cls, ctx: Context, dct: Dict[str, Any]) -> Self: + def from_dict(cls, ctx: Context, dct: str | Dict[str, Any]) -> Self: + if isinstance(dct, str): + string = dct.strip() + p = re.compile(r"^(?:([0-9\.]+) ([a-zA-Z]+) )?([\w ]+)(?: \((.*)\))?$") + match = p.match(string) + if match is None: + raise RuntimeError( + "ingredient {string} regex not matched, it should be in the format [amount(num) unit(string, one word)] name(string, any number of words) [(note(string))]" + ) + amount = float(match.group(1)) + unitstr = match.group(2) + unit = ctx.default_unit + if unit is not None: + unitx = ctx.units.get(unitstr) + if unitx is None: + ctx.issues.error(issues.ISSUE_UNKNOWN_UNIT, "unknown unit {unitstr}") + else: + unit = unitx + name = match.group(3) + note = match.group(4) + if note is None: + note = "" + return cls( + ctx=ctx, + name=name, + amount=amount, + unit=unit, + alternatives=[], + note=note, + price=None, + ) name = dct["name"] ingredient = ctx.ingredients.get(name) diff --git a/comfyrecipes/schemas/recipe.json b/comfyrecipes/schemas/recipe.json index 0ca33bd..fc34f3c 100644 --- a/comfyrecipes/schemas/recipe.json +++ b/comfyrecipes/schemas/recipe.json @@ -13,17 +13,22 @@ "ingredients": { "type": "array", "items": { - "$id": "https://example.com/ingredient.json", - "type": "object", - "additionalProperties": false, - "required": [ "name" ], - "properties": { - "name": { "type": "string" }, - "amount": { "type": "number" }, - "unit": { "type": "string" }, - "or": { "items": { "$ref": "/ingredient.json" } }, - "note": { "type": "string" } - } + "oneOf": [ + { "type": "string" }, + { + "$id": "https://example.com/ingredient.json", + "type": "object", + "additionalProperties": false, + "required": [ "name" ], + "properties": { + "name": { "type": "string" }, + "amount": { "type": "number" }, + "unit": { "type": "string" }, + "or": { "items": { "$ref": "/ingredient.json" } }, + "note": { "type": "string" } + } + } + ] } }, "steps": { diff --git a/comfyrecipes/templates/recipe.html b/comfyrecipes/templates/recipe.html index d7824cb..2ffc5b1 100644 --- a/comfyrecipes/templates/recipe.html +++ b/comfyrecipes/templates/recipe.html @@ -1,6 +1,11 @@ {% extends "base.html" %} {% macro ingredientpart(ing) -%} -{% if recipe.price != None %}{{price(ing.price)}} {%endif%}{{ing.amount|amountprint}} {{ing["unit"].name}} {{ ing.name }} {{ing.note}} +{% if recipe.price != None %}{{price(ing.price)}} {%endif%} +{% if ing.amount != None %} {{ing.amount|amountprint}} +{% if ing.unit != None %} {{ing.unit.name}}{% endif %} +{%endif%} + {{ ing.name }} +{% if ing.note != "" %} {{ing.note}}{% endif %} {%- endmacro %} {% macro ingredient(ing) -%} From 67bb8c22664d7ea309f0a89c2df6385c7b8ef0f9 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Tue, 28 Nov 2023 15:30:06 +0000 Subject: [PATCH 03/18] rename project from recipes to comfy-recipes --- Dockerfile | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 82f47d0..7243e52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,8 +5,8 @@ RUN apk add --no-cache python3 py3-build py3-hatchling && \ python3 -m build . FROM alpine:3.18 -COPY --from=build /build/dist/recipes-*-py3-none-any.whl / +COPY --from=build /build/dist/comfy-recipes-*-py3-none-any.whl / RUN apk add --no-cache python3 py3-pip && \ - pip install /recipes-*-py3-none-any.whl && \ + pip install /comfy-recipes-*-py3-none-any.whl && \ apk del py3-pip ENTRYPOINT ["/usr/bin/recipes-cli"] diff --git a/pyproject.toml b/pyproject.toml index 12f1a3f..aad751c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling"] build-backend = "hatchling.build" [project] -name = "recipes" +name = "comfy-recipes" version = "0.0.1" description = "Smart recipe static site generator" authors = [{ name = "Emi Vasilek", email = "emi.vasilek@gmail.com" }] From 816e65a00cfcca0890735df2889cb898d6cfbc76 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Tue, 28 Nov 2023 15:30:42 +0000 Subject: [PATCH 04/18] add warning about serve not being suitable for production --- comfyrecipes/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/comfyrecipes/cli.py b/comfyrecipes/cli.py index 6a48b8b..5205862 100644 --- a/comfyrecipes/cli.py +++ b/comfyrecipes/cli.py @@ -44,6 +44,7 @@ def main() -> None: (args.address, args.port), http.server.SimpleHTTPRequestHandler ) print(f"serving at http://{args.address}:{args.port}") + print("THIS WEB SERVER IS ONLY MEANT FOR LOCAL TESTING, IT IS NOT SUITABLE FOR PRODUCTION") try: httpd.serve_forever() except KeyboardInterrupt: From d8569aa43e9eb6d5c9b4b498bdd00d6737c8d08a Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Thu, 30 Nov 2023 03:04:13 +0000 Subject: [PATCH 05/18] Add README.md --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa2dec4 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# Comfy Recipes + +Comfy Recipes is a simple application that renders your recipes into HTML. + +Documentation is available at + +## Building the python package +Make sure you have hatchling and build modules installed. +```sh +python3 -m build +``` + +The package can now be installed with +```sh +pip install dist/comfy-recipes-*-py3-none-any.whl +``` + +## Building the docker container +```sh +docker build -t codeberg.org/comfy.city/comfy-recipes . +``` + +The container can now be ran +```sh +docker run --rm codeberg.org/comfy.city/comfy-recipes +``` + +## Building the documentation +```sh +cd docs +mdbook build +``` + +Documentation can now be served with +```sh +mdbook serve +``` From 70432d867e0b350a10b83b830f024b465062a062 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Thu, 30 Nov 2023 03:04:57 +0000 Subject: [PATCH 06/18] update urls in pyproject.toml --- pyproject.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index aad751c..99e6d9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,9 +17,10 @@ classifiers = [ license = { file = "LICENSE" } [project.urls] -Homepage = "https://codeberg.org/comfy.city/recipes" -Repository = "https://codeberg.org/comfy.city/recipes.git" -Issues = "https://codeberg.org/comfy.city/recipes/issues" +Homepage = "https://codeberg.org/comfy.city/comfy-recipes" +Repository = "https://codeberg.org/comfy.city/comfy-recipes.git" +Issues = "https://codeberg.org/comfy.city/comfy-recipes/issues" +Documentation = "https://comfy.city/comfy-recipes/docs" [project.scripts] recipes-cli = "comfyrecipes.cli:main" From 7a9a39f2fbf5648d894f4d959a72ae26fde34cec Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Thu, 30 Nov 2023 03:05:54 +0000 Subject: [PATCH 07/18] make pricedb currency mandatory now, if there is a price entry for an ingredient, it either has to have a currency specified or default_currency has to be set in settings.yaml --- comfyrecipes/parsing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/comfyrecipes/parsing.py b/comfyrecipes/parsing.py index 65ae589..7f73140 100644 --- a/comfyrecipes/parsing.py +++ b/comfyrecipes/parsing.py @@ -564,7 +564,7 @@ class PriceDB(Element): price: float, amount: float, unit: Unit, - currency: Optional[str], + currency: str, ) -> None: super().__init__(ctx) self.price = price @@ -591,4 +591,6 @@ class PriceDB(Element): currency = ctx.settings.default_currency if "currency" in dct: currency = dct["currency"] + if currency is None: + raise RuntimeError("currency not specified and default_currency is also not set") return cls(ctx=ctx, price=price, amount=amount, unit=unit, currency=currency) From 67cb69000bac6ef682fa8a1272429fc266731d8d Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Thu, 30 Nov 2023 03:07:19 +0000 Subject: [PATCH 08/18] fix generate-* subcommands from other directories --- comfyrecipes/cli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/comfyrecipes/cli.py b/comfyrecipes/cli.py index 5205862..74998e9 100644 --- a/comfyrecipes/cli.py +++ b/comfyrecipes/cli.py @@ -50,7 +50,8 @@ def main() -> None: except KeyboardInterrupt: pass elif args.subcommand == "generate-units": - if not args.force and os.path.isfile(args.directory + "/units.yaml"): + os.chdir(args.directory) + if not args.force and os.path.isfile("units.yaml"): print( "units.yaml already exists, pass --force if you want to overwrite it", file=sys.stderr, @@ -59,7 +60,8 @@ def main() -> None: else: builder.generate_units() elif args.subcommand == "generate-ingredients": - if not args.force and os.path.isfile(args.directory + "/ingredients.yaml"): + os.chdir(args.directory) + if not args.force and os.path.isfile("ingredients.yaml"): print( "ingredients.yaml already exists, pass --force if you want to overwrite it", file=sys.stderr, From 08fce0ae1602e2b4d44f22210b123921ba458a97 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Tue, 12 Dec 2023 02:32:04 +0000 Subject: [PATCH 09/18] update package name in dockerfile --- Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7243e52..a4621d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,8 +5,9 @@ RUN apk add --no-cache python3 py3-build py3-hatchling && \ python3 -m build . FROM alpine:3.18 -COPY --from=build /build/dist/comfy-recipes-*-py3-none-any.whl / +COPY --from=build /build/dist/ /mnt RUN apk add --no-cache python3 py3-pip && \ - pip install /comfy-recipes-*-py3-none-any.whl && \ - apk del py3-pip + pip install /mnt/comfy_recipes-*-py3-none-any.whl && \ + apk del py3-pip && \ + rm -r /mnt ENTRYPOINT ["/usr/bin/recipes-cli"] From 8046f0d237c3cae18cb5be64ecd8b8b85c6f3cc3 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Tue, 12 Dec 2023 02:33:12 +0000 Subject: [PATCH 10/18] responsive website --- comfyrecipes/templates/base.html | 1 + 1 file changed, 1 insertion(+) diff --git a/comfyrecipes/templates/base.html b/comfyrecipes/templates/base.html index cf3a0b6..720c2a8 100644 --- a/comfyrecipes/templates/base.html +++ b/comfyrecipes/templates/base.html @@ -7,6 +7,7 @@ {% block title %}{% endblock %} + {% block body %}{% endblock %} From 88f801cadbe176ef06fb790757612b39dd3d5e54 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Sun, 12 May 2024 22:18:45 +0000 Subject: [PATCH 11/18] show full recipe price every time with a clarification if necessary --- comfyrecipes/parsing.py | 27 +++++++++++++++++++++++---- comfyrecipes/templates/base.html | 11 +++++++++++ comfyrecipes/templates/index.html | 2 +- comfyrecipes/templates/recipe.html | 7 +++++-- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/comfyrecipes/parsing.py b/comfyrecipes/parsing.py index 7f73140..6778e05 100644 --- a/comfyrecipes/parsing.py +++ b/comfyrecipes/parsing.py @@ -289,7 +289,7 @@ class Recipe(Element): source: Optional[SafeHTML], ingredients: List[IngredientInstance], subrecipes: List["Recipe"], - price: Optional["PriceDB"], + price: Optional["MultiPriceDB"], stepsections: List[StepSection], ) -> None: super().__init__(ctx) @@ -317,7 +317,7 @@ class Recipe(Element): rp = Recipe.from_dict(ctx, partdct) subrecipes.append(rp) - price: Optional[PriceDB] = None + price: Optional[MultiPriceDB] = None pricex: float = 0 ingswithprice = 0 ingswithoutprice = 0 @@ -335,16 +335,22 @@ class Recipe(Element): # we don't know how to convert currencies yet currency = None break - if currency is None or ingswithoutprice != 0 or len(ingredients) == 0: + if currency is None or len(ingredients) == 0: price = None else: - price = PriceDB( + pricedb = PriceDB( ctx=ctx, price=pricex, amount=1, unit=ctx.default_unit, currency=currency, ) + price = MultiPriceDB( + ctx=ctx, + pricedb=pricedb, + item_count=len(ingredients), + item_prices_missing=ingswithoutprice, + ) stepsections: List[StepSection] = [] if "steps" in dct: @@ -594,3 +600,16 @@ class PriceDB(Element): if currency is None: raise RuntimeError("currency not specified and default_currency is also not set") return cls(ctx=ctx, price=price, amount=amount, unit=unit, currency=currency) + +class MultiPriceDB(Element): + def __init__( + self, + ctx: Context, + pricedb: PriceDB, + item_count: int, + item_prices_missing: int, + ) -> None: + super().__init__(ctx) + self.pricedb = pricedb + self.item_count = item_count + self.item_prices_missing = item_prices_missing diff --git a/comfyrecipes/templates/base.html b/comfyrecipes/templates/base.html index 720c2a8..b85b929 100644 --- a/comfyrecipes/templates/base.html +++ b/comfyrecipes/templates/base.html @@ -1,6 +1,17 @@ {% macro price(price) -%} {% if price != None and price is defined and price.price is defined %}{{price.price|round(1)|numprint}}{%else%}?{% endif %} {{price.currency}} {%- endmacro %} +{% macro multiprice(multiprice, shortform) -%} +{% if multiprice != None and multiprice.pricedb != None and multiprice.pricedb is defined and multiprice.pricedb.price is defined -%} +{{multiprice.pricedb.price|round(1)|numprint}} +{%else%} +? +{%- endif %} + {{multiprice.pricedb.currency}} +{%if multiprice.item_prices_missing != 0 and not shortform%} +({{multiprice.item_prices_missing}}/{{multiprice.item_count}} prices missing) +{%endif%} +{%- endmacro %} diff --git a/comfyrecipes/templates/index.html b/comfyrecipes/templates/index.html index 9a38e25..eaccdb5 100644 --- a/comfyrecipes/templates/index.html +++ b/comfyrecipes/templates/index.html @@ -3,6 +3,6 @@ {%block body %}

Recipes

{% for recipe in recipes %} -
  • {% if recipe.price != None %}{{price(recipe.price)}} {%endif%}{{ recipe.title }}
  • +
  • {% if recipe.price != None %}{{multiprice(recipe.price, true)}} {%endif%}{{ recipe.title }}
  • {% endfor %} {%endblock%} diff --git a/comfyrecipes/templates/recipe.html b/comfyrecipes/templates/recipe.html index 2ffc5b1..81e7591 100644 --- a/comfyrecipes/templates/recipe.html +++ b/comfyrecipes/templates/recipe.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% macro ingredientpart(ing) -%} -{% if recipe.price != None %}{{price(ing.price)}} {%endif%} +{% if ing.price != None %}{{price(ing.price)}} {%endif%} {% if ing.amount != None %} {{ing.amount|amountprint}} {% if ing.unit != None %} {{ing.unit.name}}{% endif %} {%endif%} @@ -29,7 +29,10 @@ {% for ing in rec.ingredients %}
  • {{ingredient(ing)}}
  • {% endfor %} -{% if rec.price != None %}price: {{price(rec.price)}}{%endif%} +{% if rec.price != None %} +
    +price: {{multiprice(rec.price)}} +{%endif%} {% endif %} {% if rec.stepsections|length != 0 %}

    Steps

    From 7b3aa25c955dd7456a4ecee9a0fac080d7010029 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Fri, 11 Oct 2024 22:20:08 +0200 Subject: [PATCH 12/18] Dockerfile: use python image instead of alpine, update --- Dockerfile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index a4621d8..c9bddac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,11 @@ -FROM alpine:3.18 AS build +FROM python:3.13-alpine AS build COPY . /build WORKDIR /build -RUN apk add --no-cache python3 py3-build py3-hatchling && \ +RUN pip install build hatchling && \ python3 -m build . -FROM alpine:3.18 +FROM python:3.13-alpine COPY --from=build /build/dist/ /mnt -RUN apk add --no-cache python3 py3-pip && \ - pip install /mnt/comfy_recipes-*-py3-none-any.whl && \ - apk del py3-pip && \ +RUN pip install /mnt/comfy_recipes-*-py3-none-any.whl && \ rm -r /mnt ENTRYPOINT ["/usr/bin/recipes-cli"] From e35bc3852b47dfd70286f5210eb7a893c1389aa6 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Fri, 11 Oct 2024 22:21:30 +0200 Subject: [PATCH 13/18] update URLs --- README.md | 4 ++-- pyproject.toml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index aa2dec4..3e886c8 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,12 @@ pip install dist/comfy-recipes-*-py3-none-any.whl ## Building the docker container ```sh -docker build -t codeberg.org/comfy.city/comfy-recipes . +docker buildx build -t git.comfy.city/Emi/comfy-recipes:local . ``` The container can now be ran ```sh -docker run --rm codeberg.org/comfy.city/comfy-recipes +docker run --rm git.comfy.city/Emi/comfy-recipes:local ``` ## Building the documentation diff --git a/pyproject.toml b/pyproject.toml index 99e6d9f..7cedace 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,9 +17,9 @@ classifiers = [ license = { file = "LICENSE" } [project.urls] -Homepage = "https://codeberg.org/comfy.city/comfy-recipes" -Repository = "https://codeberg.org/comfy.city/comfy-recipes.git" -Issues = "https://codeberg.org/comfy.city/comfy-recipes/issues" +Homepage = "https://git.comfy.city/Emi/comfy-recipes" +Repository = "https://git.comfy.city/Emi/comfy-recipes.git" +Issues = "https://git.comfy.city/Emi/comfy-recipes/issues" Documentation = "https://comfy.city/comfy-recipes/docs" [project.scripts] From 3e3de7ea597a6ee4d804b08beca567162d4065d9 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Sat, 12 Oct 2024 00:04:40 +0200 Subject: [PATCH 14/18] pyproject.toml: add dependency required with newer lxml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7cedace..e6bf155 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "Smart recipe static site generator" authors = [{ name = "Emi Vasilek", email = "emi.vasilek@gmail.com" }] keywords = ["recipes", "recipe", "static site generator"] requires-python = ">= 3.8" -dependencies = ["jsonschema", "jinja2", "PyYAML", "mistune", "lxml"] +dependencies = ["jsonschema", "jinja2", "PyYAML", "mistune", "lxml", "lxml_html_clean"] classifiers = [ "Development Status :: 3 - Alpha", "Programming Language :: Python", From cc9206306ab3c771a0fdc2bd6dc876d050e4abe1 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Sat, 12 Oct 2024 00:05:45 +0200 Subject: [PATCH 15/18] parsing: also accept short ingredients without amounts for example 'oil' will now be allowed, previously it would have to be `1 spoon oil` when sometimes people don't know the amount --- comfyrecipes/parsing.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/comfyrecipes/parsing.py b/comfyrecipes/parsing.py index 6778e05..fd61440 100644 --- a/comfyrecipes/parsing.py +++ b/comfyrecipes/parsing.py @@ -197,23 +197,24 @@ class IngredientInstance(Element): def from_dict(cls, ctx: Context, dct: str | Dict[str, Any]) -> Self: if isinstance(dct, str): string = dct.strip() - p = re.compile(r"^(?:([0-9\.]+) ([a-zA-Z]+) )?([\w ]+)(?: \((.*)\))?$") + p = re.compile(r"^(?:([0-9\.]+) ([a-zA-Z]+) )+([\w ]+)(?: \((.*)\))?$") match = p.match(string) - if match is None: - raise RuntimeError( - "ingredient {string} regex not matched, it should be in the format [amount(num) unit(string, one word)] name(string, any number of words) [(note(string))]" - ) - amount = float(match.group(1)) - unitstr = match.group(2) + + amount = float(1) unit = ctx.default_unit - if unit is not None: - unitx = ctx.units.get(unitstr) - if unitx is None: - ctx.issues.error(issues.ISSUE_UNKNOWN_UNIT, "unknown unit {unitstr}") - else: - unit = unitx - name = match.group(3) - note = match.group(4) + name = string + note = None + if match is not None: + amount = float(match.group(1)) + unitstr = match.group(2) + if unit is not None: + unitx = ctx.units.get(unitstr) + if unitx is None: + ctx.issues.error(issues.ISSUE_UNKNOWN_UNIT, f"unknown unit {unitstr}") + else: + unit = unitx + name = match.group(3) + note = match.group(4) if note is None: note = "" return cls( From 8a9ae16ad344876e17926b654b9db0f8b390fdfb Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Sat, 12 Oct 2024 00:12:20 +0200 Subject: [PATCH 16/18] .woodpecker: add --- .woodpecker/containers.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .woodpecker/containers.yaml diff --git a/.woodpecker/containers.yaml b/.woodpecker/containers.yaml new file mode 100644 index 0000000..3a83407 --- /dev/null +++ b/.woodpecker/containers.yaml @@ -0,0 +1,15 @@ +when: + - event: push + branch: main + +steps: + - name: publish + image: woodpeckerci/plugin-docker-buildx + settings: + platforms: linux/amd64,linux/arm64/v8 + repo: git.comfy.city/emi/comfy-recipes + registry: git.comfy.city + tags: latest + username: ${CI_REPO_OWNER} + password: + from_secret: registry_token From ae3ee28ab441b88a00addddb4b6fd9dfe8ff11fd Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Sat, 12 Oct 2024 00:20:05 +0200 Subject: [PATCH 17/18] README.md: update --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3e886c8..15c3e4b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,13 @@ Comfy Recipes is a simple application that renders your recipes into HTML. Documentation is available at -## Building the python package +## Running +```sh +docker run -v ./recipes:/recipes git.comfy.city/Emi/comfy-recipes:latest build /recipes +``` + +## Building +### Building the python package Make sure you have hatchling and build modules installed. ```sh python3 -m build @@ -15,17 +21,17 @@ The package can now be installed with pip install dist/comfy-recipes-*-py3-none-any.whl ``` -## Building the docker container +### Building the docker container ```sh docker buildx build -t git.comfy.city/Emi/comfy-recipes:local . ``` The container can now be ran ```sh -docker run --rm git.comfy.city/Emi/comfy-recipes:local +docker run -v ./recipes:/recipes git.comfy.city/Emi/comfy-recipes:local build /recipes ``` -## Building the documentation +### Building the documentation ```sh cd docs mdbook build From 2e5859342d3734dc4749ff988a7a33ec1dca95c1 Mon Sep 17 00:00:00 2001 From: Emi Vasilek Date: Sat, 12 Oct 2024 00:20:25 +0200 Subject: [PATCH 18/18] Dockerfile: fix entrypoint --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c9bddac..e2b34a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,4 @@ FROM python:3.13-alpine COPY --from=build /build/dist/ /mnt RUN pip install /mnt/comfy_recipes-*-py3-none-any.whl && \ rm -r /mnt -ENTRYPOINT ["/usr/bin/recipes-cli"] +ENTRYPOINT ["/usr/local/bin/recipes-cli"]