pyadata-cli 0.5.0__py3-none-any.whl
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.
- adata/__init__.py +10 -0
- adata/cli.py +1139 -0
- adata/commands/__init__.py +8 -0
- adata/commands/concat.py +21 -0
- adata/commands/create.py +93 -0
- adata/commands/export.py +105 -0
- adata/commands/import_data.py +144 -0
- adata/commands/info.py +199 -0
- adata/commands/ls.py +114 -0
- adata/commands/split.py +152 -0
- adata/commands/subset.py +17 -0
- adata/core/__init__.py +1 -0
- adata/core/concat.py +1084 -0
- adata/core/info.py +276 -0
- adata/core/query.py +268 -0
- adata/core/read.py +28 -0
- adata/core/select.py +122 -0
- adata/core/subset.py +767 -0
- adata/elements/__init__.py +10 -0
- adata/elements/read.py +310 -0
- adata/elements/spec.py +125 -0
- adata/elements/strings.py +90 -0
- adata/elements/write.py +255 -0
- adata/formats/__init__.py +1 -0
- adata/formats/array.py +109 -0
- adata/formats/common.py +51 -0
- adata/formats/dataframe.py +234 -0
- adata/formats/image.py +85 -0
- adata/formats/json_data.py +196 -0
- adata/formats/sparse.py +253 -0
- adata/formats/validate.py +180 -0
- adata/info.py +3 -0
- adata/py.typed +0 -0
- adata/read.py +19 -0
- adata/storage/__init__.py +529 -0
- adata/util/__init__.py +1 -0
- adata/util/path.py +9 -0
- pyadata_cli-0.5.0.dist-info/METADATA +135 -0
- pyadata_cli-0.5.0.dist-info/RECORD +42 -0
- pyadata_cli-0.5.0.dist-info/WHEEL +4 -0
- pyadata_cli-0.5.0.dist-info/entry_points.txt +4 -0
- pyadata_cli-0.5.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Tuple, Any
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
|
|
7
|
+
from adata.core.info import axis_len
|
|
8
|
+
from adata.util.path import norm_path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
OBS_AXIS_PREFIXES = ("obs", "obsm/", "obsp/")
|
|
12
|
+
VAR_AXIS_PREFIXES = ("var", "varm/", "varp/")
|
|
13
|
+
MATRIX_PREFIXES = ("X", "layers/")
|
|
14
|
+
|
|
15
|
+
#: Paths that must hold a dataframe, so writing an array there would corrupt
|
|
16
|
+
#: the store rather than merely mis-size it.
|
|
17
|
+
DATAFRAME_PATHS = frozenset({"obs", "var", "raw/var"})
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _get_axis_length(root: Any, axis: str) -> Optional[int]:
|
|
21
|
+
try:
|
|
22
|
+
return axis_len(root, axis)
|
|
23
|
+
except Exception:
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _raw_var_length(root: Any) -> Optional[int]:
|
|
28
|
+
"""Number of variables in `raw`, which is its own axis.
|
|
29
|
+
|
|
30
|
+
Taken from `raw/X`'s declared width where possible: that is the invariant
|
|
31
|
+
a replacement `raw/var` has to keep, and it usually differs from the main
|
|
32
|
+
object's var count.
|
|
33
|
+
"""
|
|
34
|
+
if "raw" not in root:
|
|
35
|
+
return None
|
|
36
|
+
raw = root["raw"]
|
|
37
|
+
|
|
38
|
+
if "X" in raw:
|
|
39
|
+
shape = raw["X"].attrs.get("shape", None)
|
|
40
|
+
if shape is not None and len(shape) >= 2:
|
|
41
|
+
return int(shape[1])
|
|
42
|
+
x_shape = getattr(raw["X"], "shape", None)
|
|
43
|
+
if x_shape is not None and len(x_shape) >= 2:
|
|
44
|
+
return int(x_shape[1])
|
|
45
|
+
|
|
46
|
+
if "var" in raw:
|
|
47
|
+
try:
|
|
48
|
+
return axis_len(raw, "var")
|
|
49
|
+
except Exception:
|
|
50
|
+
return None
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _validate_raw(
|
|
55
|
+
root: Any, obj_path: str, data_shape: Tuple[int, ...], console: Console
|
|
56
|
+
) -> bool:
|
|
57
|
+
"""Validate a path under `raw/`. Returns whether the path was recognised."""
|
|
58
|
+
if obj_path == "raw" or not obj_path.startswith("raw/"):
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
n_raw_var = _raw_var_length(root)
|
|
62
|
+
n_obs = _get_axis_length(root, "obs")
|
|
63
|
+
rest = obj_path[len("raw/"):]
|
|
64
|
+
|
|
65
|
+
if rest == "var":
|
|
66
|
+
if n_raw_var is not None and data_shape[0] != n_raw_var:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Row count mismatch: input has {data_shape[0]} rows, but raw "
|
|
69
|
+
f"has {n_raw_var} variables. Replacing raw/var with a "
|
|
70
|
+
"different length would leave raw/X inconsistent."
|
|
71
|
+
)
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
if rest == "X":
|
|
75
|
+
if len(data_shape) < 2:
|
|
76
|
+
raise ValueError(
|
|
77
|
+
f"raw/X requires 2D data, got {len(data_shape)}D."
|
|
78
|
+
)
|
|
79
|
+
if n_obs is not None and data_shape[0] != n_obs:
|
|
80
|
+
raise ValueError(
|
|
81
|
+
f"First dimension mismatch: input has {data_shape[0]} rows, "
|
|
82
|
+
f"but obs has {n_obs} cells."
|
|
83
|
+
)
|
|
84
|
+
if n_raw_var is not None and data_shape[1] != n_raw_var:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"Second dimension mismatch: input has {data_shape[1]} columns, "
|
|
87
|
+
f"but raw has {n_raw_var} variables."
|
|
88
|
+
)
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
if rest.startswith("varm/"):
|
|
92
|
+
if n_raw_var is not None and data_shape[0] != n_raw_var:
|
|
93
|
+
raise ValueError(
|
|
94
|
+
f"First dimension mismatch: input has {data_shape[0]} rows, "
|
|
95
|
+
f"but raw has {n_raw_var} variables."
|
|
96
|
+
)
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def validate_dimensions(
|
|
103
|
+
root: Any,
|
|
104
|
+
obj_path: str,
|
|
105
|
+
data_shape: Tuple[int, ...],
|
|
106
|
+
console: Console,
|
|
107
|
+
) -> None:
|
|
108
|
+
obj_path = norm_path(obj_path)
|
|
109
|
+
|
|
110
|
+
if _validate_raw(root, obj_path, data_shape, console):
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
n_obs = _get_axis_length(root, "obs")
|
|
114
|
+
n_var = _get_axis_length(root, "var")
|
|
115
|
+
|
|
116
|
+
if obj_path == "obs":
|
|
117
|
+
if n_obs is not None and data_shape[0] != n_obs:
|
|
118
|
+
raise ValueError(
|
|
119
|
+
f"Row count mismatch: input has {data_shape[0]} rows, "
|
|
120
|
+
f"but obs has {n_obs} cells."
|
|
121
|
+
)
|
|
122
|
+
return
|
|
123
|
+
if obj_path == "var":
|
|
124
|
+
if n_var is not None and data_shape[0] != n_var:
|
|
125
|
+
raise ValueError(
|
|
126
|
+
f"Row count mismatch: input has {data_shape[0]} rows, "
|
|
127
|
+
f"but var has {n_var} features."
|
|
128
|
+
)
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
for prefix in MATRIX_PREFIXES:
|
|
132
|
+
if obj_path == prefix or obj_path.startswith(prefix + "/") or obj_path.startswith(prefix):
|
|
133
|
+
if obj_path == "X" or obj_path.startswith("layers/"):
|
|
134
|
+
if len(data_shape) < 2:
|
|
135
|
+
raise ValueError(
|
|
136
|
+
f"Matrix data requires 2D shape, got {len(data_shape)}D."
|
|
137
|
+
)
|
|
138
|
+
if n_obs is not None and data_shape[0] != n_obs:
|
|
139
|
+
raise ValueError(
|
|
140
|
+
f"First dimension mismatch: input has {data_shape[0]} rows, "
|
|
141
|
+
f"but obs has {n_obs} cells."
|
|
142
|
+
)
|
|
143
|
+
if n_var is not None and data_shape[1] != n_var:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
f"Second dimension mismatch: input has {data_shape[1]} columns, "
|
|
146
|
+
f"but var has {n_var} features."
|
|
147
|
+
)
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
for prefix in OBS_AXIS_PREFIXES:
|
|
151
|
+
if obj_path.startswith(prefix) and obj_path != "obs":
|
|
152
|
+
if n_obs is not None and data_shape[0] != n_obs:
|
|
153
|
+
raise ValueError(
|
|
154
|
+
f"First dimension mismatch: input has {data_shape[0]} rows, "
|
|
155
|
+
f"but obs has {n_obs} cells."
|
|
156
|
+
)
|
|
157
|
+
if obj_path.startswith("obsp/") and len(data_shape) >= 2:
|
|
158
|
+
if data_shape[1] != n_obs:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
"obsp matrix must be square (n_obs × n_obs): "
|
|
161
|
+
f"got {data_shape[0]}×{data_shape[1]}, expected {n_obs}×{n_obs}."
|
|
162
|
+
)
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
for prefix in VAR_AXIS_PREFIXES:
|
|
166
|
+
if obj_path.startswith(prefix) and obj_path != "var":
|
|
167
|
+
if n_var is not None and data_shape[0] != n_var:
|
|
168
|
+
raise ValueError(
|
|
169
|
+
f"First dimension mismatch: input has {data_shape[0]} rows, "
|
|
170
|
+
f"but var has {n_var} features."
|
|
171
|
+
)
|
|
172
|
+
if obj_path.startswith("varp/") and len(data_shape) >= 2:
|
|
173
|
+
if data_shape[1] != n_var:
|
|
174
|
+
raise ValueError(
|
|
175
|
+
"varp matrix must be square (n_var × n_var): "
|
|
176
|
+
f"got {data_shape[0]}×{data_shape[1]}, expected {n_var}×{n_var}."
|
|
177
|
+
)
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
console.print(f"[dim]Note: No dimension validation for path '{obj_path}'[/]")
|
adata/info.py
ADDED
adata/py.typed
ADDED
|
File without changes
|
adata/read.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from adata.core.read import (
|
|
2
|
+
col_chunk_as_strings,
|
|
3
|
+
decode_str_array,
|
|
4
|
+
element_len,
|
|
5
|
+
read_categorical_column,
|
|
6
|
+
read_str_all,
|
|
7
|
+
read_str_chunk,
|
|
8
|
+
resolve_index,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"col_chunk_as_strings",
|
|
13
|
+
"decode_str_array",
|
|
14
|
+
"element_len",
|
|
15
|
+
"read_categorical_column",
|
|
16
|
+
"read_str_all",
|
|
17
|
+
"read_str_chunk",
|
|
18
|
+
"resolve_index",
|
|
19
|
+
]
|