[build-system]
requires = ["setuptools~=65.5", "pip~=22.3", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "InvokeAI"
description = "An implementation of Stable Diffusion which provides various new features and options to aid the image generation process"
requires-python = ">=3.10, <3.12"
readme = { content-type = "text/markdown", file = "README.md" }
keywords = ["stable-diffusion", "AI"]
dynamic = ["version"]
license = { file = "LICENSE" }
authors = [{ name = "The InvokeAI Project", email = "lincoln.stein@gmail.com" }]
classifiers = [
  'Development Status :: 4 - Beta',
  'Environment :: GPU',
  'Environment :: GPU :: NVIDIA CUDA',
  'Environment :: MacOS X',
  'Intended Audience :: End Users/Desktop',
  'Intended Audience :: Developers',
  'License :: OSI Approved :: MIT License',
  'Operating System :: POSIX :: Linux',
  'Operating System :: MacOS',
  'Operating System :: Microsoft :: Windows',
  'Programming Language :: Python :: 3 :: Only',
  'Programming Language :: Python :: 3.10',
  'Topic :: Artistic Software',
  'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
  'Topic :: Internet :: WWW/HTTP :: WSGI :: Server',
  'Topic :: Multimedia :: Graphics',
  'Topic :: Scientific/Engineering :: Artificial Intelligence',
  'Topic :: Scientific/Engineering :: Image Processing',
]
dependencies = [
  # Core generation dependencies, pinned for reproducible builds.
  "accelerate==0.29.2",
  "clip_anytorch==2.5.2",       # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip",
  "compel==2.0.2",
  "controlnet-aux==0.0.7",
  "diffusers[torch]==0.27.2",
  "invisible-watermark==0.2.0", # needed to install SDXL base and refiner using their repo_ids
  "mediapipe==0.10.7",          # needed for "mediapipeface" controlnet model
  "numpy==1.26.4",              # >1.24.0 is needed to use the 'strict' argument to np.testing.assert_array_equal()
  "onnx==1.15.0",
  "onnxruntime==1.16.3",
  "opencv-python==4.9.0.80",
  "pytorch-lightning==2.1.3",
  "safetensors==0.4.2",
  "timm==0.6.13",               # needed to override timm latest in controlnet_aux, see  https://github.com/isl-org/ZoeDepth/issues/26
  "torch==2.2.2",
  "torchmetrics==0.11.4",
  "torchsde==0.2.6",
  "torchvision==0.17.2",
  "transformers==4.39.3",

  # Core application dependencies, pinned for reproducible builds.
  "fastapi-events==0.11.0",
  "fastapi==0.110.0",
  "huggingface-hub==0.22.2",
  "pydantic-settings==2.2.1",
  "pydantic==2.6.3",
  "python-socketio==5.11.1",
  "uvicorn[standard]==0.28.0",

  # Auxiliary dependencies, pinned only if necessary.
  "albumentations",
  "blake3",
  "click",
  "datasets",
  "Deprecated",
  "dnspython~=2.4.0",
  "dynamicprompts",
  "easing-functions",
  "einops",
  "facexlib",
  "matplotlib",       # needed for plotting of Penner easing functions
  "npyscreen",
  "omegaconf",
  "picklescan",
  "pillow",
  "prompt-toolkit",
  "pympler~=1.0.1",
  "pypatchmatch",
  'pyperclip',
  "pyreadline3",
  "python-multipart",
  "requests~=2.28.2",
  "rich~=13.3",
  "scikit-image~=0.21.0",
  "semver~=3.0.1",
  "send2trash",
  "test-tube~=0.7.5",
  "windows-curses; sys_platform=='win32'",
]

[project.optional-dependencies]
"xformers" = [
  # Core generation dependencies, pinned for reproducible builds.
  "xformers==0.0.25post1; sys_platform!='darwin'",
  # Auxiliary dependencies, pinned only if necessary.
  "triton; sys_platform=='linux'",
]
"onnx" = ["onnxruntime"]
"onnx-cuda" = ["onnxruntime-gpu"]
"onnx-directml" = ["onnxruntime-directml"]
"dist" = ["pip-tools", "pipdeptree", "twine"]
"docs" = [
  "mkdocs-material>=9.5.13",
  "mkdocs-git-revision-date-localized-plugin",
  "mkdocs-redirects",
  "mkdocstrings[python]>=0.24.1",
]
"dev" = ["jurigged", "pudb", "snakeviz", "gprof2dot"]
"test" = [
  "ruff>=0.3.3",
  "ruff-lsp>=0.0.53",
  "mypy",
  "pre-commit",
  "pytest>6.0.0",
  "pytest-cov",
  "pytest-timeout",
  "pytest-datadir",
  "requests_testadapter",
  "httpx",
]

[project.scripts]
"invokeai-web" = "invokeai.app.run_app:run_app"
"invokeai-import-images" = "invokeai.frontend.install.import_images:main"
"invokeai-db-maintenance" = "invokeai.backend.util.db_maintenance:main"

[project.urls]
"Homepage" = "https://invoke-ai.github.io/InvokeAI/"
"Documentation" = "https://invoke-ai.github.io/InvokeAI/"
"Source" = "https://github.com/invoke-ai/InvokeAI/"
"Bug Reports" = "https://github.com/invoke-ai/InvokeAI/issues"
"Discord" = "https://discord.gg/ZmtBAhwWhy"

[tool.setuptools.dynamic]
version = { attr = "invokeai.version.__version__" }

[tool.setuptools.packages.find]
"where" = ["."]
"include" = [
  "invokeai.assets.fonts*",
  "invokeai.version*",
  "invokeai.generator*",
  "invokeai.backend*",
  "invokeai.frontend*",
  "invokeai.frontend.web.dist*",
  "invokeai.frontend.web.static*",
  "invokeai.configs*",
  "invokeai.app*",
  "invokeai.invocation_api*",
]

[tool.setuptools.package-data]
"invokeai.app.assets" = ["**/*.png"]
"invokeai.app.services.workflow_records.default_workflows" = ["*.json"]
"invokeai.assets.fonts" = ["**/*.ttf"]
"invokeai.backend" = ["**.png"]
"invokeai.configs" = ["*.example", "**/*.yaml", "*.txt"]
"invokeai.frontend.web.dist" = ["**"]
"invokeai.frontend.web.static" = ["**"]
"invokeai.app.invocations" = ["**"]

#=== Begin: PyTest and Coverage
[tool.pytest.ini_options]
addopts = "--cov-report term --cov-report html --cov-report xml --strict-markers -m \"not slow\""
markers = [
  "slow: Marks tests as slow. Disabled by default. To run all tests, use -m \"\". To run only slow tests, use -m \"slow\".",
  "timeout: Marks the timeout override.",
]
[tool.coverage.run]
branch = true
source = ["invokeai"]
omit = ["*tests*", "*migrations*", ".venv/*", "*.env"]
[tool.coverage.report]
show_missing = true
fail_under = 85     # let's set something sensible on Day 1 ...
[tool.coverage.json]
output = "coverage/coverage.json"
pretty_print = true
[tool.coverage.html]
directory = "coverage/html"
[tool.coverage.xml]
output = "coverage/index.xml"
#=== End: PyTest and Coverage

#=== Begin: Ruff
[tool.ruff]
line-length = 120
exclude = [
  ".git",
  "__pycache__",
  "build",
  "dist",
  "invokeai/frontend/web/node_modules/",
  ".venv*",
]

[tool.ruff.lint]
ignore = [
  "E501", # https://docs.astral.sh/ruff/rules/line-too-long/
  "C901", # https://docs.astral.sh/ruff/rules/complex-structure/
  "B008", # https://docs.astral.sh/ruff/rules/function-call-in-default-argument/
  "B904", # https://docs.astral.sh/ruff/rules/raise-without-from-inside-except/
]
select = ["B", "C", "E", "F", "W", "I"]
#=== End: Ruff

#=== Begin: MyPy

# global mypy config
[tool.mypy]
ignore_missing_imports = true # ignores missing types in third-party libraries
strict = true
plugins = "pydantic.mypy"
exclude = ["tests/*"]

# overrides for specific modules
[[tool.mypy.overrides]]
follow_imports = "skip" # skips type checking of the modules listed below
module = [
  "invokeai.app.api.routers.models",
  "invokeai.app.invocations.compel",
  "invokeai.app.invocations.latent",
  "invokeai.app.services.invocation_stats.invocation_stats_default",
  "invokeai.app.services.model_manager.model_manager_base",
  "invokeai.app.services.model_manager.model_manager_default",
  "invokeai.app.services.model_manager.store.model_records_sql",
  "invokeai.app.util.controlnet_utils",
  "invokeai.backend.image_util.txt2mask",
  "invokeai.backend.image_util.safety_checker",
  "invokeai.backend.image_util.patchmatch",
  "invokeai.backend.image_util.invisible_watermark",
  "invokeai.backend.install.model_install_backend",
  "invokeai.backend.ip_adapter.ip_adapter",
  "invokeai.backend.ip_adapter.resampler",
  "invokeai.backend.ip_adapter.unet_patcher",
  "invokeai.backend.model_management.convert_ckpt_to_diffusers",
  "invokeai.backend.model_management.lora",
  "invokeai.backend.model_management.model_cache",
  "invokeai.backend.model_management.model_manager",
  "invokeai.backend.model_management.model_merge",
  "invokeai.backend.model_management.model_probe",
  "invokeai.backend.model_management.model_search",
  "invokeai.backend.model_management.models.*",                            # this is needed to ignore the module's `__init__.py`
  "invokeai.backend.model_management.models.base",
  "invokeai.backend.model_management.models.controlnet",
  "invokeai.backend.model_management.models.ip_adapter",
  "invokeai.backend.model_management.models.lora",
  "invokeai.backend.model_management.models.sdxl",
  "invokeai.backend.model_management.models.stable_diffusion",
  "invokeai.backend.model_management.models.vae",
  "invokeai.backend.model_management.seamless",
  "invokeai.backend.model_management.util",
  "invokeai.backend.stable_diffusion.diffusers_pipeline",
  "invokeai.backend.stable_diffusion.diffusion.shared_invokeai_diffusion",
  "invokeai.backend.util.hotfixes",
  "invokeai.backend.util.mps_fixes",
  "invokeai.backend.util.util",
  "invokeai.frontend.install.model_install",
]
#=== End: MyPy

[tool.pyright]
# Start from strict mode
typeCheckingMode = "strict"
# This errors whenever an import is missing a type stub file - way too noisy
reportMissingTypeStubs = "none"
# These are the rest of the rules enabled by strict mode - enable them @ warning
reportConstantRedefinition = "warning"
reportDeprecated = "warning"
reportDuplicateImport = "warning"
reportIncompleteStub = "warning"
reportInconsistentConstructor = "warning"
reportInvalidStubStatement = "warning"
reportMatchNotExhaustive = "warning"
reportMissingParameterType = "warning"
reportMissingTypeArgument = "warning"
reportPrivateUsage = "warning"
reportTypeCommentUsage = "warning"
reportUnknownArgumentType = "warning"
reportUnknownLambdaType = "warning"
reportUnknownMemberType = "warning"
reportUnknownParameterType = "warning"
reportUnknownVariableType = "warning"
reportUnnecessaryCast = "warning"
reportUnnecessaryComparison = "warning"
reportUnnecessaryContains = "warning"
reportUnnecessaryIsInstance = "warning"
reportUnusedClass = "warning"
reportUnusedImport = "warning"
reportUnusedFunction = "warning"
reportUnusedVariable = "warning"
reportUntypedBaseClass = "warning"
reportUntypedClassDecorator = "warning"
reportUntypedFunctionDecorator = "warning"
reportUntypedNamedTuple = "warning"