polystore 0.1.0__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.
- polystore-0.1.0/LICENSE +22 -0
- polystore-0.1.0/PKG-INFO +266 -0
- polystore-0.1.0/README.md +189 -0
- polystore-0.1.0/pyproject.toml +200 -0
- polystore-0.1.0/setup.cfg +4 -0
- polystore-0.1.0/src/polystore/__init__.py +138 -0
- polystore-0.1.0/src/polystore/async_init.py +65 -0
- polystore-0.1.0/src/polystore/atomic.py +194 -0
- polystore-0.1.0/src/polystore/backend_registry.py +160 -0
- polystore-0.1.0/src/polystore/base.py +560 -0
- polystore-0.1.0/src/polystore/config.py +27 -0
- polystore-0.1.0/src/polystore/constants.py +52 -0
- polystore-0.1.0/src/polystore/disk.py +825 -0
- polystore-0.1.0/src/polystore/exceptions.py +33 -0
- polystore-0.1.0/src/polystore/fiji_stream.py +151 -0
- polystore-0.1.0/src/polystore/filemanager.py +770 -0
- polystore-0.1.0/src/polystore/formats.py +79 -0
- polystore-0.1.0/src/polystore/lazy_imports.py +127 -0
- polystore-0.1.0/src/polystore/memory.py +653 -0
- polystore-0.1.0/src/polystore/metadata_migration.py +273 -0
- polystore-0.1.0/src/polystore/metadata_writer.py +154 -0
- polystore-0.1.0/src/polystore/napari_stream.py +133 -0
- polystore-0.1.0/src/polystore/omero_local.py +1542 -0
- polystore-0.1.0/src/polystore/registry.py +9 -0
- polystore-0.1.0/src/polystore/roi.py +275 -0
- polystore-0.1.0/src/polystore/roi_converters.py +218 -0
- polystore-0.1.0/src/polystore/streaming.py +428 -0
- polystore-0.1.0/src/polystore/streaming_constants.py +26 -0
- polystore-0.1.0/src/polystore/utils.py +36 -0
- polystore-0.1.0/src/polystore/virtual_workspace.py +349 -0
- polystore-0.1.0/src/polystore/zarr.py +1287 -0
- polystore-0.1.0/src/polystore/zmq_config.py +23 -0
- polystore-0.1.0/src/polystore.egg-info/PKG-INFO +266 -0
- polystore-0.1.0/src/polystore.egg-info/SOURCES.txt +45 -0
- polystore-0.1.0/src/polystore.egg-info/dependency_links.txt +1 -0
- polystore-0.1.0/src/polystore.egg-info/requires.txt +62 -0
- polystore-0.1.0/src/polystore.egg-info/top_level.txt +1 -0
- polystore-0.1.0/tests/test_backend_registry.py +19 -0
- polystore-0.1.0/tests/test_basic.py +54 -0
- polystore-0.1.0/tests/test_disk_backend.py +69 -0
- polystore-0.1.0/tests/test_disk_coverage.py +556 -0
- polystore-0.1.0/tests/test_disk_more.py +104 -0
- polystore-0.1.0/tests/test_filemanager_backends.py +136 -0
- polystore-0.1.0/tests/test_filemanager_extended.py +345 -0
- polystore-0.1.0/tests/test_memory_backend.py +208 -0
- polystore-0.1.0/tests/test_memory_coverage.py +575 -0
- polystore-0.1.0/tests/test_zarr_backend.py +270 -0
polystore-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tristan Simas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
polystore-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: polystore
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Framework-agnostic multi-backend storage abstraction for ML and scientific computing
|
|
5
|
+
Author-email: Tristan Simas <tristan.simas@mail.mcgill.ca>
|
|
6
|
+
License: MIT License
|
|
7
|
+
Project-URL: Homepage, https://github.com/OpenHCSDev/PolyStore
|
|
8
|
+
Project-URL: Documentation, https://polystore.readthedocs.io
|
|
9
|
+
Project-URL: Bug Reports, https://github.com/OpenHCSDev/PolyStore/issues
|
|
10
|
+
Project-URL: Source, https://github.com/OpenHCSDev/PolyStore
|
|
11
|
+
Keywords: storage,backend,multi-framework,numpy,pytorch,jax,tensorflow,zarr,io,data
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: numpy>=1.26.0
|
|
25
|
+
Requires-Dist: portalocker>=2.8.0
|
|
26
|
+
Requires-Dist: metaclass-registry
|
|
27
|
+
Requires-Dist: zarr<3.0,>=2.18.0
|
|
28
|
+
Requires-Dist: ome-zarr>=0.11.0
|
|
29
|
+
Provides-Extra: zarr
|
|
30
|
+
Requires-Dist: zarr<3.0,>=2.18.0; extra == "zarr"
|
|
31
|
+
Requires-Dist: ome-zarr>=0.11.0; extra == "zarr"
|
|
32
|
+
Provides-Extra: torch
|
|
33
|
+
Requires-Dist: torch>=2.0.0; extra == "torch"
|
|
34
|
+
Provides-Extra: jax
|
|
35
|
+
Requires-Dist: jax>=0.4.0; extra == "jax"
|
|
36
|
+
Provides-Extra: tensorflow
|
|
37
|
+
Requires-Dist: tensorflow>=2.12.0; extra == "tensorflow"
|
|
38
|
+
Provides-Extra: cupy
|
|
39
|
+
Requires-Dist: cupy>=12.0.0; extra == "cupy"
|
|
40
|
+
Provides-Extra: streaming
|
|
41
|
+
Requires-Dist: pyzmq>=25.0.0; extra == "streaming"
|
|
42
|
+
Provides-Extra: all
|
|
43
|
+
Requires-Dist: zarr<3.0,>=2.18.0; extra == "all"
|
|
44
|
+
Requires-Dist: ome-zarr>=0.11.0; extra == "all"
|
|
45
|
+
Requires-Dist: torch>=2.0.0; extra == "all"
|
|
46
|
+
Requires-Dist: jax>=0.4.0; extra == "all"
|
|
47
|
+
Requires-Dist: tensorflow>=2.12.0; extra == "all"
|
|
48
|
+
Requires-Dist: cupy>=12.0.0; extra == "all"
|
|
49
|
+
Requires-Dist: pyzmq>=25.0.0; extra == "all"
|
|
50
|
+
Provides-Extra: dev
|
|
51
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
52
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
53
|
+
Requires-Dist: coverage>=7.3.2; extra == "dev"
|
|
54
|
+
Requires-Dist: genbadge[coverage]; extra == "dev"
|
|
55
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
56
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
57
|
+
Provides-Extra: docs
|
|
58
|
+
Requires-Dist: sphinx>=4.0.0; extra == "docs"
|
|
59
|
+
Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "docs"
|
|
60
|
+
Requires-Dist: sphinx-toolbox>=3.0.0; extra == "docs"
|
|
61
|
+
Requires-Dist: sphinx-design>=0.5.0; extra == "docs"
|
|
62
|
+
Provides-Extra: gpu
|
|
63
|
+
Requires-Dist: zarr<3.0,>=2.18.0; extra == "gpu"
|
|
64
|
+
Requires-Dist: ome-zarr>=0.11.0; extra == "gpu"
|
|
65
|
+
Requires-Dist: torch<2.8.0,>=2.6.0; extra == "gpu"
|
|
66
|
+
Requires-Dist: torchvision<0.23.0,>=0.21.0; extra == "gpu"
|
|
67
|
+
Requires-Dist: jax<0.6.0,>=0.5.3; extra == "gpu"
|
|
68
|
+
Requires-Dist: jaxlib<0.6.0,>=0.5.3; extra == "gpu"
|
|
69
|
+
Requires-Dist: jax-cuda12-pjrt<0.6.0,>=0.5.3; extra == "gpu"
|
|
70
|
+
Requires-Dist: jax-cuda12-plugin<0.6.0,>=0.5.3; extra == "gpu"
|
|
71
|
+
Requires-Dist: cupy-cuda12x<14.0.0,>=13.3.0; extra == "gpu"
|
|
72
|
+
Requires-Dist: cucim-cu12<26.0.0,>=25.6.0; extra == "gpu"
|
|
73
|
+
Requires-Dist: tensorflow<2.20.0,>=2.19.0; extra == "gpu"
|
|
74
|
+
Requires-Dist: tensorflow-probability[tf]<0.26.0,>=0.25.0; extra == "gpu"
|
|
75
|
+
Requires-Dist: pyclesperanto>=0.17.1; extra == "gpu"
|
|
76
|
+
Dynamic: license-file
|
|
77
|
+
|
|
78
|
+
# polystore
|
|
79
|
+
|
|
80
|
+
**Framework-agnostic multi-backend storage abstraction for ML and scientific computing**
|
|
81
|
+
|
|
82
|
+
[](https://badge.fury.io/py/polystore)
|
|
83
|
+
[](https://polystore.readthedocs.io/en/latest/?badge=latest)
|
|
84
|
+
[](https://www.python.org/downloads/)
|
|
85
|
+
[](https://opensource.org/licenses/MIT)
|
|
86
|
+
[](https://trissim.github.io/polystore/coverage/)
|
|
87
|
+
|
|
88
|
+
## Features
|
|
89
|
+
|
|
90
|
+
- **Pluggable Backends**: Disk, memory, Zarr, and streaming backends with auto-registration
|
|
91
|
+
- **Multi-Framework I/O**: Seamless support for NumPy, PyTorch, JAX, TensorFlow, CuPy
|
|
92
|
+
- **Atomic Operations**: Cross-platform atomic file writes with automatic locking
|
|
93
|
+
- **Batch Operations**: Efficient batch loading and saving
|
|
94
|
+
- **Format Detection**: Automatic format detection and routing
|
|
95
|
+
- **Type-Safe**: Full type hints and mypy support
|
|
96
|
+
- **Zero Dependencies**: Core requires only NumPy (framework support is optional)
|
|
97
|
+
|
|
98
|
+
## Quick Start
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from polystore import FileManager, BackendRegistry
|
|
102
|
+
|
|
103
|
+
# Create registry and file manager
|
|
104
|
+
registry = BackendRegistry()
|
|
105
|
+
fm = FileManager(registry)
|
|
106
|
+
|
|
107
|
+
# Save data to disk
|
|
108
|
+
import numpy as np
|
|
109
|
+
data = np.array([[1, 2], [3, 4]])
|
|
110
|
+
fm.save(data, "output.npy", backend="disk")
|
|
111
|
+
|
|
112
|
+
# Load data back
|
|
113
|
+
loaded = fm.load("output.npy", backend="disk")
|
|
114
|
+
|
|
115
|
+
# Use memory backend for testing
|
|
116
|
+
fm.save(data, "test.npy", backend="memory")
|
|
117
|
+
cached = fm.load("test.npy", backend="memory")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Installation
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Base installation (NumPy only)
|
|
124
|
+
pip install polystore
|
|
125
|
+
|
|
126
|
+
# With specific frameworks
|
|
127
|
+
pip install polystore[zarr]
|
|
128
|
+
pip install polystore[torch]
|
|
129
|
+
pip install polystore[jax]
|
|
130
|
+
pip install polystore[tensorflow]
|
|
131
|
+
pip install polystore[cupy]
|
|
132
|
+
|
|
133
|
+
# With streaming support
|
|
134
|
+
pip install polystore[streaming]
|
|
135
|
+
|
|
136
|
+
# With all optional dependencies
|
|
137
|
+
pip install polystore[all]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Supported Backends
|
|
141
|
+
|
|
142
|
+
| Backend | Description | Storage | Dependencies |
|
|
143
|
+
|---------|-------------|---------|--------------|
|
|
144
|
+
| **disk** | Local filesystem | Persistent | None |
|
|
145
|
+
| **memory** | In-memory cache | Volatile | None |
|
|
146
|
+
| **zarr** | Zarr/OME-Zarr arrays | Persistent | zarr, ome-zarr |
|
|
147
|
+
| **streaming** | ZeroMQ streaming | None | pyzmq |
|
|
148
|
+
|
|
149
|
+
## Supported Formats
|
|
150
|
+
|
|
151
|
+
| Format | Extensions | Frameworks |
|
|
152
|
+
|--------|-----------|------------|
|
|
153
|
+
| **NumPy** | `.npy`, `.npz` | NumPy, PyTorch, JAX, TensorFlow, CuPy |
|
|
154
|
+
| **TIFF** | `.tif`, `.tiff` | NumPy, PyTorch, JAX, TensorFlow, CuPy |
|
|
155
|
+
| **Zarr** | `.zarr` | NumPy, PyTorch, JAX, TensorFlow, CuPy |
|
|
156
|
+
| **PyTorch** | `.pt`, `.pth` | PyTorch |
|
|
157
|
+
| **CSV** | `.csv` | NumPy, pandas |
|
|
158
|
+
| **JSON** | `.json` | Python dicts |
|
|
159
|
+
|
|
160
|
+
## Architecture
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
polystore/
|
|
164
|
+
├── base.py # Abstract interfaces (DataSink, DataSource, StorageBackend)
|
|
165
|
+
├── backend_registry.py # Auto-registration system
|
|
166
|
+
├── disk.py # Disk storage backend
|
|
167
|
+
├── memory.py # In-memory backend
|
|
168
|
+
├── zarr.py # Zarr backend
|
|
169
|
+
├── streaming.py # ZeroMQ streaming backend
|
|
170
|
+
├── filemanager.py # High-level API
|
|
171
|
+
├── atomic.py # Atomic file operations
|
|
172
|
+
└── exceptions.py # Custom exceptions
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Advanced Usage
|
|
176
|
+
|
|
177
|
+
### Custom Backends
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from polystore import StorageBackend
|
|
181
|
+
|
|
182
|
+
class MyBackend(StorageBackend):
|
|
183
|
+
_backend_type = 'my_backend' # Auto-registers
|
|
184
|
+
|
|
185
|
+
def save(self, data, file_path, **kwargs):
|
|
186
|
+
# Your save logic
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
def load(self, file_path, **kwargs):
|
|
190
|
+
# Your load logic
|
|
191
|
+
pass
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Batch Operations
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
# Save multiple files
|
|
198
|
+
data_list = [np.random.rand(100, 100) for _ in range(10)]
|
|
199
|
+
paths = [f"image_{i}.npy" for i in range(10)]
|
|
200
|
+
fm.save_batch(data_list, paths, backend="disk")
|
|
201
|
+
|
|
202
|
+
# Load multiple files
|
|
203
|
+
loaded_list = fm.load_batch(paths, backend="disk")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Atomic Writes
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from polystore import atomic_write, atomic_write_json
|
|
210
|
+
|
|
211
|
+
# Atomic file write with automatic locking
|
|
212
|
+
with atomic_write("output.txt") as f:
|
|
213
|
+
f.write("data")
|
|
214
|
+
|
|
215
|
+
# Atomic JSON write
|
|
216
|
+
atomic_write_json({"key": "value"}, "config.json")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Why polystore?
|
|
220
|
+
|
|
221
|
+
**Before** (Manual backend management):
|
|
222
|
+
```python
|
|
223
|
+
if backend == 'disk':
|
|
224
|
+
np.save(path, data)
|
|
225
|
+
elif backend == 'memory':
|
|
226
|
+
cache[path] = data
|
|
227
|
+
elif backend == 'zarr':
|
|
228
|
+
zarr.save(path, data)
|
|
229
|
+
# ... 50 more lines of if/elif ...
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**After** (polystore):
|
|
233
|
+
```python
|
|
234
|
+
fm.save(data, path, backend=backend)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Documentation
|
|
238
|
+
|
|
239
|
+
Full documentation available at [polystore.readthedocs.io](https://polystore.readthedocs.io)
|
|
240
|
+
|
|
241
|
+
## Addons
|
|
242
|
+
|
|
243
|
+
Extend polystore with additional backends:
|
|
244
|
+
|
|
245
|
+
- **polystore-napari**: Napari viewer streaming backend
|
|
246
|
+
- **polystore-fiji**: Fiji/ImageJ streaming backend
|
|
247
|
+
- **polystore-omero**: OMERO server backend
|
|
248
|
+
|
|
249
|
+
## Performance
|
|
250
|
+
|
|
251
|
+
- **Zero-copy** conversions between frameworks via DLPack (when possible)
|
|
252
|
+
- **Lazy loading** for optional dependencies
|
|
253
|
+
- **Batch operations** for efficient I/O
|
|
254
|
+
- **Atomic writes** with minimal overhead
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
MIT License - see LICENSE file for details
|
|
259
|
+
|
|
260
|
+
## Contributing
|
|
261
|
+
|
|
262
|
+
Contributions welcome! Please see CONTRIBUTING.md for guidelines.
|
|
263
|
+
|
|
264
|
+
## Credits
|
|
265
|
+
|
|
266
|
+
Developed by Tristan Simas.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# polystore
|
|
2
|
+
|
|
3
|
+
**Framework-agnostic multi-backend storage abstraction for ML and scientific computing**
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/py/polystore)
|
|
6
|
+
[](https://polystore.readthedocs.io/en/latest/?badge=latest)
|
|
7
|
+
[](https://www.python.org/downloads/)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://trissim.github.io/polystore/coverage/)
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Pluggable Backends**: Disk, memory, Zarr, and streaming backends with auto-registration
|
|
14
|
+
- **Multi-Framework I/O**: Seamless support for NumPy, PyTorch, JAX, TensorFlow, CuPy
|
|
15
|
+
- **Atomic Operations**: Cross-platform atomic file writes with automatic locking
|
|
16
|
+
- **Batch Operations**: Efficient batch loading and saving
|
|
17
|
+
- **Format Detection**: Automatic format detection and routing
|
|
18
|
+
- **Type-Safe**: Full type hints and mypy support
|
|
19
|
+
- **Zero Dependencies**: Core requires only NumPy (framework support is optional)
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from polystore import FileManager, BackendRegistry
|
|
25
|
+
|
|
26
|
+
# Create registry and file manager
|
|
27
|
+
registry = BackendRegistry()
|
|
28
|
+
fm = FileManager(registry)
|
|
29
|
+
|
|
30
|
+
# Save data to disk
|
|
31
|
+
import numpy as np
|
|
32
|
+
data = np.array([[1, 2], [3, 4]])
|
|
33
|
+
fm.save(data, "output.npy", backend="disk")
|
|
34
|
+
|
|
35
|
+
# Load data back
|
|
36
|
+
loaded = fm.load("output.npy", backend="disk")
|
|
37
|
+
|
|
38
|
+
# Use memory backend for testing
|
|
39
|
+
fm.save(data, "test.npy", backend="memory")
|
|
40
|
+
cached = fm.load("test.npy", backend="memory")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Base installation (NumPy only)
|
|
47
|
+
pip install polystore
|
|
48
|
+
|
|
49
|
+
# With specific frameworks
|
|
50
|
+
pip install polystore[zarr]
|
|
51
|
+
pip install polystore[torch]
|
|
52
|
+
pip install polystore[jax]
|
|
53
|
+
pip install polystore[tensorflow]
|
|
54
|
+
pip install polystore[cupy]
|
|
55
|
+
|
|
56
|
+
# With streaming support
|
|
57
|
+
pip install polystore[streaming]
|
|
58
|
+
|
|
59
|
+
# With all optional dependencies
|
|
60
|
+
pip install polystore[all]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Supported Backends
|
|
64
|
+
|
|
65
|
+
| Backend | Description | Storage | Dependencies |
|
|
66
|
+
|---------|-------------|---------|--------------|
|
|
67
|
+
| **disk** | Local filesystem | Persistent | None |
|
|
68
|
+
| **memory** | In-memory cache | Volatile | None |
|
|
69
|
+
| **zarr** | Zarr/OME-Zarr arrays | Persistent | zarr, ome-zarr |
|
|
70
|
+
| **streaming** | ZeroMQ streaming | None | pyzmq |
|
|
71
|
+
|
|
72
|
+
## Supported Formats
|
|
73
|
+
|
|
74
|
+
| Format | Extensions | Frameworks |
|
|
75
|
+
|--------|-----------|------------|
|
|
76
|
+
| **NumPy** | `.npy`, `.npz` | NumPy, PyTorch, JAX, TensorFlow, CuPy |
|
|
77
|
+
| **TIFF** | `.tif`, `.tiff` | NumPy, PyTorch, JAX, TensorFlow, CuPy |
|
|
78
|
+
| **Zarr** | `.zarr` | NumPy, PyTorch, JAX, TensorFlow, CuPy |
|
|
79
|
+
| **PyTorch** | `.pt`, `.pth` | PyTorch |
|
|
80
|
+
| **CSV** | `.csv` | NumPy, pandas |
|
|
81
|
+
| **JSON** | `.json` | Python dicts |
|
|
82
|
+
|
|
83
|
+
## Architecture
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
polystore/
|
|
87
|
+
├── base.py # Abstract interfaces (DataSink, DataSource, StorageBackend)
|
|
88
|
+
├── backend_registry.py # Auto-registration system
|
|
89
|
+
├── disk.py # Disk storage backend
|
|
90
|
+
├── memory.py # In-memory backend
|
|
91
|
+
├── zarr.py # Zarr backend
|
|
92
|
+
├── streaming.py # ZeroMQ streaming backend
|
|
93
|
+
├── filemanager.py # High-level API
|
|
94
|
+
├── atomic.py # Atomic file operations
|
|
95
|
+
└── exceptions.py # Custom exceptions
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Advanced Usage
|
|
99
|
+
|
|
100
|
+
### Custom Backends
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from polystore import StorageBackend
|
|
104
|
+
|
|
105
|
+
class MyBackend(StorageBackend):
|
|
106
|
+
_backend_type = 'my_backend' # Auto-registers
|
|
107
|
+
|
|
108
|
+
def save(self, data, file_path, **kwargs):
|
|
109
|
+
# Your save logic
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
def load(self, file_path, **kwargs):
|
|
113
|
+
# Your load logic
|
|
114
|
+
pass
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Batch Operations
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
# Save multiple files
|
|
121
|
+
data_list = [np.random.rand(100, 100) for _ in range(10)]
|
|
122
|
+
paths = [f"image_{i}.npy" for i in range(10)]
|
|
123
|
+
fm.save_batch(data_list, paths, backend="disk")
|
|
124
|
+
|
|
125
|
+
# Load multiple files
|
|
126
|
+
loaded_list = fm.load_batch(paths, backend="disk")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Atomic Writes
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from polystore import atomic_write, atomic_write_json
|
|
133
|
+
|
|
134
|
+
# Atomic file write with automatic locking
|
|
135
|
+
with atomic_write("output.txt") as f:
|
|
136
|
+
f.write("data")
|
|
137
|
+
|
|
138
|
+
# Atomic JSON write
|
|
139
|
+
atomic_write_json({"key": "value"}, "config.json")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Why polystore?
|
|
143
|
+
|
|
144
|
+
**Before** (Manual backend management):
|
|
145
|
+
```python
|
|
146
|
+
if backend == 'disk':
|
|
147
|
+
np.save(path, data)
|
|
148
|
+
elif backend == 'memory':
|
|
149
|
+
cache[path] = data
|
|
150
|
+
elif backend == 'zarr':
|
|
151
|
+
zarr.save(path, data)
|
|
152
|
+
# ... 50 more lines of if/elif ...
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**After** (polystore):
|
|
156
|
+
```python
|
|
157
|
+
fm.save(data, path, backend=backend)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Documentation
|
|
161
|
+
|
|
162
|
+
Full documentation available at [polystore.readthedocs.io](https://polystore.readthedocs.io)
|
|
163
|
+
|
|
164
|
+
## Addons
|
|
165
|
+
|
|
166
|
+
Extend polystore with additional backends:
|
|
167
|
+
|
|
168
|
+
- **polystore-napari**: Napari viewer streaming backend
|
|
169
|
+
- **polystore-fiji**: Fiji/ImageJ streaming backend
|
|
170
|
+
- **polystore-omero**: OMERO server backend
|
|
171
|
+
|
|
172
|
+
## Performance
|
|
173
|
+
|
|
174
|
+
- **Zero-copy** conversions between frameworks via DLPack (when possible)
|
|
175
|
+
- **Lazy loading** for optional dependencies
|
|
176
|
+
- **Batch operations** for efficient I/O
|
|
177
|
+
- **Atomic writes** with minimal overhead
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT License - see LICENSE file for details
|
|
182
|
+
|
|
183
|
+
## Contributing
|
|
184
|
+
|
|
185
|
+
Contributions welcome! Please see CONTRIBUTING.md for guidelines.
|
|
186
|
+
|
|
187
|
+
## Credits
|
|
188
|
+
|
|
189
|
+
Developed by Tristan Simas.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "polystore"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Framework-agnostic multi-backend storage abstraction for ML and scientific computing"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = {text = "MIT License"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Tristan Simas", email = "tristan.simas@mail.mcgill.ca"}
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"storage",
|
|
17
|
+
"backend",
|
|
18
|
+
"multi-framework",
|
|
19
|
+
"numpy",
|
|
20
|
+
"pytorch",
|
|
21
|
+
"jax",
|
|
22
|
+
"tensorflow",
|
|
23
|
+
"zarr",
|
|
24
|
+
"io",
|
|
25
|
+
"data",
|
|
26
|
+
]
|
|
27
|
+
classifiers = [
|
|
28
|
+
"Development Status :: 3 - Alpha",
|
|
29
|
+
"Intended Audience :: Developers",
|
|
30
|
+
"Intended Audience :: Science/Research",
|
|
31
|
+
"License :: OSI Approved :: MIT License",
|
|
32
|
+
"Programming Language :: Python :: 3",
|
|
33
|
+
"Programming Language :: Python :: 3.11",
|
|
34
|
+
"Programming Language :: Python :: 3.12",
|
|
35
|
+
"Topic :: Scientific/Engineering",
|
|
36
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
dependencies = [
|
|
40
|
+
"numpy>=1.26.0",
|
|
41
|
+
"portalocker>=2.8.0", # Cross-platform file locking
|
|
42
|
+
"metaclass-registry",
|
|
43
|
+
"zarr>=2.18.0,<3.0", # Required for ZarrStorageBackend
|
|
44
|
+
"ome-zarr>=0.11.0", # Required for OME-ZARR HCS compliance
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.optional-dependencies]
|
|
48
|
+
zarr = [
|
|
49
|
+
"zarr>=2.18.0,<3.0",
|
|
50
|
+
"ome-zarr>=0.11.0",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
torch = [
|
|
54
|
+
"torch>=2.0.0",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
jax = [
|
|
58
|
+
"jax>=0.4.0",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
tensorflow = [
|
|
62
|
+
"tensorflow>=2.12.0",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
cupy = [
|
|
66
|
+
"cupy>=12.0.0",
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
streaming = [
|
|
70
|
+
"pyzmq>=25.0.0",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
all = [
|
|
74
|
+
"zarr>=2.18.0,<3.0",
|
|
75
|
+
"ome-zarr>=0.11.0",
|
|
76
|
+
"torch>=2.0.0",
|
|
77
|
+
"jax>=0.4.0",
|
|
78
|
+
"tensorflow>=2.12.0",
|
|
79
|
+
"cupy>=12.0.0",
|
|
80
|
+
"pyzmq>=25.0.0",
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
dev = [
|
|
84
|
+
"pytest>=7.4.0",
|
|
85
|
+
"pytest-cov>=4.1.0",
|
|
86
|
+
"coverage>=7.3.2",
|
|
87
|
+
"genbadge[coverage]",
|
|
88
|
+
"black>=23.0.0",
|
|
89
|
+
"ruff>=0.1.0",
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
docs = [
|
|
93
|
+
"sphinx>=4.0.0",
|
|
94
|
+
"sphinx-rtd-theme>=1.0.0",
|
|
95
|
+
"sphinx-toolbox>=3.0.0",
|
|
96
|
+
"sphinx-design>=0.5.0",
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
gpu = [
|
|
100
|
+
# Zarr
|
|
101
|
+
"zarr>=2.18.0,<3.0",
|
|
102
|
+
"ome-zarr>=0.11.0",
|
|
103
|
+
|
|
104
|
+
# PyTorch
|
|
105
|
+
"torch>=2.6.0,<2.8.0",
|
|
106
|
+
"torchvision>=0.21.0,<0.23.0",
|
|
107
|
+
|
|
108
|
+
# JAX
|
|
109
|
+
"jax>=0.5.3,<0.6.0",
|
|
110
|
+
"jaxlib>=0.5.3,<0.6.0",
|
|
111
|
+
|
|
112
|
+
# JAX CUDA plugins
|
|
113
|
+
"jax-cuda12-pjrt>=0.5.3,<0.6.0",
|
|
114
|
+
"jax-cuda12-plugin>=0.5.3,<0.6.0",
|
|
115
|
+
|
|
116
|
+
# CuPy
|
|
117
|
+
"cupy-cuda12x>=13.3.0,<14.0.0",
|
|
118
|
+
|
|
119
|
+
# CuCIM
|
|
120
|
+
"cucim-cu12>=25.6.0,<26.0.0",
|
|
121
|
+
|
|
122
|
+
# TensorFlow
|
|
123
|
+
"tensorflow>=2.19.0,<2.20.0",
|
|
124
|
+
|
|
125
|
+
# TensorFlow Probability
|
|
126
|
+
"tensorflow-probability[tf]>=0.25.0,<0.26.0",
|
|
127
|
+
|
|
128
|
+
# pyclesperanto
|
|
129
|
+
"pyclesperanto>=0.17.1",
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
[project.urls]
|
|
133
|
+
Homepage = "https://github.com/OpenHCSDev/PolyStore"
|
|
134
|
+
Documentation = "https://polystore.readthedocs.io"
|
|
135
|
+
"Bug Reports" = "https://github.com/OpenHCSDev/PolyStore/issues"
|
|
136
|
+
Source = "https://github.com/OpenHCSDev/PolyStore"
|
|
137
|
+
|
|
138
|
+
[tool.setuptools.packages.find]
|
|
139
|
+
where = ["src"]
|
|
140
|
+
include = ["polystore*"]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
[tool.pytest.ini_options]
|
|
145
|
+
testpaths = ["tests"]
|
|
146
|
+
python_files = ["test_*.py"]
|
|
147
|
+
python_classes = ["Test*"]
|
|
148
|
+
python_functions = ["test_*"]
|
|
149
|
+
addopts = [
|
|
150
|
+
"--strict-markers",
|
|
151
|
+
"--strict-config",
|
|
152
|
+
"--cov=polystore",
|
|
153
|
+
"--cov-report=term-missing",
|
|
154
|
+
"--cov-report=html",
|
|
155
|
+
"--cov-report=xml",
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
[tool.coverage.run]
|
|
159
|
+
source = ["polystore"]
|
|
160
|
+
omit = [
|
|
161
|
+
"*/tests/*",
|
|
162
|
+
"*/test_*.py",
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
[tool.coverage.report]
|
|
166
|
+
exclude_lines = [
|
|
167
|
+
"pragma: no cover",
|
|
168
|
+
"def __repr__",
|
|
169
|
+
"raise AssertionError",
|
|
170
|
+
"raise NotImplementedError",
|
|
171
|
+
"if __name__ == .__main__.:",
|
|
172
|
+
"if TYPE_CHECKING:",
|
|
173
|
+
"class .*\\bProtocol\\):",
|
|
174
|
+
"@(abc\\.)?abstractmethod",
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
[tool.black]
|
|
178
|
+
line-length = 100
|
|
179
|
+
target-version = ["py311", "py312"]
|
|
180
|
+
|
|
181
|
+
[tool.ruff]
|
|
182
|
+
line-length = 100
|
|
183
|
+
target-version = "py311"
|
|
184
|
+
select = [
|
|
185
|
+
"E", # pycodestyle errors
|
|
186
|
+
"W", # pycodestyle warnings
|
|
187
|
+
"F", # pyflakes
|
|
188
|
+
"I", # isort
|
|
189
|
+
"B", # flake8-bugbear
|
|
190
|
+
"C4", # flake8-comprehensions
|
|
191
|
+
"UP", # pyupgrade
|
|
192
|
+
]
|
|
193
|
+
ignore = [
|
|
194
|
+
"E501", # line too long (handled by black)
|
|
195
|
+
"B008", # do not perform function calls in argument defaults
|
|
196
|
+
"C901", # too complex
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
[tool.ruff.per-file-ignores]
|
|
200
|
+
"__init__.py" = ["F401"] # unused imports
|