manifold-genetics 0.2.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 (137) hide show
  1. manifold_genetics-0.2.0/.flake8 +3 -0
  2. manifold_genetics-0.2.0/.gitignore +196 -0
  3. manifold_genetics-0.2.0/CHANGELOG.md +164 -0
  4. manifold_genetics-0.2.0/LICENSE +28 -0
  5. manifold_genetics-0.2.0/PKG-INFO +607 -0
  6. manifold_genetics-0.2.0/README.md +551 -0
  7. manifold_genetics-0.2.0/pyproject.toml +141 -0
  8. manifold_genetics-0.2.0/scripts/__init__.py +0 -0
  9. manifold_genetics-0.2.0/scripts/check_sensitive_files.py +281 -0
  10. manifold_genetics-0.2.0/src/manifold_genetics/__init__.py +31 -0
  11. manifold_genetics-0.2.0/src/manifold_genetics/admixture/__init__.py +17 -0
  12. manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/__init__.py +13 -0
  13. manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/base.py +86 -0
  14. manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/fake.py +167 -0
  15. manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/neural.py +419 -0
  16. manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/precomputed.py +196 -0
  17. manifold_genetics-0.2.0/src/manifold_genetics/admixture/neural.py +150 -0
  18. manifold_genetics-0.2.0/src/manifold_genetics/cli.py +1533 -0
  19. manifold_genetics-0.2.0/src/manifold_genetics/embeddings/__init__.py +9 -0
  20. manifold_genetics-0.2.0/src/manifold_genetics/embeddings/base.py +154 -0
  21. manifold_genetics-0.2.0/src/manifold_genetics/embeddings/diffusion_map.py +225 -0
  22. manifold_genetics-0.2.0/src/manifold_genetics/embeddings/phate.py +191 -0
  23. manifold_genetics-0.2.0/src/manifold_genetics/embeddings/tsne.py +139 -0
  24. manifold_genetics-0.2.0/src/manifold_genetics/embeddings/umap.py +143 -0
  25. manifold_genetics-0.2.0/src/manifold_genetics/metrics/__init__.py +9 -0
  26. manifold_genetics-0.2.0/src/manifold_genetics/metrics/admixture.py +190 -0
  27. manifold_genetics-0.2.0/src/manifold_genetics/metrics/geographic.py +157 -0
  28. manifold_genetics-0.2.0/src/manifold_genetics/pca/__init__.py +5 -0
  29. manifold_genetics-0.2.0/src/manifold_genetics/pca/backends/__init__.py +6 -0
  30. manifold_genetics-0.2.0/src/manifold_genetics/pca/backends/base.py +79 -0
  31. manifold_genetics-0.2.0/src/manifold_genetics/pca/backends/sklearn_backend.py +262 -0
  32. manifold_genetics-0.2.0/src/manifold_genetics/pca/flashpca.py +498 -0
  33. manifold_genetics-0.2.0/src/manifold_genetics/pca/flashpca_format.py +150 -0
  34. manifold_genetics-0.2.0/src/manifold_genetics/pca/plink.py +157 -0
  35. manifold_genetics-0.2.0/src/manifold_genetics/pca/standardize.py +78 -0
  36. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/__init__.py +7 -0
  37. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/config.py +226 -0
  38. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/configfile.py +268 -0
  39. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/orchestrator.py +424 -0
  40. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/result.py +70 -0
  41. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/runner.py +206 -0
  42. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/__init__.py +64 -0
  43. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/admixture.py +133 -0
  44. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/embedding.py +183 -0
  45. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/metrics.py +122 -0
  46. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/paths.py +59 -0
  47. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/pca.py +131 -0
  48. manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/viz.py +262 -0
  49. manifold_genetics-0.2.0/src/manifold_genetics/py.typed +0 -0
  50. manifold_genetics-0.2.0/src/manifold_genetics/utils/__init__.py +0 -0
  51. manifold_genetics-0.2.0/src/manifold_genetics/utils/filter_duplicates.py +202 -0
  52. manifold_genetics-0.2.0/src/manifold_genetics/utils/io.py +408 -0
  53. manifold_genetics-0.2.0/src/manifold_genetics/utils/tools.py +579 -0
  54. manifold_genetics-0.2.0/src/manifold_genetics/utils/validation.py +509 -0
  55. manifold_genetics-0.2.0/src/manifold_genetics/visualization/__init__.py +21 -0
  56. manifold_genetics-0.2.0/src/manifold_genetics/visualization/plotting.py +1392 -0
  57. manifold_genetics-0.2.0/tests/__init__.py +6 -0
  58. manifold_genetics-0.2.0/tests/conftest.py +270 -0
  59. manifold_genetics-0.2.0/tests/fixtures/admixture/README.md +58 -0
  60. manifold_genetics-0.2.0/tests/fixtures/admixture/fit.2.csv +51 -0
  61. manifold_genetics-0.2.0/tests/fixtures/admixture/fit.3.csv +51 -0
  62. manifold_genetics-0.2.0/tests/fixtures/admixture/project.2.csv +51 -0
  63. manifold_genetics-0.2.0/tests/fixtures/admixture/project.3.csv +51 -0
  64. manifold_genetics-0.2.0/tests/fixtures/cross_cohort/README.md +12 -0
  65. manifold_genetics-0.2.0/tests/fixtures/cross_cohort/fit_colormap.json +9 -0
  66. manifold_genetics-0.2.0/tests/fixtures/cross_cohort/fit_labels.csv +51 -0
  67. manifold_genetics-0.2.0/tests/fixtures/cross_cohort/generate.py +65 -0
  68. manifold_genetics-0.2.0/tests/fixtures/cross_cohort/geographic.csv +51 -0
  69. manifold_genetics-0.2.0/tests/fixtures/cross_cohort/project_colormap.json +9 -0
  70. manifold_genetics-0.2.0/tests/fixtures/cross_cohort/project_labels.csv +51 -0
  71. manifold_genetics-0.2.0/tests/integration/__init__.py +0 -0
  72. manifold_genetics-0.2.0/tests/integration/cohorts.py +152 -0
  73. manifold_genetics-0.2.0/tests/integration/submit_cohort_tests.sh +112 -0
  74. manifold_genetics-0.2.0/tests/integration/test_cohort_pipeline_real.py +279 -0
  75. manifold_genetics-0.2.0/tests/integration/test_cohort_preflight.py +217 -0
  76. manifold_genetics-0.2.0/tests/integration/test_cohort_registry.py +161 -0
  77. manifold_genetics-0.2.0/tests/integration/test_filter_duplicates_real_data.py +209 -0
  78. manifold_genetics-0.2.0/tests/integration/test_generic_pipeline.py +311 -0
  79. manifold_genetics-0.2.0/tests/integration/test_hgdp_pipeline_real.py +172 -0
  80. manifold_genetics-0.2.0/tests/integration/test_hgdp_reproducibility.py +106 -0
  81. manifold_genetics-0.2.0/tests/integration/test_integration.py +107 -0
  82. manifold_genetics-0.2.0/tests/integration/test_pca_flashpca_parity.py +341 -0
  83. manifold_genetics-0.2.0/tests/integration/test_pipeline_contract.py +230 -0
  84. manifold_genetics-0.2.0/tests/integration/test_sdist_contents.py +132 -0
  85. manifold_genetics-0.2.0/tests/science.py +101 -0
  86. manifold_genetics-0.2.0/tests/slow/__init__.py +0 -0
  87. manifold_genetics-0.2.0/tests/test_api.py +150 -0
  88. manifold_genetics-0.2.0/tests/test_cli.py +177 -0
  89. manifold_genetics-0.2.0/tests/test_metrics.py +346 -0
  90. manifold_genetics-0.2.0/tests/unit/__init__.py +0 -0
  91. manifold_genetics-0.2.0/tests/unit/test_admixture_backends.py +261 -0
  92. manifold_genetics-0.2.0/tests/unit/test_admixture_backends_coverage.py +174 -0
  93. manifold_genetics-0.2.0/tests/unit/test_admixture_batch_size_default.py +76 -0
  94. manifold_genetics-0.2.0/tests/unit/test_cli_main.py +830 -0
  95. manifold_genetics-0.2.0/tests/unit/test_cli_run_command.py +149 -0
  96. manifold_genetics-0.2.0/tests/unit/test_config_file.py +249 -0
  97. manifold_genetics-0.2.0/tests/unit/test_embeddings.py +119 -0
  98. manifold_genetics-0.2.0/tests/unit/test_embeddings_wrapper.py +225 -0
  99. manifold_genetics-0.2.0/tests/unit/test_filter_duplicates.py +462 -0
  100. manifold_genetics-0.2.0/tests/unit/test_filter_duplicates_main.py +97 -0
  101. manifold_genetics-0.2.0/tests/unit/test_flashpca_format.py +147 -0
  102. manifold_genetics-0.2.0/tests/unit/test_io.py +241 -0
  103. manifold_genetics-0.2.0/tests/unit/test_io_helpers.py +195 -0
  104. manifold_genetics-0.2.0/tests/unit/test_metrics_edgecases.py +125 -0
  105. manifold_genetics-0.2.0/tests/unit/test_orchestrator.py +986 -0
  106. manifold_genetics-0.2.0/tests/unit/test_package_metadata.py +148 -0
  107. manifold_genetics-0.2.0/tests/unit/test_pca_backend_plumbing.py +59 -0
  108. manifold_genetics-0.2.0/tests/unit/test_pca_backend_selection.py +123 -0
  109. manifold_genetics-0.2.0/tests/unit/test_pca_backend_sklearn.py +186 -0
  110. manifold_genetics-0.2.0/tests/unit/test_pca_fit_memory_budget.py +85 -0
  111. manifold_genetics-0.2.0/tests/unit/test_pca_python_checkpoint.py +132 -0
  112. manifold_genetics-0.2.0/tests/unit/test_pca_standardize.py +111 -0
  113. manifold_genetics-0.2.0/tests/unit/test_pca_streaming_fit.py +100 -0
  114. manifold_genetics-0.2.0/tests/unit/test_pipeline_config.py +228 -0
  115. manifold_genetics-0.2.0/tests/unit/test_pipeline_result.py +230 -0
  116. manifold_genetics-0.2.0/tests/unit/test_plink_reader.py +96 -0
  117. manifold_genetics-0.2.0/tests/unit/test_plotting_coverage.py +299 -0
  118. manifold_genetics-0.2.0/tests/unit/test_plotting_projection.py +309 -0
  119. manifold_genetics-0.2.0/tests/unit/test_preset_naming.py +94 -0
  120. manifold_genetics-0.2.0/tests/unit/test_runner.py +136 -0
  121. manifold_genetics-0.2.0/tests/unit/test_science_assertions.py +131 -0
  122. manifold_genetics-0.2.0/tests/unit/test_sensitive_file_check.py +244 -0
  123. manifold_genetics-0.2.0/tests/unit/test_setup_logging.py +88 -0
  124. manifold_genetics-0.2.0/tests/unit/test_shipped_configs.py +101 -0
  125. manifold_genetics-0.2.0/tests/unit/test_step_admixture.py +286 -0
  126. manifold_genetics-0.2.0/tests/unit/test_step_embedding.py +372 -0
  127. manifold_genetics-0.2.0/tests/unit/test_step_metrics.py +193 -0
  128. manifold_genetics-0.2.0/tests/unit/test_step_paths.py +141 -0
  129. manifold_genetics-0.2.0/tests/unit/test_step_pca.py +236 -0
  130. manifold_genetics-0.2.0/tests/unit/test_step_viz.py +384 -0
  131. manifold_genetics-0.2.0/tests/unit/test_subprocess_wrappers.py +284 -0
  132. manifold_genetics-0.2.0/tests/unit/test_tool_download_urls.py +139 -0
  133. manifold_genetics-0.2.0/tests/unit/test_tools.py +301 -0
  134. manifold_genetics-0.2.0/tests/unit/test_tools_download.py +246 -0
  135. manifold_genetics-0.2.0/tests/unit/test_validation.py +389 -0
  136. manifold_genetics-0.2.0/tests/unit/test_validation_overlap_threshold.py +76 -0
  137. manifold_genetics-0.2.0/tests/unit/test_visualization.py +356 -0
