macenko-pca 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. macenko_pca-0.1.0/.editorconfig +36 -0
  2. macenko_pca-0.1.0/.github/dependabot.yml +21 -0
  3. macenko_pca-0.1.0/.github/workflows/build.yml +87 -0
  4. macenko_pca-0.1.0/.github/workflows/lint.yml +27 -0
  5. macenko_pca-0.1.0/.github/workflows/publish.yml +182 -0
  6. macenko_pca-0.1.0/.github/workflows/pytest.yml +86 -0
  7. macenko_pca-0.1.0/.gitignore +84 -0
  8. macenko_pca-0.1.0/.pre-commit-config.yaml +27 -0
  9. macenko_pca-0.1.0/CONTRIBUTING.md +166 -0
  10. macenko_pca-0.1.0/Cargo.lock +1321 -0
  11. macenko_pca-0.1.0/Cargo.toml +33 -0
  12. macenko_pca-0.1.0/Dockerfile +91 -0
  13. macenko_pca-0.1.0/LICENSE.txt +9 -0
  14. macenko_pca-0.1.0/Makefile +74 -0
  15. macenko_pca-0.1.0/PKG-INFO +337 -0
  16. macenko_pca-0.1.0/README.md +311 -0
  17. macenko_pca-0.1.0/docs/api.md +12 -0
  18. macenko_pca-0.1.0/docs/index.md +215 -0
  19. macenko_pca-0.1.0/mkdocs.yml +37 -0
  20. macenko_pca-0.1.0/pyproject.toml +177 -0
  21. macenko_pca-0.1.0/rust/color_conversion.rs +108 -0
  22. macenko_pca-0.1.0/rust/color_deconvolution.rs +153 -0
  23. macenko_pca-0.1.0/rust/complement_stain_matrix.rs +27 -0
  24. macenko_pca-0.1.0/rust/float_trait.rs +19 -0
  25. macenko_pca-0.1.0/rust/lib.rs +209 -0
  26. macenko_pca-0.1.0/rust/linalg.rs +50 -0
  27. macenko_pca-0.1.0/rust/rgb_separate_stains_macenko_pca.rs +30 -0
  28. macenko_pca-0.1.0/rust/separate_stains_macenko_pca.rs +141 -0
  29. macenko_pca-0.1.0/rust/utils.rs +34 -0
  30. macenko_pca-0.1.0/src/macenko_pca/__about__.py +6 -0
  31. macenko_pca-0.1.0/src/macenko_pca/__init__.py +54 -0
  32. macenko_pca-0.1.0/src/macenko_pca/_rust.py +76 -0
  33. macenko_pca-0.1.0/src/macenko_pca/deconvolution.py +529 -0
  34. macenko_pca-0.1.0/src/macenko_pca/py.typed +0 -0
  35. macenko_pca-0.1.0/tests/__init__.py +4 -0
  36. macenko_pca-0.1.0/tests/conftest.py +140 -0
  37. macenko_pca-0.1.0/tests/test_deconvolution.py +860 -0
