atdata 0.2.2b1__py3-none-any.whl → 0.3.0b1__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.
- atdata/.gitignore +1 -0
- atdata/__init__.py +31 -1
- atdata/_cid.py +29 -35
- atdata/_exceptions.py +168 -0
- atdata/_helpers.py +33 -17
- atdata/_hf_api.py +109 -59
- atdata/_logging.py +70 -0
- atdata/_protocols.py +74 -132
- atdata/_schema_codec.py +38 -41
- atdata/_sources.py +57 -64
- atdata/_stub_manager.py +31 -26
- atdata/_type_utils.py +47 -7
- atdata/atmosphere/__init__.py +31 -24
- atdata/atmosphere/_types.py +11 -11
- atdata/atmosphere/client.py +11 -8
- atdata/atmosphere/lens.py +27 -30
- atdata/atmosphere/records.py +34 -39
- atdata/atmosphere/schema.py +35 -31
- atdata/atmosphere/store.py +16 -20
- atdata/cli/__init__.py +163 -168
- atdata/cli/diagnose.py +12 -8
- atdata/cli/inspect.py +69 -0
- atdata/cli/local.py +5 -2
- atdata/cli/preview.py +63 -0
- atdata/cli/schema.py +109 -0
- atdata/dataset.py +678 -533
- atdata/lens.py +85 -83
- atdata/local/__init__.py +71 -0
- atdata/local/_entry.py +157 -0
- atdata/local/_index.py +940 -0
- atdata/local/_repo_legacy.py +218 -0
- atdata/local/_s3.py +349 -0
- atdata/local/_schema.py +380 -0
- atdata/manifest/__init__.py +28 -0
- atdata/manifest/_aggregates.py +156 -0
- atdata/manifest/_builder.py +163 -0
- atdata/manifest/_fields.py +154 -0
- atdata/manifest/_manifest.py +146 -0
- atdata/manifest/_query.py +150 -0
- atdata/manifest/_writer.py +74 -0
- atdata/promote.py +20 -24
- atdata/providers/__init__.py +25 -0
- atdata/providers/_base.py +140 -0
- atdata/providers/_factory.py +69 -0
- atdata/providers/_postgres.py +214 -0
- atdata/providers/_redis.py +171 -0
- atdata/providers/_sqlite.py +191 -0
- atdata/repository.py +323 -0
- atdata/testing.py +337 -0
- {atdata-0.2.2b1.dist-info → atdata-0.3.0b1.dist-info}/METADATA +5 -1
- atdata-0.3.0b1.dist-info/RECORD +54 -0
- atdata/local.py +0 -1707
- atdata-0.2.2b1.dist-info/RECORD +0 -28
- {atdata-0.2.2b1.dist-info → atdata-0.3.0b1.dist-info}/WHEEL +0 -0
- {atdata-0.2.2b1.dist-info → atdata-0.3.0b1.dist-info}/entry_points.txt +0 -0
- {atdata-0.2.2b1.dist-info → atdata-0.3.0b1.dist-info}/licenses/LICENSE +0 -0
atdata/testing.py
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""Testing utilities for atdata.
|
|
2
|
+
|
|
3
|
+
Provides mock clients, dataset factories, and pytest fixtures for writing
|
|
4
|
+
tests against atdata without requiring external services (Redis, S3, ATProto PDS).
|
|
5
|
+
|
|
6
|
+
Usage::
|
|
7
|
+
|
|
8
|
+
import atdata.testing as at_test
|
|
9
|
+
|
|
10
|
+
# Create a dataset from samples
|
|
11
|
+
ds = at_test.make_dataset(tmp_path, [sample1, sample2])
|
|
12
|
+
|
|
13
|
+
# Generate random samples
|
|
14
|
+
samples = at_test.make_samples(MyType, n=100)
|
|
15
|
+
|
|
16
|
+
# Use mock atmosphere client
|
|
17
|
+
client = at_test.MockAtmosphereClient()
|
|
18
|
+
|
|
19
|
+
# Use in-memory index (SQLite backed, temporary)
|
|
20
|
+
index = at_test.mock_index(tmp_path)
|
|
21
|
+
|
|
22
|
+
Pytest fixtures (available when ``atdata`` is installed)::
|
|
23
|
+
|
|
24
|
+
def test_something(mock_atmosphere):
|
|
25
|
+
client = mock_atmosphere
|
|
26
|
+
client.login("user", "pass")
|
|
27
|
+
...
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import tempfile
|
|
33
|
+
import uuid
|
|
34
|
+
from dataclasses import fields as dc_fields
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
from typing import Any, Sequence, Type, TypeVar
|
|
37
|
+
|
|
38
|
+
import numpy as np
|
|
39
|
+
import webdataset as wds
|
|
40
|
+
|
|
41
|
+
import atdata
|
|
42
|
+
from atdata import Dataset, PackableSample
|
|
43
|
+
from atdata.local._index import Index
|
|
44
|
+
from atdata.providers._sqlite import SqliteProvider
|
|
45
|
+
|
|
46
|
+
ST = TypeVar("ST")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
# Mock Atmosphere Client
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class MockAtmosphereClient:
|
|
55
|
+
"""In-memory mock of ``AtmosphereClient`` for testing.
|
|
56
|
+
|
|
57
|
+
Simulates login, schema publishing, dataset publishing, and record
|
|
58
|
+
retrieval without requiring a live ATProto PDS.
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
>>> client = MockAtmosphereClient()
|
|
62
|
+
>>> client.login("alice.test", "password")
|
|
63
|
+
>>> client.did
|
|
64
|
+
'did:plc:mock000000000000'
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
did: str = "did:plc:mock000000000000",
|
|
70
|
+
handle: str = "test.mock.social",
|
|
71
|
+
) -> None:
|
|
72
|
+
self.did = did
|
|
73
|
+
self.handle = handle
|
|
74
|
+
self._logged_in = False
|
|
75
|
+
self._records: dict[str, dict[str, Any]] = {}
|
|
76
|
+
self._schemas: dict[str, dict[str, Any]] = {}
|
|
77
|
+
self._datasets: dict[str, dict[str, Any]] = {}
|
|
78
|
+
self._blobs: dict[str, bytes] = {}
|
|
79
|
+
self._session_string = "mock-session-string"
|
|
80
|
+
self._call_log: list[tuple[str, dict[str, Any]]] = []
|
|
81
|
+
|
|
82
|
+
def login(self, handle: str, password: str) -> dict[str, Any]:
|
|
83
|
+
"""Simulate login. Always succeeds."""
|
|
84
|
+
self._logged_in = True
|
|
85
|
+
self.handle = handle
|
|
86
|
+
self._call_log.append(("login", {"handle": handle}))
|
|
87
|
+
return {"did": self.did, "handle": self.handle}
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def is_authenticated(self) -> bool:
|
|
91
|
+
return self._logged_in
|
|
92
|
+
|
|
93
|
+
def export_session_string(self) -> str:
|
|
94
|
+
return self._session_string
|
|
95
|
+
|
|
96
|
+
def create_record(
|
|
97
|
+
self,
|
|
98
|
+
collection: str,
|
|
99
|
+
record: dict[str, Any],
|
|
100
|
+
rkey: str | None = None,
|
|
101
|
+
) -> str:
|
|
102
|
+
"""Simulate creating a record. Returns a mock AT URI."""
|
|
103
|
+
key = rkey or uuid.uuid4().hex[:12]
|
|
104
|
+
uri = f"at://{self.did}/{collection}/{key}"
|
|
105
|
+
self._records[uri] = record
|
|
106
|
+
self._call_log.append(
|
|
107
|
+
("create_record", {"collection": collection, "rkey": key, "uri": uri})
|
|
108
|
+
)
|
|
109
|
+
return uri
|
|
110
|
+
|
|
111
|
+
def get_record(self, uri: str) -> dict[str, Any]:
|
|
112
|
+
"""Retrieve a previously created record by URI."""
|
|
113
|
+
if uri not in self._records:
|
|
114
|
+
raise KeyError(f"Record not found: {uri}")
|
|
115
|
+
return self._records[uri]
|
|
116
|
+
|
|
117
|
+
def list_records(self, collection: str) -> list[dict[str, Any]]:
|
|
118
|
+
"""List records for a collection."""
|
|
119
|
+
return [
|
|
120
|
+
{"uri": uri, "value": rec}
|
|
121
|
+
for uri, rec in self._records.items()
|
|
122
|
+
if collection in uri
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
def upload_blob(self, data: bytes) -> dict[str, Any]:
|
|
126
|
+
"""Simulate uploading a blob. Returns a mock blob ref."""
|
|
127
|
+
ref = f"blob:{uuid.uuid4().hex[:16]}"
|
|
128
|
+
self._blobs[ref] = data
|
|
129
|
+
self._call_log.append(("upload_blob", {"ref": ref, "size": len(data)}))
|
|
130
|
+
return {"ref": {"$link": ref}, "mimeType": "application/octet-stream"}
|
|
131
|
+
|
|
132
|
+
def get_blob(self, did: str, cid: str) -> bytes:
|
|
133
|
+
"""Retrieve a previously uploaded blob."""
|
|
134
|
+
if cid not in self._blobs:
|
|
135
|
+
raise KeyError(f"Blob not found: {cid}")
|
|
136
|
+
return self._blobs[cid]
|
|
137
|
+
|
|
138
|
+
def reset(self) -> None:
|
|
139
|
+
"""Clear all stored state."""
|
|
140
|
+
self._records.clear()
|
|
141
|
+
self._schemas.clear()
|
|
142
|
+
self._datasets.clear()
|
|
143
|
+
self._blobs.clear()
|
|
144
|
+
self._call_log.clear()
|
|
145
|
+
self._logged_in = False
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# ---------------------------------------------------------------------------
|
|
149
|
+
# Dataset Factory
|
|
150
|
+
# ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def make_dataset(
|
|
154
|
+
path: Path,
|
|
155
|
+
samples: Sequence[PackableSample],
|
|
156
|
+
*,
|
|
157
|
+
name: str = "test",
|
|
158
|
+
sample_type: type | None = None,
|
|
159
|
+
) -> Dataset:
|
|
160
|
+
"""Create a ``Dataset`` from a list of samples.
|
|
161
|
+
|
|
162
|
+
Writes the samples to a WebDataset tar file in *path* and returns a
|
|
163
|
+
``Dataset`` configured to read them back.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
path: Directory where the tar file will be created.
|
|
167
|
+
samples: Sequence of ``PackableSample`` (or ``@packable``) instances.
|
|
168
|
+
name: Filename prefix for the tar file.
|
|
169
|
+
sample_type: Explicit sample type for the Dataset generic parameter.
|
|
170
|
+
If ``None``, inferred from the first sample.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
A ``Dataset`` ready for iteration.
|
|
174
|
+
|
|
175
|
+
Examples:
|
|
176
|
+
>>> ds = make_dataset(tmp_path, [MySample(x=1), MySample(x=2)])
|
|
177
|
+
>>> assert len(list(ds.ordered())) == 2
|
|
178
|
+
"""
|
|
179
|
+
if not samples:
|
|
180
|
+
raise ValueError("samples must be non-empty")
|
|
181
|
+
|
|
182
|
+
tar_path = path / f"{name}-000000.tar"
|
|
183
|
+
tar_path.parent.mkdir(parents=True, exist_ok=True)
|
|
184
|
+
|
|
185
|
+
with wds.writer.TarWriter(str(tar_path)) as writer:
|
|
186
|
+
for sample in samples:
|
|
187
|
+
writer.write(sample.as_wds)
|
|
188
|
+
|
|
189
|
+
st = sample_type or type(samples[0])
|
|
190
|
+
return Dataset[st](url=str(tar_path))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def make_samples(
|
|
194
|
+
sample_type: Type[ST], n: int = 10, seed: int | None = None
|
|
195
|
+
) -> list[ST]:
|
|
196
|
+
"""Generate *n* random instances of a ``@packable`` sample type.
|
|
197
|
+
|
|
198
|
+
Inspects the dataclass fields and generates appropriate random data:
|
|
199
|
+
- ``str`` fields get ``"field_name_0"``, ``"field_name_1"``, etc.
|
|
200
|
+
- ``int`` fields get sequential integers
|
|
201
|
+
- ``float`` fields get random floats in [0, 1)
|
|
202
|
+
- ``bool`` fields alternate True/False
|
|
203
|
+
- ``bytes`` fields get random 16 bytes
|
|
204
|
+
- NDArray fields get random ``(4, 4)`` float32 arrays
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
sample_type: A ``@packable``-decorated class or ``PackableSample`` subclass.
|
|
208
|
+
n: Number of samples to generate.
|
|
209
|
+
seed: Optional random seed for reproducibility.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
List of *n* sample instances.
|
|
213
|
+
|
|
214
|
+
Examples:
|
|
215
|
+
>>> @atdata.packable
|
|
216
|
+
... class Point:
|
|
217
|
+
... x: float
|
|
218
|
+
... y: float
|
|
219
|
+
... label: str
|
|
220
|
+
>>> points = make_samples(Point, n=5, seed=42)
|
|
221
|
+
>>> len(points)
|
|
222
|
+
5
|
|
223
|
+
"""
|
|
224
|
+
rng = np.random.default_rng(seed)
|
|
225
|
+
result: list[ST] = []
|
|
226
|
+
|
|
227
|
+
for i in range(n):
|
|
228
|
+
kwargs: dict[str, Any] = {}
|
|
229
|
+
for field in dc_fields(sample_type):
|
|
230
|
+
type_str = str(field.type)
|
|
231
|
+
fname = field.name
|
|
232
|
+
|
|
233
|
+
if field.type is str or type_str == "str":
|
|
234
|
+
kwargs[fname] = f"{fname}_{i}"
|
|
235
|
+
elif field.type is int or type_str == "int":
|
|
236
|
+
kwargs[fname] = i
|
|
237
|
+
elif field.type is float or type_str == "float":
|
|
238
|
+
kwargs[fname] = float(rng.random())
|
|
239
|
+
elif field.type is bool or type_str == "bool":
|
|
240
|
+
kwargs[fname] = i % 2 == 0
|
|
241
|
+
elif field.type is bytes or type_str == "bytes":
|
|
242
|
+
kwargs[fname] = rng.bytes(16)
|
|
243
|
+
elif "NDArray" in type_str or "ndarray" in type_str.lower():
|
|
244
|
+
kwargs[fname] = rng.standard_normal((4, 4)).astype(np.float32)
|
|
245
|
+
elif "list" in type_str.lower():
|
|
246
|
+
kwargs[fname] = [f"{fname}_{i}_{j}" for j in range(3)]
|
|
247
|
+
elif "None" in type_str:
|
|
248
|
+
# Optional field — leave at default
|
|
249
|
+
if field.default is not field.default_factory: # type: ignore[attr-defined]
|
|
250
|
+
continue
|
|
251
|
+
else:
|
|
252
|
+
kwargs[fname] = f"{fname}_{i}"
|
|
253
|
+
|
|
254
|
+
result.append(sample_type(**kwargs))
|
|
255
|
+
|
|
256
|
+
return result
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# ---------------------------------------------------------------------------
|
|
260
|
+
# Mock Index
|
|
261
|
+
# ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def mock_index(path: Path | None = None, **kwargs: Any) -> Index:
|
|
265
|
+
"""Create an in-memory SQLite-backed ``Index`` for testing.
|
|
266
|
+
|
|
267
|
+
No Redis or external services required.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
path: Directory for the SQLite database file. If ``None``, uses
|
|
271
|
+
a temporary directory.
|
|
272
|
+
**kwargs: Additional keyword arguments passed to ``Index()``.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
An ``Index`` instance backed by a temporary SQLite database.
|
|
276
|
+
|
|
277
|
+
Examples:
|
|
278
|
+
>>> index = mock_index(tmp_path)
|
|
279
|
+
>>> ref = index.publish_schema(MyType, version="1.0.0")
|
|
280
|
+
"""
|
|
281
|
+
if path is None:
|
|
282
|
+
path = Path(tempfile.mkdtemp())
|
|
283
|
+
db_path = path / "test_index.db"
|
|
284
|
+
provider = SqliteProvider(str(db_path))
|
|
285
|
+
return Index(provider=provider, atmosphere=None, **kwargs)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# ---------------------------------------------------------------------------
|
|
289
|
+
# Pytest plugin (fixtures auto-discovered when atdata is installed)
|
|
290
|
+
# ---------------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
try:
|
|
293
|
+
import pytest
|
|
294
|
+
|
|
295
|
+
@pytest.fixture
|
|
296
|
+
def mock_atmosphere():
|
|
297
|
+
"""Provide a fresh ``MockAtmosphereClient`` for each test."""
|
|
298
|
+
client = MockAtmosphereClient()
|
|
299
|
+
client.login("test.mock.social", "test-password")
|
|
300
|
+
yield client
|
|
301
|
+
client.reset()
|
|
302
|
+
|
|
303
|
+
@pytest.fixture
|
|
304
|
+
def tmp_dataset(tmp_path: Path):
|
|
305
|
+
"""Provide a small ``Dataset[SharedBasicSample]`` with 10 samples.
|
|
306
|
+
|
|
307
|
+
Uses ``SharedBasicSample`` (name: str, value: int) from the test suite.
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
@atdata.packable
|
|
311
|
+
class _TmpSample:
|
|
312
|
+
name: str
|
|
313
|
+
value: int
|
|
314
|
+
|
|
315
|
+
samples = [_TmpSample(name=f"s{i}", value=i) for i in range(10)]
|
|
316
|
+
return make_dataset(tmp_path, samples, sample_type=_TmpSample)
|
|
317
|
+
|
|
318
|
+
@pytest.fixture
|
|
319
|
+
def tmp_index(tmp_path: Path):
|
|
320
|
+
"""Provide a fresh SQLite-backed ``Index`` for each test."""
|
|
321
|
+
return mock_index(tmp_path)
|
|
322
|
+
|
|
323
|
+
except ImportError:
|
|
324
|
+
# pytest not installed — skip fixture registration
|
|
325
|
+
_no_pytest = True
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# ---------------------------------------------------------------------------
|
|
329
|
+
# Public API
|
|
330
|
+
# ---------------------------------------------------------------------------
|
|
331
|
+
|
|
332
|
+
__all__ = [
|
|
333
|
+
"MockAtmosphereClient",
|
|
334
|
+
"make_dataset",
|
|
335
|
+
"make_samples",
|
|
336
|
+
"mock_index",
|
|
337
|
+
]
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atdata
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0b1
|
|
4
4
|
Summary: A loose federation of distributed, typed datasets
|
|
5
5
|
Author-email: Maxine Levesque <hello@maxine.science>, "Maxine @ Forecast Bio" <maxine@forecast.bio>
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Requires-Python: >=3.12
|
|
8
8
|
Requires-Dist: atproto>=0.0.65
|
|
9
|
+
Requires-Dist: boto3>=1.41.5
|
|
9
10
|
Requires-Dist: fastparquet>=2024.11.0
|
|
10
11
|
Requires-Dist: libipld>=3.3.2
|
|
11
12
|
Requires-Dist: msgpack>=1.1.2
|
|
@@ -19,9 +20,12 @@ Requires-Dist: requests>=2.32.5
|
|
|
19
20
|
Requires-Dist: s3fs>=2025.12.0
|
|
20
21
|
Requires-Dist: schemamodels>=0.9.1
|
|
21
22
|
Requires-Dist: tqdm>=4.67.1
|
|
23
|
+
Requires-Dist: typer>=0.21.1
|
|
22
24
|
Requires-Dist: webdataset>=1.0.2
|
|
23
25
|
Provides-Extra: atmosphere
|
|
24
26
|
Requires-Dist: atproto>=0.0.55; extra == 'atmosphere'
|
|
27
|
+
Provides-Extra: postgres
|
|
28
|
+
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
|
|
25
29
|
Description-Content-Type: text/markdown
|
|
26
30
|
|
|
27
31
|
# atdata
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
atdata/.gitignore,sha256=ROcLwaiURIGOAYGFpakac_WEeKS4hH4HxJuscfDGo2s,10
|
|
2
|
+
atdata/__init__.py,sha256=TXEvc6R_VQ4zzjHr9OIqi_hhwfc6OqerVWajtDRwJTA,3249
|
|
3
|
+
atdata/_cid.py,sha256=6wLV_dcQJy5Eb-wld7_h7Kcp7QoVixIqUDIIoSwpQms,3992
|
|
4
|
+
atdata/_exceptions.py,sha256=a2IzmTJqLyIgQ0RkW3KhaaaSDdQJGLoXzuHfEX0DfB4,5390
|
|
5
|
+
atdata/_helpers.py,sha256=e-1lChOY9jvihs5Q04Tp5Rp9oKIoVf5N4wuuwv0Hl64,2224
|
|
6
|
+
atdata/_hf_api.py,sha256=ThNoVDIztbJCLtIKSCol4Tm7Lf1TqbU4E-fFsKt5FaA,24318
|
|
7
|
+
atdata/_logging.py,sha256=Wj9MTe9xCP_awiQYfa7219Fb443Rkwu_jIqM-m2u2GA,2225
|
|
8
|
+
atdata/_protocols.py,sha256=LYeM0eIn5nQ56DssdGFd-CvJFXh9C3YR2GLOSFxg1Kw,14479
|
|
9
|
+
atdata/_schema_codec.py,sha256=OpRs8bfCPGCEJsBKlp8rfndBldco3jwQQ7k9npN-EPQ,14395
|
|
10
|
+
atdata/_sources.py,sha256=A7HMkS_dqN5Sx7rG1nZsO1Laxozt3C65_P2Hiv41VXk,16624
|
|
11
|
+
atdata/_stub_manager.py,sha256=Heh0HAYjVjnkUQcPWAEOrkkEKN3Mi9vTJPA-ZRseFw8,19141
|
|
12
|
+
atdata/_type_utils.py,sha256=mhD0ywXgIEpVaAWpGVKGneUOh0cmI96zKz6g2O1bdg0,3762
|
|
13
|
+
atdata/dataset.py,sha256=ogclAFyeDh8ZGvgiDViiDn_sbkh94rpXgR-jtwFpi6M,41123
|
|
14
|
+
atdata/lens.py,sha256=s6Ebeacth4cF_yCmnH4MuZ6TwQJmUmrFZ3eIh1jQSZI,9914
|
|
15
|
+
atdata/promote.py,sha256=W8I_OCTStKY_Mu1OJvtVyJrWqmXjRQaTQLJ_Id-nBmA,6274
|
|
16
|
+
atdata/repository.py,sha256=5ZlYOw5VQdkuN0rntfw26CA_O_YsZLYMSGaRPPPn9Gc,10205
|
|
17
|
+
atdata/testing.py,sha256=OUPXn8CBuxNVyhj-lgIiw_YkTNrewdEkgFyfwogLH3E,10858
|
|
18
|
+
atdata/atmosphere/__init__.py,sha256=g8larX6DIA4AVFgt-g3vm6Ijsb4vU3YOAFPNCDMd-sk,10064
|
|
19
|
+
atdata/atmosphere/_types.py,sha256=MRhXnmAuQLJPdoq1skrBGXCsaQYdtKG_nA3YlSjwJXY,9595
|
|
20
|
+
atdata/atmosphere/client.py,sha256=acw82w3_cxWbWDtIRvH1VDHGJSroGqhSenFFostXTXo,16210
|
|
21
|
+
atdata/atmosphere/lens.py,sha256=EnrddTD-SAnyxU0XF__QkePLUhb4lPwfFLaseL_STDc,9260
|
|
22
|
+
atdata/atmosphere/records.py,sha256=Vkc7K0XFozwXVaDgXP706Z1-De1C95ZPtra1EQE3MGQ,15860
|
|
23
|
+
atdata/atmosphere/schema.py,sha256=xvIyJbzbZrcAi7TOWFQXXfgqAyuhb5Yqttf9dSy9x50,7758
|
|
24
|
+
atdata/atmosphere/store.py,sha256=NR4tGS9u3_ogvnyyOHDVF0tRKChruj_NE9Df4qrZiDU,6324
|
|
25
|
+
atdata/cli/__init__.py,sha256=3ZtMcYmx78L_8LqzPHaLlEOlFXl_uHBJtffSL6UB-kE,5834
|
|
26
|
+
atdata/cli/diagnose.py,sha256=Det9ozOvxXKd8Abu-xEsMjaXR34H_cuSX9MJJIlhnsA,5483
|
|
27
|
+
atdata/cli/inspect.py,sha256=YoJkWeXj1cHcOuDH9Z3btWMhiFNOG6JG3x-tScee-84,2019
|
|
28
|
+
atdata/cli/local.py,sha256=dYosOuVmp_PIM8re4DFsm00uspUJftTOZ0TBBNlTqAM,8105
|
|
29
|
+
atdata/cli/preview.py,sha256=n90Eqj920JEi7nBl4NnbmEhZxKLzHoR2CfNI9lkbGuc,1735
|
|
30
|
+
atdata/cli/schema.py,sha256=JwbQOBOPcvDTF6QgptuqZF5VEEMHrjxlj959q6E1DQY,2882
|
|
31
|
+
atdata/local/__init__.py,sha256=ZBJspq-dKOYZESUfxnQ0vIqpyBXGo2Fy116RvfFtDgs,1872
|
|
32
|
+
atdata/local/_entry.py,sha256=Cea1uAbURlBVn3vlrcLD5mtwIaqYoHjgb1GVsBqrszw,5264
|
|
33
|
+
atdata/local/_index.py,sha256=lCl0JAmHxmhz9lFlMiMvO_TApYARK3dyiBAJTVUaYO4,34305
|
|
34
|
+
atdata/local/_repo_legacy.py,sha256=7njQTp9HReyWNcIOyYG_Zg90nhEI8KRVCLI0ANnoUpY,7541
|
|
35
|
+
atdata/local/_s3.py,sha256=7KuIIZgqaiaNjULlKC3QPbLkKaj7rRVSYJt5zU_OEXI,12809
|
|
36
|
+
atdata/local/_schema.py,sha256=myCZ7eTJ0hKLQuF5qBvjzttyenKSqXd3YDdamFdRw1E,11634
|
|
37
|
+
atdata/manifest/__init__.py,sha256=GB7V8OXLDAIuUX4JSBVL7_UV9CFALMiMfoeZvoNkug0,1309
|
|
38
|
+
atdata/manifest/_aggregates.py,sha256=yabfBJtdVqOBWbkNqg9gp0BgpG62wi3QsGYlHgAAcFk,4198
|
|
39
|
+
atdata/manifest/_builder.py,sha256=abU5cnRnIJZ_qf_BKr6-fMYU1HaJWkBVgmGL0WzRRzU,5252
|
|
40
|
+
atdata/manifest/_fields.py,sha256=4Mm31HGb3qRwvp5Kn9Pp-4dX0tlNrQHxEDZJnBzFpos,5003
|
|
41
|
+
atdata/manifest/_manifest.py,sha256=hPcURPjjPS5r3H_veVshwT6Qw-lC9eQll84Fos1xrCE,4852
|
|
42
|
+
atdata/manifest/_query.py,sha256=25_0i60jWQhuMXsuuVLvSPS8v9pejTi5Bik99e2L99A,4641
|
|
43
|
+
atdata/manifest/_writer.py,sha256=_g2YZof-GnN3nVLpAAE5fDmsV9GzlPYf2oa1BWYswxI,2206
|
|
44
|
+
atdata/providers/__init__.py,sha256=LDziQc6Dc0QCfJcr_sDDqxArstDB0dSZHGgXCIIXbzo,848
|
|
45
|
+
atdata/providers/_base.py,sha256=3ICfgo2AWrRyAHrH8AJM4F0ssDBVD_K5iZAuQcUFLGA,4402
|
|
46
|
+
atdata/providers/_factory.py,sha256=9clKbch3gxqJWufY-HIbbfaBstzoq1LOcMrJOKHTPhw,2039
|
|
47
|
+
atdata/providers/_postgres.py,sha256=BpbjiD9jifLO74aWttSq4JgVoecAypCoYzO_7DdAZuQ,7402
|
|
48
|
+
atdata/providers/_redis.py,sha256=VljNKSsLAX5H0NoOuqkuLQeQAFuuettq1MnpBJgnqhw,6054
|
|
49
|
+
atdata/providers/_sqlite.py,sha256=urZWl7ErgKJJ1uBpnmmdkz7uWnrKGkJDIaTvAdyN7Uo,6486
|
|
50
|
+
atdata-0.3.0b1.dist-info/METADATA,sha256=zxCV6U6eMrtYZII4hBIrY7tZ9hs4ntTdAwPRhg_HISk,7410
|
|
51
|
+
atdata-0.3.0b1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
52
|
+
atdata-0.3.0b1.dist-info/entry_points.txt,sha256=6-iQr1veSTq-ac94bLyfcyGHprrZWevPEd12BWX37tQ,39
|
|
53
|
+
atdata-0.3.0b1.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
|
|
54
|
+
atdata-0.3.0b1.dist-info/RECORD,,
|