fsspec-lamindb 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.
- fsspec_lamindb-0.1.0/.gitignore +13 -0
- fsspec_lamindb-0.1.0/LICENSE +21 -0
- fsspec_lamindb-0.1.0/PKG-INFO +371 -0
- fsspec_lamindb-0.1.0/README.md +333 -0
- fsspec_lamindb-0.1.0/pyproject.toml +106 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/__init__.py +23 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/_common.py +148 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/_hub.py +797 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/_records.py +178 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/_storage.py +461 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/_version.py +8 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/core.py +1312 -0
- fsspec_lamindb-0.1.0/src/fsspec_lamindb/py.typed +0 -0
- fsspec_lamindb-0.1.0/tests/conftest.py +113 -0
- fsspec_lamindb-0.1.0/tests/fakehub.py +534 -0
- fsspec_lamindb-0.1.0/tests/test_filesystem.py +815 -0
- fsspec_lamindb-0.1.0/tests/test_hub.py +337 -0
- fsspec_lamindb-0.1.0/tests/test_lamindb_setup.py +41 -0
- fsspec_lamindb-0.1.0/tests/test_live.py +103 -0
- fsspec_lamindb-0.1.0/tests/test_storage.py +181 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andreas Poehlmann
|
|
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.
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: fsspec-lamindb
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Read-only fsspec filesystem for LaminDB instances: lamin://<owner>/<instance>/... URIs resolved through the LaminHub REST API.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ap--/fsspec-lamindb
|
|
6
|
+
Project-URL: Issues, https://github.com/ap--/fsspec-lamindb/issues
|
|
7
|
+
Project-URL: Source, https://github.com/ap--/fsspec-lamindb
|
|
8
|
+
Project-URL: Changelog, https://github.com/ap--/fsspec-lamindb/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Andreas Poehlmann <andreas@poehlmann.io>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: filesystem,fsspec,lamindb,laminhub
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Framework :: AsyncIO
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
24
|
+
Classifier: Topic :: System :: Filesystems
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Requires-Dist: aiohttp>=3.9
|
|
28
|
+
Requires-Dist: fsspec>=2024.6.1
|
|
29
|
+
Requires-Dist: s3fs>=2024.6.1
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: gcsfs>=2024.6.1; extra == 'all'
|
|
32
|
+
Requires-Dist: huggingface-hub>=0.20; extra == 'all'
|
|
33
|
+
Provides-Extra: gcs
|
|
34
|
+
Requires-Dist: gcsfs>=2024.6.1; extra == 'gcs'
|
|
35
|
+
Provides-Extra: hf
|
|
36
|
+
Requires-Dist: huggingface-hub>=0.20; extra == 'hf'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# fsspec-lamindb
|
|
40
|
+
|
|
41
|
+
[](https://pypi.org/project/fsspec-lamindb/)
|
|
42
|
+
[](https://github.com/ap--/fsspec-lamindb/blob/main/LICENSE)
|
|
43
|
+
[](https://pypi.org/project/fsspec-lamindb/)
|
|
44
|
+
|
|
45
|
+
[](https://github.com/ap--/fsspec-lamindb/actions/workflows/tests.yml)
|
|
46
|
+
[](https://github.com/ap--/fsspec-lamindb/actions/workflows/lint.yml)
|
|
47
|
+
[](https://github.com/ap--/fsspec-lamindb/issues)
|
|
48
|
+
[](https://github.com/astral-sh/ruff)
|
|
49
|
+
|
|
50
|
+
fsspec-lamindb is a Python library that provides a read-only
|
|
51
|
+
[`filesystem_spec`][fsspec] filesystem for [LaminDB][lamindb] instances. Its
|
|
52
|
+
`lamin://` URIs are compatible with [nf-lamin][nf-lamin].
|
|
53
|
+
|
|
54
|
+
[fsspec]: https://filesystem-spec.readthedocs.io/en/latest/intro.html
|
|
55
|
+
[lamindb]: https://docs.lamin.ai
|
|
56
|
+
[nf-lamin]: https://github.com/laminlabs/nf-lamin
|
|
57
|
+
|
|
58
|
+
The package doesn't depend on `lamindb`, `lamindb-core` or `lamindb-setup`:
|
|
59
|
+
|
|
60
|
+
- **Metadata** comes from the [LaminHub REST API][lamin-rest].
|
|
61
|
+
- **Data** is read with the fsspec filesystem of each storage location, such as
|
|
62
|
+
`s3fs`, `gcsfs`, Hugging Face or HTTP.
|
|
63
|
+
- **Credentials** for S3 storage that Lamin manages are temporary credentials
|
|
64
|
+
from LaminHub.
|
|
65
|
+
|
|
66
|
+
[lamin-rest]: https://docs.lamin.ai/rest
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
Install the latest version of `fsspec-lamindb` with pip. S3 and HTTP(S) storage
|
|
72
|
+
locations work out of the box. For other storage locations, you have to install
|
|
73
|
+
additional packages, which are available as extras:
|
|
74
|
+
|
|
75
|
+
### PyPI
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
python -m pip install fsspec-lamindb
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Extras
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
python -m pip install "fsspec-lamindb[gcs]" # + Google Cloud Storage (gcsfs)
|
|
85
|
+
python -m pip install "fsspec-lamindb[hf]" # + Hugging Face (huggingface_hub)
|
|
86
|
+
python -m pip install "fsspec-lamindb[all]" # all of the above
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Adding fsspec-lamindb to your project
|
|
90
|
+
|
|
91
|
+
Below is a `pyproject.toml` based example for adding `fsspec-lamindb` to your
|
|
92
|
+
project as a dependency if you want to read from S3, HTTP(S) and Google Cloud
|
|
93
|
+
Storage locations:
|
|
94
|
+
|
|
95
|
+
```toml
|
|
96
|
+
[project]
|
|
97
|
+
name = "myproject"
|
|
98
|
+
requires-python = ">=3.11"
|
|
99
|
+
dependencies = [
|
|
100
|
+
"fsspec-lamindb[gcs]>=0.1.0",
|
|
101
|
+
]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Installing the package registers the `lamin://` protocol with fsspec, so
|
|
105
|
+
`fsspec.filesystem("lamin")` and `fsspec.open("lamin://...")` work without
|
|
106
|
+
importing `fsspec_lamindb` first.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## Basic Usage
|
|
110
|
+
|
|
111
|
+
```pycon
|
|
112
|
+
# pip install fsspec-lamindb
|
|
113
|
+
>>> import fsspec
|
|
114
|
+
>>>
|
|
115
|
+
>>> fs = fsspec.filesystem("lamin") # uses $LAMIN_API_KEY if set
|
|
116
|
+
>>> fs.ls("lamin://laminlabs/lamindata", detail=False)
|
|
117
|
+
['laminlabs/lamindata/artifact']
|
|
118
|
+
>>> fs.cat_file("lamin://laminlabs/lamindata/artifact/K415DrXcuPiJmXlX/meta.csv")[:40]
|
|
119
|
+
b',species,file_name,scientist,instrument\n'
|
|
120
|
+
>>> info = fs.info("lamin://laminlabs/lamindata/artifact/K415DrXcuPiJmXlX")
|
|
121
|
+
>>> info["type"], info["uid"], info["n_files"], info["uri"]
|
|
122
|
+
('directory', 'K415DrXcuPiJmXlX5iXI', 52, 's3://lamindata/.lamindb/K415DrXcuPiJmXlX')
|
|
123
|
+
>>> fs.artifact_uri("lamin://laminlabs/lamindata/artifact/K415DrXcuPiJmXlX/meta.csv")
|
|
124
|
+
'lamin://laminlabs/lamindata/artifact/K415DrXcuPiJmXlX5iXI/meta.csv'
|
|
125
|
+
>>> fs.find("lamin://laminlabs/lamindata/artifact/K415DrXcuPiJmXlX")
|
|
126
|
+
['laminlabs/lamindata/artifact/K415DrXcuPiJmXlX/image_collection_1/iris-0337d20a....jpg',
|
|
127
|
+
...]
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Pass the API key as a storage option to any fsspec-aware library:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
import pandas as pd
|
|
135
|
+
|
|
136
|
+
df = pd.read_parquet(
|
|
137
|
+
"lamin://laminlabs/lamindata/artifact/k2Mo0c0rRWaaHEOB",
|
|
138
|
+
storage_options={"api_key": "..."},
|
|
139
|
+
)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Public instances can be read without an API key. Pass `api_key=""` to read
|
|
143
|
+
anonymously even if `LAMIN_API_KEY` is set.
|
|
144
|
+
|
|
145
|
+
Prefer the `LAMIN_API_KEY` environment variable to the `api_key` option. Like
|
|
146
|
+
all storage options, an `api_key` becomes part of pickles of the filesystem and
|
|
147
|
+
of `fs.to_json()`, e.g. in kerchunk references or intake catalogs.
|
|
148
|
+
`fs.to_json(include_password=False)` leaves out the API key and the
|
|
149
|
+
credentials in `remote_options`.
|
|
150
|
+
|
|
151
|
+
### Async usage
|
|
152
|
+
|
|
153
|
+
In async mode, use the filesystem as an async context manager, or call
|
|
154
|
+
`await fs.close()`, to close its sessions when you're done:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
import asyncio
|
|
158
|
+
|
|
159
|
+
from fsspec_lamindb import LaminDBFileSystem
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
async def main():
|
|
163
|
+
path = "lamin://laminlabs/lamindata/artifact/K415DrXcuPiJmXlX/meta.csv"
|
|
164
|
+
async with LaminDBFileSystem(asynchronous=True) as fs:
|
|
165
|
+
return await fs._cat_file(path)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
asyncio.run(main())
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Python API
|
|
172
|
+
|
|
173
|
+
The package exports three names; everything else is private:
|
|
174
|
+
|
|
175
|
+
- `LaminDBFileSystem`, the filesystem of the `lamin` protocol.
|
|
176
|
+
- `LaminFile`, the files that `fs.open()` returns.
|
|
177
|
+
- `LaminAPIError`, an `OSError` raised for unexpected responses of LaminHub.
|
|
178
|
+
Missing paths raise `FileNotFoundError`, and missing permissions
|
|
179
|
+
`PermissionError`.
|
|
180
|
+
|
|
181
|
+
### URIs
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
lamin://
|
|
185
|
+
└── <owner>/ owners of the instances you can access
|
|
186
|
+
└── <instance>/ instances of an owner
|
|
187
|
+
└── artifact/<uid>[/<subpath>] any artifact by uid, as in nf-lamin
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
- `artifact/<uid>` addresses any artifact the way nf-lamin does. A 20-character
|
|
191
|
+
uid is that exact version. A 16-character uid addresses the version family and
|
|
192
|
+
resolves to the latest version. Listing `artifact/` shows every artifact on the
|
|
193
|
+
visible branches by its 20-character uid. That includes all versions, artifacts
|
|
194
|
+
without a key, and the artifacts lamindb creates to track runs
|
|
195
|
+
(`kind="__lamindb_run__"` or `"__lamindb_config__"`).
|
|
196
|
+
- Folder artifacts, such as `.zarr` stores, are directories. Their content is
|
|
197
|
+
listed from their storage, and `<subpath>` addresses the files and
|
|
198
|
+
directories inside them.
|
|
199
|
+
- `fs.artifact_uri(path)` resolves a path to the `artifact/<uid>` URI of the
|
|
200
|
+
exact artifact version, e.g. to pin the version that a 16-character uid
|
|
201
|
+
resolves to now. Paths inside a folder artifact keep their path inside it, as
|
|
202
|
+
in `lamin://<owner>/<instance>/artifact/<uid>/<subpath>`. Pass
|
|
203
|
+
`version_family=True` for the 16-character uid, which resolves to the latest
|
|
204
|
+
version. Paths that are neither an artifact nor inside one, such as
|
|
205
|
+
`artifact/` itself, raise `ValueError`.
|
|
206
|
+
- `ls("lamin://")` lists the owners of the instances your account can access,
|
|
207
|
+
and `ls("lamin://<owner>")` lists those instances. Other owners don't exist
|
|
208
|
+
in the filesystem, and anonymous callers can't list any. Public instances can
|
|
209
|
+
still be opened directly as `lamin://<owner>/<instance>`.
|
|
210
|
+
|
|
211
|
+
Artifact entries carry record metadata: `uid`, `key`, `suffix`, `hash`, `kind`,
|
|
212
|
+
`otype`, `description`, `version_tag`, `is_latest`, `n_files`, `n_observations`,
|
|
213
|
+
`created_at`, `updated_at`. They also carry `storage` (the storage root) and
|
|
214
|
+
`uri` (the location of the data). `fs.modified()` and `fs.created()` return the
|
|
215
|
+
record's timestamps. `fs.ukey()` and `fs.checksum()` are derived from the
|
|
216
|
+
artifact's content hash, so caches like `simplecache::` only fetch the data
|
|
217
|
+
again when it changes. Files inside folder artifacts use those of their
|
|
218
|
+
storage filesystem.
|
|
219
|
+
|
|
220
|
+
### Storage options
|
|
221
|
+
|
|
222
|
+
| Option | Default | Description |
|
|
223
|
+
| --- | --- | --- |
|
|
224
|
+
| `api_key` | `$LAMIN_API_KEY` | Lamin API key. Pass `""` for anonymous access. |
|
|
225
|
+
| `api_url` | `$LAMIN_API_URL`, else `https://aws.us-east-1.lamin.ai/api` | LaminHub API used to look up instances. Any LaminHub API finds any instance. Requests then go to the API in the instance's settings. |
|
|
226
|
+
| `hub_url` | `$LAMIN_HUB_URL`, else `https://hub.lamin.ai` | LaminHub, which grants storage credentials. |
|
|
227
|
+
| `hub_anon_key` | `$LAMIN_HUB_ANON_KEY`, else the public key of `hub.lamin.ai` | LaminHub's public key. |
|
|
228
|
+
| `branch` | `None` | Name or uid of a branch to show on top of `main`, like `lamin switch`. Its artifacts are listed under `artifact/`, and its versions win when a 16-character uid resolves to the latest version. |
|
|
229
|
+
| `storage_protocols` | `["s3", "gs", "hf", "http", "https"]` | Protocols of the storage locations that may be read. The list replaces the default. Add `"file"` to read local storage locations. |
|
|
230
|
+
| `remote_options` | `{}` | Options of the storage filesystems by protocol or storage root, e.g. `{"s3": {"profile": "x"}, "s3://bucket": {"profile": "y"}}`. Options for a root are merged over those for its protocol, and `gcs` is the same as `gs`. S3 credentials given here replace those from LaminHub. |
|
|
231
|
+
| `timeout` | `60` | Timeout of each request to LaminHub in seconds. |
|
|
232
|
+
| `max_concurrency` | `8` | Maximum number of result pages of a query fetched in parallel. |
|
|
233
|
+
| `max_requests` | `16` | Maximum number of concurrent requests to LaminHub. |
|
|
234
|
+
| `max_cached_paths` | `None` | Maximum number of paths whose lookups are cached besides the listings, e.g. the chunks of a Zarr store. The least recently used are dropped first. `None` for no limit. |
|
|
235
|
+
| `trusted_hosts` | `None` | Hosts your access token may be sent to besides `*.lamin.ai` and the host of `api_url`, e.g. `["lamin.example.com", "*.example.org"]` for on-premises deployments. |
|
|
236
|
+
|
|
237
|
+
The standard fsspec options are also supported: `asynchronous`, `loop`,
|
|
238
|
+
`use_listings_cache`, `listings_expiry_time`, and `skip_instance_cache`.
|
|
239
|
+
Listings expire after an hour (`listings_expiry_time=3600`), as artifacts are
|
|
240
|
+
added and 16-character uids resolve to their latest version. Pass
|
|
241
|
+
`listings_expiry_time=None` to keep them until `fs.invalidate_cache()` is
|
|
242
|
+
called. Use `fs.invalidate_cache()` or `fs.ls(path, refresh=True)` to pick up
|
|
243
|
+
changes sooner.
|
|
244
|
+
|
|
245
|
+
`use_listings_cache` and `listings_expiry_time` apply to everything the
|
|
246
|
+
filesystem caches from LaminHub: listings, storage locations, and folder
|
|
247
|
+
artifacts. Only the instance settings and the selected branch are kept
|
|
248
|
+
for the lifetime of the filesystem. With `use_listings_cache=False`, each call
|
|
249
|
+
still fetches what it needs only once.
|
|
250
|
+
|
|
251
|
+
### Storage access
|
|
252
|
+
|
|
253
|
+
Each storage location gets its own fsspec filesystem, created on first use:
|
|
254
|
+
|
|
255
|
+
| Storage | Credentials |
|
|
256
|
+
| --- | --- |
|
|
257
|
+
| S3 that Lamin manages | Temporary credentials from LaminHub, renewed before they expire, or once when S3 rejects them. They're also issued to anonymous callers for public instances. |
|
|
258
|
+
| Other S3 buckets | Your AWS credentials (environment, `~/.aws`, …). Without any, the bucket is read anonymously. |
|
|
259
|
+
| GCS | Your Google credentials: `GOOGLE_APPLICATION_CREDENTIALS`, `gcloud auth application-default login`, or the service account on Google Cloud. Without any, the bucket is read anonymously. |
|
|
260
|
+
| Hugging Face, HTTP(S) | Your default credentials for the filesystem, e.g. `HF_TOKEN`. |
|
|
261
|
+
|
|
262
|
+
The resulting S3 options include the storage's region. LaminHub only issues
|
|
263
|
+
credentials for S3.
|
|
264
|
+
|
|
265
|
+
Storage locations come from the records of an instance, so whoever owns an
|
|
266
|
+
instance chooses what reading it accesses. That's why only the protocols in
|
|
267
|
+
`storage_protocols` are read; others raise `PermissionError`. Local storage
|
|
268
|
+
locations only exist on the machine that created them. To read them, pass the
|
|
269
|
+
full list, e.g. `storage_protocols=["s3", "gs", "hf", "http", "https", "file"]`.
|
|
270
|
+
|
|
271
|
+
Without Google credentials, gcsfs waits 15 to 30 seconds for the metadata
|
|
272
|
+
server of Google Compute Engine before it reads anonymously. So the lamin
|
|
273
|
+
filesystem checks for credentials without network requests: the variable
|
|
274
|
+
`GOOGLE_APPLICATION_CREDENTIALS`, gcloud's application default credentials,
|
|
275
|
+
gcsfs's token cache, and whether it runs on Google Cloud. If there are none, it
|
|
276
|
+
passes `token="anon"`. Set a `token` in `remote_options`, e.g.
|
|
277
|
+
`{"gs": {"token": "cloud"}}`, if the check misses your credentials. Set
|
|
278
|
+
`NO_GCE_CHECK=true` to never use the credentials of the metadata server, which
|
|
279
|
+
also speeds up gcsfs elsewhere.
|
|
280
|
+
|
|
281
|
+
The storage filesystems are created with `use_listings_cache=False`, as the
|
|
282
|
+
lamin filesystem caches and refreshes the listings itself. Set it in
|
|
283
|
+
`remote_options` to change that.
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
## How it works
|
|
287
|
+
|
|
288
|
+
- The filesystem is an fsspec `AsyncFileSystem` built on aiohttp. Async
|
|
289
|
+
consumers such as zarr v3, kerchunk, or `fs.cat` of many files get concurrency
|
|
290
|
+
without threads. The storage filesystems run on the same event loop.
|
|
291
|
+
- An API key is exchanged for an access token, which is refreshed when it
|
|
292
|
+
expires. Transient errors like `502` and `429` are retried.
|
|
293
|
+
- The access token gives access to your whole account. The API URLs of
|
|
294
|
+
instances and storages come from their settings, so the token is only sent
|
|
295
|
+
over HTTPS (or HTTP to localhost) to `*.lamin.ai`, the host of `api_url`, and
|
|
296
|
+
`trusted_hosts`. Other requests fail with `PermissionError`.
|
|
297
|
+
- The API returns at most 200 records per request, so listing `artifact/`
|
|
298
|
+
fetches all artifacts of an instance in parallel pages. Looking up the listed
|
|
299
|
+
artifacts afterwards needs no further requests.
|
|
300
|
+
- `info()`, `open()`, and `cat()` of a single path only look up that artifact.
|
|
301
|
+
- `find()`, and so `glob("**")`, `du()`, and `get(recursive=True)`, search a
|
|
302
|
+
folder artifact with a single recursive search of its storage. A search of an
|
|
303
|
+
instance searches `artifact/`, i.e. every version of every artifact.
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
## Known limitations
|
|
307
|
+
|
|
308
|
+
- Read-only. Writing, copying, moving, deleting, and creating directories raise
|
|
309
|
+
`NotImplementedError` before any request is sent.
|
|
310
|
+
- Listings are fetched in pages of 200 records. If records are deleted while a
|
|
311
|
+
listing is being fetched, another record can be missing from that listing.
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
## Future development
|
|
315
|
+
|
|
316
|
+
The `lamin://` URIs follow nf-lamin, which only addresses artifacts by uid.
|
|
317
|
+
Once Lamin defines its URI schema further, fsspec-lamindb can support more of
|
|
318
|
+
it, for example:
|
|
319
|
+
|
|
320
|
+
- URIs that reference artifacts by their `key` instead of their uid.
|
|
321
|
+
- Writes, e.g. saving files as new artifacts or as new versions of existing
|
|
322
|
+
ones.
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
## Contributing
|
|
326
|
+
|
|
327
|
+
Contributions are very welcome. To set up a development environment, install
|
|
328
|
+
[uv][uv] and [just][just] and run:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
uv sync
|
|
332
|
+
just test # unit tests against a fake LaminHub
|
|
333
|
+
just test-live # tests and doc examples against laminlabs/lamindata
|
|
334
|
+
just test-lamindb-setup # LaminHub defaults against the latest lamindb-setup
|
|
335
|
+
just lint # lockfile, ruff, and ty
|
|
336
|
+
just fmt # format and fix the code
|
|
337
|
+
just coverage # unit tests with a branch coverage report
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Run `just` to list all recipes. Run `pre-commit install` to run the same checks
|
|
341
|
+
as `just lint` before each commit. Set `FSSPEC_LAMINDB_TEST_INSTANCE`,
|
|
342
|
+
`LAMIN_API_KEY`, and `LAMIN_API_URL` to run the live tests against another
|
|
343
|
+
instance. Docstrings follow the [numpydoc][numpydoc] style.
|
|
344
|
+
|
|
345
|
+
[uv]: https://docs.astral.sh/uv/
|
|
346
|
+
[just]: https://just.systems/
|
|
347
|
+
[numpydoc]: https://numpydoc.readthedocs.io/en/latest/format.html
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
## Changelog
|
|
351
|
+
|
|
352
|
+
See [CHANGELOG.md](https://github.com/ap--/fsspec-lamindb/blob/main/CHANGELOG.md).
|
|
353
|
+
To report a vulnerability, see
|
|
354
|
+
[SECURITY.md](https://github.com/ap--/fsspec-lamindb/blob/main/SECURITY.md).
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
## License
|
|
358
|
+
|
|
359
|
+
Distributed under the terms of the [MIT license][license],
|
|
360
|
+
*fsspec-lamindb* is free and open source software.
|
|
361
|
+
|
|
362
|
+
[license]: https://github.com/ap--/fsspec-lamindb/blob/main/LICENSE
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
## Issues
|
|
366
|
+
|
|
367
|
+
If you encounter any problems, please [file an issue][issues] along with a
|
|
368
|
+
detailed description. We are always happy to help with any problems you might
|
|
369
|
+
encounter.
|
|
370
|
+
|
|
371
|
+
[issues]: https://github.com/ap--/fsspec-lamindb/issues
|