@@ -0,0 +1,36 @@
1
+ # EditorConfig — https://editorconfig.org
2
+
3
+ root = true
4
+
5
+ [*]
6
+ indent_style = space
7
+ indent_size = 4
8
+ end_of_line = lf
9
+ charset = utf-8
10
+ trim_trailing_whitespace = true
11
+ insert_final_newline = true
12
+
13
+ [*.py]
14
+ indent_size = 4
15
+ max_line_length = 88
16
+
17
+ [*.{yml,yaml}]
18
+ indent_size = 2
19
+
20
+ [*.{json,jsonc}]
21
+ indent_size = 2
22
+
23
+ [*.{toml,cfg,ini}]
24
+ indent_size = 4
25
+
26
+ [*.md]
27
+ trim_trailing_whitespace = false
28
+
29
+ [*.{sh,bash,zsh}]
30
+ indent_size = 2
31
+
32
+ [Makefile]
33
+ indent_style = tab
34
+
35
+ [Dockerfile*]
36
+ indent_size = 4
@@ -0,0 +1,21 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+
8
+ - package-ecosystem: "github-actions"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
12
+
13
+ - package-ecosystem: "docker"
14
+ directory: "/"
15
+ schedule:
16
+ interval: "weekly"
17
+
18
+ - package-ecosystem: "cargo"
19
+ directory: "/"
20
+ schedule:
21
+ interval: "weekly"
@@ -0,0 +1,87 @@
1
+ name: Build Wheels (CI)
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+
9
+ jobs:
10
+ build-wheels:
11
+ name: Build wheels — ${{ matrix.os }}
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, macos-14]
17
+ # macos-14 = arm64
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Set up Python
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: "3.12"
26
+
27
+ - name: Install Rust toolchain
28
+ uses: dtolnay/rust-toolchain@stable
29
+
30
+ - name: Build wheels (Linux — manylinux)
31
+ if: runner.os == 'Linux'
32
+ uses: PyO3/maturin-action@v1
33
+ with:
34
+ target: x86_64
35
+ manylinux: auto
36
+ args: --release --out dist
37
+ sccache: "true"
38
+ before-script-linux: |
39
+ # Try yum (CentOS-based manylinux) first, then fall back to apt (Debian/Ubuntu).
40
+ # Install OpenBLAS and OpenSSL development headers + pkg-config so native crates can link.
41
+ yum install -y openblas-devel openssl-devel pkgconfig || \
42
+ (apt-get update && apt-get install -y libopenblas-dev libssl-dev pkg-config) || true
43
+
44
+ - name: Install macOS system deps
45
+ if: runner.os == 'macOS'
46
+ run: brew install openblas pkg-config openssl
47
+
48
+ - name: Build wheels (macOS)
49
+ if: runner.os == 'macOS'
50
+ uses: PyO3/maturin-action@v1
51
+ env:
52
+ # Help pkg-config find Homebrew's openblas and openssl on both Intel and ARM runners
53
+ PKG_CONFIG_PATH: /opt/homebrew/opt/openblas/lib/pkgconfig:/usr/local/opt/openblas/lib/pkgconfig:/opt/homebrew/opt/openssl/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig
54
+ with:
55
+ args: --release --out dist
56
+ sccache: "true"
57
+
58
+ # Windows-specific vcpkg / OpenBLAS install removed — Windows is not supported.
59
+ # See README for platform support and rationale (we only build and test on Linux/macOS).
60
+
61
+ # Windows build step removed — we only build wheels on Linux and macOS.
62
+
63
+ - name: Upload wheel artifacts
64
+ uses: actions/upload-artifact@v4
65
+ with:
66
+ name: wheels-${{ matrix.os }}
67
+ path: dist/*.whl
68
+ if-no-files-found: error
69
+
70
+ build-sdist:
71
+ name: Build sdist
72
+ runs-on: ubuntu-latest
73
+ steps:
74
+ - uses: actions/checkout@v4
75
+
76
+ - name: Build sdist
77
+ uses: PyO3/maturin-action@v1
78
+ with:
79
+ command: sdist
80
+ args: --out dist
81
+
82
+ - name: Upload sdist artifact
83
+ uses: actions/upload-artifact@v4
84
+ with:
85
+ name: sdist
86
+ path: dist/*.tar.gz
87
+ if-no-files-found: error
@@ -0,0 +1,27 @@
1
+ name: Lint and Format with Ruff
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ branches:
7
+ - main
8
+
9
+ jobs:
10
+ lint-and-format:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+
20
+ - name: Install Ruff
21
+ run: pip install ruff
22
+
23
+ - name: Check formatting with Ruff
24
+ run: ruff format src tests --check
25
+
26
+ - name: Run Ruff linter
27
+ run: ruff check src tests
@@ -0,0 +1,182 @@
1
+ # Publish to PyPI using trusted publishing (OIDC)
2
+ #
3
+ # Triggered when a GitHub Release is created (which should be done after
4
+ # tagging a version, e.g. `git tag v0.2.0 && git push --tags`).
5
+ #
6
+ # Prerequisites — one-time PyPI setup:
7
+ # 1. Go to https://pypi.org/manage/account/publishing/
8
+ # (or the org-level page for the "lavlab" org).
9
+ # 2. Add a new "pending publisher" with:
10
+ # • PyPI project name: macenko-pca
11
+ # • Owner: lavlab (GitHub org)
12
+ # • Repository: macenko-pca
13
+ # • Workflow name: publish.yml
14
+ # • Environment name: pypi
15
+ # 3. (Optional) Repeat for TestPyPI at https://test.pypi.org/manage/account/publishing/
16
+ # using environment name "testpypi".
17
+ #
18
+ # No API tokens or secrets are needed — GitHub's OIDC identity token is
19
+ # exchanged directly with PyPI via trusted publishing.
20
+
21
+ name: Publish to PyPI
22
+
23
+ on:
24
+ release:
25
+ types: [published]
26
+
27
+ # Allow manual dispatch for testing the workflow without creating a release.
28
+ workflow_dispatch:
29
+ inputs:
30
+ target:
31
+ description: "Publish target"
32
+ required: true
33
+ default: "testpypi"
34
+ type: choice
35
+ options:
36
+ - testpypi
37
+ - pypi
38
+
39
+ # Only one publish job should run at a time for the same ref.
40
+ concurrency:
41
+ group: publish-${{ github.ref }}
42
+ cancel-in-progress: false
43
+
44
+ jobs:
45
+ # ---------------------------------------------------------------------------
46
+ # Build wheels for every platform
47
+ # ---------------------------------------------------------------------------
48
+ build-wheels:
49
+ name: Build wheels — ${{ matrix.os }}
50
+ runs-on: ${{ matrix.os }}
51
+ strategy:
52
+ fail-fast: true
53
+ matrix:
54
+ os: [ubuntu-latest, macos-14]
55
+ # macos-14 = arm64
56
+
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+
60
+ - name: Set up Python
61
+ uses: actions/setup-python@v5
62
+ with:
63
+ python-version: "3.12"
64
+
65
+ - name: Install Rust toolchain
66
+ uses: dtolnay/rust-toolchain@stable
67
+
68
+ - name: Build wheels (Linux — manylinux)
69
+ if: runner.os == 'Linux'
70
+ uses: PyO3/maturin-action@v1
71
+ with:
72
+ target: x86_64
73
+ manylinux: auto
74
+ args: --release --out dist
75
+ sccache: "true"
76
+ before-script-linux: |
77
+ # Try yum (CentOS-based manylinux) first, then fall back to apt (Debian/Ubuntu).
78
+ # Install OpenBLAS, OpenSSL development headers and pkg-config so native crates can link.
79
+ yum install -y openblas-devel openssl-devel pkgconfig || \
80
+ (apt-get update && apt-get install -y libopenblas-dev libssl-dev pkg-config) || true
81
+
82
+ - name: Install macOS system deps
83
+ if: runner.os == 'macOS'
84
+ run: brew install openblas pkg-config openssl
85
+
86
+ - name: Build wheels (macOS)
87
+ if: runner.os == 'macOS'
88
+ uses: PyO3/maturin-action@v1
89
+ env:
90
+ # Help pkg-config find Homebrew's openblas and openssl on both Intel and ARM runners
91
+ PKG_CONFIG_PATH: /opt/homebrew/opt/openblas/lib/pkgconfig:/usr/local/opt/openblas/lib/pkgconfig:/opt/homebrew/opt/openssl/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig
92
+ with:
93
+ args: --release --out dist
94
+ sccache: "true"
95
+
96
+ - name: Upload wheel artifacts
97
+ uses: actions/upload-artifact@v4
98
+ with:
99
+ name: wheels-${{ matrix.os }}
100
+ path: dist/*.whl
101
+ if-no-files-found: error
102
+
103
+ # ---------------------------------------------------------------------------
104
+ # Build source distribution
105
+ # ---------------------------------------------------------------------------
106
+ build-sdist:
107
+ name: Build sdist
108
+ runs-on: ubuntu-latest
109
+ steps:
110
+ - uses: actions/checkout@v4
111
+
112
+ - name: Build sdist
113
+ uses: PyO3/maturin-action@v1
114
+ with:
115
+ command: sdist
116
+ args: --out dist
117
+
118
+ - name: Upload sdist artifact
119
+ uses: actions/upload-artifact@v4
120
+ with:
121
+ name: sdist
122
+ path: dist/*.tar.gz
123
+ if-no-files-found: error
124
+
125
+ # ---------------------------------------------------------------------------
126
+ # Publish to PyPI (production) — runs on GitHub Release
127
+ # ---------------------------------------------------------------------------
128
+ publish-pypi:
129
+ name: Publish to PyPI
130
+ needs: [build-wheels, build-sdist]
131
+ runs-on: ubuntu-latest
132
+ # Only publish on release events (not manual dispatch to testpypi)
133
+ if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
134
+ environment:
135
+ name: pypi
136
+ url: https://pypi.org/p/macenko-pca
137
+ permissions:
138
+ id-token: write # Required for trusted publishing OIDC exchange
139
+ steps:
140
+ - name: Download all artifacts
141
+ uses: actions/download-artifact@v4
142
+ with:
143
+ path: dist
144
+ merge-multiple: true
145
+
146
+ - name: List artifacts
147
+ run: ls -lhR dist/
148
+
149
+ - name: Publish to PyPI
150
+ uses: pypa/gh-action-pypi-publish@release/v1
151
+ with:
152
+ # No password needed — trusted publishing uses the OIDC token.
153
+ print-hash: true
154
+
155
+ # ---------------------------------------------------------------------------
156
+ # Publish to TestPyPI — manual dispatch only
157
+ # ---------------------------------------------------------------------------
158
+ publish-testpypi:
159
+ name: Publish to TestPyPI
160
+ needs: [build-wheels, build-sdist]
161
+ runs-on: ubuntu-latest
162
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
163
+ environment:
164
+ name: testpypi
165
+ url: https://test.pypi.org/p/macenko-pca
166
+ permissions:
167
+ id-token: write
168
+ steps:
169
+ - name: Download all artifacts
170
+ uses: actions/download-artifact@v4
171
+ with:
172
+ path: dist
173
+ merge-multiple: true
174
+
175
+ - name: List artifacts
176
+ run: ls -lhR dist/
177
+
178
+ - name: Publish to TestPyPI
179
+ uses: pypa/gh-action-pypi-publish@release/v1
180
+ with:
181
+ repository-url: https://test.pypi.org/legacy/
182
+ print-hash: true
@@ -0,0 +1,86 @@
1
+ name: Run Pytest with Maturin
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ name: Test on Python ${{ matrix.python-version }} / ${{ matrix.os }}
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest]
15
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
16
+
17
+ env:
18
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Set up Python ${{ matrix.python-version }}
24
+ uses: actions/setup-python@v5
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+
28
+ - name: Install Rust toolchain
29
+ uses: dtolnay/rust-toolchain@stable
30
+
31
+ - name: Install system dependencies (Linux)
32
+ if: runner.os == 'Linux'
33
+ run: |
34
+ sudo apt-get update
35
+ sudo apt-get install -y libopenblas-dev pkg-config
36
+
37
+ - name: Install system dependencies (macOS)
38
+ if: runner.os == 'macOS'
39
+ run: brew install openblas pkg-config
40
+
41
+ - name: Create virtualenv
42
+ run: python -m venv .venv
43
+
44
+ - name: Install Python dependencies into virtualenv
45
+ run: |
46
+ # Activate the venv and install dependencies into it. Using explicit
47
+ # `python -m pip` ensures we use the venv's pip regardless of shell.
48
+ . .venv/bin/activate
49
+ python -m pip install --upgrade pip
50
+ python -m pip install maturin pytest pytest-cov coverage
51
+
52
+ - name: Build and install extension (inside virtualenv)
53
+ run: |
54
+ . .venv/bin/activate
55
+ # Run maturin via `python -m` so it uses the venv's site-packages entrypoint.
56
+ python -m maturin develop --release
57
+
58
+ - name: Run pytest and generate coverage report (inside virtualenv)
59
+ run: |
60
+ . .venv/bin/activate
61
+ python -m pytest --cov=src --cov-report=term-missing --cov-report=xml tests/
62
+
63
+ - name: Upload coverage artifact
64
+ uses: actions/upload-artifact@v4
65
+ with:
66
+ name: coverage-xml-${{ matrix.os }}-py${{ matrix.python-version }}
67
+ path: coverage.xml
68
+
69
+ - name: Upload coverage report to Codecov
70
+ if: ${{ env.CODECOV_TOKEN != '' }}
71
+ uses: codecov/codecov-action@v4
72
+ with:
73
+ fail_ci_if_error: true
74
+ files: coverage.xml
75
+ env:
76
+ CODECOV_TOKEN: ${{ env.CODECOV_TOKEN }}
77
+
78
+ - name: Skip Codecov upload (no token)
79
+ if: ${{ env.CODECOV_TOKEN == '' }}
80
+ run: |
81
+ echo "CODECOV_TOKEN not found. Skipping Codecov upload."
82
+ echo ""
83
+ echo "If you want coverage uploaded to Codecov for protected branches, set a"
84
+ echo "repository or organization secret named CODECOV_TOKEN with your Codecov token."
85
+ echo ""
86
+ echo "Alternatively, you can rely on the uploaded coverage artifact to inspect coverage locally."
@@ -0,0 +1,84 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+ *.egg
11
+ *.whl
12
+ sdist/
13
+
14
+ # Virtual environments
15
+ .venv/
16
+ venv/
17
+ ENV/
18
+ env/
19
+
20
+ # Hatch
21
+ .hatch/
22
+
23
+ # IDE / Editor
24
+ .vscode/
25
+ .idea/
26
+ *.swp
27
+ *.swo
28
+ *~
29
+ .project
30
+ .settings/
31
+
32
+ # OS files
33
+ .DS_Store
34
+ Thumbs.db
35
+
36
+ # Testing / Coverage
37
+ htmlcov/
38
+ .coverage
39
+ .coverage.*
40
+ coverage.xml
41
+ *.cover
42
+ .pytest_cache/
43
+ .mypy_cache/
44
+
45
+ # Documentation builds
46
+ site/
47
+
48
+ # Jupyter Notebooks
49
+ .ipynb_checkpoints/
50
+
51
+ # Ruff
52
+ .ruff_cache/
53
+
54
+ # Environment variables
55
+ .env
56
+ .env.*
57
+ !.env.example
58
+
59
+ # Secrets — never commit these
60
+ *.pem
61
+ *.key
62
+
63
+ # Logs
64
+ *.log
65
+
66
+ # Type stubs
67
+ .pytype/
68
+ dmypy.json
69
+
70
+ # Pre-commit
71
+ .pre-commit-cache/
72
+
73
+ # Rust / Cargo / Maturin
74
+ target/
75
+ **/*.rs.bk
76
+ Cargo.lock
77
+ *.so
78
+ *.dylib
79
+ *.dll
80
+ *.pyd
81
+
82
+ # Misc
83
+ *.bak
84
+ *.tmp
@@ -0,0 +1,27 @@
1
+ # See https://pre-commit.com for more information
2
+ # See https://pre-commit.com/hooks.html for more hooks
3
+ repos:
4
+ - repo: https://github.com/pre-commit/pre-commit-hooks
5
+ rev: v4.6.0
6
+ hooks:
7
+ - id: trailing-whitespace
8
+ - id: end-of-file-fixer
9
+ - id: check-yaml
10
+ - id: check-toml
11
+ - id: check-added-large-files
12
+ - id: check-merge-conflict
13
+ - id: debug-statements
14
+
15
+ - repo: https://github.com/astral-sh/ruff-pre-commit
16
+ rev: v0.4.8
17
+ hooks:
18
+ - id: ruff
19
+ args: [--fix]
20
+ - id: ruff-format
21
+
22
+ - repo: https://github.com/pre-commit/mirrors-mypy
23
+ rev: v1.10.0
24
+ hooks:
25
+ - id: mypy
26
+ additional_dependencies: [numpy>=1.22]
27
+ args: [--ignore-missing-imports]