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.
@@ -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
@@ -0,0 +1,3 @@
1
+ from adata.core.info import axis_len, format_type_info, get_axis_group, get_entry_type
2
+
3
+ __all__ = ["axis_len", "format_type_info", "get_axis_group", "get_entry_type"]
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
+ ]