mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-06-05 02:28:00 +02:00
888c8c2556
Make `pyright src/` strict-clean via a hybrid: pure-logic files are fully typed (piexif gets a local typings/ stub; PIL info-dict loops guard isinstance(key, str); progress returns Callable[..., None]; availability checks use importlib.util.find_spec instead of unused imports), while the irreducibly-untyped cv2/torch/diffusers boundary files carry a documented per-file `# pyright:` relax pragma (or a ctrlregen executionEnvironment) that disables only the unknown-type rules. Public ndarray-returning signatures on the relaxed engines are annotated NDArray[Any] so strict consumers (cli.py) stay clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
166 lines
5.9 KiB
TOML
166 lines
5.9 KiB
TOML
[project]
|
|
name = "remove-ai-watermarks"
|
|
version = "0.6.11"
|
|
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",
|
|
# diffusers 0.38's auto-pipeline registry imports ``Qwen3VLForConditional
|
|
# Generation`` (its ``nucleusmoe_image`` pipeline), which only exists in
|
|
# transformers 5.x -- so ``from diffusers import AutoPipelineForImage2Image``
|
|
# fails on transformers 4.x. The real SDXL-loading break was NOT transformers
|
|
# 5.x but the tokenizers *release candidate* (0.23.0rc0) that the global
|
|
# ``prerelease = "allow"`` drags in: its CLIP tokenizer raises
|
|
# ``RobertaProcessing.__new__() got an unexpected keyword argument 'cls'``.
|
|
# Cap tokenizers to the stable 0.22 line (transformers 5.x accepts
|
|
# >=0.22,<=0.23.0) so the rc is excluded while SDXL still loads.
|
|
"transformers>=5,<6",
|
|
"tokenizers>=0.22,<0.23",
|
|
"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 AND torch (invisible-watermark declares torch a hard
|
|
# dependency, and WatermarkDecoder eagerly imports rivaGan -> torch at import
|
|
# time, so the dwtDct-only detect path still needs torch present even though it
|
|
# never runs on GPU). So `detect` alone pulls torch -- no need to add `gpu` for
|
|
# detection. identify() guards the import and skips the signal when absent.
|
|
detect = [
|
|
"invisible-watermark>=0.2.0",
|
|
]
|
|
# Adobe TrustMark decoder -- the open, keyless watermark behind Adobe Durable
|
|
# Content Credentials (soft-binding alg ``com.adobe.trustmark.P``). Optional
|
|
# because it pulls torch and downloads model weights on first use. identify()
|
|
# guards the import and skips the TrustMark signal when absent.
|
|
trustmark = [
|
|
"trustmark>=0.8.0",
|
|
]
|
|
# Universal region eraser backend -- big-LaMa via onnxruntime (Carve/LaMa-ONNX,
|
|
# Apache-2.0). CPU, no torch. Model (~200 MB) is downloaded on first use and
|
|
# cached by huggingface_hub; it is never bundled in this repo. The default cv2
|
|
# eraser backend needs none of this.
|
|
lama = [
|
|
"onnxruntime>=1.16.0",
|
|
"huggingface-hub>=0.20.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,trustmark,lama,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
|
|
|
|
# CtrlRegen is a torch/diffusers/controlnet-aux boundary: those libs ship no
|
|
# usable types, so strict pyright cannot know the tensor element types. Relax the
|
|
# unknown-type rules for this subpackage only (mirrors the per-file pragmas used
|
|
# for the cv2 engines); the rest of the codebase stays strict.
|
|
[[tool.pyright.executionEnvironments]]
|
|
root = "src/remove_ai_watermarks/noai/ctrlregen"
|
|
reportUnknownMemberType = false
|
|
reportUnknownArgumentType = false
|
|
reportUnknownVariableType = false
|
|
reportUnknownParameterType = false
|
|
reportMissingTypeArgument = false
|
|
reportMissingTypeStubs = false
|
|
reportMissingImports = false
|
|
reportArgumentType = false
|
|
reportAssignmentType = false
|
|
reportReturnType = false
|
|
reportCallIssue = false
|
|
reportIndexIssue = false
|
|
reportOperatorIssue = false
|
|
reportOptionalMemberAccess = false
|
|
reportOptionalCall = false
|
|
reportOptionalSubscript = false
|
|
reportOptionalOperand = false
|
|
reportAttributeAccessIssue = false
|
|
reportPrivateImportUsage = false
|
|
reportPrivateUsage = false
|
|
reportInvalidTypeForm = false
|
|
reportConstantRedefinition = false
|
|
reportUnnecessaryComparison = false
|