File size: 4,623 Bytes
a2907ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
[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*#",
]