fsspec-lamindb 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,23 @@
1
+ """Read-only fsspec filesystem for LaminDB instances, with nf-lamin compatible URIs.
2
+
3
+ Installing the package registers the ``lamin`` protocol with fsspec.
4
+
5
+ Examples
6
+ --------
7
+ >>> import fsspec
8
+ >>> fs = fsspec.filesystem("lamin")
9
+ >>> fs.ls("lamin://laminlabs/lamindata", detail=False)
10
+ ['laminlabs/lamindata/artifact']
11
+ >>> fs.cat_file("lamin://laminlabs/lamindata/artifact/K415DrXcuPiJmXlX/meta.csv")[:8]
12
+ b',species'
13
+ """
14
+
15
+ from ._hub import LaminAPIError
16
+ from ._version import __version__ as __version__
17
+ from .core import LaminDBFileSystem, LaminFile
18
+
19
+ __all__ = [
20
+ "LaminAPIError",
21
+ "LaminDBFileSystem",
22
+ "LaminFile",
23
+ ]
@@ -0,0 +1,148 @@
1
+ """Paths, targets, and other helpers of the filesystem."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+ from dataclasses import dataclass, field
7
+ from typing import Any
8
+
9
+ from ._hub import Instance
10
+ from ._records import Storage
11
+
12
+ PROTOCOL = "lamin"
13
+ ARTIFACT = "artifact"
14
+
15
+ Listing = dict[str, dict[str, Any]]
16
+
17
+
18
+ @dataclass
19
+ class _Target:
20
+ """What a path refers to: its entry and, for data, the storage that holds it.
21
+
22
+ Attributes
23
+ ----------
24
+ info : dict
25
+ The fsspec info of the entry.
26
+ storage : Storage or None
27
+ The storage location that holds the data of the entry, if any.
28
+ """
29
+
30
+ info: dict[str, Any]
31
+ storage: Storage | None = None
32
+
33
+ @property
34
+ def uri(self) -> str | None:
35
+ return self.info.get("uri")
36
+
37
+ @property
38
+ def is_dir(self) -> bool:
39
+ return self.info["type"] == "directory"
40
+
41
+ def location(self) -> tuple[Storage, str]:
42
+ """Return the storage and URI that hold the data of the entry.
43
+
44
+ Returns
45
+ -------
46
+ storage : Storage
47
+ The storage location.
48
+ uri : str
49
+ The URI of the data.
50
+
51
+ Raises
52
+ ------
53
+ FileNotFoundError
54
+ If the storage or URI of the entry is unknown.
55
+ """
56
+ uri = self.uri
57
+ if self.storage is None or uri is None:
58
+ raise FileNotFoundError(f"the storage of {self.info['name']} is unknown")
59
+ return self.storage, uri
60
+
61
+
62
+ @dataclass
63
+ class _State:
64
+ """An instance and the branches visible in it.
65
+
66
+ Attributes
67
+ ----------
68
+ instance : Instance
69
+ The LaminDB instance.
70
+ branch_ids : list of int
71
+ Ids of the branches whose records are visible.
72
+ branch_id : int or None
73
+ Id of the branch selected in addition to ``main``, if any.
74
+ """
75
+
76
+ instance: Instance
77
+ branch_ids: list[int]
78
+ # the branch selected in addition to main
79
+ branch_id: int | None = None
80
+
81
+ @property
82
+ def slug(self) -> str:
83
+ return self.instance.slug
84
+
85
+ def prefer(self, records: list[dict[str, Any]]) -> list[dict[str, Any]]:
86
+ """Order records so that later ones win conflicts.
87
+
88
+ Records of the selected branch win over those of ``main``, newer records win over
89
+ older ones.
90
+
91
+ Parameters
92
+ ----------
93
+ records : list of dict
94
+ The records to order.
95
+
96
+ Returns
97
+ -------
98
+ list of dict
99
+ The records, least preferred first.
100
+ """
101
+ selected = self.branch_id
102
+
103
+ def rank(record: dict[str, Any]) -> tuple[bool, int]:
104
+ return selected is not None and record.get("branch_id") == selected, record["id"]
105
+
106
+ return sorted(records, key=rank)
107
+
108
+
109
+ @dataclass
110
+ class _Folder:
111
+ """A folder artifact, whose content is listed from its storage.
112
+
113
+ Attributes
114
+ ----------
115
+ path : str
116
+ Path of the folder artifact.
117
+ info : dict
118
+ The fsspec info of the folder artifact.
119
+ storage : Storage
120
+ The storage location that holds the folder.
121
+ registered : float
122
+ When the folder artifact was registered, as a :func:`time.monotonic` timestamp.
123
+ """
124
+
125
+ path: str
126
+ info: dict[str, Any]
127
+ storage: Storage
128
+ registered: float = field(default_factory=time.monotonic)
129
+
130
+ @property
131
+ def uri(self) -> str:
132
+ return self.info["uri"]
133
+
134
+
135
+ def _parts(path: str) -> list[str]:
136
+ return path.split("/") if path else []
137
+
138
+
139
+ def _parent(path: str) -> str:
140
+ return path.rsplit("/", 1)[0] if "/" in path else ""
141
+
142
+
143
+ def _join_uri(uri: str, rel: str) -> str:
144
+ return f"{uri.rstrip('/')}/{rel}" if rel else uri
145
+
146
+
147
+ def _sorted(listing: Listing) -> list[dict[str, Any]]:
148
+ return sorted(listing.values(), key=lambda entry: entry["name"])