@@ -0,0 +1,3 @@
1
+ [flake8]
2
+ max-line-length = 88
3
+ extend-ignore = E203,W503,E501,F841,F541
@@ -0,0 +1,196 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ dist/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ pip-wheel-metadata/
25
+ share/python-wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+ MANIFEST
30
+
31
+ # PyInstaller
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ coverage.lcov
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ Pipfile.lock
89
+
90
+ # PEP 582
91
+ __pypackages__/
92
+
93
+ # Celery stuff
94
+ celerybeat-schedule
95
+ celerybeat.pid
96
+
97
+ # SageMath parsed files
98
+ *.sage.py
99
+
100
+ # Environments
101
+ .env
102
+ .venv
103
+ env/
104
+ venv/
105
+ ENV/
106
+ env.bak/
107
+ venv.bak/
108
+
109
+ # Spyder project settings
110
+ .spyderproject
111
+ .spyproject
112
+
113
+ # Rope project settings
114
+ .ropeproject
115
+
116
+ # mkdocs documentation
117
+ /site
118
+
119
+ # mypy
120
+ .mypy_cache/
121
+ .dmypy.json
122
+ dmypy.json
123
+
124
+ # Pyre type checker
125
+ .pyre/
126
+
127
+ # IDE
128
+ .vscode/
129
+ .idea/
130
+ *.swp
131
+ *.swo
132
+ *~
133
+
134
+ # OS
135
+ .DS_Store
136
+ Thumbs.db
137
+
138
+ # Project-specific (keep local only)
139
+ CLAUDE.md
140
+
141
+ # docs/ used to be ignored wholesale, which made every design doc and plan in the
142
+ # repo invisible to collaborators and made a docs site unbuildable. Only build
143
+ # artefacts are ignored now.
144
+ docs/_build/
145
+ docs/site/
146
+
147
+ # Scripts that ship with the examples are tracked; only the Dropbox packaging
148
+ # helper stays local (it encodes personal paths).
149
+ examples/hgdp_1kgp/package_data_for_dropbox.sh
150
+
151
+ # Binary tools and data
152
+ bin/
153
+ data/
154
+ logs/
155
+ examples/_shared/tools/
156
+
157
+ # Example outputs
158
+ examples/hgdp_1kgp/outputs/
159
+ examples/ukbb/*/outputs/
160
+ examples/aou/*/outputs/
161
+
162
+ # Controlled-access genetic data must never be committed.
163
+ # Binary genotype/dosage formats (PLINK, BGEN) - never belong in git
164
+ *.bed
165
+ *.bim
166
+ *.fam
167
+ *.bgen
168
+ *.pgen
169
+ *.psam
170
+ *.sample
171
+ *.bcf
172
+ *.vcf
173
+ *.vcf.gz
174
+
175
+ # Local-only data/output staging dirs (e.g. data_old/, outputs_old/, figures/)
176
+ **/data_old/
177
+ **/outputs_old/
178
+ **/data/
179
+ **/figures/
180
+
181
+ # Files holding real sample IDs / private path mappings
182
+ *_private*
183
+ *mappings_private*
184
+ *_labels.csv
185
+ *_samples.txt
186
+ # Synthetic test fixtures (SAMPLE_### IDs, no private data) must stay tracked
187
+ !tests/fixtures/cross_cohort/fit_labels.csv
188
+ !tests/fixtures/cross_cohort/project_labels.csv
189
+ examples/CaG/
190
+ examples/ukbb/60k_random/data/
191
+ examples/ukbb/60k_random/outputs/
192
+
193
+ # Local-only working dirs: superseded code kept for reference, and stray run
194
+ # output. Neither is part of the package; kept out of git rather than deleted.
195
+ deprecated/
196
+ admixture_outputs/
@@ -0,0 +1,164 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
6
+ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-09-12
11
+
12
+ First public release.
13
+
14
+ The headline is that `pip install manifold-genetics` gives you a working
15
+ pipeline. Until this release it did not: PCA required the `flashpca` binary,
16
+ which ships only as a Linux x86-64 executable and had to be fetched and placed
17
+ by hand.
18
+
19
+ The version number is deliberately low. The API is not frozen, the
20
+ `transform` -> `whole_cohort` rename landed days before this, and All of Us has
21
+ not yet been verified end to end -- so expect further breaking changes before
22
+ 1.0.
23
+
24
+ ### Added
25
+
26
+ - **Guardrails against committing controlled-access data**
27
+ ([docs/working-with-agents.md](docs/working-with-agents.md)). A pre-commit hook and
28
+ a CI job run `scripts/check_sensitive_files.py`, written against this
29
+ repository's own two incidents rather than as a generic secret scanner: it
30
+ flags files whose header declares them private, genotype containers, long
31
+ columns of biobank identifiers, local agent and editor state, and absolute
32
+ cluster paths. Public cohort identifiers (`HG00096`) deliberately do not
33
+ trigger it. Exemptions live in `.sensitive-allow`, scoped to a single rule, so
34
+ that overriding the check leaves a reviewable trace.
35
+ - **A pure-Python PCA backend**, selected by default. Reads PLINK 1 `.bed`
36
+ directly (about forty lines of numpy, no new dependency) and computes a
37
+ randomized SVD. It reproduces `flashpca`'s conventions rather than inventing
38
+ its own — dosage as the count of A1, `binom2` standardisation, eigenvalues as
39
+ `S²/n_variants`, projection through the reference cohort's statistics — to
40
+ agreement of 5e-7 or better against checked-in reference outputs. The
41
+ standardisation was determined empirically from real `.meansd` files, not from
42
+ documentation.
43
+ - **`flashpca` remains available** as an opt-in accelerator via
44
+ `--pca-backend flashpca`, and writes the same artefacts as the Python backend,
45
+ so downstream code cannot tell which produced a result.
46
+ - **Streaming fit** for cohorts too large to hold densely. Selected
47
+ automatically from `max_fit_memory_gb`: a 60,000-sample cohort needs 82 GB
48
+ dense and about 110 MB streamed.
49
+ - **`manifold-genetics run config.yaml`** — runs a whole pipeline from a config
50
+ file, with `--dry-run` to print the resolved settings first. Unknown keys are
51
+ rejected with a suggestion rather than ignored.
52
+ - **A config file for every shipped example**, replacing 1,382 lines of shell.
53
+ - **`py.typed`**, so the annotations in this package are visible to type
54
+ checkers in projects that depend on it.
55
+ - **A real-cohort test suite** (`docs/testing-real-cohorts.md`): fast preflight
56
+ checks that a cohort's data agrees with the config describing it, and an
57
+ end-to-end suite with chance-corrected assertions about the science. Includes
58
+ a SLURM entry point.
59
+ - **A documentation site** built with MkDocs Material and published to GitHub
60
+ Pages, including a tutorial notebook that runs the whole pipeline on a cohort
61
+ it simulates as it goes. The notebook is *executed* during the build and the
62
+ build runs in strict mode, so a tutorial that stopped working or a broken
63
+ internal link fails CI rather than shipping.
64
+ - **A tag-triggered release workflow** (`docs/releasing.md`) using trusted
65
+ publishing, so there is no API token in the repository and no way to publish
66
+ from a laptop. It builds from a fresh checkout, verifies the package metadata
67
+ and the distribution contents, and installs the wheel into a clean
68
+ virtualenv on Linux and macOS before anything is uploaded.
69
+
70
+ ### Changed
71
+
72
+ - **External tools are cached per user and fetched on first use.** They were
73
+ downloaded to a directory computed from `__file__`, which in a git checkout is
74
+ the repository's `bin/` and in a `pip install` is a directory *beside*
75
+ site-packages: the wrong place, frequently not writable, and discarded on
76
+ upgrade. Worse, the constructor created it eagerly, so merely building a
77
+ `ToolResolver` — which `PCA(backend="flashpca")` does — left a stray directory
78
+ behind.
79
+
80
+ Now: `$MANIFOLD_GENETICS_TOOL_DIR` if set, else the checkout's `bin/` when
81
+ running from one, else a per-user cache (`~/.cache/manifold-genetics/bin`).
82
+ Nothing is created until something is actually downloaded.
83
+ `manifold-genetics setup` stays, as the pre-fetch you want before submitting a
84
+ job to a compute node with no internet.
85
+ - **The right binary is downloaded for the platform.** Every URL was
86
+ `linux_x86_64`, so on macOS the resolver fetched a Linux binary and then
87
+ failed to execute it — which reads as a corrupt download rather than as "there
88
+ is no build for you". plink2 and plink now resolve per platform (Linux x86-64,
89
+ macOS arm64 and Intel, Windows x64), and `flashpca`, which upstream publishes
90
+ only for Linux x86-64, says exactly that and points at the in-process PCA
91
+ backend that needs no binary.
92
+
93
+ - **The `transform` preset is now `whole_cohort`.** This project used
94
+ `transform` for two things — the second cohort's dataset role and the
95
+ sklearn-style method verb. The role was renamed to `project` earlier; this
96
+ preset was the last holdout, naming a *mode* while every other use of the word
97
+ names an *operation*. The rule is now: `fit` estimates, `transform` applies,
98
+ `project` is the second cohort and its outputs, and a preset is named for the
99
+ shape of the run.
100
+
101
+ `transform` still works as a deprecated alias and warns, naming its
102
+ replacement. It is deliberately not listed among the valid choices in the
103
+ error message, because an advertised alias is a name people keep choosing.
104
+ - **PCA's default backend is now `python`.** `flashpca` produced the reference
105
+ outputs and still reproduces them bit-for-bit; the change is about being
106
+ installable, not about accuracy.
107
+ - **Landmarking defaults are consistent across large cohorts**: 10,000 random
108
+ landmarks and `t=50` for every cohort above ~50,000 samples, whether the fit
109
+ subset was chosen by majority-capping or by geometric sketching. How a subset
110
+ was selected should not change how it is embedded. A matched comparison found
111
+ the two give the same branch topology.
112
+ - **`--verbose` no longer sets the root logger.** It previously enabled DEBUG
113
+ for every library in the process, which produced 665 KB of numba SSA dumps in
114
+ two minutes of one run.
115
+ - **`manifold-genetics run --dry-run` now prints the whole effective call**,
116
+ marking `(default)` on anything the package supplied rather than the config
117
+ file. The admixture batch size is why: it is a workaround for an upstream bug,
118
+ so it appears in no config and was previously invisible in the one place built
119
+ for checking settings before a long run.
120
+
121
+ ### Fixed
122
+
123
+ - **`manifold-genetics --version` disagreed with the package.** The number was
124
+ typed into the argparse argument as a third copy and drifted a minor version
125
+ behind `manifold_genetics.__version__`. It now reads the package. Caught by a
126
+ TestPyPI rehearsal, which is what a rehearsal is for.
127
+
128
+ A test pinned the stale literal, so it passed while the command was wrong; it
129
+ now compares against the package. Two further tests assert that the CLI
130
+ reports the declared version and that the version appears in exactly one
131
+ source file.
132
+ - The wheel is now checked to contain no untracked module. It picks files by the
133
+ same "everything not gitignored" rule that put untracked working files in a
134
+ pre-release sdist; there are stale `.ipynb_checkpoints` copies of two real
135
+ backends under `src/` today, kept out only by a `.gitignore` entry.
136
+ - **The declared license was MIT; the LICENSE file is BSD 3-Clause.** The
137
+ LICENSE file is authoritative and the metadata now matches it. A release
138
+ cannot be re-uploaded under the same version, so this would have been
139
+ permanent.
140
+ - **Every `project.urls` entry pointed at `manifold-genetics` with a hyphen**,
141
+ which is not the repository name — four 404s on the PyPI sidebar.
142
+ - **Neural admixture is always given a batch size** (400). Left unset it batches
143
+ the entire dataset at once; that is a bug in the tool, and the workaround was
144
+ previously applied only in `subsample` mode, leaving the All of Us projection
145
+ example — the one running on the largest cohort — without it.
146
+ - **`validate_sample_id_overlap` now enforces a minimum overlap** (50% by
147
+ default) instead of raising only at zero. Near-total mismatch between a label
148
+ file and a genotype set previously passed silently, which is how one example's
149
+ figures came to colour 40% of their points from a superseded sample selection.
150
+ - Example label files are regenerated when they no longer match their `.fam`,
151
+ rather than being kept because they exist.
152
+ - **The source distribution contained untracked working files.** hatchling's
153
+ default is to include everything not gitignored, which is not the same as
154
+ everything tracked; a pre-release sdist carried local tool state and an
155
+ example script whose header says "NOT for external users". Its contents are now
156
+ declared explicitly and checked by a test.
157
+
158
+ ### Removed
159
+
160
+ - `examples/_shared/run_pipeline.sh`, `examples/_shared/detect_cluster.sh` and
161
+ the nine per-example `run_pipeline.sh` wrappers, superseded by config files.
162
+
163
+ [Unreleased]: https://github.com/MattScicluna/manifold_genetics/compare/v0.2.0...HEAD
164
+ [0.2.0]: https://github.com/MattScicluna/manifold_genetics/releases/tag/v0.2.0
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, Matthew Scicluna
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.