diff --git a/api/ingredients.py b/api/ingredients.py index e1bdcb0..838d4cc 100644 --- a/api/ingredients.py +++ b/api/ingredients.py @@ -34,5 +34,3 @@ async def parse_ingredient( parsed_one = ingredients_mod.parse_ingredient_from_nlp(line) matched_one = await ingredients_mod.match_existing_products(conn, [parsed_one]) return matched_one[0] - - diff --git a/api/meals.py b/api/meals.py index 12c4eab..59c7ac9 100644 --- a/api/meals.py +++ b/api/meals.py @@ -244,7 +244,9 @@ async def create_meal_scoped( valid_ids = set(users.keys()) invalid = sorted(member_ids - valid_ids) if invalid: - return error_response(request, 400, f"Invalid member id(s): {', '.join(map(str, invalid))}") + return error_response( + request, 400, f"Invalid member id(s): {', '.join(map(str, invalid))}" + ) # Validate recipes (existence and household scope) via recipes repository if domain_meal.recipes: @@ -263,7 +265,11 @@ async def create_meal_scoped( if not recipe: invalid_recipes.append(rid) if invalid_recipes: - return error_response(request, 400, f"Invalid recipe id(s): {', '.join(map(str, sorted(set(invalid_recipes))))}") + return error_response( + request, + 400, + f"Invalid recipe id(s): {', '.join(map(str, sorted(set(invalid_recipes))))}", + ) try: await meals.insert_meal_scoped(conn, domain_meal, hid) except aiosqlite.IntegrityError: @@ -338,7 +344,9 @@ async def update_meal_scoped( valid_ids = set(users.keys()) invalid = sorted(member_ids - valid_ids) if invalid: - return error_response(request, 400, f"Invalid member id(s): {', '.join(map(str, invalid))}") + return error_response( + request, 400, f"Invalid member id(s): {', '.join(map(str, invalid))}" + ) if domain_meal.recipes: from recipes.repository import find_recipe_by_id_scoped, find_recipe_by_id @@ -355,7 +363,11 @@ async def update_meal_scoped( if not recipe: invalid_recipes.append(rid) if invalid_recipes: - return error_response(request, 400, f"Invalid recipe id(s): {', '.join(map(str, sorted(set(invalid_recipes))))}") + return error_response( + request, + 400, + f"Invalid recipe id(s): {', '.join(map(str, sorted(set(invalid_recipes))))}", + ) await meals.update_meal(conn, domain_meal) # Return updated state updated = await meals.find_meal_by_id_scoped(conn, meal_id, hid) diff --git a/main.py b/main.py index 5c73b6f..942e39c 100644 --- a/main.py +++ b/main.py @@ -141,6 +141,7 @@ def create_app() -> FastAPI: app.include_router(recipes_router.router, prefix="/api/v1", tags=["recipes"]) # canonical app.include_router(recipes_router.public, prefix="/api/v1", tags=["recipes"]) # public utils from api import ingredients as ingredients_router + app.include_router(ingredients_router.router, prefix="/api/v1", tags=["ingredients"]) # scoped app.include_router(meals_router.router, prefix="/api/v1", tags=["meals"]) # canonical app.include_router(shopping_router.router, prefix="/api/v1", tags=["shopping"]) # canonical diff --git a/recipes/scraping.py b/recipes/scraping.py index cd68a5d..2c92aba 100644 --- a/recipes/scraping.py +++ b/recipes/scraping.py @@ -52,9 +52,7 @@ def _fallback_urls(url: str) -> Iterable[str]: q = dict(parse_qsl(parsed.query, keep_blank_values=True)) if q.get("output") != "amp": q["output"] = "amp" - amp_url = urlunparse( - parsed._replace(query=urlencode(q, doseq=True)) - ) + amp_url = urlunparse(parsed._replace(query=urlencode(q, doseq=True))) if amp_url != url: yield amp_url @@ -79,9 +77,7 @@ async def scrape_recipe_ldata(url: str) -> Optional[dict]: # Some CDNs prefer a referer; provide same-origin referer as a harmless hint. headers = dict(DEFAULT_HEADERS) headers.setdefault("Referer", candidate) - response = await client.get( - candidate, headers=headers, follow_redirects=True - ) + response = await client.get(candidate, headers=headers, follow_redirects=True) if response.status_code in BLOCK_STATUSES: # Try next fallback continue diff --git a/shopping/repository.py b/shopping/repository.py index 1f33b2d..3894e8a 100644 --- a/shopping/repository.py +++ b/shopping/repository.py @@ -298,7 +298,7 @@ async def request_meal_scoped( INSERT INTO ShoppingListItem (ingredient_id, person_id, meal_id, created_date, household_id) VALUES (?, ?, ?, ?, ?) """, - (None, person_id, meal.id, item.created_date.isoformat(), household_id), + (None, person_id, meal.id, item.created_date.isoformat(), household_id), ) as cursor: item.id = cursor.lastrowid diff --git a/tests/test_recipes_parse_from_url_integration_v2.py b/tests/test_recipes_parse_from_url_integration_v2.py index c625faa..bb18556 100644 --- a/tests/test_recipes_parse_from_url_integration_v2.py +++ b/tests/test_recipes_parse_from_url_integration_v2.py @@ -7,7 +7,7 @@ from db import connect, create SAMPLE_URL = "https://www.allrecipes.com/recipe/262696/cheese-omelette/" with open("tests/sample_files/recipes/cheese-omelette.html", "r", encoding="utf-8") as f: - SAMPLE_HTML = f.read() + SAMPLE_HTML = f.read() class TestRecipesParseFromUrlIntegrationV2(unittest.IsolatedAsyncioTestCase): @@ -58,7 +58,9 @@ class TestRecipesParseFromUrlIntegrationV2(unittest.IsolatedAsyncioTestCase): async def get(self, url, headers=None, follow_redirects=False): # Allow the scraper to call the base URL or an AMP fallback - assert url == SAMPLE_URL or (url.startswith(SAMPLE_URL) and ("output=amp" in url or url.endswith("/amp"))) + assert url == SAMPLE_URL or ( + url.startswith(SAMPLE_URL) and ("output=amp" in url or url.endswith("/amp")) + ) return DummyResp(200, SAMPLE_HTML) orig_client = scraping.httpx.AsyncClient diff --git a/tests/test_recipes_parse_from_url_v2.py b/tests/test_recipes_parse_from_url_v2.py index 4cce535..b066c43 100644 --- a/tests/test_recipes_parse_from_url_v2.py +++ b/tests/test_recipes_parse_from_url_v2.py @@ -49,6 +49,7 @@ class TestRecipesParseFromUrlV2(unittest.IsolatedAsyncioTestCase): # Success case import recipes as recipes_pkg + orig = recipes_pkg._scrape_recipe_ldata recipes_pkg._scrape_recipe_ldata = fake_scrape try: