[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "pyimgano"
version = "0.9.0"
description = "Enterprise-Grade Visual Anomaly Detection Toolkit with 120+ registry models and 80+ operations"
readme = "README.md"
requires-python = ">=3.9"
license = "MIT"
authors = [
    {name = "PyImgAno Contributors"},
]
maintainers = [
    {name = "PyImgAno Contributors"},
]
keywords = [
    "anomaly-detection",
    "computer-vision",
    "deep-learning",
    "machine-learning",
    "image-processing",
    "industrial-inspection",
    "defect-detection",
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "Intended Audience :: Science/Research",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Topic :: Scientific/Engineering :: Artificial Intelligence",
    "Topic :: Scientific/Engineering :: Image Recognition",
    "Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
    "numpy>=1.19",
    "scipy>=1.5.1",
    "scikit-learn>=0.22.0",
    "Pillow>=8.0.0",
    "opencv-python>=4.5.0",
    "defusedxml>=0.7.1",
    "joblib>=1.0.0",
    "tqdm>=4.0.0",
]

[project.optional-dependencies]
torch = [
    "torch>=1.9.0",
    "torchvision>=0.10.0",
]
onnx = [
    "onnx>=1.12.0",
    "onnxruntime>=1.14.0",
    # Required by torch.onnx.export on newer torch versions.
    "onnxscript>=0.1.0",
]
openvino = [
    "openvino>=2023.0.0",
]
skimage = [
    "scikit-image>=0.18.0",
]
numba = [
    "numba>=0.51",
]
diffusion = [
    "pyimgano[torch]",
    "diffusers>=0.21.0",
    "transformers>=4.30.0",
    "accelerate>=0.20.0",
]
viz = [
    "matplotlib>=3.3.0",
    "seaborn>=0.11.0",
]
anomalib = [
    "pyimgano[torch]",
    "anomalib>=0.10.0",
]
patchcore_inspection = [
    # PyPI forbids VCS/direct-URL dependencies in published metadata.
    # If you need this backend, install PatchCore-Inspection separately:
    #   pip install 'patchcore @ git+https://github.com/amazon-science/patchcore-inspection.git'
]
faiss = [
    "faiss-cpu>=1.7.4",
]
clip = [
    "pyimgano[torch]",
    "open_clip_torch>=2.0.0",
]
deploy = [
    "pyimgano[torch,onnx,openvino]",
]
benchmark = [
    "pyimgano[clip,skimage]",
]
tracking = [
    "pyimgano[torch]",
    "tensorboard>=2.14.0",
    "wandb>=0.17.0",
    "mlflow>=2.11.0",
]
cpu-offline = [
    "pyimgano[skimage,numba]",
]
dev = [
    "pytest>=7.0.0",
    "pytest-cov>=4.0.0",
    "pytest-xdist>=3.0.0",
    "black>=23.0.0",
    "isort>=5.12.0",
    "ruff>=0.1.0",
    "tox>=4.0.0",
    "build>=1.2.0",
    "twine>=6.0.0",
    "flake8>=6.0.0",
    "mypy>=1.0.0",
    "types-Pillow",
    "types-setuptools",
    "bandit[toml]>=1.7.0",
    "safety>=3.0.0",
    "pre-commit>=3.0.0",
]
docs = [
    "sphinx>=5.0.0",
    "sphinx-rtd-theme>=1.2.0",
    "sphinxcontrib-napoleon>=0.7",
]
all = [
    "pyimgano[backends,diffusion,dev,docs,viz,torch,onnx,openvino,skimage,numba]",
]
backends = [
    "pyimgano[anomalib,faiss,clip]",
]

[project.urls]
Homepage = "https://github.com/skygazer42/pyimgano"
Documentation = "https://skygazer42.github.io/pyimgano/"
Repository = "https://github.com/skygazer42/pyimgano"
"Bug Tracker" = "https://github.com/skygazer42/pyimgano/issues"
Changelog = "https://github.com/skygazer42/pyimgano/blob/main/CHANGELOG.md"

[project.scripts]
pyimgano = "pyimgano.root_cli:main"
pyimgano-bundle = "pyimgano.bundle_cli:main"
pyimgano-benchmark = "pyimgano.cli:main"
pyimgano-evaluate = "pyimgano.evaluate_cli:main"
pyim = "pyimgano.pyim_cli:main"
pyimgano-demo = "pyimgano.demo_cli:main"
pyimgano-infer = "pyimgano.infer_cli:main"
pyimgano-defects = "pyimgano.defects_cli:main"
pyimgano-robust-benchmark = "pyimgano.robust_cli:main"
pyimgano-train = "pyimgano.train_cli:main"
pyimgano-manifest = "pyimgano.manifest_cli:main"
pyimgano-export-torchscript = "pyimgano.torchscript_export_cli:main"
pyimgano-export-onnx = "pyimgano.onnx_export_cli:main"
pyimgano-synthesize = "pyimgano.synthesize_cli:main"
pyimgano-validate-infer-config = "pyimgano.validate_infer_config_cli:main"
pyimgano-features = "pyimgano.feature_cli:main"
pyimgano-datasets = "pyimgano.datasets_cli:main"
pyimgano-doctor = "pyimgano.doctor_cli:main"
pyimgano-weights = "pyimgano.weights_cli:main"
pyimgano-runs = "pyimgano.runs_cli:main"

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

[tool.setuptools.package-data]
pyimgano = ["py.typed"]

# Black configuration
[tool.black]
line-length = 100
target-version = ['py39', 'py310', 'py311', 'py312']
include = '\.pyi?$'
extend-exclude = '''
/(
  # directories
  \.eggs
  | \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | build
  | dist
)/
'''

# isort configuration
[tool.isort]
profile = "black"
line_length = 100
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
skip_gitignore = true
known_first_party = ["pyimgano"]

# pytest configuration
[tool.pytest.ini_options]
minversion = "7.0"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
    "--verbose",
    "--cov=pyimgano",
    "--cov-report=term-missing",
    "--cov-report=html",
    "--cov-report=xml",
    "--cov-branch",
    "--strict-markers",
]
markers = [
    "slow: marks tests as slow (deselect with '-m \"not slow\"')",
    "integration: marks tests as integration tests",
    "unit: marks tests as unit tests",
]

