[project]
name = "mealie"
version = "3.15.2"
description = "A Recipe Manager"
authors = [{ name = "Hayden", email = "hay-kot@pm.me" }]
license = "AGPL-3.0-only"
requires-python = ">=3.12,<3.13"
dependencies = [
    "Jinja2==3.1.6",
    "Pillow==12.2.0",
    "PyYAML==6.0.3",
    "SQLAlchemy==2.0.49",
    "aiofiles==25.1.0",
    "alembic==1.18.4",
    "aniso8601==10.0.1",
    "appdirs==1.4.4",
    "apprise==1.9.9",
    "bcrypt==5.0.0",
    "extruct==0.18.0",
    "fastapi==0.135.3",
    "httpx==0.28.1",
    "lxml==6.0.3",
    "orjson==3.11.8",
    "pydantic==2.12.5",
    "pyhumps==3.8.0",
    "python-dateutil==2.9.0.post0",
    "python-dotenv==1.2.2",
    "python-ldap==3.4.5",
    "python-multipart==0.0.26",
    "python-slugify==8.0.4",
    "recipe-scrapers==15.11.0",
    "requests==2.33.1",
    "tzdata==2026.1",
    "uvicorn[standard]==0.44.0",
    "beautifulsoup4==4.14.3",
    "isodate==0.7.2",
    "text-unidecode==1.3",
    "rapidfuzz==3.14.5",
    "authlib==1.6.9",
    "html2text==2025.4.15",
    "paho-mqtt==1.6.1",
    "pydantic-settings==2.13.1",
    "pillow-heif==1.3.0",
    "pyjwt==2.12.1",
    "openai==2.31.0",
    "typing-extensions==4.15.0",
    "itsdangerous==2.2.0",
    "yt-dlp==2026.3.17",
    "ingredient-parser-nlp==2.6.0",
    "pint==0.25.3",
    "httpx-curl-cffi==0.1.5",
]

[project.scripts]
mealie = "mealie.main:main"

[project.optional-dependencies]
pgsql = [
    "psycopg2-binary==2.9.11"
]

[dependency-groups]
docs = [
    "mkdocs-material==9.7.6",
]
dev = [
    "coverage==7.13.5",
    "coveragepy-lcov==0.1.2",
    "mkdocs-material==9.7.6",
    "mypy==1.20.0",
    "pre-commit==4.5.1",
    "pylint==4.0.5",
    "pytest==9.0.3",
    "pytest-asyncio==1.3.0",
    "rich==15.0.0",
    "ruff==0.15.10",
    "types-PyYAML==6.0.12.20260408",
    "types-python-dateutil==2.9.0.20260408",
    "types-python-slugify==8.0.2.20240310",
    "types-requests==2.33.0.20260408",
    "types-urllib3==1.26.25.14",
    "pydantic-to-typescript2==1.0.6",
    "freezegun==1.5.5",
]

[build-system]
requires = ["setuptools==82.0.1"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
include = ["mealie*"]

[tool.setuptools.package-data]
"*" = ["*"]

[tool.pytest.ini_options]
addopts = "-ra -q"
asyncio_default_fixture_loop_scope = "function"
minversion = "6.0"
python_classes = '*Tests'
python_files = 'test_*'
python_functions = 'test_*'
testpaths = ["tests"]

[tool.coverage.report]
skip_empty = true

[tool.mypy]
follow_imports = "skip"
ignore_missing_imports = true
plugins = "pydantic.mypy"
python_version = "3.12"
strict_optional = true

[tool.ruff]
target-version = "py312"
line-length = 120
output-format = "concise"

# Exclude a variety of commonly ignored directories.
exclude = [
  ".bzr",
  ".direnv",
  ".eggs",
  ".git",
  ".hg",
  ".mypy_cache",
  ".nox",
  ".pants.d",
  ".ruff_cache",
  ".svn",
  ".tox",
  ".venv",
  "__pypackages__",
  "_build",
  "buck-out",
  "build",
  "dist",
  "node_modules",
  "venv",
]

[tool.ruff.lint.isort]
known-third-party = ["alembic"]

[tool.ruff.lint]
# Enable Pyflakes `E` and `F` codes by default.
ignore = ["F403", "TID252", "B008"]
select = [
  "B",  # flake8-bugbear
  "C4", # McCabe complexity
  "C90", # flake8-comprehensions
  "DTZ", # flake8-datetimez
  "E",  # pycodestyles
  "F",  # pyflakes
  "I",  # isort
  "T",  # flake8-print
  "UP", # pyupgrade
  # "ANN", # flake8-annotations
  # "BLE", # blind-except
  # "RUF", # Ruff specific
]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["E402", "E501"]
"mealie/alembic/versions/*" = ["E501", "I001"]
"dev/scripts/all_recipes_stress_test.py" = ["E501"]
"ldap_provider.py" = ["UP032"]
"tests/conftest.py" = ["E402"]
"tests/utils/routes/__init__.py" = ["F401"]

[tool.ruff.lint.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 24  # Default is 10.

[tool.uv]
add-bounds = "exact"
