Files
JONATHAN JESNI MANISSERY 05786ce9eb refactor: enable mypy strict checking for rfdetr.datasets.transforms (#1376)
* refactor: enable mypy strict checking for rfdetr.datasets.transforms
* refactor: parameterize remaining bare ndarray annotations
2026-08-23 13:32:03 +02:00

413 lines
18 KiB
TOML

[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "rfdetr"
version = "1.10.0.dev"
description = "RF-DETR"
readme = "README.md"
authors = [
{name = "Roboflow, Inc", email = "develop@roboflow.com"}
]
license = {text = "Apache License 2.0"}
requires-python = ">=3.10"
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Typing :: Typed",
"Operating System :: POSIX",
"Operating System :: Unix",
"Operating System :: MacOS"
]
keywords = ["machine-learning", "deep-learning", "vision", "ML", "DL", "AI", "DETR", "RF-DETR", "Roboflow"]
dependencies = [
"requests", # weight download from remote URLs
"numpy", # array conversion throughout inference, evaluation, export, and visualization
"torch>=2.2.0", # core tensor ops and model forward pass
"torchvision>=0.17.0", # image transforms and ops (aligned with torch>=2.2.0)
"tqdm", # progress bars during weight download
"transformers>=5.1.0,<6.0.0", # DINOv2 backbone loading
"pydantic>=2.0,<3", # ModelConfig / TrainConfig validation
"supervision>=0.29.0", # inference output (Detections, Masks)
"pyDeprecate>=0.9,<0.10", # deprecation warnings for legacy APIs; >=0.6 for deprecated_class
]
[project.optional-dependencies]
lora = [
"peft", # LoRA backbone fine-tuning
]
train = [
"peft", # LoRA backbone fine-tuning (available during training)
"pytorch_lightning>=2.6,<3,!=2.6.2,!=2.6.3", # Keep exclusions; see issue #1016 / related advisory for why 2.6.2 and 2.6.3 are blocked
"torchmetrics[detection]>=1.8.2,<1.9.0", # one-pass COCO adapter validates the TorchMetrics 1.8 private backend contract; re-verify _validate_private_contract() (src/rfdetr/training/coco_map.py) against 1.9+ before widening this pin
"faster-coco-eval>=1.7.2",
"pycocotools",
"scipy",
"roboflow",
"rf100vl",
]
augment = [
"albumentations>=1.4.24,<3.0.0", # optional custom CPU augmentations
"kornia>=0.7,<1", # optional GPU-side augmentation
]
onnx = [
"onnx>=1.16.0,<2.0",
"onnxsim>=0.7.0", # 0.7.0 ships wheels for cp310/311/312-abi3 (3.10-3.13) on linux x86_64+aarch64, win_amd64 and macOS arm64. The old <0.6.0 pin resolved to 0.5.0, which lacks cp311/cp313/aarch64 wheels, so pip built onnxsim's bundled onnxruntime/onnx from source and the install hung (#749).
"onnx_graphsurgeon",
# onnxruntime dropped cp310 wheels after 1.23.2; 1.24.0+ ship cp311-cp314 only. Unpinned,
# a 3.10 resolve picks the newest release and then fails at install with "no source
# distribution or wheel for the current platform". Remove the split when the project's
# requires-python floor moves past 3.10.
"onnxruntime<1.24; python_version < '3.11'",
"onnxruntime; python_version >= '3.11'",
"polygraphy",
]
tensorrt = [
"onnxruntime-gpu",
"tensorrt>=8.6.1",
"polygraphy",
]
# pycuda is only used by async TRTInference in rfdetr.export.benchmark. It ships as an sdist
# and builds against the CUDA toolkit dev headers (cuda.h), which a GPU driver alone does not
# provide. Keep it out of the base [tensorrt] extra so the ONNX->engine parity path (polygraphy
# TrtRunner, no pycuda) installs on a driver-only runner; async benchmarking opts into it here.
tensorrt-bench = [
"pycuda>=2024.1",
]
tflite = [
# TFLite conversion routes every export through the ONNX pipeline first (export_onnx's
# graph optimization/simplification), so these are needed here directly rather than via
# the separate [onnx] extra — onnxruntime is NOT included: it's only for running ONNX
# inference, never touched by the TFLite export path.
"onnx>=1.20.0,<2.0; python_version >= '3.12' and python_version < '3.13'",
"onnxsim>=0.7.0; python_version >= '3.12' and python_version < '3.13'", # 0.7.0 ships a cp312 abi3 wheel; the old <0.6.0 pin resolved to 0.5.0 whose wheels don't cover every platform, so pip built from source and hung (#749).
"onnx_graphsurgeon; python_version >= '3.12' and python_version < '3.13'",
"polygraphy; python_version >= '3.12' and python_version < '3.13'",
"onnx2tf>=2.4.0,<3.0.0; python_version >= '3.12' and python_version < '3.13'",
"flatbuffers>=23.5.26; python_version >= '3.12' and python_version < '3.13'",
"tf-keras>=2.16.0; python_version >= '3.12' and python_version < '3.13'",
"tensorflow>=2.16.0; python_version >= '3.12' and python_version < '3.13'",
]
executorch = [
# torch.export -> .pte, XNNPACK CPU delegate; validated on 1.3.1.
# executorch publishes cp310-cp313 wheels only (1.3.1 is current) and has no sdist, so a
# 3.14 install fails on wheel availability rather than resolution. The marker keeps the
# extra installable-but-empty on 3.14, matching how [tflite] is gated to 3.12. Drop the
# `python_version < '3.14'` marker once executorch ships cp314 wheels.
"executorch>=1.3,<2.0; python_version < '3.14'",
]
coreml = [
# torch.export (ExportedProgram) support added in coremltools 8.0 (see
# src/rfdetr/export/_coreml/torch_ops.py, op_coverage.py for the private-API surface this pin
# guards — coremltools._TORCH_OPS_REGISTRY internals can rename across minors).
"coremltools>=8.0,<10.0",
# torch>=2.12 sharply raises the rate of a CoreML/eager numeric-parity divergence on real-image
# input (coremltools 9.0): bisected 2026-07-28 on RFDETRNano with random-init weights —
# torch<2.12 failed ~1/6 repeat runs, torch>=2.12.0 failed ~6/7 (up to ~1.0 abs diff on raw
# query outputs; tests/export/test_coreml_export.py::TestCoreMLEndToEnd::
# test_outputs_match_pytorch_supervision_image[detection]). Same decomposed op set both sides —
# looks like a coremltools MIL lowering regression exposed by torch 2.12's export graph, not a
# missing/renamed op. This pin reduces the failure rate, it does not eliminate it — the
# underlying instability (random/untrained-weight activations pushing some op toward
# overflow/nan during MIL conversion; see the divide-by-zero/overflow RuntimeWarnings logged
# during convert) is present at some low rate on torch<2.12 too. Raise this cap once the root
# cause is understood/fixed upstream; don't treat it as a guaranteed-deterministic fix.
"torch<2.12",
]
loggers = [
"tensorboard>=2.13.0",
"protobuf>=3.20.0", # Cap <4.0.0 removed — tensorflow>=2.16.0 (required by [tflite]) needs protobuf>=3.20.3 and is incompatible with <4.0.0 (see #1041)
"wandb",
"mlflow",
"clearml",
]
visual = [
"matplotlib",
"pandas",
"seaborn",
]
cli = ["jsonargparse[signatures]>=4.27.7"]
plus = ["rfdetr_plus>=1.0.1, <2.0.0"]
# XLA backend for TPU training AND hardware-free XLA validation on CPU/GPU PJRT.
# torch_xla is built on top of torch (NOT mutually exclusive — it requires torch present) and its
# _XLAC extension is ABI-locked to ONE torch minor (a mismatch surfaces as an `undefined symbol`
# ImportError on `import torch_xla`). torch_xla does not hard-pin torch in requires_dist, and PEP 508
# cannot express "equal minor", so we pin BOTH to the current known-good pair (2.9) — bump the two
# together when a newer torch_xla ships. Wheels are Linux x86_64 only (py3.10-3.13) -> sys_platform
# marker keeps macOS/Windows installs of this extra a no-op. The bare wheel runs the CPU PJRT plugin
# (PJRT_DEVICE=CPU) with no libtpu; real TPU adds torch_xla[tpu] (libtpu), GPU PJRT needs the separate
# CUDA plugin wheel. Used by ci-tests-xla.yml to exercise @pytest.mark.xla paths.
xla = [
"torch==2.9.*; sys_platform == 'linux'",
"torch_xla==2.9.*; sys_platform == 'linux'",
]
[dependency-groups]
# TODO: Temporary: GPU runner only has CUDA 12.8 driver (12080); torch>=2.11 requires a newer driver.
# Remove this group and the --group ci-gpu-pin references in CI once the driver is updated.
# Does not affect users installing rfdetr from PyPI.
ci-gpu-pin = [
"torch<2.11",
"torchvision<0.26",
]
# TODO: Temporary: executorch==1.3.1's prebuilt wheel is compiled against ~torch-2.12.x's C10 ABI
# (executorch itself only floors torch>=2.12.0a0, no ceiling). torch>=2.13.0 removed/changed a C10
# symbol the wheel links, breaking executorch.runtime at dlopen (undefined symbol). Empirically
# validated: torch==2.12.1 + executorch==1.3.1 imports executorch.runtime cleanly; torch==2.13.0
# does not. Remove this group and the --group ci-executorch-pin reference in CI once executorch
# ships a release compatible with newer torch. Does not affect users installing rfdetr from PyPI —
# see rfdetr.export._executorch.converter._check_executorch_available(require_runtime=True) for the
# equivalent runtime guidance surfaced to end users who hit this.
ci-executorch-pin = [
"torch<2.13",
]
build = [
"twine>=5.1.1",
"wheel>=0.40",
"build>=0.10"
]
tests = [
"pytest>=7.2,<10",
"pytest-cov>=4,<8",
"pytest-xdist>=3.6,<4",
"pytest-rerunfailures>=10,<15",
"pytest-timeout>=2,<3",
"pytest-doctestplus>=1.2,<2",
"pandas", # imported directly by tests/training/test_metrics_csv.py to read CSVLogger output
"tomli>=2.0; python_version < '3.11'",
]
typing = [
# Keep this pin aligned with the local mypy hook in .pre-commit-config.yaml.
"mypy==1.19.1",
# mypy 1.19.x can crash while processing NumPy 2.4 symbols in strict mode.
"numpy<2.4",
"types-PyYAML",
"types-requests",
"types-tqdm",
]
docs = [
"mkdocs-material[imaging]>=9.7",
"mkdocstrings>=0.25.2,<0.30.0",
"mkdocstrings-python>=1.10.9",
"mike>=2.0.0",
"mkdocs-jupyter>=0.24.3",
"mkdocs-git-committers-plugin-2>=2.4.1",
"mkdocs-git-revision-date-localized-plugin>=1.2.4",
"tomli>=2.0; python_version < '3.11'",
]
[project.urls]
Homepage = "https://github.com/roboflow/rf-detr"
[project.scripts]
rfdetr = "rfdetr.cli:main"
[tool.uv]
# onnx2tf>=2.4.0 pins numpy==1.26.4 (exact). Its dependency ml-dtypes==0.5.1 in turn requires
# numpy>=2.1.0 on python_full_version>='3.13' — contradicting the numpy==1.26.4 pin on 3.13.
# tflite deps carry python_version>='3.12' and <'3.13' markers because onnx2tf's numpy pin
# cannot be satisfied on 3.13 via any available release; when onnx2tf relaxes the exact pin,
# remove the <'3.13' upper bound from the tflite deps AND from the override below.
override-dependencies = [
"ml-dtypes==0.5.1; python_version >= '3.12' and python_version < '3.13'",
]
# ci-gpu-pin (torch<2.11, GPU-driver constraint) and the executorch extra (torch>=2.12.0a0,
# from executorch's own metadata) are unsatisfiable together -- no CI job combines them, but
# `uv sync --all-groups` and a plain `uv lock` need to know that so the universal resolver
# forks the two instead of failing to find one lockfile that satisfies both at once.
#
# coreml (torch<2.12, see coreml extra comment) and executorch (torch>=2.12.0a0) are likewise
# unsatisfiable together -- no CI job combines them either, same fork rationale.
conflicts = [
[
{ group = "ci-gpu-pin" },
{ extra = "executorch" },
],
[
{ extra = "coreml" },
{ extra = "executorch" },
],
# executorch and tflite extras are unsatisfiable together; declare a conflict so `uv lock` / `uv sync --all-groups` can fork.
[
{ extra = "executorch" },
{ extra = "tflite" },
],
# xla (torch==2.9.*, pinned to torch_xla's companion release) and executorch
# (torch>=2.12.0a0) are likewise unsatisfiable together -- same fork rationale.
[
{ extra = "executorch" },
{ extra = "xla" },
],
]
[tool.setuptools.packages.find]
where = ["src"]
include = ["rfdetr*"]
[tool.setuptools]
include-package-data = false
[tool.setuptools.package-data]
rfdetr = ["py.typed", "models/backbone/dinov2_configs/*.json"]
[tool.ruff]
fix = true
line-length = 120
target-version = "py310"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"N", # pep8-naming: lowercase variables (N806) and arguments (N803)
]
extend-select = [
"RUF100", # yesqa
]
ignore = [
"E722", # todo: Do not use bare `except`
]
[tool.ruff.lint.per-file-ignores]
"notebooks/*.py" = ["E402"] # cell-local imports are intentional in percent-format scripts
"docs/cookbooks/*.ipynb" = [
"E402", # cell-local imports are intentional in percent-format scripts
"E501", # jupytext notebook — markdown prose lines are intentionally unwrapped
]
"docs/cookbooks/*.py" = [
"E402", # cell-local imports are intentional in percent-format scripts
"E501", # .py mirror of jupytext notebook — markdown prose lines are intentionally unwrapped
]
[tool.docformatter]
wrap-summaries = 120
wrap-descriptions = 120
[tool.pytest.ini_options]
addopts = [
"-v", # verbose output
"--color=yes", # colored output
"--doctest-plus", # run doctests from all modules (pytest-doctestplus)
]
# Doctest collection is intentionally enabled across tests/ (no doctest_norecursedirs exclusion) so
# helper-function doctests in test modules run. This previously blanket-excluded tests/* because
# doctestplus walking every test module's attributes after the TF/ai_edge_litert stack is imported by
# the tflite export tests grows unittest.mock.call's cached child-mock graph unboundedly — observed
# 38 GB RSS and a silent SIGKILL during collection. If that recurs, reintroduce
# `doctest_norecursedirs = ["tests/*"]` or scope it to `tests/export/test_tflite_inference.py`.
pythonpath = ["src", "."]
markers = [
"gpu: tests that require GPU or are slow on CPU",
"xla: tests that require an XLA device or torch_xla runtime (TPU, or CPU/GPU PJRT)",
"tpu: tests that require real TPU hardware (libtpu/MXU); not runnable on CPU/GPU PJRT",
"coco17: tests that require COCO 2017 images or annotations",
# `flaky` is provided by pytest-rerunfailures; registered here too for clarity and to stay
# safe under --strict-markers (used by tests/benchmarks/test_training_*.py).
"flaky: tests that may fail due to nondeterminism and are retried via pytest-rerunfailures",
"e2e_executorch: ExecuTorch end-to-end export + numerical parity (opt-in)",
"e2e_coreml: CoreML end-to-end convert + numerical parity (structured and photo inputs; opt-in)",
"e2e_tensorrt: TensorRT end-to-end ONNX->engine build + parity (GPU, opt-in)",
"e2e_roboflow: live deploy_to_roboflow() upload + train-status validation (issue #1116); requires ROBOFLOW_API_KEY (opt-in)",
]
filterwarnings = [
# pytest-xdist workers close their channel before teardown completes;
# this is a known false-positive that does not affect test results.
"ignore::pluggy.PluggyTeardownRaisedWarning",
# Many tests instantiate ModelConfig variants with `pretrain_weights=None`
# to skip downloads. The pretrain-compat warning is intentional UX for
# end users; silence it globally for the test suite and re-enable it
# explicitly in the dedicated tests via `warnings.catch_warnings` plus
# `warnings.simplefilter("always")`.
# NOTE: expressed as a message regex (not as
# ``ignore::rfdetr.config.PretrainWeightsCompatibilityWarning``) because a
# class-path filter forces pytest to import ``rfdetr.config`` at
# config-parse time — before ``pytest-cov`` starts tracing — which makes
# the module's top-level statements appear uncovered.
"ignore:.*was instantiated with pretrain_weights=None:UserWarning",
"ignore:.*was instantiated with overrides that differ from the variant:UserWarning",
]
[tool.codespell]
skip = "*.pth"
ignore-words-list = "ane"
[tool.mypy]
python_version = "3.10"
ignore_missing_imports = false
explicit_package_bases = true
strict = true
mypy_path = "src"
exclude = [
"^docs/(hooks|scripts)/",
]
overrides = [
{ module = [
"tests.*",
"einops", "einops.*",
"matplotlib", "matplotlib.*",
"pandas", "pandas.*",
"seaborn", "seaborn.*",
], ignore_errors = true },
{ module = [
"torchvision", "torchvision.*",
"pycocotools", "pycocotools.*",
"timm", "timm.*",
"einops", "einops.*",
"deprecate", "deprecate.*",
"faster_coco_eval", "faster_coco_eval.*",
"matplotlib", "matplotlib.*",
"pandas", "pandas.*",
"requests", "requests.*",
"seaborn", "seaborn.*",
"tqdm", "tqdm.*",
"kornia", "kornia.*",
"albumentations", "albumentations.*",
"onnx", "onnx.*",
"onnx2tf", "onnx2tf.*",
"onnx_graphsurgeon", "onnx_graphsurgeon.*",
"onnxruntime", "onnxruntime.*",
"onnxsim", "onnxsim.*",
"polygraphy", "polygraphy.*",
"tensorrt", "tensorrt.*",
"pycuda", "pycuda.*",
"jsonargparse", "jsonargparse.*",
"tflite_runtime", "tflite_runtime.*",
"tensorflow", "tensorflow.*",
"executorch", "executorch.*",
"coremltools", "coremltools.*",
"roboflow", "roboflow.*",
"rfdetr_plus", "rfdetr_plus.*",
], ignore_missing_imports = true },
# Optional-import None assignments in console.py: type: ignore[assignment, misc] is needed when
# rich IS installed (full-venv mypy sees the assignment error) but flagged as unused by the
# pre-commit hook (which runs mypy with --ignore-missing-imports so rich types are unresolved).
{ module = ["rfdetr.utilities.console"], warn_unused_ignores = false },
# Modules with pre-existing type errors — ignored until incrementally fixed.
{ module = [
"rfdetr.datasets.coco",
], ignore_errors = true },
]