anndata 0.12.5__tar.gz → 0.12.6__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 (213) hide show
  1. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/test-gpu.yml +2 -1
  2. {anndata-0.12.5 → anndata-0.12.6}/PKG-INFO +6 -5
  3. anndata-0.12.6/ci/min-constraints.txt +1 -0
  4. {anndata-0.12.5 → anndata-0.12.6}/docs/conf.py +1 -0
  5. anndata-0.12.6/docs/release-notes/0.12.6.md +6 -0
  6. {anndata-0.12.5 → anndata-0.12.6}/hatch.toml +5 -2
  7. {anndata-0.12.5 → anndata-0.12.6}/pyproject.toml +3 -2
  8. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/anndata.py +6 -2
  9. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/file_backing.py +21 -12
  10. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/backed/_io.py +13 -7
  11. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/tests/helpers.py +50 -34
  12. {anndata-0.12.5 → anndata-0.12.6}/tests/lazy/test_read.py +11 -1
  13. {anndata-0.12.5 → anndata-0.12.6}/tests/test_dask.py +3 -3
  14. {anndata-0.12.5 → anndata-0.12.6}/tests/test_settings.py +6 -5
  15. {anndata-0.12.5 → anndata-0.12.6}/.cirun.yml +0 -0
  16. {anndata-0.12.5 → anndata-0.12.6}/.codecov.yml +0 -0
  17. {anndata-0.12.5 → anndata-0.12.6}/.editorconfig +0 -0
  18. {anndata-0.12.5 → anndata-0.12.6}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  19. {anndata-0.12.5 → anndata-0.12.6}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {anndata-0.12.5 → anndata-0.12.6}/.github/ISSUE_TEMPLATE/enhancement-request.yml +0 -0
  21. {anndata-0.12.5 → anndata-0.12.6}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  22. {anndata-0.12.5 → anndata-0.12.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  23. {anndata-0.12.5 → anndata-0.12.6}/.github/dependabot.yml +0 -0
  24. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/benchmark.yml +0 -0
  25. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/check-pr.yml +0 -0
  26. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/close-stale.yml +0 -0
  27. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/codespell.yml +0 -0
  28. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/label-stale.yml +0 -0
  29. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/publish.yml +0 -0
  30. {anndata-0.12.5 → anndata-0.12.6}/.github/workflows/test-cpu.yml +0 -0
  31. {anndata-0.12.5 → anndata-0.12.6}/.gitignore +0 -0
  32. {anndata-0.12.5 → anndata-0.12.6}/.gitmodules +0 -0
  33. {anndata-0.12.5 → anndata-0.12.6}/.pre-commit-config.yaml +0 -0
  34. {anndata-0.12.5 → anndata-0.12.6}/.prettierignore +0 -0
  35. {anndata-0.12.5 → anndata-0.12.6}/.prettierrc.yaml +0 -0
  36. {anndata-0.12.5 → anndata-0.12.6}/.readthedocs.yml +0 -0
  37. {anndata-0.12.5 → anndata-0.12.6}/.taplo.toml +0 -0
  38. {anndata-0.12.5 → anndata-0.12.6}/.vscode/launch.json +0 -0
  39. {anndata-0.12.5 → anndata-0.12.6}/.vscode/settings.json +0 -0
  40. {anndata-0.12.5 → anndata-0.12.6}/LICENSE +0 -0
  41. {anndata-0.12.5 → anndata-0.12.6}/README.md +0 -0
  42. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/README.md +0 -0
  43. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/asv.conf.json +0 -0
  44. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/benchmarks/__init__.py +0 -0
  45. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/benchmarks/anndata.py +0 -0
  46. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/benchmarks/backed_hdf5.py +0 -0
  47. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/benchmarks/dataset2d.py +0 -0
  48. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/benchmarks/readwrite.py +0 -0
  49. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/benchmarks/sparse_dataset.py +0 -0
  50. {anndata-0.12.5 → anndata-0.12.6}/benchmarks/benchmarks/utils.py +0 -0
  51. {anndata-0.12.5 → anndata-0.12.6}/biome.jsonc +0 -0
  52. {anndata-0.12.5 → anndata-0.12.6}/ci/constraints.txt +0 -0
  53. {anndata-0.12.5 → anndata-0.12.6}/ci/scripts/min-deps.py +0 -0
  54. {anndata-0.12.5 → anndata-0.12.6}/ci/scripts/towncrier_automation.py +0 -0
  55. {anndata-0.12.5 → anndata-0.12.6}/docs/Makefile +0 -0
  56. {anndata-0.12.5 → anndata-0.12.6}/docs/_key_contributors.rst +0 -0
  57. {anndata-0.12.5 → anndata-0.12.6}/docs/_static/img/anndata_schema.svg +0 -0
  58. {anndata-0.12.5 → anndata-0.12.6}/docs/_templates/autosummary/class.rst +0 -0
  59. {anndata-0.12.5 → anndata-0.12.6}/docs/api.md +0 -0
  60. {anndata-0.12.5 → anndata-0.12.6}/docs/benchmark-read-write.ipynb +0 -0
  61. {anndata-0.12.5 → anndata-0.12.6}/docs/benchmarks.md +0 -0
  62. {anndata-0.12.5 → anndata-0.12.6}/docs/concatenation.rst +0 -0
  63. {anndata-0.12.5 → anndata-0.12.6}/docs/contributing.md +0 -0
  64. {anndata-0.12.5 → anndata-0.12.6}/docs/extensions/autosummary_skip_inherited.py +0 -0
  65. {anndata-0.12.5 → anndata-0.12.6}/docs/extensions/no_skip_abc_members.py +0 -0
  66. {anndata-0.12.5 → anndata-0.12.6}/docs/extensions/patch_myst_cite.py +0 -0
  67. {anndata-0.12.5 → anndata-0.12.6}/docs/fileformat-prose.md +0 -0
  68. {anndata-0.12.5 → anndata-0.12.6}/docs/index.md +0 -0
  69. {anndata-0.12.5 → anndata-0.12.6}/docs/interoperability.md +0 -0
  70. {anndata-0.12.5 → anndata-0.12.6}/docs/news.md +0 -0
  71. {anndata-0.12.5 → anndata-0.12.6}/docs/references.rst +0 -0
  72. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.0.md +0 -0
  73. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.1.md +0 -0
  74. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.2.md +0 -0
  75. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.3.md +0 -0
  76. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.4.md +0 -0
  77. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.5.md +0 -0
  78. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.6.md +0 -0
  79. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.7.md +0 -0
  80. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.8.md +0 -0
  81. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.10.9.md +0 -0
  82. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.11.0.md +0 -0
  83. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.11.1.md +0 -0
  84. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.11.2.md +0 -0
  85. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.11.3.md +0 -0
  86. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.11.4.md +0 -0
  87. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.12.0.md +0 -0
  88. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.12.1.md +0 -0
  89. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.12.2.md +0 -0
  90. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.12.3.md +0 -0
  91. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.12.4.md +0 -0
  92. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.12.5.md +0 -0
  93. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.4.0.md +0 -0
  94. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.5.0.md +0 -0
  95. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.6.0.md +0 -0
  96. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.6.x.md +0 -0
  97. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.0.md +0 -0
  98. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.2.md +0 -0
  99. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.3.md +0 -0
  100. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.4.md +0 -0
  101. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.5.md +0 -0
  102. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.6.md +0 -0
  103. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.7.md +0 -0
  104. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.7.8.md +0 -0
  105. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.8.0.md +0 -0
  106. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.9.0.md +0 -0
  107. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.9.1.md +0 -0
  108. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/0.9.2.md +0 -0
  109. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/2172.bug.md +0 -0
  110. {anndata-0.12.5 → anndata-0.12.6}/docs/release-notes/index.md +0 -0
  111. {anndata-0.12.5 → anndata-0.12.6}/docs/tutorials/index.md +0 -0
  112. {anndata-0.12.5 → anndata-0.12.6}/docs/tutorials/zarr-v3.md +0 -0
  113. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/__init__.py +0 -0
  114. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/__init__.py +0 -0
  115. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/access.py +0 -0
  116. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/aligned_df.py +0 -0
  117. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/aligned_mapping.py +0 -0
  118. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/extensions.py +0 -0
  119. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/index.py +0 -0
  120. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/merge.py +0 -0
  121. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/raw.py +0 -0
  122. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/sparse_dataset.py +0 -0
  123. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/storage.py +0 -0
  124. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/views.py +0 -0
  125. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_core/xarray.py +0 -0
  126. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/__init__.py +0 -0
  127. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/h5ad.py +0 -0
  128. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/read.py +0 -0
  129. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/specs/__init__.py +0 -0
  130. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/specs/lazy_methods.py +0 -0
  131. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/specs/methods.py +0 -0
  132. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/specs/registry.py +0 -0
  133. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/utils.py +0 -0
  134. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/write.py +0 -0
  135. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_io/zarr.py +0 -0
  136. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_settings.py +0 -0
  137. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_settings.pyi +0 -0
  138. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_types.py +0 -0
  139. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/_warnings.py +0 -0
  140. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/abc.py +0 -0
  141. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/compat/__init__.py +0 -0
  142. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/__init__.py +0 -0
  143. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/_dispatch_io.py +0 -0
  144. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/backed/__init__.py +0 -0
  145. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/backed/_compat.py +0 -0
  146. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/backed/_lazy_arrays.py +0 -0
  147. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/merge.py +0 -0
  148. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/multi_files/__init__.py +0 -0
  149. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/multi_files/_anncollection.py +0 -0
  150. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/pytorch/__init__.py +0 -0
  151. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/experimental/pytorch/_annloader.py +0 -0
  152. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/io.py +0 -0
  153. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/logging.py +0 -0
  154. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/tests/__init__.py +0 -0
  155. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/types.py +0 -0
  156. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/typing.py +0 -0
  157. {anndata-0.12.5 → anndata-0.12.6}/src/anndata/utils.py +0 -0
  158. {anndata-0.12.5 → anndata-0.12.6}/src/testing/anndata/__init__.py +0 -0
  159. {anndata-0.12.5 → anndata-0.12.6}/src/testing/anndata/_doctest.py +0 -0
  160. {anndata-0.12.5 → anndata-0.12.6}/src/testing/anndata/_pytest.py +0 -0
  161. {anndata-0.12.5 → anndata-0.12.6}/src/testing/anndata/py.typed +0 -0
  162. {anndata-0.12.5 → anndata-0.12.6}/tests/conftest.py +0 -0
  163. {anndata-0.12.5 → anndata-0.12.6}/tests/data/adata-comments.tsv +0 -0
  164. {anndata-0.12.5 → anndata-0.12.6}/tests/data/adata.csv +0 -0
  165. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/readme.md +0 -0
  166. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/v0.11.4/adata.h5ad +0 -0
  167. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/v0.11.4/adata.zarr.zip +0 -0
  168. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/v0.11.4/readme.md +0 -0
  169. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/v0.7.0/adata.h5ad +0 -0
  170. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/v0.7.0/adata.zarr.zip +0 -0
  171. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/v0.7.8/adata.h5ad +0 -0
  172. {anndata-0.12.5 → anndata-0.12.6}/tests/data/archives/v0.7.8/adata.zarr.zip +0 -0
  173. {anndata-0.12.5 → anndata-0.12.6}/tests/data/excel.xlsx +0 -0
  174. {anndata-0.12.5 → anndata-0.12.6}/tests/data/umi_tools.tsv.gz +0 -0
  175. {anndata-0.12.5 → anndata-0.12.6}/tests/lazy/conftest.py +0 -0
  176. {anndata-0.12.5 → anndata-0.12.6}/tests/lazy/test_concat.py +0 -0
  177. {anndata-0.12.5 → anndata-0.12.6}/tests/lazy/test_write.py +0 -0
  178. {anndata-0.12.5 → anndata-0.12.6}/tests/test_anncollection.py +0 -0
  179. {anndata-0.12.5 → anndata-0.12.6}/tests/test_annot.py +0 -0
  180. {anndata-0.12.5 → anndata-0.12.6}/tests/test_awkward.py +0 -0
  181. {anndata-0.12.5 → anndata-0.12.6}/tests/test_backed_dense.py +0 -0
  182. {anndata-0.12.5 → anndata-0.12.6}/tests/test_backed_hdf5.py +0 -0
  183. {anndata-0.12.5 → anndata-0.12.6}/tests/test_backed_sparse.py +0 -0
  184. {anndata-0.12.5 → anndata-0.12.6}/tests/test_base.py +0 -0
  185. {anndata-0.12.5 → anndata-0.12.6}/tests/test_concatenate.py +0 -0
  186. {anndata-0.12.5 → anndata-0.12.6}/tests/test_concatenate_disk.py +0 -0
  187. {anndata-0.12.5 → anndata-0.12.6}/tests/test_dask_view_mem.py +0 -0
  188. {anndata-0.12.5 → anndata-0.12.6}/tests/test_deprecations.py +0 -0
  189. {anndata-0.12.5 → anndata-0.12.6}/tests/test_extensions.py +0 -0
  190. {anndata-0.12.5 → anndata-0.12.6}/tests/test_get_vector.py +0 -0
  191. {anndata-0.12.5 → anndata-0.12.6}/tests/test_gpu.py +0 -0
  192. {anndata-0.12.5 → anndata-0.12.6}/tests/test_helpers.py +0 -0
  193. {anndata-0.12.5 → anndata-0.12.6}/tests/test_inplace_subset.py +0 -0
  194. {anndata-0.12.5 → anndata-0.12.6}/tests/test_io_backwards_compat.py +0 -0
  195. {anndata-0.12.5 → anndata-0.12.6}/tests/test_io_conversion.py +0 -0
  196. {anndata-0.12.5 → anndata-0.12.6}/tests/test_io_dispatched.py +0 -0
  197. {anndata-0.12.5 → anndata-0.12.6}/tests/test_io_elementwise.py +0 -0
  198. {anndata-0.12.5 → anndata-0.12.6}/tests/test_io_partial.py +0 -0
  199. {anndata-0.12.5 → anndata-0.12.6}/tests/test_io_utils.py +0 -0
  200. {anndata-0.12.5 → anndata-0.12.6}/tests/test_io_warnings.py +0 -0
  201. {anndata-0.12.5 → anndata-0.12.6}/tests/test_layers.py +0 -0
  202. {anndata-0.12.5 → anndata-0.12.6}/tests/test_obsmvarm.py +0 -0
  203. {anndata-0.12.5 → anndata-0.12.6}/tests/test_obspvarp.py +0 -0
  204. {anndata-0.12.5 → anndata-0.12.6}/tests/test_raw.py +0 -0
  205. {anndata-0.12.5 → anndata-0.12.6}/tests/test_readwrite.py +0 -0
  206. {anndata-0.12.5 → anndata-0.12.6}/tests/test_repr.py +0 -0
  207. {anndata-0.12.5 → anndata-0.12.6}/tests/test_structured_arrays.py +0 -0
  208. {anndata-0.12.5 → anndata-0.12.6}/tests/test_transpose.py +0 -0
  209. {anndata-0.12.5 → anndata-0.12.6}/tests/test_uns.py +0 -0
  210. {anndata-0.12.5 → anndata-0.12.6}/tests/test_utils.py +0 -0
  211. {anndata-0.12.5 → anndata-0.12.6}/tests/test_views.py +0 -0
  212. {anndata-0.12.5 → anndata-0.12.6}/tests/test_x.py +0 -0
  213. {anndata-0.12.5 → anndata-0.12.6}/tests/test_xarray.py +0 -0
@@ -66,7 +66,8 @@ jobs:
66
66
  uses: astral-sh/setup-uv@v6 # TODO: upgrade once cirun image supports node 24
67
67
  with:
68
68
  enable-cache: true
69
- python-version: ${{ env.max_python_version }}
69
+ # Any Cuda 14+ will support Python 3.14: https://github.com/cupy/cupy/issues/9346
70
+ python-version: '3.13' # ${{ env.max_python_version }}
70
71
 
71
72
  - name: Install AnnData
72
73
  run: |
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anndata
3
- Version: 0.12.5
3
+ Version: 0.12.6
4
4
  Summary: Annotated data.
5
5
  Project-URL: Documentation, https://anndata.readthedocs.io/
6
6
  Project-URL: Source, https://github.com/scverse/anndata
7
7
  Project-URL: Home-page, https://github.com/scverse/anndata
8
- Author: Philipp Angerer, Alex Wolf, Isaac Virshup, Sergei Rybakov
9
- Maintainer-email: Isaac Virshup <ivirshup@gmail.com>, Philipp Angerer <philipp.angerer@helmholtz-munich.de>, Ilan Gold <ilan.gold@helmholtz-munich.de>
8
+ Author: Philipp Angerer, Alex Wolf, Isaac Virshup, Sergei Rybakov, Ilan Gold
9
+ Maintainer-email: Philipp Angerer <philipp.angerer@helmholtz-munich.de>, Ilan Gold <ilan.gold@helmholtz-munich.de>
10
10
  License-Expression: BSD-3-Clause
11
11
  License-File: LICENSE
12
12
  Classifier: Environment :: Console
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3
21
21
  Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
24
25
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
25
26
  Classifier: Topic :: Scientific/Engineering :: Visualization
26
27
  Requires-Python: >=3.11
@@ -78,7 +79,7 @@ Requires-Dist: joblib; extra == 'test'
78
79
  Requires-Dist: loompy>=3.0.5; extra == 'test'
79
80
  Requires-Dist: matplotlib; extra == 'test'
80
81
  Requires-Dist: openpyxl; extra == 'test'
81
- Requires-Dist: pyarrow<21; extra == 'test'
82
+ Requires-Dist: pyarrow; extra == 'test'
82
83
  Requires-Dist: pytest-cov; extra == 'test'
83
84
  Requires-Dist: pytest-memray; extra == 'test'
84
85
  Requires-Dist: pytest-mock; extra == 'test'
@@ -100,7 +101,7 @@ Requires-Dist: joblib; extra == 'test-min'
100
101
  Requires-Dist: loompy>=3.0.5; extra == 'test-min'
101
102
  Requires-Dist: matplotlib; extra == 'test-min'
102
103
  Requires-Dist: openpyxl; extra == 'test-min'
103
- Requires-Dist: pyarrow<21; extra == 'test-min'
104
+ Requires-Dist: pyarrow; extra == 'test-min'
104
105
  Requires-Dist: pytest-cov; extra == 'test-min'
105
106
  Requires-Dist: pytest-memray; extra == 'test-min'
106
107
  Requires-Dist: pytest-mock; extra == 'test-min'
@@ -0,0 +1 @@
1
+ pyarrow<21
@@ -134,6 +134,7 @@ intersphinx_mapping = dict(
134
134
  obstore=("https://developmentseed.org/obstore/latest/", None),
135
135
  pandas=("https://pandas.pydata.org/pandas-docs/stable", None),
136
136
  # TODO: switch to `/3` once docs are built with Python 3.14
137
+ # https://github.com/readthedocs/readthedocs.org/issues/12523
137
138
  python=("https://docs.python.org/3.13", None),
138
139
  scipy=("https://docs.scipy.org/doc/scipy", None),
139
140
  sklearn=("https://scikit-learn.org/stable", None),
@@ -0,0 +1,6 @@
1
+ (v0.12.6)=
2
+ ### 0.12.6 {small}`2025-11-06`
3
+
4
+ #### Bug fixes
5
+
6
+ - Attach {class}`h5py.File` object to {class}`~anndata.AnnData` at the `file` attribute returned from {func}`~anndata.experimental.read_lazy` {user}`ilan-gold` ({pr}`2204`)
@@ -21,7 +21,7 @@ env-vars.UV_CONSTRAINT = "ci/constraints.txt"
21
21
  overrides.matrix.deps.env-vars = [
22
22
  { if = [ "pre" ], key = "UV_PRERELEASE", value = "allow" },
23
23
  { if = [ "pre" ], key = "UV_CONSTRAINT", value = "ci/pre-deps.txt" },
24
- { if = [ "min" ], key = "UV_CONSTRAINT", value = "ci/constraints.txt ci/min-deps.txt" },
24
+ { if = [ "min" ], key = "UV_CONSTRAINT", value = "ci/constraints.txt ci/min-constraints.txt ci/min-deps.txt" },
25
25
  ]
26
26
  overrides.matrix.deps.pre-install-commands = [
27
27
  { if = [
@@ -35,7 +35,10 @@ overrides.matrix.deps.pre-install-commands = [
35
35
  ]
36
36
  overrides.matrix.deps.python = [
37
37
  { if = [ "min" ], value = "3.11" },
38
- { if = [ "stable", "pre" ], value = "3.13" },
38
+ # transitive test dep numba doesn’t support 3.14 in a stable release yet:
39
+ # https://github.com/numba/numba/issues/9957
40
+ { if = [ "stable" ], value = "3.13" },
41
+ { if = [ "pre" ], value = "3.14" },
39
42
  ]
40
43
  overrides.matrix.deps.features = [
41
44
  { if = [ "stable", "pre" ], value = "test" },
@@ -12,9 +12,9 @@ authors = [
12
12
  { name = "Alex Wolf" },
13
13
  { name = "Isaac Virshup" },
14
14
  { name = "Sergei Rybakov" },
15
+ { name = "Ilan Gold" },
15
16
  ]
16
17
  maintainers = [
17
- { name = "Isaac Virshup", email = "ivirshup@gmail.com" },
18
18
  { name = "Philipp Angerer", email = "philipp.angerer@helmholtz-munich.de" },
19
19
  { name = "Ilan Gold", email = "ilan.gold@helmholtz-munich.de" },
20
20
  ]
@@ -32,6 +32,7 @@ classifiers = [
32
32
  "Programming Language :: Python :: 3.11",
33
33
  "Programming Language :: Python :: 3.12",
34
34
  "Programming Language :: Python :: 3.13",
35
+ "Programming Language :: Python :: 3.14",
35
36
  "Topic :: Scientific/Engineering :: Bio-Informatics",
36
37
  "Topic :: Scientific/Engineering :: Visualization",
37
38
  ]
@@ -96,7 +97,7 @@ test-min = [
96
97
  "httpx<1.0", # For data downloading
97
98
  "dask[distributed]",
98
99
  "awkward>=2.3.2",
99
- "pyarrow<21", # https://github.com/scikit-hep/awkward/issues/3579
100
+ "pyarrow",
100
101
  "anndata[dask]",
101
102
  ]
102
103
  test = [ "anndata[test-min,lazy]" ]
@@ -964,7 +964,11 @@ class AnnData(metaclass=utils.DeprecationMixinMeta): # noqa: PLW1641
964
964
  @property
965
965
  def isbacked(self) -> bool:
966
966
  """`True` if object is backed on disk, `False` otherwise."""
967
- return self.filename is not None
967
+ is_filename_none = self.filename is not None
968
+ is_x_none = (
969
+ getattr(self._adata_ref if self._is_view else self, "_X", None) is None
970
+ )
971
+ return is_filename_none and is_x_none
968
972
 
969
973
  @property
970
974
  def is_view(self) -> bool:
@@ -1418,7 +1422,7 @@ class AnnData(metaclass=utils.DeprecationMixinMeta): # noqa: PLW1641
1418
1422
 
1419
1423
  @old_positionals("copy")
1420
1424
  def to_memory(self, *, copy: bool = False) -> AnnData:
1421
- """Return a new AnnData object with all backed arrays loaded into memory.
1425
+ """Return a new AnnData object with all non-in-memory arrays loaded into memory.
1422
1426
 
1423
1427
  Params
1424
1428
  ------
@@ -27,15 +27,24 @@ class AnnDataFileManager:
27
27
  def __init__(
28
28
  self,
29
29
  adata: anndata.AnnData,
30
- filename: PathLike[str] | str | None = None,
31
- filemode: Literal["r", "r+"] | None = None,
30
+ file_name: PathLike[str] | str | None = None,
31
+ file_mode: Literal["r", "r+"] | None = None,
32
+ file_obj: h5py.File | None = None,
32
33
  ):
34
+ if file_obj is not None and (file_name is not None or file_mode is not None):
35
+ msg = "Cannot provide both a h5py.File and the name and/or mode arguments to constructor"
36
+ raise ValueError(msg)
33
37
  self._adata_ref = weakref.ref(adata)
34
- self.filename = filename
35
- self._filemode = filemode
36
- self._file = None
37
- if filename:
38
- self.open()
38
+ if file_obj is not None:
39
+ self.filename = filename(file_obj)
40
+ self._filemode = file_obj.mode
41
+ self._file = file_obj
42
+ else:
43
+ self.filename = file_name
44
+ self._filemode = file_mode
45
+ self._file = file_obj
46
+ if file_name and not self._file:
47
+ self.open()
39
48
 
40
49
  def __getstate__(self):
41
50
  state = self.__dict__.copy()
@@ -82,16 +91,16 @@ class AnnDataFileManager:
82
91
  return self._filename
83
92
 
84
93
  @filename.setter
85
- def filename(self, filename: PathLike[str] | str | None):
86
- self._filename = None if filename is None else Path(filename)
94
+ def filename(self, file_name: PathLike[str] | str | None):
95
+ self._filename = None if file_name is None else Path(file_name)
87
96
 
88
97
  def open(
89
98
  self,
90
- filename: PathLike[str] | str | None = None,
99
+ file_name: PathLike[str] | str | None = None,
91
100
  filemode: Literal["r", "r+"] | None = None,
92
101
  ):
93
- if filename is not None:
94
- self.filename = filename
102
+ if file_name is not None:
103
+ self.filename = file_name
95
104
  if filemode is not None:
96
105
  self._filemode = filemode
97
106
  if self.filename is None:
@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING
8
8
 
9
9
  import h5py
10
10
 
11
+ from anndata._core.file_backing import AnnDataFileManager
11
12
  from anndata._io.specs.registry import read_elem_lazy
12
13
  from anndata._types import AnnDataElem
13
14
  from testing.anndata._doctest import doctest_needs
@@ -28,7 +29,7 @@ if TYPE_CHECKING:
28
29
  @doctest_needs("xarray")
29
30
  @requires_xarray
30
31
  def read_lazy(
31
- store: PathLike[str] | str | MutableMapping | ZarrGroup | h5py.Dataset,
32
+ store: PathLike[str] | str | MutableMapping | ZarrGroup | h5py.File | h5py.Group,
32
33
  *,
33
34
  load_annotation_index: bool = True,
34
35
  ) -> AnnData:
@@ -40,6 +41,9 @@ def read_lazy(
40
41
  ----------
41
42
  store
42
43
  A store-like object to be read in. If :class:`zarr.Group`, it is best for it to be consolidated.
44
+ If a path to an ``.h5ad`` file is provided, the open HDF5 file will be attached to the {class}`~anndata.AnnData` at the `file` attribute and it will be the user’s responsibility to close it when done with the returned object.
45
+ For this reason, it is recommended to use an {class}`h5py.File` as the `store` argument when working with h5 files.
46
+ It must remain open for at least as long as this returned object is in use.
43
47
  load_annotation_index
44
48
  Whether or not to use a range index for the `{obs,var}` :class:`xarray.Dataset` so as not to load the index into memory.
45
49
  If `False`, the real `index` will be inserted as `{obs,var}_names` in the object but not be one of the `coords` thereby preventing read operations.
@@ -83,10 +87,11 @@ def read_lazy(
83
87
  AnnData object with n_obs × n_vars = 490 × 33452
84
88
  obs: 'donor_id', 'self_reported_ethnicity_ontology_term_id', 'organism_ontology_term_id'...
85
89
  """
86
- is_h5_store = isinstance(store, h5py.Dataset | h5py.File | h5py.Group)
87
- is_h5 = (
90
+ is_store_arg_h5_store = isinstance(store, h5py.Dataset | h5py.File | h5py.Group)
91
+ is_store_arg_h5_path = (
88
92
  isinstance(store, PathLike | str) and Path(store).suffix == ".h5ad"
89
- ) or is_h5_store
93
+ )
94
+ is_h5 = is_store_arg_h5_path or is_store_arg_h5_store
90
95
 
91
96
  has_keys = True # true if consolidated or h5ad
92
97
  if not is_h5:
@@ -104,7 +109,7 @@ def read_lazy(
104
109
  f = zarr.open_group(store, mode="r")
105
110
  else:
106
111
  f = store
107
- elif is_h5_store:
112
+ elif is_store_arg_h5_store:
108
113
  f = store
109
114
  else:
110
115
  f = h5py.File(store, mode="r")
@@ -151,6 +156,7 @@ def read_lazy(
151
156
  return func(elem)
152
157
 
153
158
  with settings.override(check_uniqueness=load_annotation_index):
154
- adata = read_dispatched(f, callback=callback)
155
-
159
+ adata: AnnData = read_dispatched(f, callback=callback)
160
+ if is_store_arg_h5_path and not is_store_arg_h5_store:
161
+ adata.file = AnnDataFileManager(adata, file_obj=f)
156
162
  return adata
@@ -630,8 +630,9 @@ def assert_equal_arrayview(
630
630
 
631
631
  @assert_equal.register(BaseCompressedSparseDataset)
632
632
  @assert_equal.register(sparse.spmatrix)
633
+ @assert_equal.register(CSArray)
633
634
  def assert_equal_sparse(
634
- a: BaseCompressedSparseDataset | sparse.spmatrix,
635
+ a: BaseCompressedSparseDataset | sparse.spmatrix | CSArray,
635
636
  b: object,
636
637
  *,
637
638
  exact: bool = False,
@@ -641,13 +642,6 @@ def assert_equal_sparse(
641
642
  assert_equal(b, a, exact=exact, elem_name=elem_name)
642
643
 
643
644
 
644
- @assert_equal.register(CSArray)
645
- def assert_equal_sparse_array(
646
- a: CSArray, b: object, *, exact: bool = False, elem_name: str | None = None
647
- ):
648
- return assert_equal_sparse(a, b, exact=exact, elem_name=elem_name)
649
-
650
-
651
645
  @assert_equal.register(CupySparseMatrix)
652
646
  def assert_equal_cupy_sparse(
653
647
  a: CupySparseMatrix, b: object, *, exact: bool = False, elem_name: str | None = None
@@ -880,29 +874,53 @@ def _(a):
880
874
 
881
875
 
882
876
  @singledispatch
883
- def as_sparse_dask_array(a) -> DaskArray:
884
- import dask.array as da
885
-
886
- return da.from_array(sparse.csr_matrix(a), chunks=_half_chunk_size(a.shape))
877
+ def _as_sparse_dask(
878
+ a: NDArray | CSArray | CSMatrix | DaskArray,
879
+ *,
880
+ typ: type[CSArray | CSMatrix | CupyCSRMatrix],
881
+ chunks: tuple[int, ...] | None = None,
882
+ ) -> DaskArray:
883
+ """Convert a to a sparse dask array, preserving sparse format and container (`cs{rc}_{array,matrix}`)."""
884
+ raise NotImplementedError
887
885
 
888
886
 
889
- @as_sparse_dask_array.register(CSMatrix)
890
- def _(a):
887
+ @_as_sparse_dask.register(CSArray | CSMatrix | np.ndarray)
888
+ def _(
889
+ a: CSArray | CSMatrix | NDArray,
890
+ *,
891
+ typ: type[CSArray | CSMatrix | CupyCSRMatrix],
892
+ chunks: tuple[int, ...] | None = None,
893
+ ) -> DaskArray:
891
894
  import dask.array as da
892
895
 
893
- return da.from_array(a, _half_chunk_size(a.shape))
896
+ chunks = _half_chunk_size(a.shape) if chunks is None else chunks
897
+ return da.from_array(_as_sparse_dask_inner(a, typ=typ), chunks=chunks)
894
898
 
895
899
 
896
- @as_sparse_dask_array.register(CSArray)
897
- def _(a):
898
- import dask.array as da
900
+ @_as_sparse_dask.register(DaskArray)
901
+ def _(
902
+ a: DaskArray,
903
+ *,
904
+ typ: type[CSArray | CSMatrix | CupyCSRMatrix],
905
+ chunks: tuple[int, ...] | None = None,
906
+ ) -> DaskArray:
907
+ assert chunks is None # TODO: if needed we can add a .rechunk(chunks)
908
+ return a.map_blocks(_as_sparse_dask_inner, typ=typ, dtype=a.dtype, meta=typ((2, 2)))
899
909
 
900
- return da.from_array(sparse.csr_matrix(a), _half_chunk_size(a.shape))
901
910
 
911
+ def _as_sparse_dask_inner(
912
+ a: NDArray | CSArray | CSMatrix, *, typ: type[CSArray | CSMatrix | CupyCSRMatrix]
913
+ ) -> CSArray | CSMatrix:
914
+ """Convert into a a sparse container that dask supports (or complain)."""
915
+ if issubclass(typ, CSArray): # convert sparray to spmatrix
916
+ msg = "AnnData doesn't support `cs_{r,c}_array` inside Dask"
917
+ raise TypeError(msg)
918
+ if issubclass(typ, CupySparseMatrix):
919
+ a = as_cupy(a) # can’t Cupy sparse constructors don’t accept numpy ndarrays
920
+ return typ(a)
902
921
 
903
- @as_sparse_dask_array.register(DaskArray)
904
- def _(a):
905
- return a.map_blocks(sparse.csr_matrix)
922
+
923
+ as_sparse_dask_matrix = partial(_as_sparse_dask, typ=sparse.csr_matrix)
906
924
 
907
925
 
908
926
  @singledispatch
@@ -947,14 +965,11 @@ except ImportError:
947
965
  format_to_memory_class = {}
948
966
 
949
967
 
950
- # TODO: If there are chunks which divide along columns, then a coo_matrix is returned by compute
951
- # We should try and fix this upstream in dask/ cupy
952
968
  @singledispatch
953
- def as_cupy_sparse_dask_array(a, format="csr"):
954
- memory_class = format_to_memory_class[format]
955
- cpu_da = as_sparse_dask_array(a)
956
- return cpu_da.rechunk((cpu_da.chunks[0], -1)).map_blocks(
957
- memory_class, dtype=a.dtype, meta=memory_class(cpu_da._meta)
969
+ def as_cupy_sparse_dask_array(a, format="csr") -> DaskArray:
970
+ chunk_rows, _ = _half_chunk_size(a.shape)
971
+ return _as_sparse_dask(
972
+ a, typ=format_to_memory_class[format], chunks=(chunk_rows, -1)
958
973
  )
959
974
 
960
975
 
@@ -964,7 +979,8 @@ def _(a, format="csr"):
964
979
  import dask.array as da
965
980
 
966
981
  memory_class = format_to_memory_class[format]
967
- return da.from_array(memory_class(a), chunks=(_half_chunk_size(a.shape)[0], -1))
982
+ chunk_rows, _ = _half_chunk_size(a.shape)
983
+ return da.from_array(memory_class(a), chunks=(chunk_rows, -1))
968
984
 
969
985
 
970
986
  @as_cupy_sparse_dask_array.register(DaskArray)
@@ -982,9 +998,9 @@ def resolve_cupy_type(val):
982
998
 
983
999
  if issubclass(input_typ, np.ndarray):
984
1000
  typ = CupyArray
985
- elif issubclass(input_typ, sparse.csr_matrix):
1001
+ elif issubclass(input_typ, sparse.csr_matrix | sparse.csr_array):
986
1002
  typ = CupyCSRMatrix
987
- elif issubclass(input_typ, sparse.csc_matrix):
1003
+ elif issubclass(input_typ, sparse.csc_matrix | sparse.csc_array):
988
1004
  typ = CupyCSCMatrix
989
1005
  else:
990
1006
  msg = f"No default target type for input type {input_typ}"
@@ -1005,7 +1021,7 @@ def as_cupy(val, typ=None):
1005
1021
  if issubclass(typ, CupyArray):
1006
1022
  import cupy as cp
1007
1023
 
1008
- if isinstance(val, CSMatrix):
1024
+ if isinstance(val, CSMatrix | CSArray):
1009
1025
  val = val.toarray()
1010
1026
  return cp.array(val)
1011
1027
  elif issubclass(typ, CupyCSRMatrix):
@@ -1061,7 +1077,7 @@ BASE_MATRIX_PARAMS = [
1061
1077
 
1062
1078
  DASK_MATRIX_PARAMS = [
1063
1079
  pytest.param(as_dense_dask_array, id="dense_dask_array"),
1064
- pytest.param(as_sparse_dask_array, id="sparse_dask_array"),
1080
+ pytest.param(as_sparse_dask_matrix, id="sparse_dask_matrix"),
1065
1081
  ]
1066
1082
 
1067
1083
  CUPY_MATRIX_PARAMS = [
@@ -175,7 +175,7 @@ def test_view_of_view_to_memory(adata_remote: AnnData, adata_orig: AnnData):
175
175
 
176
176
  @pytest.mark.zarr_io
177
177
  def test_unconsolidated(tmp_path: Path, mtx_format):
178
- adata = gen_adata((1000, 1000), mtx_format, **GEN_ADATA_NO_XARRAY_ARGS)
178
+ adata = gen_adata((10, 10), mtx_format, **GEN_ADATA_NO_XARRAY_ARGS)
179
179
  orig_pth = tmp_path / "orig.zarr"
180
180
  adata.write_zarr(orig_pth)
181
181
  (orig_pth / ".zmetadata").unlink()
@@ -188,6 +188,16 @@ def test_unconsolidated(tmp_path: Path, mtx_format):
188
188
  store.assert_access_count("obs/.zgroup", 1)
189
189
 
190
190
 
191
+ def test_h5_file_obj(tmp_path: Path):
192
+ adata = gen_adata((10, 10), **GEN_ADATA_NO_XARRAY_ARGS)
193
+ orig_pth = tmp_path / "adata.h5ad"
194
+ adata.write_h5ad(orig_pth)
195
+ remote = read_lazy(orig_pth)
196
+ assert remote.file.is_open
197
+ assert remote.filename == orig_pth
198
+ assert_equal(remote.to_memory(), adata)
199
+
200
+
191
201
  @pytest.fixture(scope="session")
192
202
  def df_group(tmp_path_factory) -> zarr.Group:
193
203
  df = gen_typed_df(120)
@@ -21,7 +21,7 @@ from anndata.tests.helpers import (
21
21
  as_cupy_sparse_dask_array,
22
22
  as_dense_cupy_dask_array,
23
23
  as_dense_dask_array,
24
- as_sparse_dask_array,
24
+ as_sparse_dask_matrix,
25
25
  assert_equal,
26
26
  check_all_sharded,
27
27
  gen_adata,
@@ -288,7 +288,7 @@ def test_assign_X(adata):
288
288
  ("array_func", "mem_type"),
289
289
  [
290
290
  pytest.param(as_dense_dask_array, np.ndarray, id="dense_dask_array"),
291
- pytest.param(as_sparse_dask_array, sparse.csr_matrix, id="sparse_dask_array"),
291
+ pytest.param(as_sparse_dask_matrix, sparse.csr_matrix, id="sparse_dask_matrix"),
292
292
  pytest.param(
293
293
  as_dense_cupy_dask_array,
294
294
  CupyArray,
@@ -326,7 +326,7 @@ def test_dask_to_memory_unbacked(array_func, mem_type):
326
326
  "array_func",
327
327
  [
328
328
  pytest.param(as_dense_dask_array, id="dense_dask_array"),
329
- pytest.param(as_sparse_dask_array, id="sparse_dask_array"),
329
+ pytest.param(as_sparse_dask_matrix, id="sparse_dask_matrix"),
330
330
  pytest.param(
331
331
  as_dense_cupy_dask_array,
332
332
  id="cupy_dense_dask_array",
@@ -274,8 +274,9 @@ def test_hints():
274
274
  )
275
275
  settings_types_mod = types.ModuleType(types_loader.name)
276
276
  types_loader.exec_module(settings_types_mod)
277
- for settings_key in dir(settings):
278
- if not settings_key.startswith("_"):
279
- assert hasattr(settings_types_mod._AnnDataSettingsManager, settings_key)
280
- for settings_key in dir(settings_types_mod._AnnDataSettingsManager):
281
- assert hasattr(settings, settings_key)
277
+
278
+ obj_attrs, typing_attrs = (
279
+ {k for k in dir(o) if not k.startswith("_")}
280
+ for o in (settings, settings_types_mod._AnnDataSettingsManager)
281
+ )
282
+ assert obj_attrs == typing_attrs
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes