codeocean 0.1.0__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.
- codeocean/__init__.py +1 -0
- codeocean/capsule.py +77 -0
- codeocean/client.py +25 -0
- codeocean/components.py +68 -0
- codeocean/computation.py +171 -0
- codeocean/data_asset.py +252 -0
- codeocean-0.1.0.dist-info/METADATA +44 -0
- codeocean-0.1.0.dist-info/RECORD +10 -0
- codeocean-0.1.0.dist-info/WHEEL +4 -0
- codeocean-0.1.0.dist-info/licenses/LICENSE +21 -0
codeocean/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from codeocean.client import CodeOcean # noqa: F401
|
codeocean/capsule.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from dataclasses_json import dataclass_json
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
|
+
|
|
7
|
+
from codeocean.computation import Computation
|
|
8
|
+
from codeocean.data_asset import DataAssetAttachParams, DataAssetAttachResults
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CapsuleStatus(StrEnum):
|
|
12
|
+
NonPublished = "non-published"
|
|
13
|
+
Submitted = "submitted"
|
|
14
|
+
Publishing = "publishing"
|
|
15
|
+
Published = "published"
|
|
16
|
+
Verified = "verified"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass_json
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class OriginalCapsuleInfo:
|
|
22
|
+
id: Optional[str] = None
|
|
23
|
+
major_version: Optional[int] = None
|
|
24
|
+
minor_version: Optional[int] = None
|
|
25
|
+
name: Optional[str] = None
|
|
26
|
+
created: Optional[int] = None
|
|
27
|
+
public: Optional[bool] = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass_json
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class Capsule:
|
|
33
|
+
id: str
|
|
34
|
+
created: int
|
|
35
|
+
name: str
|
|
36
|
+
status: CapsuleStatus
|
|
37
|
+
owner: str
|
|
38
|
+
slug: str
|
|
39
|
+
article: Optional[dict] = None
|
|
40
|
+
cloned_from_url: Optional[str] = None
|
|
41
|
+
description: Optional[str] = None
|
|
42
|
+
field: Optional[str] = None
|
|
43
|
+
keywords: Optional[list[str]] = None
|
|
44
|
+
original_capsule: Optional[OriginalCapsuleInfo] = None
|
|
45
|
+
published_capsule: Optional[str] = None
|
|
46
|
+
submission: Optional[dict] = None
|
|
47
|
+
versions: Optional[list[dict]] = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class Capsules:
|
|
52
|
+
|
|
53
|
+
client: BaseUrlSession
|
|
54
|
+
|
|
55
|
+
def get_capsule(self, capsule_id: str) -> Capsule:
|
|
56
|
+
res = self.client.get(f"capsules/{capsule_id}")
|
|
57
|
+
|
|
58
|
+
return Capsule.from_dict(res.json())
|
|
59
|
+
|
|
60
|
+
def list_computations(self, capsule_id: str) -> list[Computation]:
|
|
61
|
+
res = self.client.get(f"capsules/{capsule_id}/computations")
|
|
62
|
+
|
|
63
|
+
return [Computation.from_dict(c) for c in res.json()]
|
|
64
|
+
|
|
65
|
+
def attach_data_assets(self, capsule_id: str, attach_params: list[DataAssetAttachParams]) -> DataAssetAttachResults:
|
|
66
|
+
res = self.client.post(
|
|
67
|
+
f"capsules/{capsule_id}/data_assets",
|
|
68
|
+
json=[j.to_dict() for j in attach_params],
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return DataAssetAttachResults.from_dict(res.json())
|
|
72
|
+
|
|
73
|
+
def detach_data_assets(self, capsule_id: str, data_assets: list[str]):
|
|
74
|
+
self.client.delete(
|
|
75
|
+
f"capsules/{capsule_id}/data_assets/",
|
|
76
|
+
json=data_assets,
|
|
77
|
+
)
|
codeocean/client.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from codeocean.capsule import Capsules
|
|
5
|
+
from codeocean.computation import Computations
|
|
6
|
+
from codeocean.data_asset import DataAssets
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class CodeOcean:
|
|
11
|
+
|
|
12
|
+
domain: str
|
|
13
|
+
token: str
|
|
14
|
+
|
|
15
|
+
def __post_init__(self):
|
|
16
|
+
self.session = BaseUrlSession(base_url=f"{self.domain}/api/v1/")
|
|
17
|
+
self.session.auth = (self.token, "")
|
|
18
|
+
self.session.headers.update({"Content-Type": "application/json"})
|
|
19
|
+
self.session.hooks["response"] = [
|
|
20
|
+
lambda response, *args, **kwargs: response.raise_for_status()
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
self.capsules = Capsules(client=self.session)
|
|
24
|
+
self.computations = Computations(client=self.session)
|
|
25
|
+
self.data_assets = DataAssets(client=self.session)
|
codeocean/components.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from dataclasses_json import dataclass_json
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class UserRole(StrEnum):
|
|
8
|
+
Owner = "owner"
|
|
9
|
+
Editor = "editor"
|
|
10
|
+
Viewer = "viewer"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass_json
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class UserPermissions:
|
|
16
|
+
email: str
|
|
17
|
+
role: UserRole
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GroupRole(StrEnum):
|
|
21
|
+
Owner = "owner"
|
|
22
|
+
Editor = "editor"
|
|
23
|
+
Viewer = "viewer"
|
|
24
|
+
Discoverable = "discoverable"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass_json
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class GroupPermissions:
|
|
30
|
+
group: str
|
|
31
|
+
role: GroupRole
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class EveryoneRole(StrEnum):
|
|
35
|
+
Viewer = "viewer"
|
|
36
|
+
Discoverable = "discoverable"
|
|
37
|
+
None_ = "none"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass_json
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class Permissions:
|
|
43
|
+
users: Optional[list[UserPermissions]] = None
|
|
44
|
+
groups: Optional[list[GroupPermissions]] = None
|
|
45
|
+
everyone: Optional[EveryoneRole] = None
|
|
46
|
+
share_assets: Optional[bool] = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class SortOrder(StrEnum):
|
|
50
|
+
Ascending = "asc"
|
|
51
|
+
Descending = "desc"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass_json
|
|
55
|
+
@dataclass(frozen=True)
|
|
56
|
+
class SearchFilterRange:
|
|
57
|
+
min: float
|
|
58
|
+
max: float
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass_json
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class SearchFilter:
|
|
64
|
+
key: str
|
|
65
|
+
value: Optional[str | float] = None
|
|
66
|
+
values: Optional[list[str | float]] = None
|
|
67
|
+
range: Optional[SearchFilterRange] = None
|
|
68
|
+
exclude: Optional[bool] = None
|
codeocean/computation.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from dataclasses_json import dataclass_json
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from time import sleep
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ComputationState(StrEnum):
|
|
10
|
+
Initializing = "initializing"
|
|
11
|
+
Running = "running"
|
|
12
|
+
Finalizing = "finalizing"
|
|
13
|
+
Completed = "completed"
|
|
14
|
+
Failed = "failed"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ComputationEndStatus(StrEnum):
|
|
18
|
+
Succeeded = "succeeded"
|
|
19
|
+
Failed = "failed"
|
|
20
|
+
Stopped = "stopped"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass_json
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class Param:
|
|
26
|
+
name: Optional[str] = None
|
|
27
|
+
param_name: Optional[str] = None
|
|
28
|
+
value: Optional[str] = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass_json
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class PipelineProcess:
|
|
34
|
+
name: str
|
|
35
|
+
capsule_id: str
|
|
36
|
+
version: Optional[int] = None
|
|
37
|
+
public: Optional[bool] = None
|
|
38
|
+
parameters: Optional[list[Param]] = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass_json
|
|
42
|
+
@dataclass(frozen=True)
|
|
43
|
+
class InputDataAsset:
|
|
44
|
+
id: str
|
|
45
|
+
mount: Optional[str] = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass_json
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
class Computation:
|
|
51
|
+
id: str
|
|
52
|
+
created: int
|
|
53
|
+
name: str
|
|
54
|
+
state: ComputationState
|
|
55
|
+
run_time: int
|
|
56
|
+
cloud_workstation: Optional[bool] = None
|
|
57
|
+
data_assets: Optional[list[InputDataAsset]] = None
|
|
58
|
+
end_status: Optional[ComputationEndStatus] = None
|
|
59
|
+
has_results: Optional[bool] = None
|
|
60
|
+
parameters: Optional[list[Param]] = None
|
|
61
|
+
processes: Optional[list[PipelineProcess]] = None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass_json
|
|
65
|
+
@dataclass(frozen=True)
|
|
66
|
+
class DataAssetsRunParam:
|
|
67
|
+
id: str
|
|
68
|
+
mount: str
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass_json
|
|
72
|
+
@dataclass(frozen=True)
|
|
73
|
+
class NamedRunParam:
|
|
74
|
+
param_name: str
|
|
75
|
+
value: str
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass_json
|
|
79
|
+
@dataclass(frozen=True)
|
|
80
|
+
class PipelineProcessParams:
|
|
81
|
+
name: str
|
|
82
|
+
parameters: Optional[list[str]] = None
|
|
83
|
+
named_parameters: Optional[list[NamedRunParam]] = None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass_json
|
|
87
|
+
@dataclass(frozen=True)
|
|
88
|
+
class RunParams:
|
|
89
|
+
capsule_id: Optional[str] = None
|
|
90
|
+
pipeline_id: Optional[str] = None
|
|
91
|
+
version: Optional[int] = None
|
|
92
|
+
resume_run_id: Optional[str] = None
|
|
93
|
+
data_assets: Optional[list[DataAssetsRunParam]] = None
|
|
94
|
+
parameters: Optional[list[str]] = None
|
|
95
|
+
named_parameters: Optional[list[NamedRunParam]] = None
|
|
96
|
+
processes: Optional[list[PipelineProcessParams]] = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass_json
|
|
100
|
+
@dataclass(frozen=True)
|
|
101
|
+
class FolderItem:
|
|
102
|
+
name: str
|
|
103
|
+
path: str
|
|
104
|
+
type: str
|
|
105
|
+
size: Optional[int] = None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass_json
|
|
109
|
+
@dataclass(frozen=True)
|
|
110
|
+
class Folder:
|
|
111
|
+
items: list[FolderItem]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass_json
|
|
115
|
+
@dataclass(frozen=True)
|
|
116
|
+
class ListFolderParams:
|
|
117
|
+
path: str
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass_json
|
|
121
|
+
@dataclass(frozen=True)
|
|
122
|
+
class DownloadFileURL:
|
|
123
|
+
url: str
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@dataclass
|
|
127
|
+
class Computations:
|
|
128
|
+
|
|
129
|
+
client: BaseUrlSession
|
|
130
|
+
|
|
131
|
+
def get_computation(self, computation_id: str) -> Computation:
|
|
132
|
+
res = self.client.get(f"computations/{computation_id}")
|
|
133
|
+
|
|
134
|
+
return Computation.from_dict(res.json())
|
|
135
|
+
|
|
136
|
+
def run_capsule(self, run_params: RunParams) -> Computation:
|
|
137
|
+
res = self.client.post("computations", json=run_params.to_dict())
|
|
138
|
+
|
|
139
|
+
return Computation.from_dict(res.json())
|
|
140
|
+
|
|
141
|
+
def wait_until_completed(self, computation: Computation) -> Computation:
|
|
142
|
+
"""
|
|
143
|
+
Polls the given computation until it reaches the 'Completed' or 'Failed' state.
|
|
144
|
+
"""
|
|
145
|
+
while True:
|
|
146
|
+
comp = self.get_computation(computation.id)
|
|
147
|
+
|
|
148
|
+
if comp.state in [ComputationState.Completed, ComputationState.Failed]:
|
|
149
|
+
return comp
|
|
150
|
+
|
|
151
|
+
sleep(5)
|
|
152
|
+
|
|
153
|
+
def list_computation_results(self, computation_id: str, path: str = "") -> Folder:
|
|
154
|
+
data = {
|
|
155
|
+
"path": path,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
res = self.client.post(f"computations/{computation_id}/results", json=data)
|
|
159
|
+
|
|
160
|
+
return Folder.from_dict(res.json())
|
|
161
|
+
|
|
162
|
+
def get_result_file_download_url(self, computation_id: str, path: str) -> DownloadFileURL:
|
|
163
|
+
res = self.client.get(
|
|
164
|
+
f"computations/{computation_id}/results/download_url",
|
|
165
|
+
params={"path": path},
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return DownloadFileURL.from_dict(res.json())
|
|
169
|
+
|
|
170
|
+
def delete_computation(self, computation_id: str):
|
|
171
|
+
self.client.delete(f"computations/{computation_id}")
|
codeocean/data_asset.py
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
from dataclasses_json import dataclass_json
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
5
|
+
from time import sleep
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from codeocean.components import SortOrder, SearchFilter, Permissions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DataAssetType(StrEnum):
|
|
12
|
+
Dataset = "dataset"
|
|
13
|
+
Result = "result"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DataAssetState(StrEnum):
|
|
17
|
+
Draft = "draft"
|
|
18
|
+
Ready = "ready"
|
|
19
|
+
Failed = "failed"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass_json
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class Provenance:
|
|
25
|
+
commit: str
|
|
26
|
+
run_script: str
|
|
27
|
+
data_assets: str
|
|
28
|
+
docker_image: str
|
|
29
|
+
capsule: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DataAssetOrigin(StrEnum):
|
|
33
|
+
Local = "local"
|
|
34
|
+
AWS = "aws"
|
|
35
|
+
GCP = "gcp"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass_json
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class SourceBucket:
|
|
41
|
+
origin: DataAssetOrigin
|
|
42
|
+
bucket: str
|
|
43
|
+
prefix: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass_json
|
|
47
|
+
@dataclass(frozen=True)
|
|
48
|
+
class AppParameter:
|
|
49
|
+
name: str
|
|
50
|
+
value: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass_json
|
|
54
|
+
@dataclass(frozen=True)
|
|
55
|
+
class DataAsset:
|
|
56
|
+
id: str
|
|
57
|
+
created: int
|
|
58
|
+
name: str
|
|
59
|
+
mount: str
|
|
60
|
+
state: DataAssetState
|
|
61
|
+
type: DataAssetType
|
|
62
|
+
last_used: int
|
|
63
|
+
app_parameters: Optional[list[AppParameter]] = None
|
|
64
|
+
custom_metadata: Optional[dict] = None
|
|
65
|
+
description: Optional[str] = None
|
|
66
|
+
failure_reason: Optional[str] = None
|
|
67
|
+
files: Optional[int] = None
|
|
68
|
+
provenance: Optional[Provenance] = None
|
|
69
|
+
size: Optional[int] = None
|
|
70
|
+
source_bucket: Optional[SourceBucket] = None
|
|
71
|
+
tags: Optional[list[str]] = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass_json
|
|
75
|
+
@dataclass(frozen=True)
|
|
76
|
+
class DataAssetUpdateParams:
|
|
77
|
+
name: str
|
|
78
|
+
description: str
|
|
79
|
+
tags: list[str]
|
|
80
|
+
mount: str
|
|
81
|
+
custom_metadata: Optional[dict] = None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass_json
|
|
85
|
+
@dataclass(frozen=True)
|
|
86
|
+
class AWSS3Source:
|
|
87
|
+
bucket: str
|
|
88
|
+
prefix: Optional[str] = None
|
|
89
|
+
keep_on_external_storage: Optional[bool] = None
|
|
90
|
+
public: Optional[bool] = None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass_json
|
|
94
|
+
@dataclass(frozen=True)
|
|
95
|
+
class GCPCloudStorageSource:
|
|
96
|
+
bucket: str
|
|
97
|
+
client_id: Optional[str] = None
|
|
98
|
+
client_secret: Optional[str] = None
|
|
99
|
+
prefix: Optional[str] = None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass_json
|
|
103
|
+
@dataclass(frozen=True)
|
|
104
|
+
class ComputationSource:
|
|
105
|
+
id: str
|
|
106
|
+
path: Optional[str] = None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass_json
|
|
110
|
+
@dataclass(frozen=True)
|
|
111
|
+
class Source:
|
|
112
|
+
aws: Optional[AWSS3Source] = None
|
|
113
|
+
gcp: Optional[GCPCloudStorageSource] = None
|
|
114
|
+
computation: Optional[ComputationSource] = None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass_json
|
|
118
|
+
@dataclass(frozen=True)
|
|
119
|
+
class AWSS3Target:
|
|
120
|
+
bucket: str
|
|
121
|
+
prefix: Optional[str] = None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass_json
|
|
125
|
+
@dataclass(frozen=True)
|
|
126
|
+
class Target:
|
|
127
|
+
aws: Optional[AWSS3Target] = None
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass_json
|
|
131
|
+
@dataclass(frozen=True)
|
|
132
|
+
class DataAssetParams:
|
|
133
|
+
name: str
|
|
134
|
+
tags: list[str]
|
|
135
|
+
mount: str
|
|
136
|
+
description: Optional[str] = None
|
|
137
|
+
source: Optional[Source] = None
|
|
138
|
+
target: Optional[Target] = None
|
|
139
|
+
custom_metadata: Optional[dict] = None
|
|
140
|
+
data_asset_ids: Optional[list[str]] = None
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass_json
|
|
144
|
+
@dataclass(frozen=True)
|
|
145
|
+
class DataAssetAttachParams:
|
|
146
|
+
id: str
|
|
147
|
+
mount: Optional[str] = None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclass_json
|
|
151
|
+
@dataclass(frozen=True)
|
|
152
|
+
class DataAssetAttachResults:
|
|
153
|
+
id: str
|
|
154
|
+
mount: str
|
|
155
|
+
mount_state: str
|
|
156
|
+
job_id: str
|
|
157
|
+
external: bool
|
|
158
|
+
ready: bool
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class DataAssetSortBy(StrEnum):
|
|
162
|
+
Created = "created"
|
|
163
|
+
Type = "type"
|
|
164
|
+
Name = "name"
|
|
165
|
+
Size = "size"
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class DataAssetOwnership(StrEnum):
|
|
169
|
+
Private = "private"
|
|
170
|
+
Shared = "shared"
|
|
171
|
+
Created = "created"
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class DataAssetSearchOrigin(StrEnum):
|
|
175
|
+
Internal = "internal"
|
|
176
|
+
External = "external"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@dataclass_json
|
|
180
|
+
@dataclass(frozen=True)
|
|
181
|
+
class DataAssetSearchParams:
|
|
182
|
+
limit: int
|
|
183
|
+
offset: int
|
|
184
|
+
archived: bool
|
|
185
|
+
favorite: bool
|
|
186
|
+
query: Optional[str] = None
|
|
187
|
+
sort_field: Optional[DataAssetSortBy] = None
|
|
188
|
+
sort_order: Optional[SortOrder] = None
|
|
189
|
+
type: Optional[DataAssetType] = None
|
|
190
|
+
ownership: Optional[DataAssetOwnership] = None
|
|
191
|
+
origin: Optional[DataAssetSearchOrigin] = None
|
|
192
|
+
filters: Optional[list[SearchFilter]] = None
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@dataclass_json
|
|
196
|
+
@dataclass(frozen=True)
|
|
197
|
+
class DataAssetSearchResults:
|
|
198
|
+
has_more: bool
|
|
199
|
+
results: list[DataAsset]
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass
|
|
203
|
+
class DataAssets:
|
|
204
|
+
|
|
205
|
+
client: BaseUrlSession
|
|
206
|
+
|
|
207
|
+
def get_data_asset(self, data_asset_id: str) -> DataAsset:
|
|
208
|
+
res = self.client.get(f"data_assets/{data_asset_id}")
|
|
209
|
+
|
|
210
|
+
return DataAsset.from_dict(res.json())
|
|
211
|
+
|
|
212
|
+
def update_metadata(self, data_asset_id: str, update_params: DataAssetUpdateParams) -> DataAsset:
|
|
213
|
+
res = self.client.put(f"data_assets/{data_asset_id}", json=update_params.to_dict())
|
|
214
|
+
|
|
215
|
+
return DataAsset.from_dict(res.json())
|
|
216
|
+
|
|
217
|
+
def create_data_asset(self, data_asset_params: DataAssetParams) -> DataAsset:
|
|
218
|
+
res = self.client.post("data_assets", json=data_asset_params.to_dict())
|
|
219
|
+
|
|
220
|
+
return DataAsset.from_dict(res.json())
|
|
221
|
+
|
|
222
|
+
def wait_until_ready(self, data_asset: DataAsset) -> DataAsset:
|
|
223
|
+
"""
|
|
224
|
+
Polls the given data asset until it reaches the 'Ready' or 'Failed' state.
|
|
225
|
+
"""
|
|
226
|
+
while True:
|
|
227
|
+
da = self.get_data_asset(data_asset.id)
|
|
228
|
+
|
|
229
|
+
if da.state in [DataAssetState.Ready, DataAssetState.Failed]:
|
|
230
|
+
return da
|
|
231
|
+
|
|
232
|
+
sleep(5)
|
|
233
|
+
|
|
234
|
+
def delete_data_asset(self, data_asset_id: str):
|
|
235
|
+
self.client.delete(f"data_assets/{data_asset_id}")
|
|
236
|
+
|
|
237
|
+
def update_permissions(self, data_asset_id: str, permissions: Permissions):
|
|
238
|
+
self.client.post(
|
|
239
|
+
f"data_assets/{data_asset_id}/permissions",
|
|
240
|
+
json=permissions.to_dict(),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
def archive_data_asset(self, data_asset_id: str, archive: bool):
|
|
244
|
+
self.client.patch(
|
|
245
|
+
f"data_assets/{data_asset_id}/archive",
|
|
246
|
+
params={"archive": archive},
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def search_data_assets(self, search_params: DataAssetSearchParams) -> DataAssetSearchResults:
|
|
250
|
+
res = self.client.post("data_assets/search", json=search_params.to_dict())
|
|
251
|
+
|
|
252
|
+
return DataAssetSearchResults.from_dict(res.json())
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: codeocean
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Code Ocean Python SDK
|
|
5
|
+
Project-URL: Homepage, https://github.com/codeocean/codeocean-sdk-python
|
|
6
|
+
Project-URL: Issues, https://github.com/codeocean/codeocean-sdk-python/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/codeocean/codeocean-sdk-python/blob/main/CHANGELOG.md
|
|
8
|
+
Author-email: Code Ocean <dev@codeocean.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: dataclasses
|
|
16
|
+
Requires-Dist: dataclasses-json
|
|
17
|
+
Requires-Dist: requests
|
|
18
|
+
Requires-Dist: requests-toolbelt
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: flake8; extra == 'dev'
|
|
21
|
+
Provides-Extra: publish
|
|
22
|
+
Requires-Dist: hatch; extra == 'publish'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
# Code Ocean Python SDK
|
|
27
|
+
The Code Ocean Python SDK provides convenient access to the Code Ocean API from applications written in the Python language.
|
|
28
|
+
This SDK enables you to manage Code Ocean resources such as Capsules, Data Assets, and Computations in your Python applications.
|
|
29
|
+
|
|
30
|
+
## Documentation
|
|
31
|
+
|
|
32
|
+
The Code Ocean REST API documentation can be found in the [Code Ocean User Guide](https://docs.codeocean.com/user-guide/code-ocean-api).
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
pip install -U codeocean
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For development, install from source with:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
pip install -e .[dev] -U
|
|
44
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
codeocean/__init__.py,sha256=U35lft7yuygFsrSPhmTVKDsNMPgcSA9JvzTAGo8XfVg,53
|
|
2
|
+
codeocean/capsule.py,sha256=W6PmWxAwiEVUxnm_W-_rNRGie8VcvafUtTTbbC40yYE,2314
|
|
3
|
+
codeocean/client.py,sha256=BzxKpMe3i49vL_rfGsgN-fob97pxRMlrjmg38y1g7TY,831
|
|
4
|
+
codeocean/components.py,sha256=uVVCa-A4nG7MFu0KiNhhXsv3G6ZK5mS76TLbbg8oqM8,1315
|
|
5
|
+
codeocean/computation.py,sha256=M0xcnIafZ9QoU61frBChxLkMbcvvMFkB_Y4hwdUURp8,4281
|
|
6
|
+
codeocean/data_asset.py,sha256=R1FkmtyeIRRNuTVxVRP3PFvMmybQhT6RZhE-Fwp38ko,6114
|
|
7
|
+
codeocean-0.1.0.dist-info/METADATA,sha256=1NuTafPBHeEtzSEkvhK8FdSKE3LRUPpuXgfYZrfWej8,1542
|
|
8
|
+
codeocean-0.1.0.dist-info/WHEEL,sha256=LL0B1KxSLwaTWceo7tT-0aDLd-qq9dmbnsnk1DnXlg8,87
|
|
9
|
+
codeocean-0.1.0.dist-info/licenses/LICENSE,sha256=_TRkqGNByemZnRbLIKXWkDssI_A7qGq3yAho-lvkdaw,1092
|
|
10
|
+
codeocean-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [2024] [Code Ocean]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|