pyadata-cli 0.5.0__tar.gz → 0.5.1__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.
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/PKG-INFO +2 -2
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/README.md +1 -1
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/pyproject.toml +1 -1
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/storage/__init__.py +62 -5
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/LICENSE +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/__init__.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/cli.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/__init__.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/concat.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/create.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/export.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/import_data.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/info.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/ls.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/split.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/commands/subset.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/core/__init__.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/core/concat.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/core/info.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/core/query.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/core/read.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/core/select.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/core/subset.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/elements/__init__.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/elements/read.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/elements/spec.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/elements/strings.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/elements/write.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/__init__.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/array.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/common.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/dataframe.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/image.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/json_data.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/sparse.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/formats/validate.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/info.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/py.typed +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/read.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/util/__init__.py +0 -0
- {pyadata_cli-0.5.0 → pyadata_cli-0.5.1}/src/adata/util/path.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyadata-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Streaming CLI for exploring and editing large AnnData .h5ad and .zarr stores
|
|
5
5
|
Keywords: anndata,h5ad,zarr,bioinformatics,single-cell,cli
|
|
6
6
|
Author: Aljes Binkevich
|
|
@@ -131,5 +131,5 @@ adata concat per_sample/*.h5ad -o merged.h5ad --join outer --label sample
|
|
|
131
131
|
A docker image is available on QUAY: `quay.io/cellgeni/adata-cli:latest`. Pull and run with:
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
|
-
docker run --rm -it -v /path/to/data:/data quay.io/cellgeni/adata-cli:latest view /data/your_file.h5ad
|
|
134
|
+
docker run --rm -it -v /path/to/data:/data quay.io/cellgeni/adata-cli:latest adata view /data/your_file.h5ad
|
|
135
135
|
```
|
|
@@ -91,5 +91,5 @@ adata concat per_sample/*.h5ad -o merged.h5ad --join outer --label sample
|
|
|
91
91
|
A docker image is available on QUAY: `quay.io/cellgeni/adata-cli:latest`. Pull and run with:
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
docker run --rm -it -v /path/to/data:/data quay.io/cellgeni/adata-cli:latest view /data/your_file.h5ad
|
|
94
|
+
docker run --rm -it -v /path/to/data:/data quay.io/cellgeni/adata-cli:latest adata view /data/your_file.h5ad
|
|
95
95
|
```
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# so the distribution is published as `pyadata-cli`. The import package
|
|
4
4
|
# and the command are both still `adata`.
|
|
5
5
|
name = "pyadata-cli"
|
|
6
|
-
version = "0.5.
|
|
6
|
+
version = "0.5.1"
|
|
7
7
|
description = "Streaming CLI for exploring and editing large AnnData .h5ad and .zarr stores"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
requires-python = ">=3.12"
|
|
@@ -440,12 +440,69 @@ def _is_string_src(src: Any) -> bool:
|
|
|
440
440
|
return is_string_dtype(getattr(src, "dtype", None))
|
|
441
441
|
|
|
442
442
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
#: Byte budget for a single read when streaming a dataset.
|
|
444
|
+
#:
|
|
445
|
+
#: Using a source's chunk height as the read size means inheriting whatever
|
|
446
|
+
#: the writer chose, and a store chunked `(1, n_cols)` is then copied one row
|
|
447
|
+
#: per read. On a local disk that is merely wasteful; on a network filesystem
|
|
448
|
+
#: (Lustre, NFS) every read is a round-trip costing milliseconds, so a
|
|
449
|
+
#: million-row copy spends nearly all of its time waiting. 32 MiB sits
|
|
450
|
+
#: comfortably above a typical 1 MiB Lustre stripe while bounding peak memory.
|
|
451
|
+
TARGET_READ_BYTES = 32 * 1024 * 1024
|
|
452
|
+
|
|
453
|
+
#: Assumed width of a variable-length string element, for read sizing only.
|
|
454
|
+
#: h5py reports `itemsize` 8 for vlen strings because the value is a pointer,
|
|
455
|
+
#: which would overestimate the row count by an order of magnitude and break
|
|
456
|
+
#: the memory bound. Real cell and gene names sit well under this.
|
|
457
|
+
VLEN_ELEMENT_BYTES = 64
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def _row_bytes(shape: Sequence[int], dtype: Any) -> int:
|
|
461
|
+
"""In-memory size of one row along the first axis."""
|
|
462
|
+
width = 1
|
|
463
|
+
for dim in shape[1:]:
|
|
464
|
+
width *= max(1, int(dim))
|
|
465
|
+
|
|
466
|
+
itemsize = int(getattr(dtype, "itemsize", 0) or 0)
|
|
467
|
+
# 'O' is how h5py spells vlen str, 'T' is numpy StringDType as reported by
|
|
468
|
+
# zarr-python 3. Neither itemsize reflects the bytes actually stored.
|
|
469
|
+
if itemsize <= 0 or getattr(dtype, "kind", None) in ("O", "T"):
|
|
470
|
+
itemsize = VLEN_ELEMENT_BYTES
|
|
471
|
+
|
|
472
|
+
return max(1, width * itemsize)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _chunk_step(
|
|
476
|
+
shape: Sequence[int], chunks: Optional[Sequence[int]], dtype: Any
|
|
477
|
+
) -> int:
|
|
478
|
+
"""Rows to copy per read, sized for the filesystem rather than the source.
|
|
479
|
+
|
|
480
|
+
The step is grown to `TARGET_READ_BYTES`, then rounded down to a whole
|
|
481
|
+
number of source chunks: reading part of a chunk still costs decompressing
|
|
482
|
+
all of it, so a step that splits one wastes the remainder.
|
|
483
|
+
"""
|
|
446
484
|
if not shape:
|
|
447
485
|
return 1
|
|
448
|
-
|
|
486
|
+
|
|
487
|
+
n_rows = int(shape[0])
|
|
488
|
+
if n_rows <= 0:
|
|
489
|
+
return 1
|
|
490
|
+
|
|
491
|
+
chunk_rows = 0
|
|
492
|
+
if chunks is not None and len(chunks) > 0 and chunks[0]:
|
|
493
|
+
chunk_rows = max(1, int(chunks[0]))
|
|
494
|
+
|
|
495
|
+
step = max(1, TARGET_READ_BYTES // _row_bytes(shape, dtype))
|
|
496
|
+
if chunk_rows:
|
|
497
|
+
# Never go below a single chunk: a partial read still decompresses the
|
|
498
|
+
# whole thing, so a smaller step costs the same I/O for less data. That
|
|
499
|
+
# makes TARGET_READ_BYTES a target rather than a cap -- a source whose
|
|
500
|
+
# own chunk already exceeds the budget (say 1000 x 1e6 float32, chunked
|
|
501
|
+
# whole) reads that chunk regardless. This matches the previous
|
|
502
|
+
# behaviour, which used the chunk height verbatim.
|
|
503
|
+
step = max(chunk_rows, (step // chunk_rows) * chunk_rows)
|
|
504
|
+
|
|
505
|
+
return min(step, n_rows)
|
|
449
506
|
|
|
450
507
|
|
|
451
508
|
def copy_dataset(src: Any, dst_group: Any, name: str) -> Any:
|
|
@@ -475,7 +532,7 @@ def copy_dataset(src: Any, dst_group: Any, name: str) -> Any:
|
|
|
475
532
|
ds[()] = src[()]
|
|
476
533
|
return ds
|
|
477
534
|
|
|
478
|
-
step = _chunk_step(shape, getattr(src, "chunks", None))
|
|
535
|
+
step = _chunk_step(shape, getattr(src, "chunks", None), src.dtype)
|
|
479
536
|
for start in range(0, shape[0], step):
|
|
480
537
|
end = min(start + step, shape[0])
|
|
481
538
|
if len(shape) == 1:
|
|
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
|
|
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
|