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()