juniper-data-client 0.3.1__tar.gz → 0.4.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.
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/PKG-INFO +8 -2
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/README.md +7 -1
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client/__init__.py +2 -9
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client/client.py +121 -10
- juniper_data_client-0.4.0/juniper_data_client/testing/__init__.py +45 -0
- juniper_data_client-0.4.0/juniper_data_client/testing/fake_client.py +715 -0
- juniper_data_client-0.4.0/juniper_data_client/testing/generators.py +284 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client.egg-info/PKG-INFO +8 -2
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client.egg-info/SOURCES.txt +8 -1
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/pyproject.toml +28 -5
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/tests/test_client.py +200 -9
- juniper_data_client-0.4.0/tests/test_fake_client.py +568 -0
- juniper_data_client-0.4.0/tests/test_fake_client_batch.py +312 -0
- juniper_data_client-0.4.0/tests/test_performance.py +402 -0
- juniper_data_client-0.4.0/tests/test_versioning.py +215 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/LICENSE +0 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client/exceptions.py +0 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client/py.typed +0 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client.egg-info/dependency_links.txt +0 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client.egg-info/requires.txt +0 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/juniper_data_client.egg-info/top_level.txt +0 -0
- {juniper_data_client-0.3.1 → juniper_data_client-0.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: juniper-data-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: HTTP client for the JuniperData dataset generation service
|
|
5
5
|
Author: Paul Calnon
|
|
6
6
|
License-Expression: MIT
|
|
@@ -206,6 +206,12 @@ y_train = torch.from_numpy(arrays["y_train"]) # torch.float32
|
|
|
206
206
|
| `download_artifact_bytes(id)` | Download raw NPZ bytes |
|
|
207
207
|
| `get_preview(id, n)` | Get JSON preview of samples |
|
|
208
208
|
| `delete_dataset(id)` | Delete a dataset |
|
|
209
|
+
| `list_versions(name)` | List version history for a dataset |
|
|
210
|
+
| `get_latest(name)` | Get latest version by name |
|
|
211
|
+
| `batch_delete(dataset_ids)` | Delete multiple datasets |
|
|
212
|
+
| `batch_create(datasets)` | Create multiple datasets |
|
|
213
|
+
| `batch_update_tags(dataset_ids, add_tags, remove_tags)` | Update tags on multiple datasets |
|
|
214
|
+
| `batch_export(dataset_ids)` | Export multiple datasets as ZIP |
|
|
209
215
|
| `close()` | Close the client session |
|
|
210
216
|
|
|
211
217
|
### Exceptions
|
|
@@ -242,7 +248,7 @@ Downloaded artifacts contain the following numpy arrays (all `float32`):
|
|
|
242
248
|
|
|
243
249
|
## Requirements
|
|
244
250
|
|
|
245
|
-
- Python >=3.
|
|
251
|
+
- Python >=3.12
|
|
246
252
|
- numpy >=1.24.0
|
|
247
253
|
- requests >=2.28.0
|
|
248
254
|
- urllib3 >=2.0.0
|
|
@@ -164,6 +164,12 @@ y_train = torch.from_numpy(arrays["y_train"]) # torch.float32
|
|
|
164
164
|
| `download_artifact_bytes(id)` | Download raw NPZ bytes |
|
|
165
165
|
| `get_preview(id, n)` | Get JSON preview of samples |
|
|
166
166
|
| `delete_dataset(id)` | Delete a dataset |
|
|
167
|
+
| `list_versions(name)` | List version history for a dataset |
|
|
168
|
+
| `get_latest(name)` | Get latest version by name |
|
|
169
|
+
| `batch_delete(dataset_ids)` | Delete multiple datasets |
|
|
170
|
+
| `batch_create(datasets)` | Create multiple datasets |
|
|
171
|
+
| `batch_update_tags(dataset_ids, add_tags, remove_tags)` | Update tags on multiple datasets |
|
|
172
|
+
| `batch_export(dataset_ids)` | Export multiple datasets as ZIP |
|
|
167
173
|
| `close()` | Close the client session |
|
|
168
174
|
|
|
169
175
|
### Exceptions
|
|
@@ -200,7 +206,7 @@ Downloaded artifacts contain the following numpy arrays (all `float32`):
|
|
|
200
206
|
|
|
201
207
|
## Requirements
|
|
202
208
|
|
|
203
|
-
- Python >=3.
|
|
209
|
+
- Python >=3.12
|
|
204
210
|
- numpy >=1.24.0
|
|
205
211
|
- requests >=2.28.0
|
|
206
212
|
- urllib3 >=2.0.0
|
|
@@ -5,16 +5,9 @@ dataset generation service, used by both JuniperCascor and juniper-canopy.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from juniper_data_client.client import JuniperDataClient
|
|
8
|
-
from juniper_data_client.exceptions import
|
|
9
|
-
JuniperDataClientError,
|
|
10
|
-
JuniperDataConfigurationError,
|
|
11
|
-
JuniperDataConnectionError,
|
|
12
|
-
JuniperDataNotFoundError,
|
|
13
|
-
JuniperDataTimeoutError,
|
|
14
|
-
JuniperDataValidationError,
|
|
15
|
-
)
|
|
8
|
+
from juniper_data_client.exceptions import JuniperDataClientError, JuniperDataConfigurationError, JuniperDataConnectionError, JuniperDataNotFoundError, JuniperDataTimeoutError, JuniperDataValidationError
|
|
16
9
|
|
|
17
|
-
__version__ = "0.
|
|
10
|
+
__version__ = "0.4.0"
|
|
18
11
|
|
|
19
12
|
__all__ = [
|
|
20
13
|
"JuniperDataClient",
|
|
@@ -15,13 +15,7 @@ import requests
|
|
|
15
15
|
from requests.adapters import HTTPAdapter
|
|
16
16
|
from urllib3.util.retry import Retry
|
|
17
17
|
|
|
18
|
-
from juniper_data_client.exceptions import
|
|
19
|
-
JuniperDataClientError,
|
|
20
|
-
JuniperDataConnectionError,
|
|
21
|
-
JuniperDataNotFoundError,
|
|
22
|
-
JuniperDataTimeoutError,
|
|
23
|
-
JuniperDataValidationError,
|
|
24
|
-
)
|
|
18
|
+
from juniper_data_client.exceptions import JuniperDataClientError, JuniperDataConnectionError, JuniperDataNotFoundError, JuniperDataTimeoutError, JuniperDataValidationError
|
|
25
19
|
|
|
26
20
|
|
|
27
21
|
class JuniperDataClient:
|
|
@@ -104,7 +98,7 @@ class JuniperDataClient:
|
|
|
104
98
|
total=self.retries,
|
|
105
99
|
backoff_factor=self.backoff_factor,
|
|
106
100
|
status_forcelist=[429, 500, 502, 503, 504],
|
|
107
|
-
allowed_methods=["HEAD", "GET", "POST", "DELETE"],
|
|
101
|
+
allowed_methods=["HEAD", "GET", "POST", "PATCH", "DELETE"],
|
|
108
102
|
)
|
|
109
103
|
|
|
110
104
|
adapter = HTTPAdapter(
|
|
@@ -233,7 +227,16 @@ class JuniperDataClient:
|
|
|
233
227
|
response = self._request("GET", f"/v1/generators/{name}/schema")
|
|
234
228
|
return response.json()
|
|
235
229
|
|
|
236
|
-
def create_dataset(
|
|
230
|
+
def create_dataset(
|
|
231
|
+
self,
|
|
232
|
+
generator: str,
|
|
233
|
+
params: Dict[str, Any],
|
|
234
|
+
persist: bool = True,
|
|
235
|
+
name: Optional[str] = None,
|
|
236
|
+
description: Optional[str] = None,
|
|
237
|
+
created_by: Optional[str] = None,
|
|
238
|
+
parent_dataset_id: Optional[str] = None,
|
|
239
|
+
) -> Dict[str, Any]:
|
|
237
240
|
"""Create a new dataset via the JuniperData API.
|
|
238
241
|
|
|
239
242
|
If a dataset with the same parameters already exists, the existing
|
|
@@ -243,6 +246,11 @@ class JuniperDataClient:
|
|
|
243
246
|
generator: Name of the dataset generator to use (e.g., "spiral")
|
|
244
247
|
params: Parameters to pass to the generator
|
|
245
248
|
persist: Whether to persist the dataset (default: True)
|
|
249
|
+
name: Optional dataset name for versioning. When provided, the service
|
|
250
|
+
automatically assigns an incrementing version number.
|
|
251
|
+
description: Optional human-readable description of the dataset.
|
|
252
|
+
created_by: Optional identifier for the creator (user or system).
|
|
253
|
+
parent_dataset_id: Optional ID of the parent dataset this was derived from.
|
|
246
254
|
|
|
247
255
|
Returns:
|
|
248
256
|
Parsed JSON response containing dataset_id, generator, meta, and artifact_url
|
|
@@ -251,15 +259,50 @@ class JuniperDataClient:
|
|
|
251
259
|
JuniperDataValidationError: If parameters are invalid
|
|
252
260
|
JuniperDataNotFoundError: If generator not found
|
|
253
261
|
"""
|
|
254
|
-
payload = {
|
|
262
|
+
payload: Dict[str, Any] = {
|
|
255
263
|
"generator": generator,
|
|
256
264
|
"params": params,
|
|
257
265
|
"persist": persist,
|
|
258
266
|
}
|
|
267
|
+
if name is not None:
|
|
268
|
+
payload["name"] = name
|
|
269
|
+
if description is not None:
|
|
270
|
+
payload["description"] = description
|
|
271
|
+
if created_by is not None:
|
|
272
|
+
payload["created_by"] = created_by
|
|
273
|
+
if parent_dataset_id is not None:
|
|
274
|
+
payload["parent_dataset_id"] = parent_dataset_id
|
|
259
275
|
|
|
260
276
|
response = self._request("POST", "/v1/datasets", json=payload)
|
|
261
277
|
return response.json()
|
|
262
278
|
|
|
279
|
+
def list_versions(self, name: str) -> Dict[str, Any]:
|
|
280
|
+
"""List all versions of a named dataset.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
name: Dataset name to list versions for.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Dict with dataset_name, versions list, total count, and latest_version.
|
|
287
|
+
"""
|
|
288
|
+
response = self._request("GET", "/v1/datasets/versions", params={"name": name})
|
|
289
|
+
return response.json()
|
|
290
|
+
|
|
291
|
+
def get_latest(self, name: str) -> Dict[str, Any]:
|
|
292
|
+
"""Get the latest version of a named dataset.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
name: Dataset name to get latest version of.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
Dataset metadata for the latest version.
|
|
299
|
+
|
|
300
|
+
Raises:
|
|
301
|
+
JuniperDataNotFoundError: If no versions exist for the given name.
|
|
302
|
+
"""
|
|
303
|
+
response = self._request("GET", "/v1/datasets/latest", params={"name": name})
|
|
304
|
+
return response.json()
|
|
305
|
+
|
|
263
306
|
def list_datasets(self, limit: int = 100, offset: int = 0) -> List[str]:
|
|
264
307
|
"""List dataset IDs.
|
|
265
308
|
|
|
@@ -394,6 +437,74 @@ class JuniperDataClient:
|
|
|
394
437
|
|
|
395
438
|
return self.create_dataset("spiral", params)
|
|
396
439
|
|
|
440
|
+
# ─── Batch Operations ────────────────────────────────────────────────
|
|
441
|
+
|
|
442
|
+
def batch_delete(self, dataset_ids: List[str]) -> Dict[str, Any]:
|
|
443
|
+
"""Delete multiple datasets in a single request.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
dataset_ids: List of dataset IDs to delete (1-100).
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
Dictionary with deleted, not_found, and total_deleted.
|
|
450
|
+
"""
|
|
451
|
+
response = self._request("POST", "/v1/datasets/batch-delete", json={"dataset_ids": dataset_ids})
|
|
452
|
+
return response.json()
|
|
453
|
+
|
|
454
|
+
def batch_create(self, datasets: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
455
|
+
"""Create multiple datasets in a single request.
|
|
456
|
+
|
|
457
|
+
Each item should have 'generator' and 'params' keys, and optionally
|
|
458
|
+
'persist', 'tags', and 'ttl_seconds'.
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
datasets: List of dataset specifications (1-50).
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
Dictionary with results, total_created, and total_failed.
|
|
465
|
+
"""
|
|
466
|
+
response = self._request("POST", "/v1/datasets/batch-create", json={"datasets": datasets})
|
|
467
|
+
return response.json()
|
|
468
|
+
|
|
469
|
+
def batch_update_tags(
|
|
470
|
+
self,
|
|
471
|
+
dataset_ids: List[str],
|
|
472
|
+
add_tags: Optional[List[str]] = None,
|
|
473
|
+
remove_tags: Optional[List[str]] = None,
|
|
474
|
+
) -> Dict[str, Any]:
|
|
475
|
+
"""Add or remove tags from multiple datasets.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
dataset_ids: List of dataset IDs to update (1-100).
|
|
479
|
+
add_tags: Tags to add to all specified datasets.
|
|
480
|
+
remove_tags: Tags to remove from all specified datasets.
|
|
481
|
+
|
|
482
|
+
Returns:
|
|
483
|
+
Dictionary with updated, not_found, and total_updated.
|
|
484
|
+
"""
|
|
485
|
+
payload: Dict[str, Any] = {"dataset_ids": dataset_ids}
|
|
486
|
+
if add_tags:
|
|
487
|
+
payload["add_tags"] = add_tags
|
|
488
|
+
if remove_tags:
|
|
489
|
+
payload["remove_tags"] = remove_tags
|
|
490
|
+
response = self._request("PATCH", "/v1/datasets/batch-tags", json=payload)
|
|
491
|
+
return response.json()
|
|
492
|
+
|
|
493
|
+
def batch_export(self, dataset_ids: List[str]) -> bytes:
|
|
494
|
+
"""Export multiple datasets as a ZIP archive of NPZ files.
|
|
495
|
+
|
|
496
|
+
Args:
|
|
497
|
+
dataset_ids: List of dataset IDs to export (1-50).
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
Raw bytes of the ZIP archive.
|
|
501
|
+
|
|
502
|
+
Raises:
|
|
503
|
+
JuniperDataNotFoundError: If none of the datasets exist.
|
|
504
|
+
"""
|
|
505
|
+
response = self._request("POST", "/v1/datasets/batch-export", json={"dataset_ids": dataset_ids})
|
|
506
|
+
return response.content
|
|
507
|
+
|
|
397
508
|
def close(self) -> None:
|
|
398
509
|
"""Close the client session and release resources."""
|
|
399
510
|
self.session.close()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#####################################################################################################################################################################################################
|
|
2
|
+
# Project: Juniper
|
|
3
|
+
# Sub-Project: juniper-data-client
|
|
4
|
+
# Application: juniper_data_client
|
|
5
|
+
# File Name: __init__.py
|
|
6
|
+
# Author: Paul Calnon
|
|
7
|
+
# Version: 0.4.0
|
|
8
|
+
#
|
|
9
|
+
# Date Created: 2026-02-27
|
|
10
|
+
# Last Modified: 2026-02-27
|
|
11
|
+
#
|
|
12
|
+
# License: MIT License
|
|
13
|
+
# Copyright: Copyright (c) 2024-2026 Paul Calnon
|
|
14
|
+
#
|
|
15
|
+
# Description:
|
|
16
|
+
# Testing submodule for juniper-data-client. Provides FakeDataClient,
|
|
17
|
+
# a drop-in replacement for JuniperDataClient that generates synthetic
|
|
18
|
+
# datasets in-memory without requiring a running JuniperData service.
|
|
19
|
+
#####################################################################################################################################################################################################
|
|
20
|
+
|
|
21
|
+
"""Testing utilities for juniper-data-client.
|
|
22
|
+
|
|
23
|
+
Provides :class:`FakeDataClient` for use in unit tests of consumers
|
|
24
|
+
like JuniperCascor and juniper-canopy, as well as standalone synthetic
|
|
25
|
+
dataset generators.
|
|
26
|
+
|
|
27
|
+
Usage::
|
|
28
|
+
|
|
29
|
+
from juniper_data_client.testing import FakeDataClient
|
|
30
|
+
|
|
31
|
+
with FakeDataClient() as client:
|
|
32
|
+
result = client.create_spiral_dataset(n_spirals=2, seed=42)
|
|
33
|
+
arrays = client.download_artifact_npz(result["dataset_id"])
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from juniper_data_client.testing.fake_client import FakeDataClient
|
|
37
|
+
from juniper_data_client.testing.generators import generate_circle, generate_moon, generate_spiral, generate_xor
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"FakeDataClient",
|
|
41
|
+
"generate_circle",
|
|
42
|
+
"generate_moon",
|
|
43
|
+
"generate_spiral",
|
|
44
|
+
"generate_xor",
|
|
45
|
+
]
|