[build-system] requires = ["setuptools>=68", "setuptools_scm>=8"] build-backend = "setuptools.build_meta" [project] name = "cinoc" description = "Banc d'essai déterministe de pipelines de transcription (OCR / HTR / VLM)." readme = "README.md" requires-python = ">=3.11" license = { text = "Apache-2.0" } dynamic = ["version"] dependencies = [ "pydantic>=2", "lxml>=5", "pyyaml>=6", "scipy>=1.11", "rapidfuzz>=3", # numpy est une dépendance directe de evaluation/ (jusqu'ici tirée via scipy). # Plafond <2.5 : numpy 2.5 (Python >=3.12 uniquement) livre des stubs en # syntaxe PEP 695 `type X = ...` que mypy, ciblant python_version 3.11, refuse # de parser. À relever quand l'interaction mypy/numpy est résolue en amont. "numpy<2.5", ] [project.optional-dependencies] dev = [ "ruff", "mypy", "pytest", "pytest-cov", "pytest-xdist", "lxml-stubs", "types-PyYAML", "jiwer", "fastapi", "httpx", "httpcore", "jinja2", "python-multipart", "Pillow", ] tesseract = ["pytesseract"] kraken = ["kraken"] pero = ["pero-ocr"] # OCR/HTR local (imprimé ancien + manuscrit) — non déployé au Space calamari = ["calamari-ocr"] # OCR local par ligne — non déployé au Space openai = ["openai"] anthropic = ["anthropic"] mistral = ["mistralai>=1.5,<2"] # 2.x = SDK incompatible (pas de `from mistralai import Mistral`) google = ["httpx", "httpcore"] # Vision via REST (≠ SDK gRPC lourd) — clé GOOGLE_VISION_API_KEY azure = ["httpx", "httpcore"] # Document Intelligence via REST — AZURE_DOC_INTEL_ENDPOINT + _KEY ollama = ["httpx", "httpcore"] huggingface = ["datasets", "huggingface_hub"] # datasets = streaming ; huggingface_hub = publication (scripts/) + snapshot dataset curé (import_curated_hf_corpus) segment = ["paddlex"] ner = ["spacy"] # extraction d'entités nommées — modèle téléchargé à part (`spacy download`) serve = ["fastapi", "uvicorn", "jinja2", "python-multipart", "httpx", "httpcore"] images = ["Pillow"] # vignettes réelles du rapport (redimensionnement) — dégradé gracieux sans # Oracle de conformité HIPE (golden test, jamais en runtime — SPEC_HIPE §5). # Extra DÉDIÉ (pas dans dev) : le scorer exige Python >= 3.12, l'inclure dans # dev casserait l'installation 3.11. Installé par le seul job CI 3.12. hipe-oracle = ["hipe-ocrepair-scorer==0.9.9"] [project.scripts] cinoc = "cinoc.interfaces.cli:main" [tool.setuptools.packages.find] include = ["cinoc*"] # La coquille web embarque ses gabarits + assets auto-hébergés (CSS, polices) ; # ils doivent voyager dans le wheel pour exister après ``pip install`` (Space/CI). [tool.setuptools.package-data] "cinoc.interfaces.web" = [ "templates/*.html", "static/css/*.css", "static/js/*.js", "static/fonts/*", ] # Le rapport autonome (couche 7) incorpore ses polices (data-URI) et son script # de comparaison (inliné) : woff2 + compare.js doivent voyager dans le wheel. "cinoc.reports" = ["_assets/*.woff2", "_assets/*.js"] # Glossaire pédagogique (donnée FR/EN) — doit voyager dans le wheel. "cinoc.reports.glossary" = ["*.yaml"] # Table de tarifs (donnée datée) du calcul économique (couche 3). "cinoc.evaluation" = ["pricing.json"] # Prompts curés par période (donnée LLM/VLM) — doivent voyager dans le wheel. "cinoc.prompts" = ["*.txt"] [tool.setuptools_scm] fallback_version = "0.1.0" version_file = "cinoc/_version.py" [tool.ruff] line-length = 88 target-version = "py311" [tool.ruff.lint] select = ["E", "F", "W", "I", "UP", "B"] [tool.mypy] python_version = "3.11" strict = true warn_unused_ignores = false plugins = ["pydantic.mypy"] [tool.pytest.ini_options] pythonpath = ["."] testpaths = ["tests"] # Coverage = concern du GATE, pas de la boucle locale : pas dans addopts (sinon # chaque `pytest`, même un sous-ensemble, paierait ×3,4 le tracing). Elle est # injectée explicitement par `make cov`/`make ci` et la CI (cf. Makefile/ci.yml). markers = [ "slow: tests lents (opt-in)", "network: tests qui touchent le réseau (opt-in)", "live: tests contre une vraie API/binaire (opt-in)", ] filterwarnings = [ # `starlette.testclient` (versions 2026) émet une dépréciation httpx→httpx2 # à l'IMPORT — purement côté tests (la prod sert via uvicorn, sans TestClient). # Dette amont, hors de notre code ; filtrée pour garder la sortie propre. "ignore:Using .httpx. with .starlette.testclient.:Warning", ] [tool.coverage.run] omit = ["*/_version.py"] [tool.coverage.report] exclude_also = [ "if TYPE_CHECKING:", "raise NotImplementedError", "^\\s*\\.\\.\\.$", "^\\s*\\.\\.\\.\\s*#", ]