spatialdata-js-util 0.1.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.
- spatialdata_js_util/__init__.py +107 -0
- spatialdata_js_util/cli.py +803 -0
- spatialdata_js_util/codecs/__init__.py +67 -0
- spatialdata_js_util/codecs/backends.py +250 -0
- spatialdata_js_util/codecs/chunks.py +40 -0
- spatialdata_js_util/codecs/encoding.py +154 -0
- spatialdata_js_util/codecs/htj2k_wasm.py +266 -0
- spatialdata_js_util/codecs/names.py +26 -0
- spatialdata_js_util/codecs/probe/multicomponent.j2c +0 -0
- spatialdata_js_util/codecs/probe/multicomponent.json +3 -0
- spatialdata_js_util/codecs/probe/multicomponent.npy +0 -0
- spatialdata_js_util/codecs/vendor/__init__.py +1 -0
- spatialdata_js_util/codecs/vendor/encode-plane.mjs +164 -0
- spatialdata_js_util/codecs/vendor/openjph/index.mjs +131 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph.mjs +2 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph.wasm +0 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph_simd.mjs +2 -0
- spatialdata_js_util/codecs/vendor/openjph/wasm/libopenjph_simd.wasm +0 -0
- spatialdata_js_util/codecs/zarr_codec.py +149 -0
- spatialdata_js_util/errors.py +5 -0
- spatialdata_js_util/images.py +849 -0
- spatialdata_js_util/index_permutations.py +311 -0
- spatialdata_js_util/points.py +445 -0
- spatialdata_js_util/points_zarr.py +799 -0
- spatialdata_js_util/provenance.py +17 -0
- spatialdata_js_util/pyramids.py +318 -0
- spatialdata_js_util/runners.py +458 -0
- spatialdata_js_util/store.py +305 -0
- spatialdata_js_util/tables.py +310 -0
- spatialdata_js_util/tui/__init__.py +0 -0
- spatialdata_js_util/tui/app.py +112 -0
- spatialdata_js_util/tui/models.py +45 -0
- spatialdata_js_util/tui/screens.py +1255 -0
- spatialdata_js_util/tui/widgets.py +50 -0
- spatialdata_js_util/verify.py +338 -0
- spatialdata_js_util-0.1.0.dist-info/METADATA +412 -0
- spatialdata_js_util-0.1.0.dist-info/RECORD +40 -0
- spatialdata_js_util-0.1.0.dist-info/WHEEL +5 -0
- spatialdata_js_util-0.1.0.dist-info/entry_points.txt +7 -0
- spatialdata_js_util-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
from collections.abc import Callable, Iterator
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Sequence, TypeVar
|
|
10
|
+
|
|
11
|
+
import pandas as pd
|
|
12
|
+
import pyarrow.dataset as ds
|
|
13
|
+
|
|
14
|
+
from .errors import WriterCommandError
|
|
15
|
+
from .index_permutations import (
|
|
16
|
+
DEFAULT_CONDITIONS,
|
|
17
|
+
FEATURE_SELECTIVITY_CONDITIONS,
|
|
18
|
+
IndexCondition,
|
|
19
|
+
write_index_permutations,
|
|
20
|
+
)
|
|
21
|
+
from .points import EncodingPolicy
|
|
22
|
+
from .points_zarr import (
|
|
23
|
+
DEFAULT_CHUNK_ROWS,
|
|
24
|
+
DEFAULT_SHARD_CHUNKS,
|
|
25
|
+
SIDECAR_GROUP,
|
|
26
|
+
PointsSource,
|
|
27
|
+
add_points_zarr_to_store,
|
|
28
|
+
write_points_zarr_store,
|
|
29
|
+
)
|
|
30
|
+
from .points import (
|
|
31
|
+
build_spatialdata_multiscale_metadata,
|
|
32
|
+
write_morton_points_parquet,
|
|
33
|
+
write_multiscale_points_parquet,
|
|
34
|
+
)
|
|
35
|
+
from .store import (
|
|
36
|
+
copy_points_element_metadata,
|
|
37
|
+
experimental_points_output_path,
|
|
38
|
+
list_points_keys,
|
|
39
|
+
points_parquet_path,
|
|
40
|
+
read_points_dataframe,
|
|
41
|
+
read_points_element_attrs,
|
|
42
|
+
register_points_elements_in_consolidated_metadata,
|
|
43
|
+
validate_points_key,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
_T = TypeVar("_T")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
class MortonZarrOutput:
|
|
51
|
+
source_parquet: Path
|
|
52
|
+
output_parquet: Path
|
|
53
|
+
in_place: bool
|
|
54
|
+
output_points_key: str | None
|
|
55
|
+
collection: str
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _as_command_error(action: Callable[[], _T]) -> _T:
|
|
59
|
+
try:
|
|
60
|
+
return action()
|
|
61
|
+
except WriterCommandError:
|
|
62
|
+
raise
|
|
63
|
+
except (FileNotFoundError, ValueError) as exc:
|
|
64
|
+
raise WriterCommandError(str(exc)) from exc
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def read_input_dataframe(path: str | Path) -> pd.DataFrame:
|
|
68
|
+
input_path = Path(path)
|
|
69
|
+
if input_path.is_dir():
|
|
70
|
+
return read_points_dataframe(input_path)
|
|
71
|
+
suffix = input_path.suffix.lower()
|
|
72
|
+
if suffix == ".csv":
|
|
73
|
+
return pd.read_csv(input_path)
|
|
74
|
+
if suffix in {".parquet", ".pq"}:
|
|
75
|
+
return pd.read_parquet(input_path)
|
|
76
|
+
raise WriterCommandError(
|
|
77
|
+
f"Unsupported input: {path}\n"
|
|
78
|
+
"Expected a .csv file, .parquet file, or a directory of Parquet parts."
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def run_list_points(zarr: str | Path) -> dict[str, Any]:
|
|
83
|
+
keys = list_points_keys(zarr)
|
|
84
|
+
if not keys:
|
|
85
|
+
raise WriterCommandError(f"No Points elements found under {Path(zarr) / 'points'}")
|
|
86
|
+
return {"zarr": str(zarr), "points_keys": keys}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def run_morton_points(
|
|
90
|
+
input_path: str | Path,
|
|
91
|
+
output_path: str | Path,
|
|
92
|
+
*,
|
|
93
|
+
feature_key: str | None = None,
|
|
94
|
+
row_group_size: int = 50_000,
|
|
95
|
+
compression: str = "zstd",
|
|
96
|
+
) -> dict[str, Any]:
|
|
97
|
+
df = _as_command_error(lambda: read_input_dataframe(input_path))
|
|
98
|
+
sorted_df = _as_command_error(
|
|
99
|
+
lambda: write_morton_points_parquet(
|
|
100
|
+
df,
|
|
101
|
+
output_path,
|
|
102
|
+
feature_key=feature_key,
|
|
103
|
+
row_group_size=row_group_size,
|
|
104
|
+
compression=compression,
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
return {
|
|
108
|
+
"format": "morton-points",
|
|
109
|
+
"rows": int(len(sorted_df)),
|
|
110
|
+
"output": str(output_path),
|
|
111
|
+
"row_group_size": row_group_size,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def run_points_zarr(
|
|
116
|
+
input_path: str | Path,
|
|
117
|
+
output_store: str | Path,
|
|
118
|
+
*,
|
|
119
|
+
feature_key: str,
|
|
120
|
+
coordinates: Sequence[str] = ("x", "y"),
|
|
121
|
+
points_key: str = "transcripts",
|
|
122
|
+
tile_size: float = 100.0,
|
|
123
|
+
n_levels: int | None = None,
|
|
124
|
+
seed: int = 0,
|
|
125
|
+
chunk_rows: int = DEFAULT_CHUNK_ROWS,
|
|
126
|
+
shard_chunks: int = DEFAULT_SHARD_CHUNKS,
|
|
127
|
+
overwrite: bool = False,
|
|
128
|
+
) -> dict[str, Any]:
|
|
129
|
+
if Path(output_store).exists() and not overwrite:
|
|
130
|
+
raise WriterCommandError(
|
|
131
|
+
f"Output already exists: {output_store}\nChoose another path or enable overwrite."
|
|
132
|
+
)
|
|
133
|
+
source = _as_command_error(
|
|
134
|
+
lambda: _points_source(input_path, [*coordinates, feature_key])
|
|
135
|
+
)
|
|
136
|
+
return _as_command_error(
|
|
137
|
+
lambda: write_points_zarr_store(
|
|
138
|
+
source,
|
|
139
|
+
output_store,
|
|
140
|
+
points_key=points_key,
|
|
141
|
+
overwrite=overwrite,
|
|
142
|
+
feature_key=feature_key,
|
|
143
|
+
coordinates=coordinates,
|
|
144
|
+
tile_size=tile_size,
|
|
145
|
+
n_levels=n_levels,
|
|
146
|
+
seed=seed,
|
|
147
|
+
chunk_rows=chunk_rows,
|
|
148
|
+
shard_chunks=shard_chunks,
|
|
149
|
+
progress=lambda message: print(message, file=sys.stderr, flush=True),
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def run_add_points_zarr(
|
|
155
|
+
store: str | Path,
|
|
156
|
+
*,
|
|
157
|
+
points_key: str,
|
|
158
|
+
tile_size: float = 100.0,
|
|
159
|
+
n_levels: int | None = None,
|
|
160
|
+
seed: int = 0,
|
|
161
|
+
chunk_rows: int = DEFAULT_CHUNK_ROWS,
|
|
162
|
+
shard_chunks: int = DEFAULT_SHARD_CHUNKS,
|
|
163
|
+
overwrite: bool = False,
|
|
164
|
+
) -> dict[str, Any]:
|
|
165
|
+
existing = Path(store) / "points" / points_key / SIDECAR_GROUP
|
|
166
|
+
if existing.exists() and not overwrite:
|
|
167
|
+
raise WriterCommandError(
|
|
168
|
+
f"Output already exists: {existing}\nChoose another element or enable overwrite."
|
|
169
|
+
)
|
|
170
|
+
return _as_command_error(
|
|
171
|
+
lambda: add_points_zarr_to_store(
|
|
172
|
+
None,
|
|
173
|
+
store,
|
|
174
|
+
points_key=points_key,
|
|
175
|
+
overwrite=overwrite,
|
|
176
|
+
tile_size=tile_size,
|
|
177
|
+
n_levels=n_levels,
|
|
178
|
+
seed=seed,
|
|
179
|
+
chunk_rows=chunk_rows,
|
|
180
|
+
shard_chunks=shard_chunks,
|
|
181
|
+
progress=lambda message: print(message, file=sys.stderr, flush=True),
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _points_source(path: str | Path, columns: list[str]) -> pd.DataFrame | PointsSource:
|
|
187
|
+
"""Parquet is streamed a batch at a time, so it need not fit in memory; CSV is read whole."""
|
|
188
|
+
input_path = Path(path)
|
|
189
|
+
if input_path.suffix.lower() == ".csv":
|
|
190
|
+
return read_input_dataframe(input_path)
|
|
191
|
+
if not input_path.exists():
|
|
192
|
+
raise FileNotFoundError(f"Input not found: {input_path}")
|
|
193
|
+
dataset = ds.dataset(input_path, format="parquet")
|
|
194
|
+
|
|
195
|
+
def batches() -> Iterator[pd.DataFrame]:
|
|
196
|
+
for batch in dataset.to_batches(columns=columns, batch_size=4_000_000):
|
|
197
|
+
yield batch.to_pandas()
|
|
198
|
+
|
|
199
|
+
return batches
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def run_multiscale_points(
|
|
203
|
+
input_path: str | Path,
|
|
204
|
+
output_path: str | Path,
|
|
205
|
+
*,
|
|
206
|
+
metadata_json: str | Path | None = None,
|
|
207
|
+
row_group_size: int = 50_000,
|
|
208
|
+
compression: str = "zstd",
|
|
209
|
+
) -> dict[str, Any]:
|
|
210
|
+
df = _as_command_error(lambda: read_input_dataframe(input_path))
|
|
211
|
+
if metadata_json:
|
|
212
|
+
metadata = _as_command_error(lambda: json.loads(Path(metadata_json).read_text()))
|
|
213
|
+
else:
|
|
214
|
+
metadata = _as_command_error(lambda: build_spatialdata_multiscale_metadata(df))
|
|
215
|
+
_as_command_error(
|
|
216
|
+
lambda: write_multiscale_points_parquet(
|
|
217
|
+
df,
|
|
218
|
+
output_path,
|
|
219
|
+
metadata=metadata,
|
|
220
|
+
row_group_size=row_group_size,
|
|
221
|
+
compression=compression,
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
return {
|
|
225
|
+
"format": "spatialdata_multiscale_points",
|
|
226
|
+
"rows": int(len(df)),
|
|
227
|
+
"output": str(output_path),
|
|
228
|
+
"row_group_size": row_group_size,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def resolve_morton_from_zarr_output(
|
|
233
|
+
zarr_path: Path,
|
|
234
|
+
points_key: str,
|
|
235
|
+
*,
|
|
236
|
+
output: str | Path | None = None,
|
|
237
|
+
output_points_key: str | None = None,
|
|
238
|
+
experimental: bool = False,
|
|
239
|
+
) -> MortonZarrOutput:
|
|
240
|
+
if output is not None and output_points_key is not None:
|
|
241
|
+
raise WriterCommandError("Pass either output or output_points_key, not both.")
|
|
242
|
+
source_parquet = points_parquet_path(zarr_path, points_key)
|
|
243
|
+
if output:
|
|
244
|
+
resolved_output = Path(output)
|
|
245
|
+
return MortonZarrOutput(
|
|
246
|
+
source_parquet=source_parquet,
|
|
247
|
+
output_parquet=resolved_output,
|
|
248
|
+
in_place=resolved_output == source_parquet,
|
|
249
|
+
output_points_key=None,
|
|
250
|
+
collection="path",
|
|
251
|
+
)
|
|
252
|
+
if experimental:
|
|
253
|
+
resolved_output_key = validate_points_key(output_points_key or points_key)
|
|
254
|
+
resolved_output = experimental_points_output_path(zarr_path, resolved_output_key)
|
|
255
|
+
return MortonZarrOutput(
|
|
256
|
+
source_parquet=source_parquet,
|
|
257
|
+
output_parquet=resolved_output,
|
|
258
|
+
in_place=False,
|
|
259
|
+
output_points_key=resolved_output_key,
|
|
260
|
+
collection="points.experimental",
|
|
261
|
+
)
|
|
262
|
+
resolved_output_key = validate_points_key(output_points_key or points_key)
|
|
263
|
+
resolved_output = points_parquet_path(zarr_path, resolved_output_key)
|
|
264
|
+
return MortonZarrOutput(
|
|
265
|
+
source_parquet=source_parquet,
|
|
266
|
+
output_parquet=resolved_output,
|
|
267
|
+
in_place=resolved_output == source_parquet,
|
|
268
|
+
output_points_key=resolved_output_key,
|
|
269
|
+
collection="points",
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def run_morton_points_from_zarr(
|
|
274
|
+
zarr: str | Path,
|
|
275
|
+
*,
|
|
276
|
+
points_key: str | None = None,
|
|
277
|
+
experimental: bool = False,
|
|
278
|
+
output: str | Path | None = None,
|
|
279
|
+
output_points_key: str | None = None,
|
|
280
|
+
feature_key: str | None = None,
|
|
281
|
+
overwrite: bool = False,
|
|
282
|
+
row_group_size: int = 50_000,
|
|
283
|
+
compression: str = "zstd",
|
|
284
|
+
) -> dict[str, Any]:
|
|
285
|
+
zarr_path = Path(zarr)
|
|
286
|
+
keys = list_points_keys(zarr_path)
|
|
287
|
+
if not keys:
|
|
288
|
+
raise WriterCommandError(f"No Points elements found under {zarr_path / 'points'}")
|
|
289
|
+
|
|
290
|
+
resolved_key = points_key
|
|
291
|
+
if resolved_key is None:
|
|
292
|
+
if len(keys) == 1:
|
|
293
|
+
resolved_key = keys[0]
|
|
294
|
+
else:
|
|
295
|
+
raise WriterCommandError(
|
|
296
|
+
"Multiple Points elements found; pass points_key. "
|
|
297
|
+
f"Available keys: {', '.join(keys)}"
|
|
298
|
+
)
|
|
299
|
+
if resolved_key not in keys:
|
|
300
|
+
raise WriterCommandError(
|
|
301
|
+
f"Unknown Points element {resolved_key!r}. Available: {', '.join(keys)}"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
attrs = _as_command_error(lambda: read_points_element_attrs(zarr_path, resolved_key))
|
|
305
|
+
resolved_feature_key = feature_key or attrs.get("feature_key")
|
|
306
|
+
output_spec = resolve_morton_from_zarr_output(
|
|
307
|
+
zarr_path,
|
|
308
|
+
resolved_key,
|
|
309
|
+
output=output,
|
|
310
|
+
output_points_key=output_points_key,
|
|
311
|
+
experimental=experimental,
|
|
312
|
+
)
|
|
313
|
+
if (
|
|
314
|
+
output_spec.output_parquet.exists()
|
|
315
|
+
and not output_spec.in_place
|
|
316
|
+
and not overwrite
|
|
317
|
+
):
|
|
318
|
+
raise WriterCommandError(
|
|
319
|
+
f"Output already exists: {output_spec.output_parquet}\n"
|
|
320
|
+
"Choose another element name/path or enable overwrite."
|
|
321
|
+
)
|
|
322
|
+
if (
|
|
323
|
+
output_spec.collection == "points"
|
|
324
|
+
and output_spec.output_points_key is not None
|
|
325
|
+
and output_spec.output_points_key != resolved_key
|
|
326
|
+
):
|
|
327
|
+
target_element_dir = zarr_path / "points" / output_spec.output_points_key
|
|
328
|
+
if target_element_dir.exists() and not overwrite:
|
|
329
|
+
raise WriterCommandError(
|
|
330
|
+
f"Points element already exists: points/{output_spec.output_points_key}\n"
|
|
331
|
+
"Choose another element name or enable overwrite."
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
df = _as_command_error(lambda: read_points_dataframe(output_spec.source_parquet))
|
|
335
|
+
if output_spec.output_parquet.exists():
|
|
336
|
+
if output_spec.output_parquet.is_dir():
|
|
337
|
+
shutil.rmtree(output_spec.output_parquet)
|
|
338
|
+
else:
|
|
339
|
+
output_spec.output_parquet.unlink()
|
|
340
|
+
if (
|
|
341
|
+
output_spec.collection == "points"
|
|
342
|
+
and output_spec.output_points_key is not None
|
|
343
|
+
and output_spec.output_points_key != resolved_key
|
|
344
|
+
):
|
|
345
|
+
_as_command_error(
|
|
346
|
+
lambda: copy_points_element_metadata(
|
|
347
|
+
zarr_path,
|
|
348
|
+
source_key=resolved_key,
|
|
349
|
+
dest_key=output_spec.output_points_key,
|
|
350
|
+
)
|
|
351
|
+
)
|
|
352
|
+
sorted_df = _as_command_error(
|
|
353
|
+
lambda: write_morton_points_parquet(
|
|
354
|
+
df,
|
|
355
|
+
output_spec.output_parquet,
|
|
356
|
+
feature_key=resolved_feature_key,
|
|
357
|
+
row_group_size=row_group_size,
|
|
358
|
+
compression=compression,
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
if (
|
|
362
|
+
output_spec.collection == "points"
|
|
363
|
+
and output_spec.output_points_key is not None
|
|
364
|
+
and output_spec.output_points_key != resolved_key
|
|
365
|
+
):
|
|
366
|
+
_as_command_error(
|
|
367
|
+
lambda: register_points_elements_in_consolidated_metadata(
|
|
368
|
+
zarr_path,
|
|
369
|
+
[resolved_key, output_spec.output_points_key],
|
|
370
|
+
template_key=resolved_key,
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
return {
|
|
374
|
+
"format": "morton-points",
|
|
375
|
+
"zarr": str(zarr_path),
|
|
376
|
+
"points_key": resolved_key,
|
|
377
|
+
"output_points_key": output_spec.output_points_key,
|
|
378
|
+
"output_collection": output_spec.collection,
|
|
379
|
+
"source": str(output_spec.source_parquet),
|
|
380
|
+
"output": str(output_spec.output_parquet),
|
|
381
|
+
"in_place": output_spec.in_place,
|
|
382
|
+
"feature_key": resolved_feature_key,
|
|
383
|
+
"rows": int(len(sorted_df)),
|
|
384
|
+
"row_group_size": row_group_size,
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def run_write_index_permutations(
|
|
389
|
+
source_zarr: str | Path,
|
|
390
|
+
dest_zarr: str | Path,
|
|
391
|
+
*,
|
|
392
|
+
points_key: str | None = None,
|
|
393
|
+
max_rows: int | None = None,
|
|
394
|
+
condition_ids: Sequence[str] | None = None,
|
|
395
|
+
overwrite: bool = False,
|
|
396
|
+
row_group_size: int = 50_000,
|
|
397
|
+
compression: str = "zstd",
|
|
398
|
+
encodings: EncodingPolicy = "auto",
|
|
399
|
+
write_page_index: bool = True,
|
|
400
|
+
) -> dict[str, Any]:
|
|
401
|
+
selected: tuple[IndexCondition, ...] | None = None
|
|
402
|
+
if condition_ids:
|
|
403
|
+
by_id = {
|
|
404
|
+
condition.id: condition
|
|
405
|
+
for condition in (*DEFAULT_CONDITIONS, *FEATURE_SELECTIVITY_CONDITIONS)
|
|
406
|
+
}
|
|
407
|
+
missing = [value for value in condition_ids if value not in by_id]
|
|
408
|
+
if missing:
|
|
409
|
+
raise WriterCommandError(f"Unknown conditions: {', '.join(missing)}")
|
|
410
|
+
selected = tuple(by_id[value] for value in condition_ids)
|
|
411
|
+
|
|
412
|
+
return _as_command_error(
|
|
413
|
+
lambda: write_index_permutations(
|
|
414
|
+
source_zarr,
|
|
415
|
+
dest_zarr,
|
|
416
|
+
points_key=points_key,
|
|
417
|
+
max_rows=max_rows,
|
|
418
|
+
conditions=selected,
|
|
419
|
+
overwrite=overwrite,
|
|
420
|
+
row_group_size=row_group_size,
|
|
421
|
+
compression=compression,
|
|
422
|
+
encodings=encodings,
|
|
423
|
+
write_page_index=write_page_index,
|
|
424
|
+
)
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def run_tables_to_csc(
|
|
429
|
+
source: str | Path,
|
|
430
|
+
dest: str | Path | None = None,
|
|
431
|
+
*,
|
|
432
|
+
tables: Sequence[str] | None = None,
|
|
433
|
+
layers: bool = True,
|
|
434
|
+
densify: bool = False,
|
|
435
|
+
overwrite: bool = False,
|
|
436
|
+
) -> dict[str, Any]:
|
|
437
|
+
from .tables import convert_store_tables_to_csc
|
|
438
|
+
|
|
439
|
+
result = _as_command_error(
|
|
440
|
+
lambda: convert_store_tables_to_csc(
|
|
441
|
+
source,
|
|
442
|
+
dest,
|
|
443
|
+
tables=tables,
|
|
444
|
+
layers=layers,
|
|
445
|
+
densify=densify,
|
|
446
|
+
overwrite=overwrite,
|
|
447
|
+
)
|
|
448
|
+
)
|
|
449
|
+
return result.manifest
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def run_list_tables(zarr: str | Path) -> dict[str, Any]:
|
|
453
|
+
from .store import list_element_keys
|
|
454
|
+
|
|
455
|
+
keys = list_element_keys(zarr, "tables")
|
|
456
|
+
if not keys:
|
|
457
|
+
raise WriterCommandError(f"No table elements found under {Path(zarr) / 'tables'}")
|
|
458
|
+
return {"zarr": str(zarr), "table_keys": keys}
|