From 368ed2aaf30cff6369a4f389caca2f16385c02b7 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 28 Jul 2025 19:29:20 +0200 Subject: [PATCH] updated pytest and fixed ingredient parser --- .github/workflows/ci.yml | 2 +- .gitignore | 2 + cookbook/helper/ingredient_parser.py | 71 +- .../tests/other/docs/reports/tests/pytest.xml | 157 ---- .../tests/other/docs/reports/tests/tests.html | 770 ------------------ .../tests/other/test_ingredient_parser.py | 12 +- pytest.ini | 3 +- requirements.txt | 8 +- 8 files changed, 55 insertions(+), 970 deletions(-) delete mode 100644 cookbook/tests/other/docs/reports/tests/pytest.xml delete mode 100644 cookbook/tests/other/docs/reports/tests/tests.html diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8651ff628..56006b360 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: ./cookbook/static ./staticfiles key: | - ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.node-version }}-collectstatic-${{ hashFiles('**/*.css', '**/*.js', 'vue/src/*') }} + ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.node-version }}-collectstatic-${{ hashFiles('**/*.css', '**/*.js', 'vue3/src/*') }} # Build Vue frontend & Dependencies - name: Set up Node ${{ matrix.node-version }} diff --git a/.gitignore b/.gitignore index 24df2fd47..16ceed730 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,5 @@ venv/ .idea/easy-i18n.xml cookbook/static/vue3 vue3/node_modules +cookbook/tests/other/docs/reports/tests/tests.html +cookbook/tests/other/docs/reports/tests/pytest.xml diff --git a/cookbook/helper/ingredient_parser.py b/cookbook/helper/ingredient_parser.py index 66c94415c..a99efb421 100644 --- a/cookbook/helper/ingredient_parser.py +++ b/cookbook/helper/ingredient_parser.py @@ -211,44 +211,46 @@ class IngredientParser: # three arguments if it already has a unit there can't be # a fraction for the amount if len(tokens) > 2: + never_unit_applied = False if not self.ignore_rules: tokens, never_unit_applied = self.automation.apply_never_unit_automation(tokens) - if never_unit_applied: - unit = tokens[1] - food, note = self.parse_food(tokens[2:]) - else: - try: - if unit is not None: - # a unit is already found, no need to try the second argument for a fraction - # probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except - raise ValueError - # try to parse second argument as amount and add that, in case of '2 1/2' or '2 ½' - if tokens[1]: - amount += self.parse_fraction(tokens[1]) - # assume that units can't end with a comma - if len(tokens) > 3 and not tokens[2].endswith(','): - # try to use third argument as unit and everything else as food, use everything as food if it fails - try: - food, note = self.parse_food(tokens[3:]) - unit = tokens[2] - except ValueError: - food, note = self.parse_food(tokens[2:]) - else: + + if never_unit_applied: + unit = tokens[1] + food, note = self.parse_food(tokens[2:]) + else: + try: + if unit is not None: + # a unit is already found, no need to try the second argument for a fraction + # probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except + raise ValueError + # try to parse second argument as amount and add that, in case of '2 1/2' or '2 ½' + if tokens[1]: + amount += self.parse_fraction(tokens[1]) + # assume that units can't end with a comma + if len(tokens) > 3 and not tokens[2].endswith(','): + # try to use third argument as unit and everything else as food, use everything as food if it fails + try: + food, note = self.parse_food(tokens[3:]) + unit = tokens[2] + except ValueError: food, note = self.parse_food(tokens[2:]) - except ValueError: - # assume that units can't end with a comma - if not tokens[1].endswith(','): - # try to use second argument as unit and everything else as food, use everything as food if it fails - try: - food, note = self.parse_food(tokens[2:]) - if unit is None: - unit = tokens[1] - else: - note = tokens[1] - except ValueError: - food, note = self.parse_food(tokens[1:]) - else: + else: + food, note = self.parse_food(tokens[2:]) + except ValueError: + # assume that units can't end with a comma + if not tokens[1].endswith(','): + # try to use second argument as unit and everything else as food, use everything as food if it fails + try: + food, note = self.parse_food(tokens[2:]) + if unit is None: + unit = tokens[1] + else: + note = tokens[1] + except ValueError: food, note = self.parse_food(tokens[1:]) + else: + food, note = self.parse_food(tokens[1:]) else: # only two arguments, first one is the amount # which means this is the food @@ -269,6 +271,7 @@ class IngredientParser: if food and not self.ignore_rules: food = self.automation.apply_food_automation(food) + if len(food) > Food._meta.get_field('name').max_length: # test if food name is to long # try splitting it at a space and taking only the first arg if len(food.split()) > 1 and len(food.split()[0]) < Food._meta.get_field('name').max_length: diff --git a/cookbook/tests/other/docs/reports/tests/pytest.xml b/cookbook/tests/other/docs/reports/tests/pytest.xml deleted file mode 100644 index 692255ba3..000000000 --- a/cookbook/tests/other/docs/reports/tests/pytest.xml +++ /dev/null @@ -1,157 +0,0 @@ -args = () -kwargs = {'request': <SubRequest 'space_1' for <Function test_never_unit_automation[arg0]>>} -k = 'space_1__name' - - @functools.wraps(fixture_function) - def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: - for k in set(kwargs.keys()) - function_args: - del kwargs[k] -> return fixture_function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:88: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:49: in fn - return function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^ -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -request = <SubRequest 'space_1' for <Function test_never_unit_automation[arg0]>> -factory_name = 'space_factory' - - def model_fixture(request: SubRequest, factory_name: str) -> object: - """Model fixture implementation.""" - factoryboy_request: FactoryboyRequest = request.getfixturevalue("factoryboy_request") - - # Try to evaluate as much post-generation dependencies as possible - factoryboy_request.evaluate(request) - - assert request.fixturename # NOTE: satisfy mypy - fixture_name = request.fixturename - prefix = "".join((fixture_name, SEPARATOR)) - - factory_class: type[Factory[object]] = request.getfixturevalue(factory_name) - - # Create model fixture instance -> NewFactory: type[Factory[object]] = cast(type[Factory[object]], type("Factory", (factory_class,), {})) - ^^^^^^^^^^^^^^^ -E TypeError: type 'Factory' is not subscriptable - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixture.py:360: TypeErrorargs = () -kwargs = {'request': <SubRequest 'space_1' for <Function test_never_unit_automation[arg2]>>} -k = 'space_1__name' - - @functools.wraps(fixture_function) - def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: - for k in set(kwargs.keys()) - function_args: - del kwargs[k] -> return fixture_function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:88: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:49: in fn - return function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^ -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -request = <SubRequest 'space_1' for <Function test_never_unit_automation[arg2]>> -factory_name = 'space_factory' - - def model_fixture(request: SubRequest, factory_name: str) -> object: - """Model fixture implementation.""" - factoryboy_request: FactoryboyRequest = request.getfixturevalue("factoryboy_request") - - # Try to evaluate as much post-generation dependencies as possible - factoryboy_request.evaluate(request) - - assert request.fixturename # NOTE: satisfy mypy - fixture_name = request.fixturename - prefix = "".join((fixture_name, SEPARATOR)) - - factory_class: type[Factory[object]] = request.getfixturevalue(factory_name) - - # Create model fixture instance -> NewFactory: type[Factory[object]] = cast(type[Factory[object]], type("Factory", (factory_class,), {})) - ^^^^^^^^^^^^^^^ -E TypeError: type 'Factory' is not subscriptable - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixture.py:360: TypeErrorargs = () -kwargs = {'request': <SubRequest 'space_1' for <Function test_never_unit_automation[arg3]>>} -k = 'space_1__name' - - @functools.wraps(fixture_function) - def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: - for k in set(kwargs.keys()) - function_args: - del kwargs[k] -> return fixture_function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:88: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:49: in fn - return function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^ -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -request = <SubRequest 'space_1' for <Function test_never_unit_automation[arg3]>> -factory_name = 'space_factory' - - def model_fixture(request: SubRequest, factory_name: str) -> object: - """Model fixture implementation.""" - factoryboy_request: FactoryboyRequest = request.getfixturevalue("factoryboy_request") - - # Try to evaluate as much post-generation dependencies as possible - factoryboy_request.evaluate(request) - - assert request.fixturename # NOTE: satisfy mypy - fixture_name = request.fixturename - prefix = "".join((fixture_name, SEPARATOR)) - - factory_class: type[Factory[object]] = request.getfixturevalue(factory_name) - - # Create model fixture instance -> NewFactory: type[Factory[object]] = cast(type[Factory[object]], type("Factory", (factory_class,), {})) - ^^^^^^^^^^^^^^^ -E TypeError: type 'Factory' is not subscriptable - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixture.py:360: TypeErrorargs = () -kwargs = {'request': <SubRequest 'space_1' for <Function test_never_unit_automation[arg1]>>} -k = 'space_1__name' - - @functools.wraps(fixture_function) - def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: - for k in set(kwargs.keys()) - function_args: - del kwargs[k] -> return fixture_function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:88: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixturegen.py:49: in fn - return function(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^ -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -request = <SubRequest 'space_1' for <Function test_never_unit_automation[arg1]>> -factory_name = 'space_factory' - - def model_fixture(request: SubRequest, factory_name: str) -> object: - """Model fixture implementation.""" - factoryboy_request: FactoryboyRequest = request.getfixturevalue("factoryboy_request") - - # Try to evaluate as much post-generation dependencies as possible - factoryboy_request.evaluate(request) - - assert request.fixturename # NOTE: satisfy mypy - fixture_name = request.fixturename - prefix = "".join((fixture_name, SEPARATOR)) - - factory_class: type[Factory[object]] = request.getfixturevalue(factory_name) - - # Create model fixture instance -> NewFactory: type[Factory[object]] = cast(type[Factory[object]], type("Factory", (factory_class,), {})) - ^^^^^^^^^^^^^^^ -E TypeError: type 'Factory' is not subscriptable - -..\..\..\venv\Lib\site-packages\pytest_factoryboy\fixture.py:360: TypeError \ No newline at end of file diff --git a/cookbook/tests/other/docs/reports/tests/tests.html b/cookbook/tests/other/docs/reports/tests/tests.html deleted file mode 100644 index 8da3718d1..000000000 --- a/cookbook/tests/other/docs/reports/tests/tests.html +++ /dev/null @@ -1,770 +0,0 @@ - - - - - tests.html - - - -