# Coverage configuration
[tool.coverage.run]
source = ["pyimgano"]
relative_files = true
omit = [
    "*/tests/*",
    "*/test_*.py",
]

[tool.coverage.report]
exclude_lines = [
    "pragma: no cover",
    "def __repr__",
    "if self.debug:",
    "if __name__ == .__main__.:",
    "raise AssertionError",
    "raise NotImplementedError",
    "if TYPE_CHECKING:",
    "if typing.TYPE_CHECKING:",
    "@abstractmethod",
]

# MyPy configuration
[tool.mypy]
python_version = "3.9"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = false
disallow_incomplete_defs = false
check_untyped_defs = true
disallow_untyped_decorators = false
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
follow_imports = "normal"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = [
    "cv2.*",
    "sklearn.*",
    "torch.*",
    "torchvision.*",
    "numba.*",
]
ignore_missing_imports = true

# Ruff configuration (modern alternative to flake8)
[tool.ruff]
line-length = 100
target-version = "py39"

[tool.ruff.lint]
select = [
    "E",   # pycodestyle errors
    "W",   # pycodestyle warnings
    "F",   # pyflakes
    "I",   # isort
    "B006",  # mutable-argument-default (real bug risk)
]
ignore = [
    "E501",  # line too long (handled by black)
    "E402",  # allow intentional lazy/optional imports
    "B008",  # do not perform function calls in argument defaults
    "C901",  # too complex
    "W191",  # indentation contains tabs
]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]  # unused imports
"tests/*" = ["F401", "F811"]

[tool.ruff.lint.isort]
known-first-party = ["pyimgano"]
