updated pytest and fixed ingredient parser

This commit is contained in:
vabene1111
2025-07-28 19:29:20 +02:00
parent 50400e1d20
commit 368ed2aaf3
8 changed files with 55 additions and 970 deletions

View File

@@ -38,7 +38,7 @@ jobs:
./cookbook/static ./cookbook/static
./staticfiles ./staticfiles
key: | 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 # Build Vue frontend & Dependencies
- name: Set up Node ${{ matrix.node-version }} - name: Set up Node ${{ matrix.node-version }}

2
.gitignore vendored
View File

@@ -89,3 +89,5 @@ venv/
.idea/easy-i18n.xml .idea/easy-i18n.xml
cookbook/static/vue3 cookbook/static/vue3
vue3/node_modules vue3/node_modules
cookbook/tests/other/docs/reports/tests/tests.html
cookbook/tests/other/docs/reports/tests/pytest.xml

View File

@@ -211,44 +211,46 @@ class IngredientParser:
# three arguments if it already has a unit there can't be # three arguments if it already has a unit there can't be
# a fraction for the amount # a fraction for the amount
if len(tokens) > 2: if len(tokens) > 2:
never_unit_applied = False
if not self.ignore_rules: if not self.ignore_rules:
tokens, never_unit_applied = self.automation.apply_never_unit_automation(tokens) tokens, never_unit_applied = self.automation.apply_never_unit_automation(tokens)
if never_unit_applied:
unit = tokens[1] if never_unit_applied:
food, note = self.parse_food(tokens[2:]) unit = tokens[1]
else: food, note = self.parse_food(tokens[2:])
try: else:
if unit is not None: try:
# a unit is already found, no need to try the second argument for a fraction if unit is not None:
# 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 # a unit is already found, no need to try the second argument for a fraction
raise ValueError # 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
# try to parse second argument as amount and add that, in case of '2 1/2' or '2 ½' raise ValueError
if tokens[1]: # try to parse second argument as amount and add that, in case of '2 1/2' or '2 ½'
amount += self.parse_fraction(tokens[1]) if tokens[1]:
# assume that units can't end with a comma amount += self.parse_fraction(tokens[1])
if len(tokens) > 3 and not tokens[2].endswith(','): # assume that units can't end with a comma
# try to use third argument as unit and everything else as food, use everything as food if it fails if len(tokens) > 3 and not tokens[2].endswith(','):
try: # try to use third argument as unit and everything else as food, use everything as food if it fails
food, note = self.parse_food(tokens[3:]) try:
unit = tokens[2] food, note = self.parse_food(tokens[3:])
except ValueError: unit = tokens[2]
food, note = self.parse_food(tokens[2:]) except ValueError:
else:
food, note = self.parse_food(tokens[2:]) food, note = self.parse_food(tokens[2:])
except ValueError: else:
# assume that units can't end with a comma food, note = self.parse_food(tokens[2:])
if not tokens[1].endswith(','): except ValueError:
# try to use second argument as unit and everything else as food, use everything as food if it fails # assume that units can't end with a comma
try: if not tokens[1].endswith(','):
food, note = self.parse_food(tokens[2:]) # try to use second argument as unit and everything else as food, use everything as food if it fails
if unit is None: try:
unit = tokens[1] food, note = self.parse_food(tokens[2:])
else: if unit is None:
note = tokens[1] unit = tokens[1]
except ValueError: else:
food, note = self.parse_food(tokens[1:]) note = tokens[1]
else: except ValueError:
food, note = self.parse_food(tokens[1:]) food, note = self.parse_food(tokens[1:])
else:
food, note = self.parse_food(tokens[1:])
else: else:
# only two arguments, first one is the amount # only two arguments, first one is the amount
# which means this is the food # which means this is the food
@@ -269,6 +271,7 @@ class IngredientParser:
if food and not self.ignore_rules: if food and not self.ignore_rules:
food = self.automation.apply_food_automation(food) food = self.automation.apply_food_automation(food)
if len(food) > Food._meta.get_field('name').max_length: # test if food name is to long 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 # 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: if len(food.split()) > 1 and len(food.split()[0]) < Food._meta.get_field('name').max_length:

View File

