diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 721b4c7e4067..03dd88a97bd0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,10 +10,10 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace exclude: ^tests/data/ - - repo: https://github.com/sondrelg/pep585-upgrade - rev: "v1.0.1" # Use the sha / tag you want to point at + - repo: https://github.com/asottile/pyupgrade + rev: v3.1.0 hooks: - - id: upgrade-type-hints + - id: pyupgrade - repo: https://github.com/pycqa/isort rev: 5.10.1 hooks: diff --git a/mealie/core/settings/settings.py b/mealie/core/settings/settings.py index 17d3dd6ed5f9..4c2045fe812c 100644 --- a/mealie/core/settings/settings.py +++ b/mealie/core/settings/settings.py @@ -13,7 +13,7 @@ def determine_secrets(data_dir: Path, production: bool) -> str: secrets_file = data_dir.joinpath(".secret") if secrets_file.is_file(): - with open(secrets_file, "r") as f: + with open(secrets_file) as f: return f.read() else: data_dir.mkdir(parents=True, exist_ok=True) diff --git a/mealie/routes/admin/admin_maintenance.py b/mealie/routes/admin/admin_maintenance.py index fccf650e0ce9..17c34dae5efc 100644 --- a/mealie/routes/admin/admin_maintenance.py +++ b/mealie/routes/admin/admin_maintenance.py @@ -57,7 +57,7 @@ def clean_recipe_folders(root_dir: Path, dry_run: bool) -> int: def tail_log(log_file: Path, n: int) -> list[str]: try: - with open(log_file, "r") as f: + with open(log_file) as f: lines = f.readlines() except FileNotFoundError: return ["no log file found"] diff --git a/mealie/schema/group/group_shopping_list.py b/mealie/schema/group/group_shopping_list.py index 211ea62fb88b..dad4b481fbef 100644 --- a/mealie/schema/group/group_shopping_list.py +++ b/mealie/schema/group/group_shopping_list.py @@ -1,7 +1,6 @@ from __future__ import annotations from datetime import datetime -from typing import Optional, Union from pydantic import UUID4 from pydantic.utils import GetterDict @@ -33,19 +32,19 @@ class ShoppingListItemCreate(MealieModel): is_food: bool = False - note: Optional[str] = "" + note: str | None = "" quantity: float = 1 unit_id: UUID4 = None - unit: Optional[IngredientUnit] + unit: IngredientUnit | None food_id: UUID4 = None - food: Optional[IngredientFood] + food: IngredientFood | None - label_id: Optional[UUID4] = None + label_id: UUID4 | None = None recipe_references: list[ShoppingListItemRecipeRef] = [] - extras: Optional[dict] = {} + extras: dict | None = {} - created_at: Optional[datetime] - update_at: Optional[datetime] + created_at: datetime | None + update_at: datetime | None class ShoppingListItemUpdate(ShoppingListItemCreate): @@ -53,8 +52,8 @@ class ShoppingListItemUpdate(ShoppingListItemCreate): class ShoppingListItemOut(ShoppingListItemUpdate): - label: Optional[MultiPurposeLabelSummary] - recipe_references: list[Union[ShoppingListItemRecipeRef, ShoppingListItemRecipeRefOut]] = [] + label: MultiPurposeLabelSummary | None + recipe_references: list[ShoppingListItemRecipeRef | ShoppingListItemRecipeRefOut] = [] class Config: orm_mode = True @@ -69,10 +68,10 @@ class ShoppingListItemOut(ShoppingListItemUpdate): class ShoppingListCreate(MealieModel): name: str = None - extras: Optional[dict] = {} + extras: dict | None = {} - created_at: Optional[datetime] - update_at: Optional[datetime] + created_at: datetime | None + update_at: datetime | None class ShoppingListRecipeRefOut(MealieModel): @@ -119,8 +118,8 @@ class ShoppingListOut(ShoppingListUpdate): orm_mode = True -from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelSummary -from mealie.schema.recipe.recipe import RecipeSummary +from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelSummary # noqa: E402 +from mealie.schema.recipe.recipe import RecipeSummary # noqa: E402 ShoppingListRecipeRefOut.update_forward_refs() ShoppingListItemOut.update_forward_refs() diff --git a/mealie/schema/recipe/recipe.py b/mealie/schema/recipe/recipe.py index 7d1f79e75cfd..42e8080ff468 100644 --- a/mealie/schema/recipe/recipe.py +++ b/mealie/schema/recipe/recipe.py @@ -2,7 +2,7 @@ from __future__ import annotations import datetime from pathlib import Path -from typing import Any, Optional +from typing import Any from uuid import uuid4 from pydantic import UUID4, BaseModel, Field, validator @@ -69,35 +69,35 @@ class CreateRecipe(MealieModel): class RecipeSummary(MealieModel): - id: Optional[UUID4] + id: UUID4 | None user_id: UUID4 = Field(default_factory=uuid4) group_id: UUID4 = Field(default_factory=uuid4) - name: Optional[str] + name: str | None slug: str = "" - image: Optional[Any] - recipe_yield: Optional[str] + image: Any | None + recipe_yield: str | None - total_time: Optional[str] = None - prep_time: Optional[str] = None - cook_time: Optional[str] = None - perform_time: Optional[str] = None + total_time: str | None = None + prep_time: str | None = None + cook_time: str | None = None + perform_time: str | None = None - description: Optional[str] = "" - recipe_category: Optional[list[RecipeCategory]] = [] - tags: Optional[list[RecipeTag]] = [] + description: str | None = "" + recipe_category: list[RecipeCategory] | None = [] + tags: list[RecipeTag] | None = [] tools: list[RecipeTool] = [] - rating: Optional[int] - org_url: Optional[str] = Field(None, alias="orgURL") + rating: int | None + org_url: str | None = Field(None, alias="orgURL") - recipe_ingredient: Optional[list[RecipeIngredient]] = [] + recipe_ingredient: list[RecipeIngredient] | None = [] - date_added: Optional[datetime.date] - date_updated: Optional[datetime.datetime] + date_added: datetime.date | None + date_updated: datetime.datetime | None - created_at: Optional[datetime.datetime] - update_at: Optional[datetime.datetime] + created_at: datetime.datetime | None + update_at: datetime.datetime | None class Config: orm_mode = True @@ -137,17 +137,17 @@ class RecipePagination(PaginationBase): class Recipe(RecipeSummary): recipe_ingredient: list[RecipeIngredient] = [] - recipe_instructions: Optional[list[RecipeStep]] = [] - nutrition: Optional[Nutrition] + recipe_instructions: list[RecipeStep] | None = [] + nutrition: Nutrition | None # Mealie Specific - settings: Optional[RecipeSettings] = None - assets: Optional[list[RecipeAsset]] = [] - notes: Optional[list[RecipeNote]] = [] - extras: Optional[dict] = {} - is_ocr_recipe: Optional[bool] = False + settings: RecipeSettings | None = None + assets: list[RecipeAsset] | None = [] + notes: list[RecipeNote] | None = [] + extras: dict | None = {} + is_ocr_recipe: bool | None = False - comments: Optional[list[RecipeCommentOut]] = [] + comments: list[RecipeCommentOut] | None = [] @staticmethod def directory_from_id(recipe_id: UUID4 | str) -> Path: @@ -205,7 +205,7 @@ class Recipe(RecipeSummary): return recipe_ingredient -from mealie.schema.recipe.recipe_ingredient import RecipeIngredient +from mealie.schema.recipe.recipe_ingredient import RecipeIngredient # noqa: E402 RecipeSummary.update_forward_refs() Recipe.update_forward_refs() diff --git a/mealie/schema/recipe/recipe_ingredient.py b/mealie/schema/recipe/recipe_ingredient.py index fcc88d1b267e..1455b3c22bba 100644 --- a/mealie/schema/recipe/recipe_ingredient.py +++ b/mealie/schema/recipe/recipe_ingredient.py @@ -2,7 +2,6 @@ from __future__ import annotations import datetime import enum -from typing import Optional, Union from uuid import UUID, uuid4 from pydantic import UUID4, Field, validator @@ -17,11 +16,11 @@ from mealie.schema.response.pagination import PaginationBase class UnitFoodBase(MealieModel): name: str description: str = "" - extras: Optional[dict] = {} + extras: dict | None = {} class CreateIngredientFood(UnitFoodBase): - label_id: Optional[UUID4] = None + label_id: UUID4 | None = None class SaveIngredientFood(CreateIngredientFood): @@ -30,9 +29,9 @@ class SaveIngredientFood(CreateIngredientFood): class IngredientFood(CreateIngredientFood): id: UUID4 - label: Optional[MultiPurposeLabelSummary] = None - created_at: Optional[datetime.datetime] - update_at: Optional[datetime.datetime] + label: MultiPurposeLabelSummary | None = None + created_at: datetime.datetime | None + update_at: datetime.datetime | None class Config: orm_mode = True @@ -61,8 +60,8 @@ class SaveIngredientUnit(CreateIngredientUnit): class IngredientUnit(CreateIngredientUnit): id: UUID4 - created_at: Optional[datetime.datetime] - update_at: Optional[datetime.datetime] + created_at: datetime.datetime | None + update_at: datetime.datetime | None class Config: orm_mode = True @@ -73,13 +72,13 @@ class IngredientUnitPagination(PaginationBase): class RecipeIngredient(MealieModel): - title: Optional[str] - note: Optional[str] - unit: Optional[Union[IngredientUnit, CreateIngredientUnit]] - food: Optional[Union[IngredientFood, CreateIngredientFood]] + title: str | None + note: str | None + unit: IngredientUnit | CreateIngredientUnit | None + food: IngredientFood | CreateIngredientFood | None disable_amount: bool = True quantity: NoneFloat = 1 - original_text: Optional[str] + original_text: str | None # Ref is used as a way to distinguish between an individual ingredient on the frontend # It is required for the reorder and section titles to function properly because of how @@ -123,7 +122,7 @@ class IngredientConfidence(MealieModel): class ParsedIngredient(MealieModel): - input: Optional[str] + input: str | None confidence: IngredientConfidence = IngredientConfidence() ingredient: RecipeIngredient @@ -153,6 +152,6 @@ class MergeUnit(MealieModel): to_unit: UUID4 -from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelSummary +from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelSummary # noqa: E402 IngredientFood.update_forward_refs() diff --git a/mealie/schema/response/query_filter.py b/mealie/schema/response/query_filter.py index d74dc65a216f..3f46a4cf922b 100644 --- a/mealie/schema/response/query_filter.py +++ b/mealie/schema/response/query_filter.py @@ -2,7 +2,7 @@ from __future__ import annotations import re from enum import Enum -from typing import Any, TypeVar, Union, cast +from typing import Any, TypeVar, cast from dateutil import parser as date_parser from dateutil.parser import ParserError @@ -209,13 +209,13 @@ class QueryFilter: @staticmethod def _parse_base_components_into_filter_components( base_components: list[str], - ) -> list[Union[str, QueryFilterComponent, LogicalOperator]]: + ) -> list[str | QueryFilterComponent | LogicalOperator]: """Walk through base components and construct filter collections""" relational_operators = [op.value for op in RelationalOperator] logical_operators = [op.value for op in LogicalOperator] # parse QueryFilterComponents and logical operators - components: list[Union[str, QueryFilterComponent, LogicalOperator]] = [] + components: list[str | QueryFilterComponent | LogicalOperator] = [] for i, base_component in enumerate(base_components): if base_component in QueryFilter.seps: components.append(base_component) diff --git a/mealie/services/backups_v2/backup_file.py b/mealie/services/backups_v2/backup_file.py index ce7d9ad537bf..711d89369af0 100644 --- a/mealie/services/backups_v2/backup_file.py +++ b/mealie/services/backups_v2/backup_file.py @@ -36,7 +36,7 @@ class BackupContents: def read_tables(self) -> dict: if self._tables is None: - with open(self.tables, "r") as f: + with open(self.tables) as f: self._tables = json.load(f) return self._tables diff --git a/mealie/services/migrations/utils/migration_helpers.py b/mealie/services/migrations/utils/migration_helpers.py index a25c2b7edf2b..20723f5b6294 100644 --- a/mealie/services/migrations/utils/migration_helpers.py +++ b/mealie/services/migrations/utils/migration_helpers.py @@ -10,7 +10,7 @@ from mealie.services.recipe.recipe_data_service import RecipeDataService class MigrationReaders: @staticmethod def json(json_file: Path) -> dict: - with open(json_file, "r") as f: + with open(json_file) as f: return json.loads(f.read()) @staticmethod @@ -24,7 +24,7 @@ class MigrationReaders: Returns: dict: representing the yaml file as a dictionary """ - with open(yaml_file, "r") as f: + with open(yaml_file) as f: contents = f.read().split("---") recipe_data = {} for document in contents: diff --git a/mealie/services/parser_services/crfpp/utils.py b/mealie/services/parser_services/crfpp/utils.py index da46ad938e1e..fef3854cde45 100644 --- a/mealie/services/parser_services/crfpp/utils.py +++ b/mealie/services/parser_services/crfpp/utils.py @@ -95,7 +95,7 @@ def insideParenthesis(token, tokens): else: line = " ".join(tokens) return ( - re.match(r".*\(.*" + re.escape(token) + ".*\).*", line) is not None # noqa: W605 - invalid dscape sequence + re.match(r".*\(.*" + re.escape(token) + r".*\).*", line) is not None # noqa: W605 - invalid dscape sequence ) @@ -107,7 +107,7 @@ def displayIngredient(ingredient): # => 1 cat pie """ - return "".join(["%s" % (tag, " ".join(tokens)) for tag, tokens in ingredient]) + return "".join(["{}".format(tag, " ".join(tokens)) for tag, tokens in ingredient]) # HACK: fix this @@ -189,7 +189,7 @@ def import_data(lines): # turn B-NAME/123 back into "name" tag, confidence = re.split(r"/", columns[-1], 1) - tag = re.sub("^[BI]\-", "", tag).lower() # noqa: W605 - invalid dscape sequence + tag = re.sub(r"^[BI]\-", "", tag).lower() # noqa: W605 - invalid dscape sequence # ==================== # Confidence Getter @@ -231,9 +231,7 @@ def import_data(lines): data[-1][tag].append(token) # reassemble the output into a list of dicts. - output = [ - dict([(k, smartJoin(tokens)) for k, tokens in ingredient.items()]) for ingredient in data if len(ingredient) - ] + output = [{k: smartJoin(tokens) for k, tokens in ingredient.items()} for ingredient in data if len(ingredient)] # Preclean Confidence for i, c in enumerate(confidence_all): diff --git a/mealie/services/recipe/template_service.py b/mealie/services/recipe/template_service.py index 36515eb884dd..d1a2377c1377 100644 --- a/mealie/services/recipe/template_service.py +++ b/mealie/services/recipe/template_service.py @@ -105,7 +105,7 @@ class TemplateService(BaseService): if not j2_path.is_file(): raise FileNotFoundError(f"Template '{j2_path}' not found.") - with open(j2_path, "r") as f: + with open(j2_path) as f: template_text = f.read() template = Template(template_text) diff --git a/tests/unit_tests/repository_tests/test_recipe_repository.py b/tests/unit_tests/repository_tests/test_recipe_repository.py index fffca83cc4ed..a32bca78c27c 100644 --- a/tests/unit_tests/repository_tests/test_recipe_repository.py +++ b/tests/unit_tests/repository_tests/test_recipe_repository.py @@ -11,7 +11,7 @@ from tests.utils.fixture_schemas import TestUser def test_recipe_repo_get_by_categories_basic(database: AllRepositories, unique_user: TestUser): # Bootstrap the database with categories - slug1, slug2, slug3 = [random_string(10) for _ in range(3)] + slug1, slug2, slug3 = (random_string(10) for _ in range(3)) categories: list[CategoryOut | CategorySave] = [ CategorySave(group_id=unique_user.group_id, name=slug1, slug=slug1), @@ -68,7 +68,7 @@ def test_recipe_repo_get_by_categories_basic(database: AllRepositories, unique_u def test_recipe_repo_get_by_categories_multi(database: AllRepositories, unique_user: TestUser): - slug1, slug2 = [random_string(10) for _ in range(2)] + slug1, slug2 = (random_string(10) for _ in range(2)) categories = [ CategorySave(group_id=unique_user.group_id, name=slug1, slug=slug1), @@ -120,7 +120,7 @@ def test_recipe_repo_get_by_categories_multi(database: AllRepositories, unique_u def test_recipe_repo_pagination_by_categories(database: AllRepositories, unique_user: TestUser): - slug1, slug2 = [random_string(10) for _ in range(2)] + slug1, slug2 = (random_string(10) for _ in range(2)) categories = [ CategorySave(group_id=unique_user.group_id, name=slug1, slug=slug1), @@ -201,7 +201,7 @@ def test_recipe_repo_pagination_by_categories(database: AllRepositories, unique_ def test_recipe_repo_pagination_by_tags(database: AllRepositories, unique_user: TestUser): - slug1, slug2 = [random_string(10) for _ in range(2)] + slug1, slug2 = (random_string(10) for _ in range(2)) tags = [ TagSave(group_id=unique_user.group_id, name=slug1, slug=slug1), @@ -280,7 +280,7 @@ def test_recipe_repo_pagination_by_tags(database: AllRepositories, unique_user: def test_recipe_repo_pagination_by_tools(database: AllRepositories, unique_user: TestUser): - slug1, slug2 = [random_string(10) for _ in range(2)] + slug1, slug2 = (random_string(10) for _ in range(2)) tools = [ RecipeToolSave(group_id=unique_user.group_id, name=slug1, slug=slug1), diff --git a/tests/unit_tests/services_tests/test_ocr_service.py b/tests/unit_tests/services_tests/test_ocr_service.py index c0d2cb320f1e..aee3487e92b2 100644 --- a/tests/unit_tests/services_tests/test_ocr_service.py +++ b/tests/unit_tests/services_tests/test_ocr_service.py @@ -11,7 +11,7 @@ ocr_service = OcrService() def test_image_to_string(): with open(Path("tests/data/images/test-ocr.png"), "rb") as image: result = ocr_service.image_to_string(image) - with open(Path("tests/data/text/test-ocr.txt"), "r", encoding="utf-8") as expected_result: + with open(Path("tests/data/text/test-ocr.txt"), encoding="utf-8") as expected_result: assert result == expected_result.read() @@ -19,7 +19,7 @@ def test_image_to_string(): def test_image_to_tsv(): with open(Path("tests/data/images/test-ocr.png"), "rb") as image: result = ocr_service.image_to_tsv(image.read()) - with open(Path("tests/data/text/test-ocr.tsv"), "r", encoding="utf-8") as expected_result: + with open(Path("tests/data/text/test-ocr.tsv"), encoding="utf-8") as expected_result: assert result == expected_result.read()