tests.html

-

Report generated on 17-Jul-2025 at 12:15:50 by pytest-html - v4.1.1

-
-

Environment

-
-
- - - - - -
-
-

Summary

-
-
-

0 test took 00:01:28.

-

(Un)check the boxes to filter the results.

-
- -
-
-
-
- - 0 Failed, - - 0 Passed, - - 0 Skipped, - - 0 Expected failures, - - 0 Unexpected passes, - - 4 Errors, - - 0 Reruns -
-
-  /  -
-
-
-
-
-
-
-
- - - - - - - - - -
ResultTestDurationLinks
- - - \ No newline at end of file diff --git a/cookbook/tests/other/test_ingredient_parser.py b/cookbook/tests/other/test_ingredient_parser.py index 30c6eb6ab..c4cda057e 100644 --- a/cookbook/tests/other/test_ingredient_parser.py +++ b/cookbook/tests/other/test_ingredient_parser.py @@ -1,3 +1,4 @@ +import pytest from django.contrib import auth from django.test import RequestFactory from django_scopes import scope @@ -5,7 +6,11 @@ from django_scopes import scope from cookbook.helper.ingredient_parser import IngredientParser -def test_ingredient_parser(u1_s1): +@pytest.mark.parametrize("arg", [ + [True], + [False], +]) +def test_ingredient_parser(arg, u1_s1): expectations = { "2¼ l Wasser": (2.25, "l", "Wasser", ""), "3¼l Wasser": (3.25, "l", "Wasser", ""), @@ -67,7 +72,8 @@ def test_ingredient_parser(u1_s1): "1 Porreestange(n) , ca. 200 g": (1.0, None, 'Porreestange(n)', 'ca. 200 g'), # leading space before comma # test for over long food entries to get properly split into the note field "1 Lorem ipsum dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l Lorem ipsum dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l": ( - 1.0, 'Lorem', 'ipsum', 'dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l Lorem ipsum dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l'), + 1.0, 'Lorem', 'ipsum', + 'dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l Lorem ipsum dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut l'), "1 LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl": ( 1.0, None, 'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingeli', 'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl'), @@ -86,7 +92,7 @@ def test_ingredient_parser(u1_s1): request = RequestFactory() request.user = user request.space = space - ingredient_parser = IngredientParser(request, False, ignore_automations=True) + ingredient_parser = IngredientParser(request, False, ignore_automations=arg[0]) count = 0 with scope(space=space): diff --git a/pytest.ini b/pytest.ini index a3d26ec48..2755dc99d 100644 --- a/pytest.ini +++ b/pytest.ini @@ -4,4 +4,5 @@ testpaths = cookbook/tests python_files = tests.py test_*.py *_tests.py # uncomment to run coverage reports addopts = -n auto --cov=. --cov-report=html:docs/reports/coverage --cov-report=xml:docs/reports/coverage/coverage.xml --junitxml=docs/reports/tests/pytest.xml --html=docs/reports/tests/tests.html -# addopts = -n auto --junitxml=docs/reports/tests/pytest.xml --html=docs/reports/tests/tests.html \ No newline at end of file +# addopts = -n auto --junitxml=docs/reports/tests/pytest.xml --html=docs/reports/tests/tests.html +asyncio_default_fixture_loop_scope = fixture \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index f0e7a21f5..ae629f162 100644 --- a/requirements.txt +++ b/requirements.txt @@ -55,11 +55,11 @@ litellm==1.64.1 # Development pytest==8.4.1 pytest-django==4.11.0 -pytest-cov===6.0.0 -pytest-factoryboy==2.8.0 +pytest-cov===6.2.1 +pytest-factoryboy==2.8.1 pytest-html==4.1.1 -pytest-asyncio==0.25.3 -pytest-xdist==3.7.0 +pytest-asyncio==1.1.0 +pytest-xdist==3.8.0 autopep8==2.3.2 flake8==7.3.0 yapf==0.40.2