adaptive-sdk 0.1.14__py3-none-any.whl → 0.12.1__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.
- adaptive_sdk/graphql_client/__init__.py +704 -12
- adaptive_sdk/graphql_client/custom_fields.py +1640 -960
- adaptive_sdk/graphql_client/custom_mutations.py +332 -177
- adaptive_sdk/graphql_client/custom_queries.py +278 -133
- adaptive_sdk/graphql_client/custom_typing_fields.py +74 -0
- adaptive_sdk/graphql_client/enums.py +38 -0
- adaptive_sdk/graphql_client/input_types.py +586 -213
- adaptive_sdk/resources/abtests.py +2 -0
- adaptive_sdk/resources/base_resource.py +22 -0
- adaptive_sdk/resources/chat.py +16 -7
- adaptive_sdk/resources/compute_pools.py +16 -4
- adaptive_sdk/resources/embeddings.py +11 -7
- adaptive_sdk/resources/feedback.py +22 -33
- adaptive_sdk/resources/interactions.py +6 -3
- adaptive_sdk/resources/jobs.py +90 -6
- adaptive_sdk/resources/models.py +20 -3
- adaptive_sdk/resources/permissions.py +12 -1
- adaptive_sdk/resources/recipes.py +177 -31
- adaptive_sdk/resources/roles.py +15 -8
- adaptive_sdk/resources/teams.py +30 -1
- adaptive_sdk/resources/use_cases.py +9 -6
- adaptive_sdk/resources/users.py +37 -22
- {adaptive_sdk-0.1.14.dist-info → adaptive_sdk-0.12.1.dist-info}/METADATA +1 -1
- {adaptive_sdk-0.1.14.dist-info → adaptive_sdk-0.12.1.dist-info}/RECORD +25 -25
- {adaptive_sdk-0.1.14.dist-info → adaptive_sdk-0.12.1.dist-info}/WHEEL +0 -0
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import io
|
|
4
|
-
import zipfile
|
|
5
4
|
import mimetypes
|
|
5
|
+
import os
|
|
6
|
+
import zipfile
|
|
6
7
|
from contextlib import contextmanager
|
|
7
|
-
from loguru import logger
|
|
8
|
-
from hypothesis_jsonschema import from_schema
|
|
9
|
-
from typing import TYPE_CHECKING, Sequence, Any
|
|
10
8
|
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Sequence
|
|
11
10
|
|
|
12
|
-
from
|
|
13
|
-
from
|
|
11
|
+
from hypothesis_jsonschema import from_schema
|
|
12
|
+
from loguru import logger
|
|
14
13
|
|
|
15
|
-
from .base_resource import SyncAPIResource, AsyncAPIResource, UseCaseResource
|
|
16
14
|
from adaptive_sdk.graphql_client import (
|
|
15
|
+
CreateRecipeInput,
|
|
17
16
|
CustomRecipeData,
|
|
18
17
|
CustomRecipeFilterInput,
|
|
19
|
-
CreateRecipeInput,
|
|
20
|
-
UpdateRecipeInput,
|
|
21
18
|
LabelInput,
|
|
19
|
+
UpdateRecipeInput,
|
|
22
20
|
Upload,
|
|
23
21
|
)
|
|
24
22
|
|
|
23
|
+
from .base_resource import AsyncAPIResource, SyncAPIResource, UseCaseResource
|
|
24
|
+
|
|
25
25
|
if TYPE_CHECKING:
|
|
26
26
|
from adaptive_sdk.client import Adaptive, AsyncAdaptive
|
|
27
27
|
|
|
@@ -36,6 +36,14 @@ class Recipes(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
36
36
|
UseCaseResource.__init__(self, client)
|
|
37
37
|
|
|
38
38
|
def list(self, use_case: str | None = None) -> Sequence[CustomRecipeData]:
|
|
39
|
+
"""List all custom recipes for a use case.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
A sequence of custom recipe data objects.
|
|
46
|
+
"""
|
|
39
47
|
filter = CustomRecipeFilterInput()
|
|
40
48
|
return self._gql_client.list_custom_recipes(use_case=self.use_case_key(use_case), filter=filter).custom_recipes
|
|
41
49
|
|
|
@@ -53,18 +61,27 @@ class Recipes(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
53
61
|
Upload a recipe from either a single Python file or a directory (path).
|
|
54
62
|
|
|
55
63
|
Args:
|
|
56
|
-
path: Path to a Python file or directory containing the recipe
|
|
64
|
+
path: Path to a Python file or directory containing the recipe.
|
|
57
65
|
recipe_key: Optional unique key for the recipe. If not provided, inferred from:
|
|
58
66
|
- File name (without .py) if path is a file
|
|
59
67
|
- "dir_name/entrypoint_name" if path is a directory and custom entrypoint is specified
|
|
60
68
|
- Directory name if path is a directory and no custom entrypoint is specified
|
|
61
|
-
entrypoint: Optional
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
entrypoint: Optional path to the recipe entrypoint file, relative to the `path` directory.
|
|
70
|
+
**Only applicable when path is a directory.**
|
|
71
|
+
|
|
72
|
+
Raises ValueError if:
|
|
73
|
+
- path is a single file (entrypoint not supported for single files)
|
|
74
|
+
- path is a directory that already contains main.py
|
|
75
|
+
|
|
76
|
+
Raises FileNotFoundError if:
|
|
77
|
+
- the specified entrypoint file doesn't exist in the directory
|
|
78
|
+
|
|
79
|
+
If path is a directory and entrypoint is None:
|
|
80
|
+
- The directory must contain a main.py file, or FileNotFoundError is raised
|
|
81
|
+
name: Optional display name for the recipe.
|
|
82
|
+
description: Optional description.
|
|
83
|
+
labels: Optional key-value labels.
|
|
84
|
+
use_case: Optional use case identifier.
|
|
68
85
|
"""
|
|
69
86
|
p = Path(path)
|
|
70
87
|
if recipe_key is None:
|
|
@@ -91,6 +108,15 @@ class Recipes(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
91
108
|
recipe_key: str,
|
|
92
109
|
use_case: str | None = None,
|
|
93
110
|
) -> CustomRecipeData | None:
|
|
111
|
+
"""Get details for a specific recipe.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
recipe_key: The key or ID of the recipe.
|
|
115
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The recipe data if found, otherwise None.
|
|
119
|
+
"""
|
|
94
120
|
return self._gql_client.get_custom_recipe(
|
|
95
121
|
id_or_key=recipe_key, use_case=self.use_case_key(use_case)
|
|
96
122
|
).custom_recipe
|
|
@@ -105,6 +131,32 @@ class Recipes(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
105
131
|
labels: Sequence[tuple[str, str]] | None = None,
|
|
106
132
|
use_case: str | None = None,
|
|
107
133
|
) -> CustomRecipeData:
|
|
134
|
+
"""Update an existing recipe.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
recipe_key: The key of the recipe to update.
|
|
138
|
+
path: Optional new path to a Python file or directory to replace recipe code.
|
|
139
|
+
If None, only metadata (name, description, labels) is updated.
|
|
140
|
+
entrypoint: Optional path to the recipe entrypoint file, relative to the `path` directory.
|
|
141
|
+
**Only applicable when path is a directory.**
|
|
142
|
+
|
|
143
|
+
Raises ValueError if:
|
|
144
|
+
- path is a single file (entrypoint not supported for single files)
|
|
145
|
+
- path is a directory that already contains main.py
|
|
146
|
+
|
|
147
|
+
Raises FileNotFoundError if:
|
|
148
|
+
- the specified entrypoint file doesn't exist in the directory
|
|
149
|
+
|
|
150
|
+
If path is a directory and entrypoint is None:
|
|
151
|
+
- The directory must contain a main.py file, or FileNotFoundError is raised
|
|
152
|
+
name: Optional new display name.
|
|
153
|
+
description: Optional new description.
|
|
154
|
+
labels: Optional new key-value labels as tuples of (key, value).
|
|
155
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
The updated recipe data.
|
|
159
|
+
"""
|
|
108
160
|
label_inputs = [LabelInput(key=k, value=v) for k, v in labels] if labels else None
|
|
109
161
|
input = UpdateRecipeInput(
|
|
110
162
|
name=name,
|
|
@@ -133,11 +185,32 @@ class Recipes(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
133
185
|
recipe_key: str,
|
|
134
186
|
use_case: str | None = None,
|
|
135
187
|
) -> bool:
|
|
188
|
+
"""Delete a recipe.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
recipe_key: The key or ID of the recipe to delete.
|
|
192
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
True if deletion was successful.
|
|
196
|
+
"""
|
|
136
197
|
return self._gql_client.delete_custom_recipe(
|
|
137
198
|
use_case=self.use_case_key(use_case), id=recipe_key
|
|
138
199
|
).delete_custom_recipe
|
|
139
200
|
|
|
140
201
|
def generate_sample_input(self, recipe_key: str, use_case: str | None = None) -> dict:
|
|
202
|
+
"""Generate a sample input dictionary based on the recipe's JSON schema.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
recipe_key: The key or ID of the recipe.
|
|
206
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
A sample input dictionary conforming to the recipe's schema.
|
|
210
|
+
|
|
211
|
+
Raises:
|
|
212
|
+
ValueError: If the recipe is not found.
|
|
213
|
+
"""
|
|
141
214
|
recipe_details = self.get(recipe_key=recipe_key, use_case=self.use_case_key(use_case))
|
|
142
215
|
if recipe_details is None:
|
|
143
216
|
raise ValueError(f"Recipe {recipe_key} was not found")
|
|
@@ -174,6 +247,14 @@ class AsyncRecipes(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
174
247
|
UseCaseResource.__init__(self, client)
|
|
175
248
|
|
|
176
249
|
async def list(self, use_case: str | None = None) -> Sequence[CustomRecipeData]:
|
|
250
|
+
"""List all custom recipes for a use case.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
A sequence of custom recipe data objects.
|
|
257
|
+
"""
|
|
177
258
|
filter = CustomRecipeFilterInput()
|
|
178
259
|
return (
|
|
179
260
|
await self._gql_client.list_custom_recipes(use_case=self.use_case_key(use_case), filter=filter)
|
|
@@ -193,18 +274,27 @@ class AsyncRecipes(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
193
274
|
Upload a recipe from either a single Python file or a directory (path).
|
|
194
275
|
|
|
195
276
|
Args:
|
|
196
|
-
path: Path to a Python file or directory containing the recipe
|
|
277
|
+
path: Path to a Python file or directory containing the recipe.
|
|
197
278
|
recipe_key: Optional unique key for the recipe. If not provided, inferred from:
|
|
198
279
|
- File name (without .py) if path is a file
|
|
199
280
|
- "dir_name/entrypoint_name" if path is a directory and custom entrypoint is specified
|
|
200
281
|
- Directory name if path is a directory and no custom entrypoint is specified
|
|
201
|
-
entrypoint: Optional
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
282
|
+
entrypoint: Optional path to the recipe entrypoint file, relative to the `path` directory.
|
|
283
|
+
**Only applicable when path is a directory.**
|
|
284
|
+
|
|
285
|
+
Raises ValueError if:
|
|
286
|
+
- path is a single file (entrypoint not supported for single files)
|
|
287
|
+
- path is a directory that already contains main.py
|
|
288
|
+
|
|
289
|
+
Raises FileNotFoundError if:
|
|
290
|
+
- the specified entrypoint file doesn't exist in the directory
|
|
291
|
+
|
|
292
|
+
If path is a directory and entrypoint is None:
|
|
293
|
+
- The directory must contain a main.py file, or FileNotFoundError is raised
|
|
294
|
+
name: Optional display name for the recipe.
|
|
295
|
+
description: Optional description.
|
|
296
|
+
labels: Optional key-value labels as tuples of (key, value).
|
|
297
|
+
use_case: Optional use case identifier.
|
|
208
298
|
"""
|
|
209
299
|
p = Path(path)
|
|
210
300
|
if recipe_key is None:
|
|
@@ -232,6 +322,15 @@ class AsyncRecipes(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
232
322
|
recipe_key: str,
|
|
233
323
|
use_case: str | None = None,
|
|
234
324
|
) -> CustomRecipeData | None:
|
|
325
|
+
"""Get details for a specific recipe.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
recipe_key: The key or ID of the recipe.
|
|
329
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
The recipe data if found, otherwise None.
|
|
333
|
+
"""
|
|
235
334
|
return (
|
|
236
335
|
await self._gql_client.get_custom_recipe(id_or_key=recipe_key, use_case=self.use_case_key(use_case))
|
|
237
336
|
).custom_recipe
|
|
@@ -246,6 +345,32 @@ class AsyncRecipes(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
246
345
|
labels: Sequence[tuple[str, str]] | None = None,
|
|
247
346
|
use_case: str | None = None,
|
|
248
347
|
) -> CustomRecipeData:
|
|
348
|
+
"""Update an existing recipe.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
recipe_key: The key or ID of the recipe to update.
|
|
352
|
+
path: Optional new path to a Python file or directory to replace recipe code.
|
|
353
|
+
If None, only metadata (name, description, labels) is updated.
|
|
354
|
+
entrypoint: Optional path to the recipe entrypoint file, relative to the `path` directory.
|
|
355
|
+
**Only applicable when path is a directory.**
|
|
356
|
+
|
|
357
|
+
Raises ValueError if:
|
|
358
|
+
- path is a single file (entrypoint not supported for single files)
|
|
359
|
+
- path is a directory that already contains main.py
|
|
360
|
+
|
|
361
|
+
Raises FileNotFoundError if:
|
|
362
|
+
- the specified entrypoint file doesn't exist in the directory
|
|
363
|
+
|
|
364
|
+
If path is a directory and entrypoint is None:
|
|
365
|
+
- The directory must contain a main.py file, or FileNotFoundError is raised
|
|
366
|
+
name: Optional new display name.
|
|
367
|
+
description: Optional new description.
|
|
368
|
+
labels: Optional new key-value labels as tuples of (key, value).
|
|
369
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
The updated recipe data.
|
|
373
|
+
"""
|
|
249
374
|
label_inputs = [LabelInput(key=k, value=v) for k, v in labels] if labels else None
|
|
250
375
|
input = UpdateRecipeInput(
|
|
251
376
|
name=name,
|
|
@@ -278,11 +403,32 @@ class AsyncRecipes(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
278
403
|
recipe_key: str,
|
|
279
404
|
use_case: str | None = None,
|
|
280
405
|
) -> bool:
|
|
406
|
+
"""Delete a recipe.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
recipe_key: The key or ID of the recipe to delete.
|
|
410
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
True if deletion was successful.
|
|
414
|
+
"""
|
|
281
415
|
return (
|
|
282
416
|
await self._gql_client.delete_custom_recipe(use_case=self.use_case_key(use_case), id=recipe_key)
|
|
283
417
|
).delete_custom_recipe
|
|
284
418
|
|
|
285
419
|
async def generate_sample_input(self, recipe_key: str, use_case: str | None = None) -> dict:
|
|
420
|
+
"""Generate a sample input dictionary based on the recipe's JSON schema.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
recipe_key: The key or ID of the recipe.
|
|
424
|
+
use_case: Optional use case key. Falls back to client's default.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
A sample input dictionary conforming to the recipe's schema.
|
|
428
|
+
|
|
429
|
+
Raises:
|
|
430
|
+
ValueError: If the recipe is not found.
|
|
431
|
+
"""
|
|
286
432
|
recipe_details = await self.get(recipe_key=recipe_key, use_case=self.use_case_key(use_case))
|
|
287
433
|
if recipe_details is None:
|
|
288
434
|
raise ValueError(f"Recipe {recipe_key} was not found")
|
|
@@ -359,8 +505,8 @@ def _validate_recipe_directory(dir_path: Path, entrypoint: str | None = None) ->
|
|
|
359
505
|
if entrypoint:
|
|
360
506
|
if main_py_exists:
|
|
361
507
|
raise ValueError(
|
|
362
|
-
|
|
363
|
-
f"Either remove/rename main.py or use it directly without specifying an entrypoint."
|
|
508
|
+
"Cannot specify entrypoint when main.py already exists in directory: "
|
|
509
|
+
f"{dir_path}. Either remove/rename main.py or use it directly without specifying an entrypoint."
|
|
364
510
|
)
|
|
365
511
|
entrypoint_path = dir_path / entrypoint
|
|
366
512
|
if not entrypoint_path.exists() or not entrypoint_path.is_file():
|
|
@@ -368,7 +514,7 @@ def _validate_recipe_directory(dir_path: Path, entrypoint: str | None = None) ->
|
|
|
368
514
|
else:
|
|
369
515
|
if not main_py_exists:
|
|
370
516
|
raise FileNotFoundError(
|
|
371
|
-
|
|
517
|
+
"Directory must contain a 'main.py' file, or in alternative you must specify an `entrypoint` file"
|
|
372
518
|
)
|
|
373
519
|
|
|
374
520
|
|
|
@@ -393,7 +539,7 @@ def _upload_from_path(path: str, entrypoint: str | None = None):
|
|
|
393
539
|
|
|
394
540
|
if p.is_file():
|
|
395
541
|
if entrypoint:
|
|
396
|
-
raise ValueError(
|
|
542
|
+
raise ValueError("Entrypoint parameter is not supported for single file recipe uploads")
|
|
397
543
|
_validate_python_file(p)
|
|
398
544
|
filename = p.name
|
|
399
545
|
content_type = mimetypes.guess_type(str(p))[0] or "application/octet-stream"
|
|
@@ -408,7 +554,7 @@ def _upload_from_path(path: str, entrypoint: str | None = None):
|
|
|
408
554
|
try:
|
|
409
555
|
zip_buffer = _zip_directory_to_bytes_io(p, entrypoint=entrypoint)
|
|
410
556
|
except Exception:
|
|
411
|
-
logger.error(
|
|
557
|
+
logger.error("Failed to create in-memory zip for directory upload.")
|
|
412
558
|
raise
|
|
413
559
|
filename = f"{p.name}.zip"
|
|
414
560
|
try:
|
adaptive_sdk/resources/roles.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from typing import TYPE_CHECKING, List
|
|
3
4
|
|
|
4
|
-
from adaptive_sdk.graphql_client import ListRolesRoles, RoleCreate
|
|
5
|
+
from adaptive_sdk.graphql_client import CreateRoleCreateRole, ListRolesRoles, RoleCreate
|
|
5
6
|
|
|
6
|
-
from .base_resource import
|
|
7
|
+
from .base_resource import AsyncAPIResource, SyncAPIResource, UseCaseResource
|
|
7
8
|
|
|
8
9
|
if TYPE_CHECKING:
|
|
9
10
|
from adaptive_sdk.client import Adaptive, AsyncAdaptive
|
|
@@ -19,11 +20,14 @@ class Roles(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
19
20
|
UseCaseResource.__init__(self, client)
|
|
20
21
|
|
|
21
22
|
def list(self) -> List[ListRolesRoles]:
|
|
23
|
+
"""List all roles.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
A list of role objects.
|
|
27
|
+
"""
|
|
22
28
|
return self._gql_client.list_roles().roles
|
|
23
29
|
|
|
24
|
-
def create(
|
|
25
|
-
self, key: str, permissions: List[str], name: str | None = None
|
|
26
|
-
) -> CreateRoleCreateRole:
|
|
30
|
+
def create(self, key: str, permissions: List[str], name: str | None = None) -> CreateRoleCreateRole:
|
|
27
31
|
"""
|
|
28
32
|
Creates new role.
|
|
29
33
|
|
|
@@ -46,11 +50,14 @@ class AsyncRoles(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
46
50
|
UseCaseResource.__init__(self, client)
|
|
47
51
|
|
|
48
52
|
async def list(self) -> List[ListRolesRoles]:
|
|
53
|
+
"""List all roles.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
A list of role objects.
|
|
57
|
+
"""
|
|
49
58
|
return (await self._gql_client.list_roles()).roles
|
|
50
59
|
|
|
51
|
-
async def create(
|
|
52
|
-
self, key: str, permissions: List[str], name: str | None = None
|
|
53
|
-
) -> CreateRoleCreateRole:
|
|
60
|
+
async def create(self, key: str, permissions: List[str], name: str | None = None) -> CreateRoleCreateRole:
|
|
54
61
|
"""
|
|
55
62
|
Creates new role.
|
|
56
63
|
|
adaptive_sdk/resources/teams.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from typing import TYPE_CHECKING, List
|
|
3
4
|
|
|
4
5
|
from adaptive_sdk.graphql_client import CreateTeamCreateTeam, ListTeamsTeams, TeamCreate
|
|
5
6
|
|
|
6
|
-
from .base_resource import
|
|
7
|
+
from .base_resource import AsyncAPIResource, SyncAPIResource, UseCaseResource
|
|
7
8
|
|
|
8
9
|
if TYPE_CHECKING:
|
|
9
10
|
from adaptive_sdk.client import Adaptive, AsyncAdaptive
|
|
@@ -19,9 +20,23 @@ class Teams(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
19
20
|
UseCaseResource.__init__(self, client)
|
|
20
21
|
|
|
21
22
|
def list(self) -> List[ListTeamsTeams]:
|
|
23
|
+
"""List all teams.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
A list of team objects.
|
|
27
|
+
"""
|
|
22
28
|
return self._gql_client.list_teams().teams
|
|
23
29
|
|
|
24
30
|
def create(self, key: str, name: str | None = None) -> CreateTeamCreateTeam:
|
|
31
|
+
"""Create a new team.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
key: Unique key for the team.
|
|
35
|
+
name: Human-readable team name. If not provided, defaults to key.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
The created team data.
|
|
39
|
+
"""
|
|
25
40
|
input = TeamCreate(key=key, name=name or key)
|
|
26
41
|
return self._gql_client.create_team(input).create_team
|
|
27
42
|
|
|
@@ -36,8 +51,22 @@ class AsyncTeams(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
36
51
|
UseCaseResource.__init__(self, client)
|
|
37
52
|
|
|
38
53
|
async def list(self) -> List[ListTeamsTeams]:
|
|
54
|
+
"""List all teams.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
A list of team objects.
|
|
58
|
+
"""
|
|
39
59
|
return (await self._gql_client.list_teams()).teams
|
|
40
60
|
|
|
41
61
|
async def create(self, key: str, name: str | None = None) -> CreateTeamCreateTeam:
|
|
62
|
+
"""Create a new team.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
key: Unique key for the team.
|
|
66
|
+
name: Human-readable team name. If not provided, defaults to key.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
The created team data.
|
|
70
|
+
"""
|
|
42
71
|
input = TeamCreate(key=key, name=name or key)
|
|
43
72
|
return (await self._gql_client.create_team(input)).create_team
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Sequence
|
|
4
|
+
|
|
3
5
|
from loguru import logger
|
|
4
6
|
|
|
5
7
|
from adaptive_sdk.graphql_client import (
|
|
6
8
|
UseCaseCreate,
|
|
7
|
-
UseCaseSettingsInput,
|
|
8
9
|
UseCaseData,
|
|
9
|
-
|
|
10
|
+
UseCaseSettingsInput,
|
|
10
11
|
UseCaseShareInput,
|
|
12
|
+
UseCaseShares,
|
|
11
13
|
)
|
|
12
14
|
|
|
13
|
-
from .base_resource import
|
|
15
|
+
from .base_resource import AsyncAPIResource, SyncAPIResource, UseCaseResource
|
|
14
16
|
|
|
15
17
|
if TYPE_CHECKING:
|
|
16
18
|
from adaptive_sdk.client import Adaptive, AsyncAdaptive
|
|
@@ -40,6 +42,7 @@ class UseCase(SyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
40
42
|
name: Human-readable use case name which will be rendered in the UI.
|
|
41
43
|
If not set, will be the same as `key`.
|
|
42
44
|
description: Description of model which will be rendered in the UI.
|
|
45
|
+
team: Team key to associate the use case with.
|
|
43
46
|
"""
|
|
44
47
|
|
|
45
48
|
input = UseCaseCreate(
|
|
@@ -155,7 +158,6 @@ class AsyncUseCase(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
155
158
|
name: str | None = None,
|
|
156
159
|
description: str | None = None,
|
|
157
160
|
team: str | None = None,
|
|
158
|
-
default_feedback_key: str | None = None,
|
|
159
161
|
) -> UseCaseData:
|
|
160
162
|
"""
|
|
161
163
|
Create new use case.
|
|
@@ -165,13 +167,14 @@ class AsyncUseCase(AsyncAPIResource, UseCaseResource): # type: ignore[misc]
|
|
|
165
167
|
name: Human-readable use case name which will be rendered in the UI.
|
|
166
168
|
If not set, will be the same as `key`.
|
|
167
169
|
description: Description of model which will be rendered in the UI.
|
|
170
|
+
team: Team key to associate the use case with.
|
|
168
171
|
"""
|
|
169
172
|
input = UseCaseCreate(
|
|
170
173
|
name=name if name else key,
|
|
171
174
|
key=key,
|
|
172
175
|
description=description,
|
|
173
176
|
team=team,
|
|
174
|
-
settings=UseCaseSettingsInput(defaultMetric=
|
|
177
|
+
settings=UseCaseSettingsInput(defaultMetric=None),
|
|
175
178
|
)
|
|
176
179
|
result = await self._gql_client.create_use_case(input)
|
|
177
180
|
return result.create_use_case
|
adaptive_sdk/resources/users.py
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from typing import TYPE_CHECKING, Sequence
|
|
3
4
|
|
|
4
5
|
from adaptive_sdk.graphql_client import (
|
|
5
|
-
|
|
6
|
+
TeamMemberRemove,
|
|
6
7
|
TeamMemberSet,
|
|
7
8
|
UpdateUserSetTeamMember,
|
|
8
|
-
TeamMemberRemove,
|
|
9
9
|
UserCreate,
|
|
10
10
|
UserCreateTeamWithRole,
|
|
11
|
+
UserData,
|
|
11
12
|
)
|
|
12
13
|
|
|
13
|
-
from .base_resource import
|
|
14
|
+
from .base_resource import AsyncAPIResource, SyncAPIResource
|
|
14
15
|
|
|
15
16
|
if TYPE_CHECKING:
|
|
16
17
|
from adaptive_sdk.client import Adaptive, AsyncAdaptive
|
|
@@ -36,20 +37,23 @@ class Users(SyncAPIResource): # type: ignore[misc]
|
|
|
36
37
|
"""
|
|
37
38
|
return self._gql_client.list_users().users
|
|
38
39
|
|
|
39
|
-
def create(
|
|
40
|
-
self, email: str, name: str, teams_with_role: Sequence[tuple[str, str]]
|
|
41
|
-
) -> UserData:
|
|
40
|
+
def create(self, email: str, name: str, teams_with_role: Sequence[tuple[str, str]]) -> UserData:
|
|
42
41
|
"""
|
|
43
|
-
Create a user
|
|
42
|
+
Create a user with preset teams and roles.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
email: User's email address.
|
|
46
|
+
name: User's display name.
|
|
47
|
+
teams_with_role: Sequence of (team_key, role_key) tuples assigning the user to teams with specific roles.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
The created user data.
|
|
44
51
|
"""
|
|
45
52
|
return self._gql_client.create_user(
|
|
46
53
|
input=UserCreate(
|
|
47
54
|
email=email,
|
|
48
55
|
name=name,
|
|
49
|
-
teams=[
|
|
50
|
-
UserCreateTeamWithRole(team=team, role=role)
|
|
51
|
-
for (team, role) in teams_with_role
|
|
52
|
-
],
|
|
56
|
+
teams=[UserCreateTeamWithRole(team=team, role=role) for (team, role) in teams_with_role],
|
|
53
57
|
)
|
|
54
58
|
).create_user
|
|
55
59
|
|
|
@@ -78,6 +82,11 @@ class Users(SyncAPIResource): # type: ignore[misc]
|
|
|
78
82
|
return self._gql_client.remove_team_member(input).remove_team_member
|
|
79
83
|
|
|
80
84
|
def delete(self, email: str):
|
|
85
|
+
"""Delete a user from the system.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
email: The email address of the user to delete.
|
|
89
|
+
"""
|
|
81
90
|
self._gql_client.delete_user(email)
|
|
82
91
|
|
|
83
92
|
|
|
@@ -103,27 +112,28 @@ class AsyncUsers(AsyncAPIResource): # type: ignore[misc]
|
|
|
103
112
|
result = await self._gql_client.list_users()
|
|
104
113
|
return result.users
|
|
105
114
|
|
|
106
|
-
async def create(
|
|
107
|
-
self, email: str, name: str, teams_with_role: Sequence[tuple[str, str]]
|
|
108
|
-
) -> UserData:
|
|
115
|
+
async def create(self, email: str, name: str, teams_with_role: Sequence[tuple[str, str]]) -> UserData:
|
|
109
116
|
"""
|
|
110
|
-
Create a user
|
|
117
|
+
Create a user with preset teams and roles.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
email: User's email address.
|
|
121
|
+
name: User's display name.
|
|
122
|
+
teams_with_role: Sequence of (team_key, role_key) tuples assigning the user to teams with specific roles.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
The created user data.
|
|
111
126
|
"""
|
|
112
127
|
result = await self._gql_client.create_user(
|
|
113
128
|
input=UserCreate(
|
|
114
129
|
email=email,
|
|
115
130
|
name=name,
|
|
116
|
-
teams=[
|
|
117
|
-
UserCreateTeamWithRole(team=team, role=role)
|
|
118
|
-
for (team, role) in teams_with_role
|
|
119
|
-
],
|
|
131
|
+
teams=[UserCreateTeamWithRole(team=team, role=role) for (team, role) in teams_with_role],
|
|
120
132
|
)
|
|
121
133
|
)
|
|
122
134
|
return result.create_user
|
|
123
135
|
|
|
124
|
-
async def add_to_team(
|
|
125
|
-
self, email: str, team: str, role: str
|
|
126
|
-
) -> UpdateUserSetTeamMember:
|
|
136
|
+
async def add_to_team(self, email: str, team: str, role: str) -> UpdateUserSetTeamMember:
|
|
127
137
|
"""
|
|
128
138
|
Update team and role for user.
|
|
129
139
|
|
|
@@ -149,4 +159,9 @@ class AsyncUsers(AsyncAPIResource): # type: ignore[misc]
|
|
|
149
159
|
return (await self._gql_client.remove_team_member(input)).remove_team_member
|
|
150
160
|
|
|
151
161
|
async def delete(self, email: str):
|
|
162
|
+
"""Delete a user from the system.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
email: The email address of the user to delete.
|
|
166
|
+
"""
|
|
152
167
|
await self._gql_client.delete_user(email)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adaptive-sdk
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.12.1
|
|
4
4
|
Summary: Python SDK for Adaptive Engine
|
|
5
5
|
Author-email: Vincent Debergue <vincent@adaptive-ml.com>, Joao Moura <joao@adaptive-ml.com>, Yacine Bouraoui <yacine@adaptive-ml.com>
|
|
6
6
|
Requires-Python: >=3.10
|