[project] name = "cadx" version = "0.0.0" description = "胰腺囊性肿瘤多模态会诊诊断的研究代码" requires-python = ">=3.12" dependencies = [ "matplotlib>=3.11.2", "medsam2", "numpy>=2.5.4", "opencv-python-headless>=5.0.0.93", "openpyxl>=3.1.5", "pillow>=12.3.0", "pydantic>=2.14.1", "pyyaml>=6.0.3", "scipy>=1.18.1", ] [dependency-groups] dev = [ "ruff>=0.6", "pyright>=1.1.380", "pytest>=8.3", "import-linter>=2.1", "pre-commit>=4.0", "types-pyyaml>=6.0.12.20260906", "types-openpyxl>=3.1.5.20260827", ] [tool.uv] # 只在本机和远程服务器(都是 Linux x86_64)上跑;只为这一种平台解析依赖, # 免得 torch 的各平台 CUDA 轮子都要下载一遍。 environments = ["sys_platform == 'linux' and platform_machine == 'x86_64'"] [tool.uv.sources] medsam2 = { path = "reference/MedSAM2", editable = true } [build-system] requires = ["hatchling>=1.26"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/cadx"] [tool.ruff] line-length = 100 target-version = "py312" src = ["src", "tests", "scripts"] extend-exclude = ["research-wiki", "reference", "reference-pdf", "runs", "data"] [tool.ruff.lint] select = ["E", "W", "F", "I", "UP", "B", "BLE", "S", "SIM", "RUF"] # 允许注释和文档字符串里的中文全角标点。 ignore = ["RUF001", "RUF002", "RUF003"] [tool.ruff.lint.per-file-ignores] "tests/**" = ["S101"] [tool.pyright] include = ["src", "tests", "scripts"] pythonVersion = "3.12" typeCheckingMode = "strict" venvPath = "." venv = ".venv" # medsam2 以 setuptools 的导入钩子方式可编辑安装,pyright 跟不过去,直接指给它源码目录。 extraPaths = ["tests", "scripts", "reference/MedSAM2"] [tool.pytest.ini_options] testpaths = ["tests"] # 测试辅助(假交付包生成器)放在 tests/ 下,按普通模块导入;scripts/ 也在路径上, # ceus_align_review 引用 ceus_quant 的配置模型(直接运行脚本时 scripts/ 本来就在 sys.path 上)。 pythonpath = ["tests", "scripts"] addopts = "--strict-markers --import-mode=importlib" markers = [ "live: 真实模型调用,花钱,需要 .env 里的密钥", "gpu: 需要 CUDA 显卡(MedSAM2 分割)", ] # 导入边界。改契约先改 research-wiki/explanation/结构.md,再改这里; # 不靠 ignore_imports 让违规通过。规划中的契约见结构.md 第五部分,模块落地时随任务书加入。 [tool.importlinter] root_packages = ["cadx"] include_external_packages = true [[tool.importlinter.contracts]] # design 0001:torch 与 MedSAM2 只许出现在分割模块。import-linter 不能写「除 segment 外的 cadx」 # (只有 ignore_imports 能开例外),所以逐个列出其余模块;新模块落地时加进 source_modules。 name = "cadx 里只有 segment 引用 torch、sam2" type = "forbidden" source_modules = [ "cadx.delivery", "cadx.library", "cadx.answers", "cadx.runs", "cadx.build", "cadx.ceus", ] forbidden_modules = ["torch", "sam2"] [[tool.importlinter.contracts]] # 结构.md 第三部分依赖表:segment 不引用其他 cadx 模块(它不认识分屏和绿框)。 name = "segment 不引用其他 cadx 模块" type = "forbidden" source_modules = ["cadx.segment"] forbidden_modules = [ "cadx.delivery", "cadx.library", "cadx.answers", "cadx.runs", "cadx.build", "cadx.ceus", "cadx.llm", "cadx.ledger", "cadx.consult", "cadx.evaluate", "cadx.verdicts", ] [[tool.importlinter.contracts]] # 结构.md 第三部分依赖表:外部层与格式层的模块不依赖其他 cadx 模块。 name = "delivery、library、answers、runs 互不依赖" type = "independence" modules = ["cadx.delivery", "cadx.library", "cadx.answers", "cadx.runs"] [[tool.importlinter.contracts]] # 同上,依赖表的另一半:它们也不引用上层和其余规划中的模块(独立契约只管它们之间)。 name = "delivery、library、answers、runs 不引用其他 cadx 模块" type = "forbidden" source_modules = ["cadx.delivery", "cadx.library", "cadx.answers", "cadx.runs"] forbidden_modules = [ "cadx.build", "cadx.ceus", "cadx.segment", "cadx.llm", "cadx.ledger", "cadx.consult", "cadx.evaluate", "cadx.verdicts", ] [[tool.importlinter.contracts]] # 结构.md 第三部分依赖表:ceus 是纯计算,不引用其他 cadx 模块(含 segment,分割结果由脚本传进来)。 name = "ceus 不引用其他 cadx 模块" type = "forbidden" source_modules = ["cadx.ceus"] forbidden_modules = [ "cadx.delivery", "cadx.library", "cadx.answers", "cadx.runs", "cadx.build", "cadx.segment", "cadx.llm", "cadx.ledger", "cadx.consult", "cadx.evaluate", "cadx.verdicts", ] [[tool.importlinter.contracts]] # 结构.md 第三部分依赖表:build 只依赖 delivery、library、answers、runs(ceus 落地时加入)。 name = "build 只引用 delivery、library、answers、runs" type = "forbidden" source_modules = ["cadx.build"] forbidden_modules = [ "cadx.ceus", "cadx.segment", "cadx.llm", "cadx.ledger", "cadx.consult", "cadx.evaluate", "cadx.verdicts", ] allow_indirect_imports = true [[tool.importlinter.contracts]] # 结构.md 第五部分:交付包的 Excel 只有 delivery 碰。 name = "只有 delivery 引用 openpyxl" type = "forbidden" source_modules = ["cadx.library", "cadx.answers", "cadx.runs", "cadx.build"] forbidden_modules = ["openpyxl"] allow_indirect_imports = true [[tool.importlinter.contracts]] # 结构.md 第五部分:写资料库的图片(去掉元数据)只有 library 碰。 name = "只有 library 引用 PIL" type = "forbidden" source_modules = ["cadx.delivery", "cadx.answers", "cadx.runs", "cadx.build"] forbidden_modules = ["PIL"] allow_indirect_imports = true