@@ -1,157 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="4" failures="0" skipped="0" tests="4" time="34.750" timestamp="2025-07-17T12:15:15.274960+02:00" hostname="DESKTOP-RM10LP5"><testcase classname="cookbook.tests.other.test_automations" name="test_never_unit_automation[arg0]" time="22.035"><error message="failed on setup with &quot;TypeError: type 'Factory' is not subscriptable&quot;">args = ()
kwargs = {'request': &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg0]&gt;&gt;}
k = 'space_1__name'
@functools.wraps(fixture_function)
def wrapper(*args: P.args, **kwargs: P.kwargs) -&gt; T:
for k in set(kwargs.keys()) - function_args:
del kwargs[k]
&gt; 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 = &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg0]&gt;&gt;
factory_name = 'space_factory'
def model_fixture(request: SubRequest, factory_name: str) -&gt; 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
&gt; 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</error></testcase><testcase classname="cookbook.tests.other.test_automations" name="test_never_unit_automation[arg2]" time="22.047"><error message="failed on setup with &quot;TypeError: type 'Factory' is not subscriptable&quot;">args = ()
kwargs = {'request': &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg2]&gt;&gt;}
k = 'space_1__name'
@functools.wraps(fixture_function)
def wrapper(*args: P.args, **kwargs: P.kwargs) -&gt; T:
for k in set(kwargs.keys()) - function_args:
del kwargs[k]
&gt; 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 = &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg2]&gt;&gt;
factory_name = 'space_factory'
def model_fixture(request: SubRequest, factory_name: str) -&gt; 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
&gt; 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</error></testcase><testcase classname="cookbook.tests.other.test_automations" name="test_never_unit_automation[arg3]" time="22.106"><error message="failed on setup with &quot;TypeError: type 'Factory' is not subscriptable&quot;">args = ()
kwargs = {'request': &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg3]&gt;&gt;}
k = 'space_1__name'
@functools.wraps(fixture_function)
def wrapper(*args: P.args, **kwargs: P.kwargs) -&gt; T:
for k in set(kwargs.keys()) - function_args:
del kwargs[k]
&gt; 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 = &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg3]&gt;&gt;
factory_name = 'space_factory'
def model_fixture(request: SubRequest, factory_name: str) -&gt; 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
&gt; 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</error></testcase><testcase classname="cookbook.tests.other.test_automations" name="test_never_unit_automation[arg1]" time="22.143"><error message="failed on setup with &quot;TypeError: type 'Factory' is not subscriptable&quot;">args = ()
kwargs = {'request': &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg1]&gt;&gt;}
k = 'space_1__name'
@functools.wraps(fixture_function)
def wrapper(*args: P.args, **kwargs: P.kwargs) -&gt; T:
for k in set(kwargs.keys()) - function_args:
del kwargs[k]
&gt; 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 = &lt;SubRequest 'space_1' for &lt;Function test_never_unit_automation[arg1]&gt;&gt;
factory_name = 'space_factory'
def model_fixture(request: SubRequest, factory_name: str) -&gt; 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
&gt; 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</error></testcase></testsuite></testsuites>

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,4 @@
import pytest
from django.contrib import auth from django.contrib import auth
from django.test import RequestFactory from django.test import RequestFactory
from django_scopes import scope from django_scopes import scope
@@ -5,7 +6,11 @@ from django_scopes import scope
from cookbook.helper.ingredient_parser import IngredientParser 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 = { expectations = {
"2¼ l Wasser": (2.25, "l", "Wasser", ""), "2¼ l Wasser": (2.25, "l", "Wasser", ""),
"3¼l Wasser": (3.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 "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 # 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 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 LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl": (
1.0, None, 'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingeli', 1.0, None, 'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingeli',
'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl'), 'LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl'),
@@ -86,7 +92,7 @@ def test_ingredient_parser(u1_s1):
request = RequestFactory() request = RequestFactory()
request.user = user request.user = user
request.space = space request.space = space
ingredient_parser = IngredientParser(request, False, ignore_automations=True) ingredient_parser = IngredientParser(request, False, ignore_automations=arg[0])
count = 0 count = 0
with scope(space=space): with scope(space=space):

View File

@@ -4,4 +4,5 @@ testpaths = cookbook/tests
python_files = tests.py test_*.py *_tests.py python_files = tests.py test_*.py *_tests.py
# uncomment to run coverage reports # 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 --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 # addopts = -n auto --junitxml=docs/reports/tests/pytest.xml --html=docs/reports/tests/tests.html
asyncio_default_fixture_loop_scope = fixture

View File

@@ -55,11 +55,11 @@ litellm==1.64.1
# Development # Development
pytest==8.4.1 pytest==8.4.1
pytest-django==4.11.0 pytest-django==4.11.0
pytest-cov===6.0.0 pytest-cov===6.2.1
pytest-factoryboy==2.8.0 pytest-factoryboy==2.8.1
pytest-html==4.1.1 pytest-html==4.1.1
pytest-asyncio==0.25.3 pytest-asyncio==1.1.0
pytest-xdist==3.7.0 pytest-xdist==3.8.0
autopep8==2.3.2 autopep8==2.3.2
flake8==7.3.0 flake8==7.3.0
yapf==0.40.2 yapf==0.40.2