codeocean 0.9.1__tar.gz → 0.11.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.
- {codeocean-0.9.1 → codeocean-0.11.0}/CHANGELOG.md +8 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/LICENSE +1 -1
- {codeocean-0.9.1 → codeocean-0.11.0}/PKG-INFO +1 -1
- {codeocean-0.9.1 → codeocean-0.11.0}/pyproject.toml +1 -1
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/capsule.py +237 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/client.py +3 -1
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/computation.py +21 -2
- codeocean-0.11.0/src/codeocean/custom_metadata.py +96 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/data_asset.py +21 -2
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/folder.py +21 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/.flake8 +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/.gitignore +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/README.md +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/RELEASE.md +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/examples/create_data_asset.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/examples/run_capsule.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/examples/run_pipeline.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/__init__.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/components.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/enum.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/src/codeocean/error.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/tests/__init__.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/tests/test_client.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/tests/test_error.py +0 -0
- {codeocean-0.9.1 → codeocean-0.11.0}/tests/test_package.py +0 -0
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## 0.11.0 (2025-10-07)
|
|
5
|
+
- [#55](https://github.com/codeocean/codeocean-sdk-python/pull/55) feat: Code Ocean version 4.0 functionality
|
|
6
|
+
- **Minimum Code Ocean platform version updated to `4.0.0`.**
|
|
7
|
+
|
|
8
|
+
## 0.10.0 (2025-09-01)
|
|
9
|
+
- [#54](https://github.com/codeocean/codeocean-sdk-python/pull/54) feat: Code Ocean version 3.9 functionality
|
|
10
|
+
- **Minimum Code Ocean platform version updated to `3.9.0`.**
|
|
11
|
+
|
|
4
12
|
## 0.9.1 (2025-08-29)
|
|
5
13
|
- [#56](https://github.com/codeocean/codeocean-sdk-python/pull/56) fix: update query description in search APIs
|
|
6
14
|
|
|
@@ -26,6 +26,29 @@ class CapsuleSortBy(StrEnum):
|
|
|
26
26
|
Name = "name"
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
class AppPanelDataAssetKind(StrEnum):
|
|
30
|
+
"""The kind of data asset displayed in an app panel.
|
|
31
|
+
|
|
32
|
+
- 'Internal' → Data stored inside Code Ocean.
|
|
33
|
+
- 'External' → Data stored external to Code Ocean.
|
|
34
|
+
- 'Combined' → Data containing multiple external data assets.
|
|
35
|
+
|
|
36
|
+
In pipelines, a data asset can only be replaced with one of the same kind.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
Internal = "internal"
|
|
40
|
+
External = "external"
|
|
41
|
+
Combined = "combined"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class AppPanelParameterType(StrEnum):
|
|
45
|
+
"""The type of parameter displayed in an app panel."""
|
|
46
|
+
|
|
47
|
+
Text = "text"
|
|
48
|
+
List = "list"
|
|
49
|
+
File = "file"
|
|
50
|
+
|
|
51
|
+
|
|
29
52
|
@dataclass_json
|
|
30
53
|
@dataclass(frozen=True)
|
|
31
54
|
class OriginalCapsuleInfo:
|
|
@@ -81,6 +104,10 @@ class Capsule:
|
|
|
81
104
|
slug: str = dataclass_field(
|
|
82
105
|
metadata={"description": "Alternate capsule ID (URL-friendly identifier)"},
|
|
83
106
|
)
|
|
107
|
+
last_accessed: Optional[int] = dataclass_field(
|
|
108
|
+
default=None,
|
|
109
|
+
metadata={"description": "Capsule last accessed time (int64 timestamp)"},
|
|
110
|
+
)
|
|
84
111
|
article: Optional[dict] = dataclass_field(
|
|
85
112
|
default=None,
|
|
86
113
|
metadata={
|
|
@@ -245,6 +272,199 @@ class CapsuleSearchResults:
|
|
|
245
272
|
)
|
|
246
273
|
|
|
247
274
|
|
|
275
|
+
@dataclass_json
|
|
276
|
+
@dataclass(frozen=True)
|
|
277
|
+
class AppPanelCategories:
|
|
278
|
+
"""Categories for a capsule's App Panel parameters."""
|
|
279
|
+
|
|
280
|
+
id: str = dataclass_field(
|
|
281
|
+
metadata={"description": "Unique identifier for the category."},
|
|
282
|
+
)
|
|
283
|
+
name: str = dataclass_field(
|
|
284
|
+
metadata={"description": "Human-readable name of the category."},
|
|
285
|
+
)
|
|
286
|
+
description: Optional[str] = dataclass_field(
|
|
287
|
+
default=None,
|
|
288
|
+
metadata={"description": "Optional detailed description of the category."},
|
|
289
|
+
)
|
|
290
|
+
help_text: Optional[str] = dataclass_field(
|
|
291
|
+
default=None,
|
|
292
|
+
metadata={"description": "Optional help text providing guidance or additional information about the category."},
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
@dataclass_json
|
|
297
|
+
@dataclass(frozen=True)
|
|
298
|
+
class AppPanelParameters:
|
|
299
|
+
"""Parameters for a capsule's App Panel."""
|
|
300
|
+
|
|
301
|
+
name: str = dataclass_field(
|
|
302
|
+
metadata={"description": "Parameter label/display name."}
|
|
303
|
+
)
|
|
304
|
+
type: AppPanelParameterType = dataclass_field(
|
|
305
|
+
metadata={"description": "Type of the parameter (text, list, file)."}
|
|
306
|
+
)
|
|
307
|
+
category: Optional[str] = dataclass_field(
|
|
308
|
+
default=None,
|
|
309
|
+
metadata={"description": "ID of category the parameter belongs to."}
|
|
310
|
+
)
|
|
311
|
+
param_name: Optional[str] = dataclass_field(
|
|
312
|
+
default=None,
|
|
313
|
+
metadata={"description": "The parameter name/argument key"}
|
|
314
|
+
)
|
|
315
|
+
description: Optional[str] = dataclass_field(
|
|
316
|
+
default=None,
|
|
317
|
+
metadata={"description": "Description of the parameter."}
|
|
318
|
+
)
|
|
319
|
+
help_text: Optional[str] = dataclass_field(
|
|
320
|
+
default=None,
|
|
321
|
+
metadata={"description": "Help text for the parameter."}
|
|
322
|
+
)
|
|
323
|
+
value_type: Optional[str] = dataclass_field(
|
|
324
|
+
default=None,
|
|
325
|
+
metadata={"description": "Value type of the parameter."}
|
|
326
|
+
)
|
|
327
|
+
default_value: Optional[str] = dataclass_field(
|
|
328
|
+
default=None,
|
|
329
|
+
metadata={"description": "Default value of the parameter."}
|
|
330
|
+
)
|
|
331
|
+
required: Optional[bool] = dataclass_field(
|
|
332
|
+
default=None,
|
|
333
|
+
metadata={"description": "Indicates if the parameter is required."}
|
|
334
|
+
)
|
|
335
|
+
hidden: Optional[bool] = dataclass_field(
|
|
336
|
+
default=None,
|
|
337
|
+
metadata={"description": "Indicates if the parameter is hidden."}
|
|
338
|
+
)
|
|
339
|
+
minimum: Optional[float] = dataclass_field(
|
|
340
|
+
default=None,
|
|
341
|
+
metadata={"description": "Minimum value for the parameter."}
|
|
342
|
+
)
|
|
343
|
+
maximum: Optional[float] = dataclass_field(
|
|
344
|
+
default=None,
|
|
345
|
+
metadata={"description": "Maximum value for the parameter."}
|
|
346
|
+
)
|
|
347
|
+
pattern: Optional[str] = dataclass_field(
|
|
348
|
+
default=None,
|
|
349
|
+
metadata={"description": "Regular expression pattern for the parameter."}
|
|
350
|
+
)
|
|
351
|
+
value_options: Optional[list[str]] = dataclass_field(
|
|
352
|
+
default=None,
|
|
353
|
+
metadata={"description": "Allowed values for the parameter."}
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
@dataclass_json
|
|
358
|
+
@dataclass(frozen=True)
|
|
359
|
+
class AppPanelGeneral:
|
|
360
|
+
"""General information about a capsule's App Panel."""
|
|
361
|
+
|
|
362
|
+
title: Optional[str] = dataclass_field(
|
|
363
|
+
default=None,
|
|
364
|
+
metadata={"description": "Title of the App Panel."}
|
|
365
|
+
)
|
|
366
|
+
instructions: Optional[str] = dataclass_field(
|
|
367
|
+
default=None,
|
|
368
|
+
metadata={"description": "Instructions for using the App Panel."}
|
|
369
|
+
)
|
|
370
|
+
help_text: Optional[str] = dataclass_field(
|
|
371
|
+
default=None,
|
|
372
|
+
metadata={"description": "Help text for the App Panel."}
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
@dataclass_json
|
|
377
|
+
@dataclass(frozen=True)
|
|
378
|
+
class AppPanelDataAsset:
|
|
379
|
+
"""Data asset parameter for the App Panel."""
|
|
380
|
+
|
|
381
|
+
id: str = dataclass_field(
|
|
382
|
+
metadata={"description": "Unique identifier for the data asset."}
|
|
383
|
+
)
|
|
384
|
+
mount: str = dataclass_field(
|
|
385
|
+
metadata={"description": "Mount path of the data asset within the capsule. "
|
|
386
|
+
"Use this mount path to replace the currently attached data asset with your own"}
|
|
387
|
+
)
|
|
388
|
+
name: str = dataclass_field(
|
|
389
|
+
metadata={"description": "Display name of the data asset."}
|
|
390
|
+
)
|
|
391
|
+
kind: AppPanelDataAssetKind = dataclass_field(
|
|
392
|
+
metadata={"description": "Kind of the data asset (internal, external, combined)."}
|
|
393
|
+
)
|
|
394
|
+
accessible: bool = dataclass_field(
|
|
395
|
+
metadata={"description": "Indicates if the data asset is accessible to the user."}
|
|
396
|
+
)
|
|
397
|
+
description: Optional[str] = dataclass_field(
|
|
398
|
+
default=None,
|
|
399
|
+
metadata={"description": "Optional description of the data asset parameter."}
|
|
400
|
+
)
|
|
401
|
+
help_text: Optional[str] = dataclass_field(
|
|
402
|
+
default=None,
|
|
403
|
+
metadata={"description": "Optional help text for the data asset parameter."}
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
@dataclass_json
|
|
408
|
+
@dataclass(frozen=True)
|
|
409
|
+
class AppPanelResult:
|
|
410
|
+
"""Selected result files to display once the computation is complete."""
|
|
411
|
+
|
|
412
|
+
file_name: str = dataclass_field(
|
|
413
|
+
metadata={"description": "Name of the result file."}
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
@dataclass_json
|
|
418
|
+
@dataclass(frozen=True)
|
|
419
|
+
class AppPanelProcess:
|
|
420
|
+
"""Pipeline process name and its corresponding app panel (for pipelines of capsules only)"""
|
|
421
|
+
|
|
422
|
+
name: str = dataclass_field(
|
|
423
|
+
metadata={"description": "Name of the pipeline process."}
|
|
424
|
+
)
|
|
425
|
+
categories: Optional[AppPanelCategories] = dataclass_field(
|
|
426
|
+
default=None,
|
|
427
|
+
metadata={"description": "Categories for the pipeline process's app panel parameters."}
|
|
428
|
+
)
|
|
429
|
+
parameters: Optional[AppPanelParameters] = dataclass_field(
|
|
430
|
+
default=None,
|
|
431
|
+
metadata={"description": "Parameters for the pipeline process's app panel."}
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@dataclass_json
|
|
436
|
+
@dataclass(frozen=True)
|
|
437
|
+
class AppPanel:
|
|
438
|
+
"""App Panel configuration for a capsule or pipeline, including general info, data assets,
|
|
439
|
+
categories, parameters, and results.
|
|
440
|
+
"""
|
|
441
|
+
|
|
442
|
+
general: Optional[AppPanelGeneral] = dataclass_field(
|
|
443
|
+
default=None,
|
|
444
|
+
metadata={"description": "General information about the App Panel."}
|
|
445
|
+
)
|
|
446
|
+
data_assets: Optional[list[AppPanelDataAsset]] = dataclass_field(
|
|
447
|
+
default=None,
|
|
448
|
+
metadata={"description": "List of data assets used in the App Panel."}
|
|
449
|
+
)
|
|
450
|
+
categories: Optional[list[AppPanelCategories]] = dataclass_field(
|
|
451
|
+
default=None,
|
|
452
|
+
metadata={"description": "Categories for organizing App Panel parameters."}
|
|
453
|
+
)
|
|
454
|
+
parameters: Optional[list[AppPanelParameters]] = dataclass_field(
|
|
455
|
+
default=None,
|
|
456
|
+
metadata={"description": "Parameters for the App Panel."}
|
|
457
|
+
)
|
|
458
|
+
results: Optional[list[AppPanelResult]] = dataclass_field(
|
|
459
|
+
default=None,
|
|
460
|
+
metadata={"description": "Result files to display after computation."}
|
|
461
|
+
)
|
|
462
|
+
processes: Optional[list[AppPanelProcess]] = dataclass_field(
|
|
463
|
+
default=None,
|
|
464
|
+
metadata={"description": "Pipeline processes and their App Panels."}
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
|
|
248
468
|
@dataclass
|
|
249
469
|
class Capsules:
|
|
250
470
|
"""Client for interacting with Code Ocean capsule APIs."""
|
|
@@ -257,6 +477,16 @@ class Capsules:
|
|
|
257
477
|
|
|
258
478
|
return Capsule.from_dict(res.json())
|
|
259
479
|
|
|
480
|
+
def delete_capsule(self, capsule_id: str):
|
|
481
|
+
"""Delete a capsule permanently."""
|
|
482
|
+
self.client.delete(f"capsules/{capsule_id}")
|
|
483
|
+
|
|
484
|
+
def get_capsule_app_panel(self, capsule_id: str, version: Optional[int] = None) -> AppPanel:
|
|
485
|
+
"""Retrieve app panel information for a specific capsule by its ID."""
|
|
486
|
+
res = self.client.get(f"capsules/{capsule_id}/app_panel", params={"version": version} if version else None)
|
|
487
|
+
|
|
488
|
+
return AppPanel.from_dict(res.json())
|
|
489
|
+
|
|
260
490
|
def list_computations(self, capsule_id: str) -> list[Computation]:
|
|
261
491
|
"""Get all computations associated with a specific capsule."""
|
|
262
492
|
res = self.client.get(f"capsules/{capsule_id}/computations")
|
|
@@ -290,6 +520,13 @@ class Capsules:
|
|
|
290
520
|
json=data_assets,
|
|
291
521
|
)
|
|
292
522
|
|
|
523
|
+
def archive_capsule(self, capsule_id: str, archive: bool):
|
|
524
|
+
"""Archive or unarchive a capsule to control its visibility and accessibility."""
|
|
525
|
+
self.client.patch(
|
|
526
|
+
f"capsules/{capsule_id}/archive",
|
|
527
|
+
params={"archive": archive},
|
|
528
|
+
)
|
|
529
|
+
|
|
293
530
|
def search_capsules(self, search_params: CapsuleSearchParams) -> CapsuleSearchResults:
|
|
294
531
|
"""Search for capsules with filtering, sorting, and pagination
|
|
295
532
|
options."""
|
|
@@ -9,6 +9,7 @@ import requests
|
|
|
9
9
|
|
|
10
10
|
from codeocean.capsule import Capsules
|
|
11
11
|
from codeocean.computation import Computations
|
|
12
|
+
from codeocean.custom_metadata import CustomMetadataSchema
|
|
12
13
|
from codeocean.data_asset import DataAssets
|
|
13
14
|
from codeocean.error import Error
|
|
14
15
|
|
|
@@ -36,7 +37,7 @@ class CodeOcean:
|
|
|
36
37
|
agent_id: Optional[str] = None
|
|
37
38
|
|
|
38
39
|
# Minimum server version required by this SDK
|
|
39
|
-
MIN_SERVER_VERSION = "
|
|
40
|
+
MIN_SERVER_VERSION = "4.0.0"
|
|
40
41
|
|
|
41
42
|
def __post_init__(self):
|
|
42
43
|
self.session = BaseUrlSession(base_url=f"{self.domain}/api/v1/")
|
|
@@ -52,6 +53,7 @@ class CodeOcean:
|
|
|
52
53
|
|
|
53
54
|
self.capsules = Capsules(client=self.session)
|
|
54
55
|
self.computations = Computations(client=self.session)
|
|
56
|
+
self.custom_metadata = CustomMetadataSchema(client=self.session)
|
|
55
57
|
self.data_assets = DataAssets(client=self.session)
|
|
56
58
|
|
|
57
59
|
def _error_handler(self, response, *args, **kwargs):
|
|
@@ -5,9 +5,10 @@ from dataclasses_json import dataclass_json
|
|
|
5
5
|
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
6
|
from typing import Optional
|
|
7
7
|
from time import sleep, time
|
|
8
|
+
from warnings import warn
|
|
8
9
|
|
|
9
10
|
from codeocean.enum import StrEnum
|
|
10
|
-
from codeocean.folder import Folder, DownloadFileURL
|
|
11
|
+
from codeocean.folder import FileURLs, Folder, DownloadFileURL
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class ComputationState(StrEnum):
|
|
@@ -332,7 +333,16 @@ class Computations:
|
|
|
332
333
|
return Folder.from_dict(res.json())
|
|
333
334
|
|
|
334
335
|
def get_result_file_download_url(self, computation_id: str, path: str) -> DownloadFileURL:
|
|
335
|
-
"""Generate a download URL for a specific result file from a computation.
|
|
336
|
+
"""[DEPRECATED] Generate a download URL for a specific result file from a computation.
|
|
337
|
+
|
|
338
|
+
Deprecated: Use get_result_file_urls instead.
|
|
339
|
+
"""
|
|
340
|
+
warn(
|
|
341
|
+
"get_result_file_download_url is deprecated and will be removed in a future release. "
|
|
342
|
+
"Use get_result_file_urls instead.",
|
|
343
|
+
DeprecationWarning,
|
|
344
|
+
stacklevel=2,
|
|
345
|
+
)
|
|
336
346
|
res = self.client.get(
|
|
337
347
|
f"computations/{computation_id}/results/download_url",
|
|
338
348
|
params={"path": path},
|
|
@@ -340,6 +350,15 @@ class Computations:
|
|
|
340
350
|
|
|
341
351
|
return DownloadFileURL.from_dict(res.json())
|
|
342
352
|
|
|
353
|
+
def get_result_file_urls(self, computation_id: str, path: str) -> FileURLs:
|
|
354
|
+
"""Generate view and download URLs for a specific result file from a computation."""
|
|
355
|
+
res = self.client.get(
|
|
356
|
+
f"computations/{computation_id}/results/urls",
|
|
357
|
+
params={"path": path},
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
return FileURLs.from_dict(res.json())
|
|
361
|
+
|
|
343
362
|
def delete_computation(self, computation_id: str):
|
|
344
363
|
"""Delete a computation and stop it if currently running."""
|
|
345
364
|
self.client.delete(f"computations/{computation_id}")
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field as dataclass_field
|
|
4
|
+
from dataclasses_json import dataclass_json
|
|
5
|
+
from typing import Optional, Union
|
|
6
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
7
|
+
|
|
8
|
+
from codeocean.enum import StrEnum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CustomMetadataFieldType(StrEnum):
|
|
12
|
+
""" Type of the custom metadata field value. """
|
|
13
|
+
|
|
14
|
+
String = "string"
|
|
15
|
+
Number = "number"
|
|
16
|
+
Date = "date"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass_json
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class CustomMetadataFieldRange:
|
|
22
|
+
""" Range of valid values for a custom metadata field. """
|
|
23
|
+
|
|
24
|
+
min: Optional[float] = dataclass_field(
|
|
25
|
+
default=None,
|
|
26
|
+
metadata={"description": "Minimum valid value"}
|
|
27
|
+
)
|
|
28
|
+
max: Optional[float] = dataclass_field(
|
|
29
|
+
default=None,
|
|
30
|
+
metadata={"description": "Maximum valid value"}
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass_json
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class CustomMetadataField:
|
|
37
|
+
""" Represents a custom metadata field in the Code Ocean platform. """
|
|
38
|
+
|
|
39
|
+
name: str = dataclass_field(
|
|
40
|
+
metadata={"description": "Name of the custom metadata field"}
|
|
41
|
+
)
|
|
42
|
+
type: CustomMetadataFieldType = dataclass_field(
|
|
43
|
+
metadata={"description": "Type of the custom metadata field value (string, number, date)"}
|
|
44
|
+
)
|
|
45
|
+
range: Optional[CustomMetadataFieldRange] = dataclass_field(
|
|
46
|
+
default=None,
|
|
47
|
+
metadata={"description": "Range of valid values for the field"}
|
|
48
|
+
)
|
|
49
|
+
allowed_values: Optional[Union[list[str], list[float]]] = dataclass_field(
|
|
50
|
+
default=None,
|
|
51
|
+
metadata={"description": "Allowed values for the field (item type according to field type)"}
|
|
52
|
+
)
|
|
53
|
+
multiple: Optional[bool] = dataclass_field(
|
|
54
|
+
default=None,
|
|
55
|
+
metadata={"description": "Whether multiple values are allowed"}
|
|
56
|
+
)
|
|
57
|
+
units: Optional[str] = dataclass_field(
|
|
58
|
+
default=None,
|
|
59
|
+
metadata={"description": "Units of the field value"}
|
|
60
|
+
)
|
|
61
|
+
category: Optional[str] = dataclass_field(
|
|
62
|
+
default=None,
|
|
63
|
+
metadata={"description": "Category of the field"}
|
|
64
|
+
)
|
|
65
|
+
required: Optional[bool] = dataclass_field(
|
|
66
|
+
default=None,
|
|
67
|
+
metadata={"description": "Whether the field is required"}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass_json
|
|
72
|
+
@dataclass(frozen=True)
|
|
73
|
+
class CustomMetadata:
|
|
74
|
+
""" Represents the custom metadata schema in the Code Ocean platform. """
|
|
75
|
+
|
|
76
|
+
fields: Optional[list[CustomMetadataField]] = dataclass_field(
|
|
77
|
+
default=None,
|
|
78
|
+
metadata={"description": "List of custom metadata fields"}
|
|
79
|
+
)
|
|
80
|
+
categories: Optional[list[str]] = dataclass_field(
|
|
81
|
+
default=None,
|
|
82
|
+
metadata={"description": "List of categories for custom metadata fields"}
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass
|
|
87
|
+
class CustomMetadataSchema:
|
|
88
|
+
"""Client for getting the Code Ocean custom metadata schema."""
|
|
89
|
+
|
|
90
|
+
client: BaseUrlSession
|
|
91
|
+
|
|
92
|
+
def get_custom_metadata(self) -> CustomMetadata:
|
|
93
|
+
"""Retrieve the Code Ocean deployment's custom metadata schema."""
|
|
94
|
+
res = self.client.get("custom_metadata")
|
|
95
|
+
|
|
96
|
+
return CustomMetadata.from_dict(res.json())
|
|
@@ -5,11 +5,12 @@ from dataclasses import dataclass, field
|
|
|
5
5
|
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
6
|
from time import sleep, time
|
|
7
7
|
from typing import Optional, Iterator
|
|
8
|
+
from warnings import warn
|
|
8
9
|
|
|
9
10
|
from codeocean.components import Ownership, SortOrder, SearchFilter, Permissions
|
|
10
11
|
from codeocean.computation import PipelineProcess, Param
|
|
11
12
|
from codeocean.enum import StrEnum
|
|
12
|
-
from codeocean.folder import Folder, DownloadFileURL
|
|
13
|
+
from codeocean.folder import FileURLs, Folder, DownloadFileURL
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class DataAssetType(StrEnum):
|
|
@@ -849,7 +850,16 @@ class DataAssets:
|
|
|
849
850
|
return Folder.from_dict(res.json())
|
|
850
851
|
|
|
851
852
|
def get_data_asset_file_download_url(self, data_asset_id: str, path: str) -> DownloadFileURL:
|
|
852
|
-
"""Generate a download URL for a specific file from an internal data asset.
|
|
853
|
+
"""(Deprecated) Generate a download URL for a specific file from an internal data asset.
|
|
854
|
+
|
|
855
|
+
Deprecated: Use get_data_asset_file_urls instead.
|
|
856
|
+
"""
|
|
857
|
+
warn(
|
|
858
|
+
"get_data_asset_file_download_url is deprecated and will be removed in a future release. "
|
|
859
|
+
"Use get_data_asset_file_urls instead.",
|
|
860
|
+
DeprecationWarning,
|
|
861
|
+
stacklevel=2,
|
|
862
|
+
)
|
|
853
863
|
res = self.client.get(
|
|
854
864
|
f"data_assets/{data_asset_id}/files/download_url",
|
|
855
865
|
params={"path": path},
|
|
@@ -857,6 +867,15 @@ class DataAssets:
|
|
|
857
867
|
|
|
858
868
|
return DownloadFileURL.from_dict(res.json())
|
|
859
869
|
|
|
870
|
+
def get_data_asset_file_urls(self, data_asset_id: str, path: str) -> FileURLs:
|
|
871
|
+
"""Generate view and download URLs for a specific file from an internal data asset."""
|
|
872
|
+
res = self.client.get(
|
|
873
|
+
f"data_assets/{data_asset_id}/files/urls",
|
|
874
|
+
params={"path": path},
|
|
875
|
+
)
|
|
876
|
+
|
|
877
|
+
return FileURLs.from_dict(res.json())
|
|
878
|
+
|
|
860
879
|
def transfer_data_asset(self, data_asset_id: str, transfer_params: TransferDataParams):
|
|
861
880
|
"""
|
|
862
881
|
Transfer a data asset's files to a different S3 storage location (Admin only).
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses_json import dataclass_json
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from typing import Optional
|
|
6
|
+
from warnings import warn
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
@dataclass_json
|
|
@@ -53,3 +54,23 @@ class DownloadFileURL:
|
|
|
53
54
|
url: str = field(
|
|
54
55
|
metadata={"description": "Pre-signed URL for downloading the specified file"}
|
|
55
56
|
)
|
|
57
|
+
|
|
58
|
+
def __post_init__(self):
|
|
59
|
+
warn(
|
|
60
|
+
"DownloadFileURL is deprecated and will be removed in a future release.",
|
|
61
|
+
DeprecationWarning,
|
|
62
|
+
stacklevel=2
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass_json
|
|
67
|
+
@dataclass(frozen=True)
|
|
68
|
+
class FileURLs:
|
|
69
|
+
"""Represents a collection of file download URLs."""
|
|
70
|
+
|
|
71
|
+
download_url: str = field(
|
|
72
|
+
metadata={"description": "Signed URL for downloading the file"}
|
|
73
|
+
)
|
|
74
|
+
view_url: str = field(
|
|
75
|
+
metadata={"description": "Signed URL for viewing the file in the browser"}
|
|
76
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|