ComDAS 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.
@@ -0,0 +1,429 @@
1
+ """
2
+ FiberIO plugin for the ComDAS HDF5 container format.
3
+
4
+ The ComDAS HDF5 container format is designed to store patches
5
+ in a codec-agnostic manner
6
+
7
+ Registers the ``COMDAS`` format with DASCore's FiberIO manager. Once
8
+ this module is imported (or the package is pip-installed, via the
9
+ ``dascore.fiber_io`` entry point in ``pyproject.toml``), ``dc.spool(path)``
10
+ and ``dc.write(patches, path, file_format="COMDAS")`` work
11
+ like any other DASCore format regardless of which
12
+ :class:`~comdas.codecs.base.Codec` was used to compress each patch.
13
+
14
+ File layout
15
+ -----------
16
+ ::
17
+
18
+ / (root)
19
+ attrs:
20
+ __format__ = "COMDAS"
21
+ __COMDAS_version__ = "1"
22
+ /patches
23
+ /patch_0000
24
+ attrs:
25
+ codec_name (str) -- e.g. "SVD"; looked up in the codec registry
26
+ codec_version (str) -- the codec's own version string
27
+ compression_params (dict) -- parameters used for compression
28
+ original_shape (tuple[int, ...])
29
+ dtype (str) -- original array dtype
30
+ dims (str) -- comma-separated dim names, in order
31
+ attrs_json (str) -- PatchAttrs.model_dump_json()
32
+ <codec-specific datasets/attrs, written by codec.payload_to_group>
33
+ /coords
34
+ <dim_name> -- one dataset per dim, full coord array
35
+ attrs: dtype (str), units (str, empty if none)
36
+ /patch_0001
37
+ ...
38
+
39
+ Everything above the codec-specific datasets is written and read by
40
+ this module. Only what's inside a patch's own group (beyond
41
+ ``coords``) is delegated to ``codec.payload_to_group`` /
42
+ ``codec.payload_from_group``.
43
+
44
+ Patches are appended, not overwritten: calling ``write`` again on an
45
+ existing file adds new ``patch_XXXX`` groups after the existing ones
46
+ (``H5Writer`` opens in ``"a"`` mode).
47
+
48
+ Once ``comdas`` is installed, plain ``dc.spool(path)`` finds and uses this
49
+ format automatically. Writing has one convenience function,
50
+ :func:`write_compressed`.
51
+ """
52
+
53
+ from __future__ import annotations
54
+
55
+ import numpy as np
56
+
57
+ import dascore as dc
58
+ from dascore.io import FiberIO
59
+ from dascore.utils.hdf5 import H5Reader, H5Writer
60
+
61
+ from comdas.arrays.duck_array import DuckArray
62
+ from comdas.codecs.base import Codec
63
+
64
+ FORMAT_NAME = "COMDAS"
65
+ FORMAT_VERSION = "1"
66
+ _PATCH_GROUP_PREFIX = "patch_"
67
+
68
+
69
+ def _patch_group_names(h5file) -> list[str]:
70
+ """
71
+ List patch group names in a COMDAS file, in write order.
72
+
73
+ :param h5file: An open ``h5py.File`` for a COMDAS container.
74
+ :returns: Sorted patch group names (empty if the file has none yet).
75
+ :rtype: list[str]
76
+ """
77
+ if "patches" not in h5file:
78
+ return []
79
+ return sorted(h5file["patches"].keys())
80
+
81
+
82
+ def _next_patch_index(h5file) -> int:
83
+ """
84
+ The next unused ``patch_XXXX`` index for appending to ``h5file``.
85
+
86
+ :param h5file: An open ``h5py.File`` for a COMDAS container.
87
+ :returns: The next patch index to use.
88
+ :rtype: int
89
+ """
90
+ names = _patch_group_names(h5file)
91
+ if not names:
92
+ return 0
93
+ return int(names[-1][len(_PATCH_GROUP_PREFIX) :]) + 1
94
+
95
+
96
+ def _dump_coord_array(arr: np.ndarray) -> tuple[np.ndarray, str]:
97
+ """
98
+ Convert a coordinate array to something h5py can store directly.
99
+
100
+ h5py can't store ``datetime64``/``timedelta64`` directly, so those
101
+ are viewed as ``int64`` for storage; the exact original dtype
102
+ string is returned so :func:`_load_coord_array` can cast back.
103
+
104
+ :param arr: The coordinate array to prepare for storage.
105
+ :type arr: numpy.ndarray
106
+ :returns: A ``(storable_array, dtype_str)`` pair.
107
+ :rtype: tuple[numpy.ndarray, str]
108
+ """
109
+ dtype_str = str(arr.dtype)
110
+ if np.issubdtype(arr.dtype, np.datetime64) or np.issubdtype(
111
+ arr.dtype, np.timedelta64
112
+ ):
113
+ return arr.astype("int64"), dtype_str
114
+ return arr, dtype_str
115
+
116
+
117
+ def _load_coord_array(arr: np.ndarray, dtype_str: str) -> np.ndarray:
118
+ """
119
+ Invert :func:`_dump_coord_array`.
120
+
121
+ :param arr: The array as read from the HDF5 dataset.
122
+ :type arr: numpy.ndarray
123
+ :param dtype_str: The original dtype string, as stored on write.
124
+ :type dtype_str: str
125
+ :returns: The coordinate array cast back to its original dtype.
126
+ :rtype: numpy.ndarray
127
+ """
128
+ return arr.astype(dtype_str)
129
+
130
+
131
+ def _range_overlaps(requested, actual_min, actual_max) -> bool:
132
+ """
133
+ Whether a ``(lo, hi)`` request overlaps an ``[actual_min, actual_max]`` range.
134
+
135
+ :param requested: A ``(lo, hi)`` tuple (either bound may be
136
+ ``None`` for "unbounded"), or ``None`` for "no constraint".
137
+ :param actual_min: The range's actual minimum, or ``None``.
138
+ :param actual_max: The range's actual maximum, or ``None``.
139
+ :returns: True if the two ranges overlap (or either is unbounded).
140
+ :rtype: bool
141
+ """
142
+ if requested is None:
143
+ return True
144
+ lo, hi = requested
145
+ if lo is not None and actual_max is not None and lo > actual_max:
146
+ return False
147
+ if hi is not None and actual_min is not None and hi < actual_min:
148
+ return False
149
+ return True
150
+
151
+
152
+ def _patch_matches_kwargs(attrs: dc.PatchAttrs, kwargs: dict) -> bool:
153
+ """
154
+ Whether a stored patch's coord ranges match DASCore's selection kwargs.
155
+
156
+ :param attrs: The candidate patch's attrs (with a ``coords``
157
+ summary mapping dim name to a min/max-bearing object).
158
+ :type attrs: dascore.PatchAttrs
159
+ :param kwargs: Keyword arguments as received by
160
+ :meth:`ComdasV1.read`; only keys matching a dim name in
161
+ ``attrs.coords`` are consulted.
162
+ :returns: True if every dim-range constraint in ``kwargs`` overlaps
163
+ this patch's own range for that dim.
164
+ :rtype: bool
165
+ """
166
+ for dim, summary in attrs.coords.items():
167
+ if dim not in kwargs or kwargs[dim] is None:
168
+ continue
169
+ if not _range_overlaps(kwargs[dim], summary.min, summary.max):
170
+ return False
171
+ return True
172
+
173
+
174
+ def _write_patch(
175
+ patches_group, name: str, patch, codec: Codec, encode_kwargs: dict
176
+ ) -> None:
177
+ """
178
+ Compress and write one patch into ``patches_group[name]``.
179
+
180
+ :param patches_group: The open ``/patches`` HDF5 group.
181
+ :type patches_group: h5py.Group
182
+ :param name: The new patch group's name (e.g. ``"patch_0003"``).
183
+ :type name: str
184
+ :param patch: The (uncompressed) patch to write.
185
+ :type patch: dascore.Patch
186
+ :param codec: The codec to compress ``patch.data`` with.
187
+ :type codec: Codec
188
+ :param encode_kwargs: Forwarded to ``codec.encode``.
189
+ :type encode_kwargs: dict
190
+ :raises ValueError: If ``patch.data`` is not 2D (the only shape
191
+ ComDAS codecs currently support).
192
+ """
193
+ dense = np.asarray(patch.data)
194
+ if dense.ndim != 2:
195
+ raise ValueError(
196
+ "ComDAS codecs currently only support 2D patches (e.g. "
197
+ f"channel x time), got shape {dense.shape} for dims {patch.dims}"
198
+ )
199
+ payload = codec.encode(dense, **encode_kwargs)
200
+
201
+ grp = patches_group.create_group(name)
202
+ grp.attrs["codec_name"] = codec.name
203
+ grp.attrs["codec_version"] = codec.version
204
+ grp.attrs["original_shape"] = payload.original_shape
205
+ grp.attrs["dtype"] = str(payload.dtype)
206
+ grp.attrs["dims"] = ",".join(patch.dims)
207
+ grp.attrs["attrs_json"] = patch.attrs.model_dump_json()
208
+
209
+ codec.payload_to_group(payload, grp)
210
+
211
+ coord_grp = grp.create_group("coords")
212
+ for dim in patch.dims:
213
+ arr = patch.coords.get_array(dim)
214
+ storable, dtype_str = _dump_coord_array(arr)
215
+ cds = coord_grp.create_dataset(dim, data=storable)
216
+ cds.attrs["dtype"] = dtype_str
217
+ coord = patch.coords.get_coord(dim)
218
+ units = getattr(coord, "units", None)
219
+ cds.attrs["units"] = str(units) if units is not None else ""
220
+
221
+
222
+ def _read_patch(patch_group) -> dc.Patch:
223
+ """
224
+ Read one patch group back into an ordinary compressed Patch.
225
+
226
+ :param patch_group: An open patch group (e.g. ``f["patches"]["patch_0000"]``).
227
+ :type patch_group: h5py.Group
228
+ :returns: The reconstructed Patch, backed by a
229
+ :class:`~comdas.arrays.duck_array.DuckArray`.
230
+ :rtype: dascore.Patch
231
+ """
232
+ codec_cls = Codec.get_registered(patch_group.attrs["codec_name"])
233
+ codec = codec_cls()
234
+ original_shape = tuple(patch_group.attrs["original_shape"])
235
+ dtype = np.dtype(patch_group.attrs["dtype"])
236
+ payload = codec.payload_from_group(
237
+ patch_group, original_shape=original_shape, dtype=dtype
238
+ )
239
+ compressed_array = DuckArray(payload, codec)
240
+
241
+ dims = tuple(patch_group.attrs["dims"].split(","))
242
+ coord_grp = patch_group["coords"]
243
+ coords = {}
244
+ for dim in dims:
245
+ ds = coord_grp[dim]
246
+ raw = ds[:]
247
+ dtype_str = ds.attrs.get("dtype", str(raw.dtype))
248
+ coords[dim] = _load_coord_array(raw, dtype_str)
249
+
250
+ attrs = dc.PatchAttrs.model_validate_json(patch_group.attrs["attrs_json"])
251
+
252
+ return dc.Patch(
253
+ data=compressed_array, coords=coords, dims=dims, attrs=attrs
254
+ )
255
+
256
+
257
+ class ComdasV1(FiberIO):
258
+ """
259
+ FiberIO support for the codec-agnostic ComDAS HDF5 container, v1.
260
+
261
+ Each patch stores which :class:`~comdas.codecs.base.Codec` it was
262
+ compressed with. This means a single file can hold patches
263
+ compressed with different codecs.
264
+ """
265
+
266
+ name = FORMAT_NAME
267
+ version = FORMAT_VERSION
268
+ preferred_extensions = ("h5", "hdf5")
269
+
270
+ def get_format(
271
+ self, resource: H5Reader, **kwargs
272
+ ) -> tuple[str, str] | bool:
273
+ """
274
+ Identify a COMDAS file via its root-level magic attrs.
275
+
276
+ :param resource: An open, readable HDF5 file (auto-opened by
277
+ DASCore from a path via the ``H5Reader`` type hint).
278
+ :type resource: h5py.File
279
+ :param kwargs: Unused; accepted for FiberIO API compatibility.
280
+ :returns: ``(format_name, format_version)`` if this file is a
281
+ COMDAS container, else ``False``.
282
+ :rtype: tuple[str, str] or bool
283
+ """
284
+ fmt = resource.attrs.get("__format__")
285
+ if fmt == FORMAT_NAME:
286
+ version = resource.attrs.get(
287
+ f"__{FORMAT_NAME}_version__", FORMAT_VERSION
288
+ )
289
+ return FORMAT_NAME, str(version)
290
+ return False
291
+
292
+ def scan(self, resource: H5Reader, **kwargs) -> list[dc.PatchAttrs]:
293
+ """
294
+ Read every patch's attrs without touching datasets.
295
+
296
+ :param resource: An open, readable COMDAS HDF5 file.
297
+ :type resource: h5py.File
298
+ :param kwargs: Unused; accepted for FiberIO API compatibility.
299
+ :returns: One :class:`dascore.PatchAttrs` per stored patch.
300
+ :rtype: list[dascore.PatchAttrs]
301
+ """
302
+ out = []
303
+ for name in _patch_group_names(resource):
304
+ grp = resource["patches"][name]
305
+ attrs = dc.PatchAttrs.model_validate_json(grp.attrs["attrs_json"])
306
+ attrs = attrs.update(
307
+ file_format=self.name,
308
+ file_version=self.version,
309
+ path=str(resource.filename),
310
+ )
311
+ out.append(attrs)
312
+ return out
313
+
314
+ def read(self, resource: H5Reader, **kwargs) -> dc.BaseSpool:
315
+ """
316
+ Read patches.
317
+
318
+ Honors dimension-range kwargs.
319
+
320
+ :param resource: An open, readable COMDAS HDF5 file.
321
+ :type resource: h5py.File
322
+ :param kwargs: Optional dimension-range constraints (e.g.
323
+ ``time=(t1, t2)``); any key not matching a coord's dim
324
+ name is ignored.
325
+ :returns: A spool of the matching patches.
326
+ :rtype: dascore.BaseSpool
327
+ """
328
+ patches = []
329
+ for name in _patch_group_names(resource):
330
+ grp = resource["patches"][name]
331
+ attrs = dc.PatchAttrs.model_validate_json(grp.attrs["attrs_json"])
332
+ if _patch_matches_kwargs(attrs, kwargs):
333
+ patches.append(_read_patch(grp))
334
+ return dc.spool(patches)
335
+
336
+ def write(
337
+ self,
338
+ spool,
339
+ resource: H5Writer,
340
+ *,
341
+ codec: Codec | None = None,
342
+ **encode_kwargs,
343
+ ) -> None:
344
+ """
345
+ Compress and write a Patch/spool of Patches to the container.
346
+
347
+ :param spool: A single Patch, or any iterable of Patches, to
348
+ write.
349
+ :type spool: dascore.Patch or dascore.BaseSpool or Sequence[dascore.Patch]
350
+ :param resource: An open, writable HDF5 file (auto-opened by
351
+ DASCore from a path via the ``H5Writer`` type hint, in
352
+ append mode).
353
+ :type resource: h5py.File
354
+ :param codec: The codec to compress every patch in ``spool``
355
+ with. (e.g. ``SVDCodec(rank=20)``.)
356
+ :type codec: Codec
357
+ :param encode_kwargs: Forwarded to ``codec.encode`` for every
358
+ patch.
359
+ :raises ValueError: If ``codec`` is not given.
360
+ """
361
+ if codec is None:
362
+ raise ValueError(
363
+ "A `codec` must be provided to write a COMDAS container "
364
+ "(e.g. codec=SVDCodec(rank=20))."
365
+ )
366
+ resource.attrs["__format__"] = FORMAT_NAME
367
+ resource.attrs[f"__{FORMAT_NAME}_version__"] = FORMAT_VERSION
368
+
369
+ if "patches" not in resource:
370
+ resource.create_group("patches")
371
+ patches_group = resource["patches"]
372
+
373
+ patches = [spool] if isinstance(spool, dc.Patch) else list(spool)
374
+ idx = _next_patch_index(resource)
375
+ for patch in patches:
376
+ name = f"{_PATCH_GROUP_PREFIX}{idx:04d}"
377
+ _write_patch(patches_group, name, patch, codec, encode_kwargs)
378
+ idx += 1
379
+
380
+
381
+ def write_compressed(source, path, codec: Codec, **encode_kwargs) -> None:
382
+ """
383
+ Compress ``source`` and write it to ``path`` as a COMDAS container.
384
+
385
+ This is the intended way to turn uncompressed DAS data
386
+ into a compressed COMDAS file.
387
+
388
+ :param source: Where the uncompressed data comes from (a file or
389
+ directory path, a single Patch, a sequence of Patches, or an
390
+ existing Spool).
391
+ :type source: str or pathlib.Path or dascore.Patch or dascore.BaseSpool or Sequence[dascore.Patch]
392
+ :param path: Destination path for the COMDAS container. If it
393
+ already exists as a COMDAS file, patches are appended rather
394
+ than overwriting existing ones.
395
+ :type path: str or pathlib.Path
396
+ :param codec: The codec to compress every patch with, e.g.
397
+ ``SVDCodec(rank=20)``.
398
+ :type codec: Codec
399
+ :param encode_kwargs: Forwarded to ``codec.encode`` for every
400
+ patch (e.g. ``rank=``/``energy=`` for
401
+ :class:`~comdas.codecs.svd.SVDCodec`, overriding the codec's
402
+ own defaults for this call).
403
+
404
+ :Example:
405
+
406
+ .. code-block:: python
407
+
408
+ import dascore as dc
409
+ from comdas import write_compressed, SVDCodec
410
+
411
+ # from an existing uncompressed file
412
+ write_compressed("raw.h5", "compressed.h5", SVDCodec(rank=20))
413
+
414
+ # from a patch already in memory
415
+ patch = dc.get_example_patch()
416
+ write_compressed(patch, "compressed.h5", SVDCodec(rank=20))
417
+
418
+ # reading back needs nothing ComDAS-specific
419
+ read_back = dc.spool("compressed.h5")
420
+ """
421
+ spool = dc.spool(source)
422
+ dc.write(
423
+ spool,
424
+ path,
425
+ file_format=FORMAT_NAME,
426
+ file_version=FORMAT_VERSION,
427
+ codec=codec,
428
+ **encode_kwargs,
429
+ )
comdas/utils.py ADDED
@@ -0,0 +1,35 @@
1
+ """
2
+ Utility functions for working with compressed patches.
3
+ Includes:
4
+ - :func:`compress_patch` Compress an in-memory DASCore patch's data using a specified codec.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import numpy as np
10
+
11
+ from comdas.arrays.duck_array import DuckArray
12
+ from comdas.codecs.base import Codec
13
+
14
+
15
+ def compress_patch(patch, codec: Codec, **encode_kwargs):
16
+ """
17
+ Return a new ``dascore.Patch`` whose data is compressed with ``codec``.
18
+
19
+ Coords and attrs are unchanged. The returned Patch is an ordinary Patch
20
+ (via ``patch.new``) with the internal data replaced by a
21
+ :class:`~comdas.arrays.duck_array.DuckArray`.
22
+
23
+ :param patch: The uncompressed source patch.
24
+ :type patch: dascore.Patch
25
+ :param codec: The codec to compress ``patch.data`` with.
26
+ :type codec: Codec
27
+ :param encode_kwargs: Forwarded verbatim to ``codec.encode``.
28
+ :returns: A new Patch with the same coords/attrs, backed by a
29
+ :class:`~comdas.arrays.duck_array.DuckArray`.
30
+ :rtype: dascore.Patch
31
+ """
32
+ dense = np.asarray(patch.data)
33
+ payload = codec.encode(dense, **encode_kwargs)
34
+ compressed_array = DuckArray(payload, codec)
35
+ return patch.new(data=compressed_array)
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: ComDAS
3
+ Version: 0.1.0
4
+ Summary: DASCORE companion package that adds support for compressed DAS data
5
+ Author-email: Byron-Selvage <bselvage@mines.edu>
6
+ License: LGPL-3.0-or-later
7
+ Keywords: dascore,compression,das,dasdae
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: numpy>=1.24
12
+ Requires-Dist: dascore>=0.1.0
13
+ Requires-Dist: h5py
14
+ Requires-Dist: PyWavelets
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest; extra == "dev"
17
+ Requires-Dist: ruff; extra == "dev"
18
+ Requires-Dist: sphinx; extra == "dev"
19
+ Requires-Dist: furo; extra == "dev"
20
+ Requires-Dist: sphinx-autodoc-typehints; extra == "dev"
21
+ Requires-Dist: myst-nb; extra == "dev"
22
+ Requires-Dist: matplotlib; extra == "dev"
23
+ Requires-Dist: ipykernel; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # ComDAS
27
+
28
+ ![Python versions tested](https://img.shields.io/badge/Python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)
29
+
30
+ ComDAS (Compressed DAS) lets you store and work with compressed distributed acoustic sensing (DAS) data using ordinary [DASCore](https://dascore.org/) tools.
31
+
32
+ With ComDAS you can:
33
+
34
+ - **Shrink DAS data in memory.** Compress a DASCore patch and keep using it like any other.
35
+ - **Save compressed files.** Write patches, spools, or whole directories of raw data to a compressed HDF5 file or files.
36
+ - **Read compressed files with plain DASCore.** Once ComDAS is installed, `dascore.spool()` opens compressed files directly without needing to know how the data was compressed.
37
+ - **Choose your compression level.** Pick a codec and set how much detail to keep, from near-lossless to aggressive compression.
38
+ - **Implement your own algorithm.** Add a new compression method by writing a codec class.
39
+
40
+ > [!NOTE]
41
+ > ComDAS is in active development. The file format and public API may change between releases.
42
+
43
+ ## Supported codecs
44
+
45
+ | Codec | Main setting | Reference |
46
+ | --- | --- | --- |
47
+ | [SVD](https://byron-selvage.github.io/ComDAS/codecs/svd.html) | `rank` or retained `energy` | [NumPy SVD](https://numpy.org/doc/1.22/reference/generated/numpy.linalg.svd.html) |
48
+ | [Wavelet](https://byron-selvage.github.io/ComDAS/codecs/wavelet.html) | `keep_fraction` or `threshold` | [PyWavelets](https://doi.org/10.21105/joss.01237); [DeVore et al. (1992)](https://doi.org/10.1109/18.119733) |
49
+
50
+ ## Installation
51
+
52
+ ComDAS requires Python 3.10 or newer.
53
+
54
+ ```bash
55
+ pip install comdas
56
+ ```
57
+
58
+ ## Documentation
59
+
60
+ Full documentation is available at [byron-selvage.github.io/ComDAS](https://byron-selvage.github.io/ComDAS/), including:
61
+
62
+ - [Quick start](https://byron-selvage.github.io/ComDAS/quickstart.html): compress a patch, save a compressed file, and read it back
63
+ - [Codecs](https://byron-selvage.github.io/ComDAS/codecs/svd.html): configuration options and examples for each codec
64
+ - [Examples](https://byron-selvage.github.io/ComDAS/examples/compression_comparison.html)
65
+ - [API reference](https://byron-selvage.github.io/ComDAS/api/index.html)
66
+
67
+ ## License
68
+
69
+ ComDAS is licensed under the [GNU Lesser General Public License](LICENSE).
@@ -0,0 +1,16 @@
1
+ comdas/__init__.py,sha256=R7M9IFbD5BdOqQGCU1onPjTQNSDMn5tNV8t9kJHlQno,1187
2
+ comdas/utils.py,sha256=A-aeA8VlYB9AmyXnqG1SUOCdmV4PFXjfXgSQRpJvcR4,1203
3
+ comdas/arrays/__init__.py,sha256=X1vsUKtcblCQVpi047nGtXsOW556b4nbacH1bNJ9DnQ,221
4
+ comdas/arrays/duck_array.py,sha256=3BN-xESymPtnEtOSTC2UszUtMbDf_-swLMG9cFSIlnU,10775
5
+ comdas/codecs/__init__.py,sha256=baaEoxKe09LuZ2El_wnqhFxRa7RUs-vhgTlz-DN2v7U,356
6
+ comdas/codecs/base.py,sha256=hNSMc7AqItonSNWp7TVhEwBgCX3rBvd2A2aiub3F5cc,9712
7
+ comdas/codecs/svd.py,sha256=RRWhBs29ELiDEdkR-KYMnBwvw_uB4LZHn6nGnGa5dA8,8656
8
+ comdas/codecs/wavelet.py,sha256=-GjauCly_-dqqxSjBW9JTR_GQterzCc2l-vPgImDPAg,9719
9
+ comdas/io/__init__.py,sha256=aoweeIH-QebldKGyZXNLPn4aQFhZ2CMg627kOSE_ywU,564
10
+ comdas/io/h5_container.py,sha256=Xi5WnNKg9nJrFAhjRkq5GqdDXaba-6OyqrUAiqkXQig,15272
11
+ comdas-0.1.0.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
12
+ comdas-0.1.0.dist-info/METADATA,sha256=jIKvsK5Rl9GDFfX9TXa0AqZogoYOLUJQnoZV3eZdwow,3042
13
+ comdas-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
14
+ comdas-0.1.0.dist-info/entry_points.txt,sha256=dHkx7dydw-xH3uJ4SYKbhF6EvxjHGFxrh99I5_DV8xY,64
15
+ comdas-0.1.0.dist-info/top_level.txt,sha256=zkMksyvy9YtJW3mt1ZseiS55h0NbPT84Sbt4B2KrRtE,7
16
+ comdas-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [dascore.fiber_io]
2
+ COMDAS__V1 = comdas.io.h5_container:ComdasV1