diff --git a/.changeset/clustcr-runenv.md b/.changeset/clustcr-runenv.md new file mode 100644 index 0000000..3b987f6 --- /dev/null +++ b/.changeset/clustcr-runenv.md @@ -0,0 +1,17 @@ +--- +"@platforma-open/milaboratories.runenv-python-3.10.21-clustcr": minor +"@platforma-open/milaboratories.runenv-python-3": minor +--- + +Add the `3.10.21-clustcr` Python run environment: clusTCR (`immunewatch-clustcr`, module `imw_clustcr`) +plus its runtime closure, faiss-cpu and polars-lts-cpu, for the clusTCR Clustering block. + +Python 3.10 rather than the repo's usual 3.12.10, deliberately: clusTCR requires SciPy 1.8, which no +Python 3.11+ release supports, and that requirement is load-bearing — on SciPy 1.8 a sparse array is still +an `spmatrix`, which is what makes clusTCR's Markov-clustering step work, while newer SciPy breaks it and +NumPy 2 breaks its FAISS-backed paths. Targeting 3.10 lets the package be installed and used unmodified: +no dependency metadata skipped, no numpy ceiling, and no runtime patching in the consuming block. Intended +to be temporary — see the package README. Python 3.10 is EOL 2026-10-31. + +`python-louvain` ships no wheel for any version and is built on the runner via `buildWheel` with an +explicit setuptools backend, since pip's build isolation cannot reach an index for one. diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 045c596..0be5661 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -108,6 +108,11 @@ jobs: {"os":"macos-15-large", "arch":"amd64", "selector":"./python-3.12.10-clustering"}, {"os":"windows-latest", "arch":"amd64", "selector":"./python-3.12.10-clustering"}, + {"os":"ubuntu-large-arm64", "arch":"arm64", "selector":"./python-3.10.21-clustcr"}, + {"os":"ubuntu-large-amd64", "arch":"amd64", "selector":"./python-3.10.21-clustcr"}, + {"os":"macos-15", "arch":"arm64", "selector":"./python-3.10.21-clustcr"}, + {"os":"macos-15-large", "arch":"amd64", "selector":"./python-3.10.21-clustcr"}, + {"os":"ubuntu-large-arm64", "arch":"arm64", "selector":"./python-3.12.10-pgen"}, {"os":"ubuntu-large-amd64", "arch":"amd64", "selector":"./python-3.12.10-pgen"}, {"os":"macos-15", "arch":"arm64", "selector":"./python-3.12.10-pgen"}, diff --git a/catalogue/package.json b/catalogue/package.json index b656b38..b465900 100644 --- a/catalogue/package.json +++ b/catalogue/package.json @@ -44,6 +44,9 @@ }, "3.12.10-pgen": { "reference": "@platforma-open/milaboratories.runenv-python-3.12.10-pgen/dist/tengo/software/main.sw.json" + }, + "3.10.21-clustcr": { + "reference": "@platforma-open/milaboratories.runenv-python-3.10.21-clustcr/dist/tengo/software/main.sw.json" } } }, @@ -62,9 +65,10 @@ "@platforma-open/milaboratories.runenv-python-3.12.10-humanness": "workspace:*", "@platforma-open/milaboratories.runenv-python-3.12.10-torch-cuda": "workspace:*", "@platforma-open/milaboratories.runenv-python-3.12.10-clustering": "workspace:*", - "@platforma-open/milaboratories.runenv-python-3.12.10-pgen": "workspace:*" + "@platforma-open/milaboratories.runenv-python-3.12.10-pgen": "workspace:*", + "@platforma-open/milaboratories.runenv-python-3.10.21-clustcr": "workspace:*" }, "devDependencies": { "@platforma-sdk/package-builder": "catalog:" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 063067d..f2dbaad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: catalogue: dependencies: + '@platforma-open/milaboratories.runenv-python-3.10.21-clustcr': + specifier: workspace:* + version: link:../python-3.10.21-clustcr '@platforma-open/milaboratories.runenv-python-3.12.10': specifier: workspace:* version: link:../python-3.12.10 @@ -97,6 +100,18 @@ importers: specifier: 'catalog:' version: 3.10.7 + python-3.10.21-clustcr: + devDependencies: + '@platforma-sdk/package-builder': + specifier: 'catalog:' + version: 3.10.7 + runenv-python-builder: + specifier: workspace:* + version: link:../builder + tsx: + specifier: 'catalog:' + version: 4.20.6 + python-3.12.10: devDependencies: '@platforma-sdk/package-builder': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e144236..5fd8e5f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,6 +11,7 @@ packages: - python-3.12.10-humanness - python-3.12.10-torch-cuda - python-3.12.10-clustering + - python-3.10.21-clustcr - python-3.12.10-pgen - catalogue diff --git a/python-3.10.21-clustcr/README.md b/python-3.10.21-clustcr/README.md new file mode 100644 index 0000000..e2f98c8 --- /dev/null +++ b/python-3.10.21-clustcr/README.md @@ -0,0 +1,3 @@ +Python **3.10.21** run environment for the **clusTCR Clustering** block (`tcr-clustering-clusttcr`): +clusTCR (`immunewatch-clustcr`, importable as `imw_clustcr`) plus its runtime closure and faiss-cpu, with +polars-lts-cpu for the block runner's own I/O. \ No newline at end of file diff --git a/python-3.10.21-clustcr/config.json b/python-3.10.21-clustcr/config.json new file mode 100644 index 0000000..fbea308 --- /dev/null +++ b/python-3.10.21-clustcr/config.json @@ -0,0 +1,59 @@ +{ + "packages": { + "dependencies": [ + "immunewatch-clustcr==1.0.1", + "scipy==1.8.0", + "numpy==1.24.4", + "pandas==2.3.3", + "networkx==3.4.2", + "scikit-learn==1.7.2", + "markov_clustering==0.0.6.dev0", + "parmap==1.7.0", + "python-louvain==0.16", + "matplotlib==3.10.9", + "faiss-cpu==1.8.0.post1", + "polars-lts-cpu==1.33.1" + ], + "noDeps": [ + "immunewatch-clustcr" + ], + "skip": {}, + "overrides": {}, + "platformSpecific": {}, + "resolution": { + "strictMissing": true + }, + "buildWheel": { + "python-louvain": { + "linux-x64": { + "reason": "python-louvain ships NO wheel for any version (0.1-0.16 are all sdist), so it must be built on the runner. It is pure Python, so no compiler is needed - but pip's build isolation tries to fetch the setuptools backend, and the build runs with --find-links pointing only at the local package dir, so that fetch fails. Pre-installing the backend via buildRequires makes the builder pass --no-build-isolation, which avoids the isolated env entirely.", + "buildRequires": [ + "setuptools>=40.8.0", + "wheel" + ] + }, + "linux-aarch64": { + "reason": "python-louvain ships NO wheel for any version (0.1-0.16 are all sdist), so it must be built on the runner. It is pure Python, so no compiler is needed - but pip's build isolation tries to fetch the setuptools backend, and the build runs with --find-links pointing only at the local package dir, so that fetch fails. Pre-installing the backend via buildRequires makes the builder pass --no-build-isolation, which avoids the isolated env entirely.", + "buildRequires": [ + "setuptools>=40.8.0", + "wheel" + ] + }, + "macosx-x64": { + "reason": "python-louvain ships NO wheel for any version (0.1-0.16 are all sdist), so it must be built on the runner. It is pure Python, so no compiler is needed - but pip's build isolation tries to fetch the setuptools backend, and the build runs with --find-links pointing only at the local package dir, so that fetch fails. Pre-installing the backend via buildRequires makes the builder pass --no-build-isolation, which avoids the isolated env entirely.", + "buildRequires": [ + "setuptools>=40.8.0", + "wheel" + ] + }, + "macosx-aarch64": { + "reason": "python-louvain ships NO wheel for any version (0.1-0.16 are all sdist), so it must be built on the runner. It is pure Python, so no compiler is needed - but pip's build isolation tries to fetch the setuptools backend, and the build runs with --find-links pointing only at the local package dir, so that fetch fails. Pre-installing the backend via buildRequires makes the builder pass --no-build-isolation, which avoids the isolated env entirely.", + "buildRequires": [ + "setuptools>=40.8.0", + "wheel" + ] + } + } + } + } +} diff --git a/python-3.10.21-clustcr/package.json b/python-3.10.21-clustcr/package.json new file mode 100644 index 0000000..22e6253 --- /dev/null +++ b/python-3.10.21-clustcr/package.json @@ -0,0 +1,42 @@ +{ + "name": "@platforma-open/milaboratories.runenv-python-3.10.21-clustcr", + "version": "0.1.0", + "description": "Python 3.10.21 run environment for the clusTCR Clustering block (immunewatch-clustcr on the SciPy 1.8 generation it requires)", + "scripts": { + "cleanup": "rm -rf ./pkg-*.tgz ./pydist ./dist/ ./build/", + "reset": "pnpm run cleanup && rm -rf ./node_modules ./.turbo", + "build": "pl-py-builder", + "after-prebuild": "pl-pkg publish packages", + "before-publish": "pl-pkg prepublish" + }, + "files": [ + "dist/" + ], + "block-software": { + "entrypoints": { + "main": { + "environment": { + "artifact": { + "type": "environment", + "runtime": "python", + "registry": "platforma-open", + "python-version": "3.10.21", + "roots": { + "linux-x64": "./pydist/linux-x64", + "linux-aarch64": "./pydist/linux-aarch64", + "macosx-x64": "./pydist/macosx-x64", + "macosx-aarch64": "./pydist/macosx-aarch64" + }, + "binDir": "bin" + } + } + } + } + }, + "license": "UNLICENSED", + "devDependencies": { + "@platforma-sdk/package-builder": "catalog:", + "runenv-python-builder": "workspace:*", + "tsx": "catalog:" + } +}