[project]
name = "remove-ai-watermarks"
version = "0.5.1"
description = "Remove visible and invisible AI watermarks from images (Gemini / Nano Banana, ChatGPT, Stable Diffusion)"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
dependencies = [
    "pillow>=10.0.0",
    "piexif>=1.1.3",
    "numpy>=1.24.0",
    "opencv-python-headless>=4.8.0",
    "click>=8.0.0",
    "rich>=13.0.0",
    "python-dotenv>=1.0.0",
]

[project.optional-dependencies]
gpu = [
    "torch>=2.0.0",
    "diffusers>=0.38.0",
    "transformers>=4.35.0",
    "accelerate>=0.25.0",
    "controlnet-aux>=0.0.9",
    "safetensors",
    "ultralytics>=8.0.0",
    "color-matcher>=0.5.0",
]
# Open invisible-watermark (imwatermark) decoder for detecting the DWT-DCT
# watermarks embedded by Stable Diffusion / SDXL / FLUX. Optional because it
# pulls non-headless opencv; identify() guards the import and skips the signal
# when absent.
detect = [
    "invisible-watermark>=0.2.0",
]
dev = [
    "pytest>=8.0.0",
    "pytest-cov>=4.1.0",
    "ruff>=0.4.0",
    "pyright>=1.1.0",
    "invisible-watermark>=0.2.0",
]
all = ["remove-ai-watermarks[gpu,detect,dev]"]

# diffusers 0.38.0 (security fix for GHSA-98h9-4798-4q5v) declares a dependency
# on safetensors>=0.8.0rc0 — a pre-release. Allow pre-releases globally so the
# resolver can satisfy that. Drop once diffusers publishes a release with a
# stable safetensors pin (or once safetensors 0.8.0 stable is out).
[tool.uv]
prerelease = "allow"

[project.scripts]
remove-ai-watermarks = "remove_ai_watermarks.cli:main"

[project.urls]
Repository = "https://github.com/wiltodelta/remove-ai-watermarks"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/remove_ai_watermarks"]

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
addopts = "-v --tb=short"

[tool.ruff]
target-version = "py310"
line-length = 120
exclude = ["_refs"]

[tool.ruff.lint]
select = ["E", "F", "B", "I", "S", "UP", "SIM", "RET", "COM", "C4", "G", "PT", "PIE", "T20", "DTZ", "ICN", "TCH", "RUF", "ANN"]
ignore = [
    "COM812",  # missing trailing comma (conflicts with ruff formatter)
    "ANN401",  # typing.Any — sometimes unavoidable with third-party libs
]

[tool.ruff.lint.per-file-ignores]
"tests/*.py" = ["ANN", "S101", "S105", "S106", "S108"]
"src/remove_ai_watermarks/noai/watermark_remover.py" = ["S603", "S606", "S607", "T201"]  # subprocess calls for auto-install/CUDA fix
"src/remove_ai_watermarks/noai/c2pa.py" = ["S110"]  # try-except-pass for corrupt file handling
"src/remove_ai_watermarks/noai/ctrlregen/engine.py" = ["S101", "S603"]  # assert for loaded state, subprocess for auto-install

[tool.ruff.format]
quote-style = "double"
indent-style = "space"

[tool.pyright]
pythonVersion = "3.10"
typeCheckingMode = "strict"
exclude = ["_refs"]

[[tool.pyright.executionEnvironments]]
root = "tests"
extraPaths = ["."]
reportAttributeAccessIssue = false
reportOptionalSubscript = false
reportOptionalMemberAccess = false
reportArgumentType = false
reportUnknownMemberType = false
reportUnknownArgumentType = false
reportUnknownVariableType = false
reportMissingTypeArgument = false
