1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-06 05:55:23 +02:00

feat: plural foods and units, and aliases (#2674)

* added plural names and alias tables to foods/units

* updated models to include plural names and aliases

* updated parser to include plural and aliases

* fixed migrations

* fixed recursive models

* added plural abbreviation to migration

* updated parser and display prop

* update displays to use plurals

* fix display edgecase and remove print

* added/updated display tests

* fixed model bug and added parser tests

* added tests for aliases

* added new plural options to data management page

* removed unique constraint

* made base dialog more customizable

* added alias management to food and unit data pages

* removed unused awaits

* 🧹
This commit is contained in:
Michael Genson 2023-11-14 09:39:07 -06:00 committed by GitHub
parent 4b55b838ed
commit d440d51ffe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1181 additions and 104 deletions

View file

@ -0,0 +1,202 @@
from uuid import uuid4
import pytest
from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit, RecipeIngredient
from tests.utils.factories import random_string
@pytest.mark.parametrize(
["quantity", "quantity_display_decimal", "quantity_display_fraction", "expect_plural_unit", "expect_plural_food"],
[
[0, "", "", False, True],
[0.5, "0.5", "¹/₂", False, False],
[1, "1", "1", False, False],
[1.5, "1.5", "1 ¹/₂", True, True],
[2, "2", "2", True, True],
],
)
@pytest.mark.parametrize(
["unit", "expect_display_fraction", "expected_unit_singular_string", "expected_unit_plural_string"],
[
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name=None,
abbreviation="tbsp",
plural_abbreviation=None,
use_abbreviation=False,
fraction=True,
),
True,
"tablespoon",
"tablespoon",
],
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name=None,
abbreviation="tbsp",
plural_abbreviation=None,
use_abbreviation=False,
fraction=False,
),
False,
"tablespoon",
"tablespoon",
],
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name=None,
abbreviation="tbsp",
plural_abbreviation=None,
use_abbreviation=True,
fraction=True,
),
True,
"tbsp",
"tbsp",
],
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name=None,
abbreviation="tbsp",
plural_abbreviation=None,
use_abbreviation=True,
fraction=False,
),
False,
"tbsp",
"tbsp",
],
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name="tablespoons",
abbreviation="tbsp",
plural_abbreviation="tbsps",
use_abbreviation=False,
fraction=True,
),
True,
"tablespoon",
"tablespoons",
],
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name="tablespoons",
abbreviation="tbsp",
plural_abbreviation="tbsps",
use_abbreviation=False,
fraction=False,
),
False,
"tablespoon",
"tablespoons",
],
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name="tablespoons",
abbreviation="tbsp",
plural_abbreviation="tbsps",
use_abbreviation=True,
fraction=True,
),
True,
"tbsp",
"tbsps",
],
[
IngredientUnit(
id=uuid4(),
name="tablespoon",
plural_name="tablespoons",
abbreviation="tbsp",
plural_abbreviation="tbsps",
use_abbreviation=True,
fraction=False,
),
False,
"tbsp",
"tbsps",
],
],
)
@pytest.mark.parametrize(
["food", "expected_food_singular_string", "expected_food_plural_string"],
[
[
IngredientFood(id=uuid4(), name="chopped onion", plural_name=None),
"chopped onion",
"chopped onion",
],
[
IngredientFood(id=uuid4(), name="chopped onion", plural_name="chopped onions"),
"chopped onion",
"chopped onions",
],
],
)
@pytest.mark.parametrize("note", ["very thin", ""])
@pytest.mark.parametrize("use_food", [True, False])
def test_ingredient_display(
quantity: float | None,
quantity_display_decimal: str,
quantity_display_fraction: str,
unit: IngredientUnit,
food: IngredientFood,
note: str,
use_food: bool,
expect_display_fraction: bool,
expect_plural_unit: bool,
expect_plural_food: bool,
expected_unit_singular_string: str,
expected_unit_plural_string: str,
expected_food_singular_string: str,
expected_food_plural_string: str,
):
expected_components = []
if use_food:
if expect_display_fraction:
expected_components.append(quantity_display_fraction)
else:
expected_components.append(quantity_display_decimal)
if quantity:
if expect_plural_unit:
expected_components.append(expected_unit_plural_string)
else:
expected_components.append(expected_unit_singular_string)
if expect_plural_food:
expected_components.append(expected_food_plural_string)
else:
expected_components.append(expected_food_singular_string)
expected_components.append(note)
else:
if quantity != 0 and quantity != 1:
if expect_display_fraction:
expected_components.append(quantity_display_fraction)
else:
expected_components.append(quantity_display_decimal)
expected_components.append(note)
expected_display_value = " ".join(c for c in expected_components if c)
ingredient = RecipeIngredient(
quantity=quantity, unit=unit, food=food, note=note, use_food=use_food, disable_amount=not use_food
)
assert ingredient.display == expected_display_value

View file

@ -9,7 +9,9 @@ from mealie.db.db_setup import session_context
from mealie.repos.repository_factory import AllRepositories
from mealie.schema.recipe.recipe_ingredient import (
CreateIngredientFood,
CreateIngredientFoodAlias,
CreateIngredientUnit,
CreateIngredientUnitAlias,
IngredientFood,
IngredientUnit,
ParsedIngredient,
@ -67,6 +69,12 @@ def parsed_ingredient_data(
SaveIngredientFood(name="fresh ginger", group_id=unique_local_group_id),
SaveIngredientFood(name="ground ginger", group_id=unique_local_group_id),
SaveIngredientFood(name="ñör̃m̈ãl̈ĩz̈ẽm̈ẽ", group_id=unique_local_group_id),
SaveIngredientFood(name="PluralFoodTest", plural_name="myfoodisplural", group_id=unique_local_group_id),
SaveIngredientFood(
name="IHaveAnAlias",
group_id=unique_local_group_id,
aliases=[CreateIngredientFoodAlias(name="thisismyalias")],
),
]
)
@ -86,6 +94,18 @@ def parsed_ingredient_data(
SaveIngredientUnit(name="Teaspoon", group_id=unique_local_group_id),
SaveIngredientUnit(name="Stalk", group_id=unique_local_group_id),
SaveIngredientUnit(name="My Very Long Unit Name", abbreviation="mvlun", group_id=unique_local_group_id),
SaveIngredientUnit(
name="PluralUnitName",
plural_name="abc123",
abbreviation="doremiabc",
plural_abbreviation="doremi123",
group_id=unique_local_group_id,
),
SaveIngredientUnit(
name="IHaveAnAliasToo",
group_id=unique_local_group_id,
aliases=[CreateIngredientUnitAlias(name="thisismyalias")],
),
]
)
@ -267,6 +287,46 @@ def test_brute_parser(unique_user: TestUser):
True,
id="normalization",
),
pytest.param(
build_parsed_ing(unit=None, food="myfoodisplural"),
None,
"PluralFoodTest",
False,
True,
id="plural food name",
),
pytest.param(
build_parsed_ing(unit="abc123", food=None),
"PluralUnitName",
None,
True,
False,
id="plural unit name",
),
pytest.param(
build_parsed_ing(unit="doremi123", food=None),
"PluralUnitName",
None,
True,
False,
id="plural unit abbreviation",
),
pytest.param(
build_parsed_ing(unit=None, food="thisismyalias"),
None,
"IHaveAnAlias",
False,
True,
id="food alias",
),
pytest.param(
build_parsed_ing(unit="thisismyalias", food=None),
"IHaveAnAliasToo",
None,
True,
False,
id="unit alias",
),
),
)
def test_parser_ingredient_match(