# pyproject.toml # ───────────────────────────────────────────────────────────────────────────── # Unified tool configuration for NoDupeLabs. # All thresholds match the Orchestrator prompt and .clinerules exactly. # ───────────────────────────────────────────────────────────────────────────── [build-system] requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.backends.legacy:build" # ─── PROJECT METADATA ──────────────────────────────────────────────────────── [project] name = "nodupe" version = "1.0.0" description = "Advanced duplicate file detection and management system" readme = "README.md" requires-python = ">=3.9" [project.optional-dependencies] dev = [ # Testing "pytest>=8.0", "pytest-cov>=5.0", "pytest-xdist>=3.0", "pytest-timeout>=2.3", "coverage[toml]>=7.0", "hypothesis>=6.0", # Docstrings "interrogate>=1.7", # Type checking "mypy>=1.9", # Quality (fallback for when Project Health Auditor MCP is unavailable) "radon>=6.0", "pylint>=3.0", "flake8>=7.0", "flake8-bugbear>=24.0", "flake8-docstrings>=1.7", "flake8-simplify>=0.21", "vulture>=2.11", # Security (subprocess — pip-audit/safety always run; bandit is MCP fallback) "bandit[toml]>=1.7", "pip-audit>=2.7", "safety>=3.0", # Formatting "black>=24.0", "isort>=5.13", ] # ─── PYTEST ────────────────────────────────────────────────────────────────── [tool.pytest.ini_options] minversion = "8.0" testpaths = ["tests"] python_files = ["test_*.py", "*_test.py"] python_classes = ["Test*"] python_functions = ["test_*"] addopts = [ "--tb=short", "--strict-markers", "--strict-config", "-ra", "--cov=.", "--cov-branch", "--cov-report=term-missing", "--cov-report=html:reports/coverage", "--cov-report=xml:reports/coverage.xml", "--cov-fail-under=80", "--timeout=30", ] markers = [ "unit: pure unit tests with no external dependencies", "integration: tests that touch external systems", "slow: tests that take longer than 5 seconds", ] # ─── COVERAGE ──────────────────────────────────────────────────────────────── [tool.coverage.run] branch = true source = ["nodupe"] omit = [ "tests/*", "test_*.py", "*_test.py", "setup.py", "conftest.py", "scripts/*", ".venv/*", "*/site-packages/*", "__pycache__/*", "*.pyi", ] [tool.coverage.report] fail_under = 80 show_missing = true skip_covered = false skip_empty = true exclude_also = [ "def __repr__", "def __str__", "if TYPE_CHECKING:", "@(abc\\.)?abstractmethod", "raise NotImplementedError", "\\.\\.\\.", "if __name__ == .__main__.:", ] precision = 2 [tool.coverage.html] directory = "reports/coverage" [tool.coverage.xml] output = "reports/coverage.xml" # ─── INTERROGATE ─────────────────────────────────────────────────────────── [tool.interrogate] ignore-init-method = false ignore-init-module = false ignore-magic = false ignore-semiprivate = false ignore-private = true ignore-property-decorators = false ignore-module = false ignore-nested-functions = false ignore-nested-classes = false ignore-setters = false fail-under = 100 exclude = ["setup.py", "docs/", ".venv/", "build/", "dist/", "scripts/"] verbose = 2 quiet = false color = true omit-covered-files = false generate-badge = "reports/" # ─── MYPY ─────────────────────────────────────────────────────────────────── [tool.mypy] python_version = "3.9" strict = true warn_return_any = true warn_unused_configs = true warn_unused_ignores = true warn_redundant_casts = true warn_unreachable = true disallow_untyped_defs = true disallow_incomplete_defs = true disallow_untyped_calls = true disallow_any_generics = true disallow_any_unimported = true no_implicit_optional = true check_untyped_defs = true show_error_codes = true show_column_numbers = true error_summary = true pretty = true exclude = ["build/", "dist/", ".venv/", "docs/", "scripts/"] # ─── BLACK ───────────────────────────────────────────────────────────────── [tool.black] line-length = 100 target-version = ["py39"] include = '\\.pyi?$' extend-exclude = ''' /( | \.venv | build | dist | docs | scripts )/ ''' # ─── ISORT ───────────────────────────────────────────────────────────────── [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 split_on_trailing_comma = true known_first_party = ["nodupe"] sections = [ "FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER", ] skip = [".venv", "build", "dist", "docs", "scripts"] skip_glob = ["*.pyi"] # ─── PYLINT (fallback — Project Health Auditor MCP is preferred) ───────────── [tool.pylint.main] fail-under = 9.0 jobs = 0 recursive = true ignore = ["CVS", ".venv", "build", "dist", "docs", "scripts"] ignore-patterns = ["test_.*\\.py", ".*_test\\.py", "conftest\\.py"] [tool.pylint.messages_control] disable = [ "C0114", # missing-module-docstring → interrogate handles this "C0115", # missing-class-docstring → interrogate handles this "C0116", # missing-function-docstring → interrogate handles this "C0301", # line-too-long → black handles this "C0303", # trailing-whitespace → black handles this "C0304", # missing-final-newline → black handles this "W0611", # unused-import → flake8 F401 handles this ] [tool.pylint.design] max-args = 10 max-attributes = 10 max-bool-expr = 5 max-branches = 20 max-locals = 25 max-parents = 7 max-public-methods = 20 max-returns = 6 max-statements = 75 [tool.pylint.format] max-line-length = 120 [tool.pylint.similarities] min-similarity-lines = 6 ignore-comments = true ignore-docstrings = true ignore-imports = true # ─── BANDIT (fallback — Semgrep MCP is preferred) ─────────────────────────── [tool.bandit] targets = ["."] recursive = true severity = "medium" confidence = "medium" exclude_dirs = [".venv", "build", "dist", "docs", "tests", "scripts"] skips = [] # ─── VULTURE (fallback — Project Health Auditor MCP is preferred) ────────── [tool.vulture] min_confidence = 80 paths = ["nodupe"] exclude = [".venv/", "build/", "dist/", "docs/", "scripts/"] ignore_decorators = [ "@app.route", "@pytest.fixture", "@property", "@staticmethod", "@classmethod", "@abstractmethod", "@click.command", "@click.option", ] ignore_names = ["_", "setUp", "tearDown", "setUpClass", "tearDownClass", "setUpModule", "tearDownModule"] make_whitelist = false # ─── RADON (fallback — Project Health Auditor MCP is preferred) ───────────── # Radon does not support pyproject.toml — thresholds enforced via CLI in audit.py # Target thresholds (match .clinerules and Orchestrator prompt): # cyclomatic complexity : Grade C ceiling (CC ≤ 10) # maintainability index : Grade B floor (MI ≥ 65)