codeocean 0.2.0__tar.gz → 0.3.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.2.0 → codeocean-0.3.0}/CHANGELOG.md +9 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/PKG-INFO +2 -3
- {codeocean-0.2.0 → codeocean-0.3.0}/pyproject.toml +3 -4
- {codeocean-0.2.0 → codeocean-0.3.0}/src/codeocean/capsule.py +40 -7
- {codeocean-0.2.0 → codeocean-0.3.0}/src/codeocean/client.py +3 -1
- {codeocean-0.2.0 → codeocean-0.3.0}/src/codeocean/components.py +6 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/src/codeocean/computation.py +11 -30
- {codeocean-0.2.0 → codeocean-0.3.0}/src/codeocean/data_asset.py +78 -23
- codeocean-0.3.0/src/codeocean/folder.py +32 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/.flake8 +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/.gitignore +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/LICENSE +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/README.md +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/examples/create_data_asset.py +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/examples/run_capsule.py +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/examples/run_pipeline.py +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/src/codeocean/__init__.py +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/src/codeocean/enum.py +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/tests/__init__.py +0 -0
- {codeocean-0.2.0 → codeocean-0.3.0}/tests/test_package.py +0 -0
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## 0.3.0 (2025-01-07)
|
|
5
|
+
|
|
6
|
+
- [#25](https://github.com/codeocean/codeocean-sdk-python/pull/25) feat: Add support for Python 3.13
|
|
7
|
+
- [#24](https://github.com/codeocean/codeocean-sdk-python/pull/24) feat: Paginated data asset search
|
|
8
|
+
- [#22](https://github.com/codeocean/codeocean-sdk-python/pull/22) feat: add support for rename computation API
|
|
9
|
+
- [#21](https://github.com/codeocean/codeocean-sdk-python/pull/21) feat: Code Ocean Version 3.1 updates
|
|
10
|
+
- [#18](https://github.com/codeocean/codeocean-sdk-python/pull/18) feat: Combined data asset
|
|
11
|
+
- [#16](https://github.com/codeocean/codeocean-sdk-python/pull/16) fix: revert default number of retries to 0
|
|
12
|
+
|
|
4
13
|
## 0.2.0 (2024-10-21)
|
|
5
14
|
|
|
6
15
|
- [#15](https://github.com/codeocean/codeocean-sdk-python/pull/15) feat: Add option for custom retries
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: codeocean
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Code Ocean Python SDK
|
|
5
5
|
Project-URL: Homepage, https://github.com/codeocean/codeocean-sdk-python
|
|
6
6
|
Project-URL: Issues, https://github.com/codeocean/codeocean-sdk-python/issues
|
|
@@ -13,7 +13,6 @@ Classifier: Operating System :: OS Independent
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Requires-Python: >=3.9
|
|
15
15
|
Requires-Dist: backports-strenum>=1.3.1; python_version < '3.11'
|
|
16
|
-
Requires-Dist: dataclasses
|
|
17
16
|
Requires-Dist: dataclasses-json
|
|
18
17
|
Requires-Dist: requests
|
|
19
18
|
Requires-Dist: requests-toolbelt
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codeocean"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Code Ocean", email="dev@codeocean.com" },
|
|
10
10
|
]
|
|
@@ -17,8 +17,7 @@ classifiers = [
|
|
|
17
17
|
"Operating System :: OS Independent",
|
|
18
18
|
]
|
|
19
19
|
dependencies = [
|
|
20
|
-
"dataclasses",
|
|
21
|
-
"dataclasses_json",
|
|
20
|
+
"dataclasses-json",
|
|
22
21
|
"requests",
|
|
23
22
|
"requests_toolbelt",
|
|
24
23
|
"backports.strenum>=1.3.1; python_version<'3.11'",
|
|
@@ -51,4 +50,4 @@ lint = "flake8 src tests examples"
|
|
|
51
50
|
test = "python -m unittest -v"
|
|
52
51
|
|
|
53
52
|
[[tool.hatch.envs.test.matrix]]
|
|
54
|
-
python = ["3.9", "3.10", "3.11", "3.12"]
|
|
53
|
+
python = ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
@@ -5,17 +5,21 @@ from dataclasses_json import dataclass_json
|
|
|
5
5
|
from typing import Optional
|
|
6
6
|
from requests_toolbelt.sessions import BaseUrlSession
|
|
7
7
|
|
|
8
|
+
from codeocean.components import Ownership, SortOrder, SearchFilter
|
|
8
9
|
from codeocean.computation import Computation
|
|
9
10
|
from codeocean.data_asset import DataAssetAttachParams, DataAssetAttachResults
|
|
10
11
|
from codeocean.enum import StrEnum
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class CapsuleStatus(StrEnum):
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
NonRelease = "non_release"
|
|
16
|
+
Release = "release"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CapsuleSortBy(StrEnum):
|
|
20
|
+
Created = "created"
|
|
21
|
+
LastAccessed = "last_accessed"
|
|
22
|
+
Name = "name"
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
@dataclass_json
|
|
@@ -42,13 +46,37 @@ class Capsule:
|
|
|
42
46
|
cloned_from_url: Optional[str] = None
|
|
43
47
|
description: Optional[str] = None
|
|
44
48
|
field: Optional[str] = None
|
|
45
|
-
|
|
49
|
+
tags: Optional[list[str]] = None
|
|
46
50
|
original_capsule: Optional[OriginalCapsuleInfo] = None
|
|
47
|
-
|
|
51
|
+
release_capsule: Optional[str] = None
|
|
48
52
|
submission: Optional[dict] = None
|
|
49
53
|
versions: Optional[list[dict]] = None
|
|
50
54
|
|
|
51
55
|
|
|
56
|
+
@dataclass_json
|
|
57
|
+
@dataclass(frozen=True)
|
|
58
|
+
class CapsuleSearchParams:
|
|
59
|
+
query: Optional[str] = None
|
|
60
|
+
next_token: Optional[str] = None
|
|
61
|
+
offset: Optional[int] = None
|
|
62
|
+
limit: Optional[int] = None
|
|
63
|
+
sort_field: Optional[CapsuleSortBy] = None
|
|
64
|
+
sort_order: Optional[SortOrder] = None
|
|
65
|
+
ownership: Optional[Ownership] = None
|
|
66
|
+
status: Optional[CapsuleStatus] = None
|
|
67
|
+
favorite: Optional[bool] = None
|
|
68
|
+
archived: Optional[bool] = None
|
|
69
|
+
filters: Optional[list[SearchFilter]] = None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass_json
|
|
73
|
+
@dataclass(frozen=True)
|
|
74
|
+
class CapsuleSearchResults:
|
|
75
|
+
has_more: bool
|
|
76
|
+
results: list[Capsule]
|
|
77
|
+
next_token: Optional[str] = None
|
|
78
|
+
|
|
79
|
+
|
|
52
80
|
@dataclass
|
|
53
81
|
class Capsules:
|
|
54
82
|
|
|
@@ -80,3 +108,8 @@ class Capsules:
|
|
|
80
108
|
f"capsules/{capsule_id}/data_assets/",
|
|
81
109
|
json=data_assets,
|
|
82
110
|
)
|
|
111
|
+
|
|
112
|
+
def search_capsules(self, search_params: CapsuleSearchParams) -> CapsuleSearchResults:
|
|
113
|
+
res = self.client.post("capsules/search", json=search_params.to_dict())
|
|
114
|
+
|
|
115
|
+
return CapsuleSearchResults.from_dict(res.json())
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from dataclasses import dataclass
|
|
2
4
|
from requests_toolbelt.adapters.socket_options import TCPKeepAliveAdapter
|
|
3
5
|
from requests_toolbelt.sessions import BaseUrlSession
|
|
@@ -14,7 +16,7 @@ class CodeOcean:
|
|
|
14
16
|
|
|
15
17
|
domain: str
|
|
16
18
|
token: str
|
|
17
|
-
retries: Optional[Retry] =
|
|
19
|
+
retries: Optional[Retry | int] = 0
|
|
18
20
|
|
|
19
21
|
def __post_init__(self):
|
|
20
22
|
self.session = BaseUrlSession(base_url=f"{self.domain}/api/v1/")
|
|
@@ -7,6 +7,7 @@ from typing import Optional
|
|
|
7
7
|
from time import sleep, time
|
|
8
8
|
|
|
9
9
|
from codeocean.enum import StrEnum
|
|
10
|
+
from codeocean.folder import Folder, DownloadFileURL
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class ComputationState(StrEnum):
|
|
@@ -54,14 +55,15 @@ class Computation:
|
|
|
54
55
|
id: str
|
|
55
56
|
created: int
|
|
56
57
|
name: str
|
|
57
|
-
state: ComputationState
|
|
58
58
|
run_time: int
|
|
59
|
+
state: ComputationState
|
|
59
60
|
cloud_workstation: Optional[bool] = None
|
|
60
61
|
data_assets: Optional[list[InputDataAsset]] = None
|
|
61
|
-
end_status: Optional[ComputationEndStatus] = None
|
|
62
|
-
has_results: Optional[bool] = None
|
|
63
62
|
parameters: Optional[list[Param]] = None
|
|
64
63
|
processes: Optional[list[PipelineProcess]] = None
|
|
64
|
+
end_status: Optional[ComputationEndStatus] = None
|
|
65
|
+
exit_code: Optional[int] = None
|
|
66
|
+
has_results: Optional[bool] = None
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
@dataclass_json
|
|
@@ -99,33 +101,6 @@ class RunParams:
|
|
|
99
101
|
processes: Optional[list[PipelineProcessParams]] = None
|
|
100
102
|
|
|
101
103
|
|
|
102
|
-
@dataclass_json
|
|
103
|
-
@dataclass(frozen=True)
|
|
104
|
-
class FolderItem:
|
|
105
|
-
name: str
|
|
106
|
-
path: str
|
|
107
|
-
type: str
|
|
108
|
-
size: Optional[int] = None
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
@dataclass_json
|
|
112
|
-
@dataclass(frozen=True)
|
|
113
|
-
class Folder:
|
|
114
|
-
items: list[FolderItem]
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
@dataclass_json
|
|
118
|
-
@dataclass(frozen=True)
|
|
119
|
-
class ListFolderParams:
|
|
120
|
-
path: str
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@dataclass_json
|
|
124
|
-
@dataclass(frozen=True)
|
|
125
|
-
class DownloadFileURL:
|
|
126
|
-
url: str
|
|
127
|
-
|
|
128
|
-
|
|
129
104
|
@dataclass
|
|
130
105
|
class Computations:
|
|
131
106
|
|
|
@@ -195,3 +170,9 @@ class Computations:
|
|
|
195
170
|
|
|
196
171
|
def delete_computation(self, computation_id: str):
|
|
197
172
|
self.client.delete(f"computations/{computation_id}")
|
|
173
|
+
|
|
174
|
+
def rename_computation(self, computation_id: str, name: str):
|
|
175
|
+
self.client.patch(
|
|
176
|
+
f"computations/{computation_id}",
|
|
177
|
+
params={"name": name}
|
|
178
|
+
)
|
|
@@ -4,16 +4,19 @@ from dataclasses_json import dataclass_json
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
6
|
from time import sleep, time
|
|
7
|
-
from typing import Optional
|
|
7
|
+
from typing import Optional, Iterator
|
|
8
8
|
|
|
9
|
-
from codeocean.components import SortOrder, SearchFilter, Permissions
|
|
9
|
+
from codeocean.components import Ownership, SortOrder, SearchFilter, Permissions
|
|
10
10
|
from codeocean.computation import PipelineProcess, Param
|
|
11
11
|
from codeocean.enum import StrEnum
|
|
12
|
+
from codeocean.folder import Folder, DownloadFileURL
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class DataAssetType(StrEnum):
|
|
15
16
|
Dataset = "dataset"
|
|
16
17
|
Result = "result"
|
|
18
|
+
Combined = "combined"
|
|
19
|
+
Model = "model"
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
class DataAssetState(StrEnum):
|
|
@@ -25,10 +28,10 @@ class DataAssetState(StrEnum):
|
|
|
25
28
|
@dataclass_json
|
|
26
29
|
@dataclass(frozen=True)
|
|
27
30
|
class Provenance:
|
|
28
|
-
commit: str
|
|
29
|
-
run_script: str
|
|
30
|
-
docker_image: str
|
|
31
|
-
capsule: str
|
|
31
|
+
commit: Optional[str] = None
|
|
32
|
+
run_script: Optional[str] = None
|
|
33
|
+
docker_image: Optional[str] = None
|
|
34
|
+
capsule: Optional[str] = None
|
|
32
35
|
data_assets: Optional[list[str]] = None
|
|
33
36
|
|
|
34
37
|
|
|
@@ -77,15 +80,18 @@ class DataAsset:
|
|
|
77
80
|
state: DataAssetState
|
|
78
81
|
type: DataAssetType
|
|
79
82
|
last_used: int
|
|
80
|
-
app_parameters: Optional[list[AppParameter]] = None
|
|
81
|
-
custom_metadata: Optional[dict] = None
|
|
82
|
-
description: Optional[str] = None
|
|
83
|
-
failure_reason: Optional[str] = None
|
|
84
83
|
files: Optional[int] = None
|
|
85
|
-
provenance: Optional[Provenance] = None
|
|
86
84
|
size: Optional[int] = None
|
|
87
|
-
|
|
85
|
+
description: Optional[str] = None
|
|
88
86
|
tags: Optional[list[str]] = None
|
|
87
|
+
provenance: Optional[Provenance] = None
|
|
88
|
+
source_bucket: Optional[SourceBucket] = None
|
|
89
|
+
custom_metadata: Optional[dict] = None
|
|
90
|
+
app_parameters: Optional[list[AppParameter]] = None
|
|
91
|
+
contained_data_assets: Optional[list[ContainedDataAsset]] = None
|
|
92
|
+
last_transferred: Optional[int] = None
|
|
93
|
+
transfer_error: Optional[str] = None
|
|
94
|
+
failure_reason: Optional[str] = None
|
|
89
95
|
|
|
90
96
|
|
|
91
97
|
@dataclass_json
|
|
@@ -183,12 +189,6 @@ class DataAssetSortBy(StrEnum):
|
|
|
183
189
|
Size = "size"
|
|
184
190
|
|
|
185
191
|
|
|
186
|
-
class DataAssetOwnership(StrEnum):
|
|
187
|
-
Private = "private"
|
|
188
|
-
Shared = "shared"
|
|
189
|
-
Created = "created"
|
|
190
|
-
|
|
191
|
-
|
|
192
192
|
class DataAssetSearchOrigin(StrEnum):
|
|
193
193
|
Internal = "internal"
|
|
194
194
|
External = "external"
|
|
@@ -197,16 +197,17 @@ class DataAssetSearchOrigin(StrEnum):
|
|
|
197
197
|
@dataclass_json
|
|
198
198
|
@dataclass(frozen=True)
|
|
199
199
|
class DataAssetSearchParams:
|
|
200
|
-
limit: int
|
|
201
|
-
offset: int
|
|
202
|
-
archived: bool
|
|
203
|
-
favorite: bool
|
|
204
200
|
query: Optional[str] = None
|
|
201
|
+
next_token: Optional[str] = None
|
|
202
|
+
offset: Optional[int] = None
|
|
203
|
+
limit: Optional[int] = None
|
|
205
204
|
sort_field: Optional[DataAssetSortBy] = None
|
|
206
205
|
sort_order: Optional[SortOrder] = None
|
|
207
206
|
type: Optional[DataAssetType] = None
|
|
208
|
-
ownership: Optional[
|
|
207
|
+
ownership: Optional[Ownership] = None
|
|
209
208
|
origin: Optional[DataAssetSearchOrigin] = None
|
|
209
|
+
favorite: Optional[bool] = None
|
|
210
|
+
archived: Optional[bool] = None
|
|
210
211
|
filters: Optional[list[SearchFilter]] = None
|
|
211
212
|
|
|
212
213
|
|
|
@@ -215,6 +216,22 @@ class DataAssetSearchParams:
|
|
|
215
216
|
class DataAssetSearchResults:
|
|
216
217
|
has_more: bool
|
|
217
218
|
results: list[DataAsset]
|
|
219
|
+
next_token: Optional[str] = None
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@dataclass_json
|
|
223
|
+
@dataclass(frozen=True)
|
|
224
|
+
class ContainedDataAsset:
|
|
225
|
+
id: Optional[str] = None
|
|
226
|
+
mount: Optional[str] = None
|
|
227
|
+
size: Optional[int] = None
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@dataclass_json
|
|
231
|
+
@dataclass(frozen=True)
|
|
232
|
+
class TransferDataParams:
|
|
233
|
+
target: Target
|
|
234
|
+
force: Optional[bool] = None
|
|
218
235
|
|
|
219
236
|
|
|
220
237
|
@dataclass
|
|
@@ -291,3 +308,41 @@ class DataAssets:
|
|
|
291
308
|
res = self.client.post("data_assets/search", json=search_params.to_dict())
|
|
292
309
|
|
|
293
310
|
return DataAssetSearchResults.from_dict(res.json())
|
|
311
|
+
|
|
312
|
+
def search_data_assets_iterator(self, search_params: DataAssetSearchParams) -> Iterator[DataAsset]:
|
|
313
|
+
params = search_params.to_dict()
|
|
314
|
+
while True:
|
|
315
|
+
response = self.search_data_assets(
|
|
316
|
+
search_params=DataAssetSearchParams(**params)
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
for result in response.results:
|
|
320
|
+
yield result
|
|
321
|
+
|
|
322
|
+
if not response.has_more:
|
|
323
|
+
return
|
|
324
|
+
|
|
325
|
+
params["next_token"] = response.next_token
|
|
326
|
+
|
|
327
|
+
def list_data_asset_files(self, data_asset_id: str, path: str = "") -> Folder:
|
|
328
|
+
data = {
|
|
329
|
+
"path": path,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
res = self.client.post(f"data_assets/{data_asset_id}/files", json=data)
|
|
333
|
+
|
|
334
|
+
return Folder.from_dict(res.json())
|
|
335
|
+
|
|
336
|
+
def get_data_asset_file_download_url(self, data_asset_id: str, path: str) -> DownloadFileURL:
|
|
337
|
+
res = self.client.get(
|
|
338
|
+
f"data_assets/{data_asset_id}/files/download_url",
|
|
339
|
+
params={"path": path},
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
return DownloadFileURL.from_dict(res.json())
|
|
343
|
+
|
|
344
|
+
def transfer_data_asset(self, data_asset_id: str, transfer_params: TransferDataParams):
|
|
345
|
+
self.client.post(
|
|
346
|
+
f"data_assets/{data_asset_id}/transfer",
|
|
347
|
+
json=transfer_params.to_dict()
|
|
348
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses_json import dataclass_json
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass_json
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class FolderItem:
|
|
11
|
+
name: str
|
|
12
|
+
path: str
|
|
13
|
+
type: str
|
|
14
|
+
size: Optional[int] = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass_json
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class Folder:
|
|
20
|
+
items: list[FolderItem]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass_json
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class ListFolderParams:
|
|
26
|
+
path: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass_json
|
|
30
|
+
@dataclass(frozen=True)
|
|
31
|
+
class DownloadFileURL:
|
|
32
|
+
url: str
|
|
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
|