codeocean 0.1.2__tar.gz → 0.1.4__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.1.4/CHANGELOG.md +21 -0
- {codeocean-0.1.2 → codeocean-0.1.4}/LICENSE +21 -21
- {codeocean-0.1.2 → codeocean-0.1.4}/PKG-INFO +4 -4
- {codeocean-0.1.2 → codeocean-0.1.4}/pyproject.toml +11 -4
- {codeocean-0.1.2 → codeocean-0.1.4}/src/codeocean/capsule.py +82 -77
- {codeocean-0.1.2 → codeocean-0.1.4}/src/codeocean/client.py +27 -25
- {codeocean-0.1.2 → codeocean-0.1.4}/src/codeocean/components.py +4 -1
- {codeocean-0.1.2 → codeocean-0.1.4}/src/codeocean/computation.py +174 -171
- {codeocean-0.1.2 → codeocean-0.1.4}/src/codeocean/data_asset.py +270 -252
- codeocean-0.1.4/src/codeocean/enum.py +6 -0
- codeocean-0.1.4/tests/__init__.py +0 -0
- codeocean-0.1.4/tests/test_package.py +23 -0
- codeocean-0.1.2/CHANGELOG.md +0 -10
- {codeocean-0.1.2 → codeocean-0.1.4}/.flake8 +0 -0
- {codeocean-0.1.2 → codeocean-0.1.4}/.gitignore +0 -0
- {codeocean-0.1.2 → codeocean-0.1.4}/README.md +0 -0
- {codeocean-0.1.2 → codeocean-0.1.4}/examples/create_data_asset.py +0 -0
- {codeocean-0.1.2 → codeocean-0.1.4}/examples/run_capsule.py +0 -0
- {codeocean-0.1.2 → codeocean-0.1.4}/examples/run_pipeline.py +0 -0
- {codeocean-0.1.2 → codeocean-0.1.4}/src/codeocean/__init__.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
CHANGELOG
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
## 0.1.4 (2024-08-02)
|
|
5
|
+
|
|
6
|
+
- Add support for Python >= 3.9
|
|
7
|
+
|
|
8
|
+
## 0.1.3 (2024-07-09)
|
|
9
|
+
|
|
10
|
+
- [#8](https://github.com/codeocean/codeocean-sdk-python/pull/8) fix: add TCPKeepAlive to client requests
|
|
11
|
+
- [#6](https://github.com/codeocean/codeocean-sdk-python/pull/6) feat: Add ResultsInfo to DataAssetParams
|
|
12
|
+
- [#5](https://github.com/codeocean/codeocean-sdk-python/pull/5) fix: SourceBucket optional fields
|
|
13
|
+
- [#3](https://github.com/codeocean/codeocean-sdk-python/pull/3) feat: Add external field to SourceBucket
|
|
14
|
+
|
|
15
|
+
## 0.1.2 (2024-03-20)
|
|
16
|
+
|
|
17
|
+
- Fix minimum required Pyhton version (3.11)
|
|
18
|
+
|
|
19
|
+
## 0.1.0 (2024-03-18)
|
|
20
|
+
|
|
21
|
+
Initial version
|
|
@@ -1,21 +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.
|
|
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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: codeocean
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
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
|
|
@@ -11,15 +11,15 @@ License-File: LICENSE
|
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Requires-Python: >=3.
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Requires-Dist: backports-strenum>=1.3.1; python_version < '3.11'
|
|
15
16
|
Requires-Dist: dataclasses
|
|
16
17
|
Requires-Dist: dataclasses-json
|
|
17
18
|
Requires-Dist: requests
|
|
18
19
|
Requires-Dist: requests-toolbelt
|
|
19
20
|
Provides-Extra: dev
|
|
20
21
|
Requires-Dist: flake8; extra == 'dev'
|
|
21
|
-
|
|
22
|
-
Requires-Dist: hatch; extra == 'publish'
|
|
22
|
+
Requires-Dist: hatch; extra == 'dev'
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
25
25
|

|
|
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codeocean"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Code Ocean", email="dev@codeocean.com" },
|
|
10
10
|
]
|
|
11
11
|
description = "Code Ocean Python SDK"
|
|
12
12
|
readme = "README.md"
|
|
13
|
-
requires-python = ">=3.
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
14
|
classifiers = [
|
|
15
15
|
"Programming Language :: Python :: 3",
|
|
16
16
|
"License :: OSI Approved :: MIT License",
|
|
@@ -21,12 +21,12 @@ dependencies = [
|
|
|
21
21
|
"dataclasses_json",
|
|
22
22
|
"requests",
|
|
23
23
|
"requests_toolbelt",
|
|
24
|
+
"backports.strenum>=1.3.1; python_version<'3.11'",
|
|
24
25
|
]
|
|
25
26
|
license = "MIT"
|
|
26
27
|
|
|
27
28
|
[project.optional-dependencies]
|
|
28
|
-
dev = ["flake8"]
|
|
29
|
-
publish = ["hatch"]
|
|
29
|
+
dev = ["flake8", "hatch"]
|
|
30
30
|
|
|
31
31
|
[project.urls]
|
|
32
32
|
Homepage = "https://github.com/codeocean/codeocean-sdk-python"
|
|
@@ -45,3 +45,10 @@ exclude = [
|
|
|
45
45
|
|
|
46
46
|
[tool.hatch.build.targets.wheel]
|
|
47
47
|
packages = ["src/codeocean"]
|
|
48
|
+
|
|
49
|
+
[tool.hatch.envs.default.scripts]
|
|
50
|
+
lint = "flake8 src tests examples"
|
|
51
|
+
test = "python -m unittest -v"
|
|
52
|
+
|
|
53
|
+
[[tool.hatch.envs.test.matrix]]
|
|
54
|
+
python = ["3.9", "3.10", "3.11", "3.12"]
|
|
@@ -1,77 +1,82 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
from codeocean.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from dataclasses_json import dataclass_json
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
7
|
+
|
|
8
|
+
from codeocean.computation import Computation
|
|
9
|
+
from codeocean.data_asset import DataAssetAttachParams, DataAssetAttachResults
|
|
10
|
+
from codeocean.enum import StrEnum
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CapsuleStatus(StrEnum):
|
|
14
|
+
NonPublished = "non-published"
|
|
15
|
+
Submitted = "submitted"
|
|
16
|
+
Publishing = "publishing"
|
|
17
|
+
Published = "published"
|
|
18
|
+
Verified = "verified"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass_json
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class OriginalCapsuleInfo:
|
|
24
|
+
id: Optional[str] = None
|
|
25
|
+
major_version: Optional[int] = None
|
|
26
|
+
minor_version: Optional[int] = None
|
|
27
|
+
name: Optional[str] = None
|
|
28
|
+
created: Optional[int] = None
|
|
29
|
+
public: Optional[bool] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass_json
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class Capsule:
|
|
35
|
+
id: str
|
|
36
|
+
created: int
|
|
37
|
+
name: str
|
|
38
|
+
status: CapsuleStatus
|
|
39
|
+
owner: str
|
|
40
|
+
slug: str
|
|
41
|
+
article: Optional[dict] = None
|
|
42
|
+
cloned_from_url: Optional[str] = None
|
|
43
|
+
description: Optional[str] = None
|
|
44
|
+
field: Optional[str] = None
|
|
45
|
+
keywords: Optional[list[str]] = None
|
|
46
|
+
original_capsule: Optional[OriginalCapsuleInfo] = None
|
|
47
|
+
published_capsule: Optional[str] = None
|
|
48
|
+
submission: Optional[dict] = None
|
|
49
|
+
versions: Optional[list[dict]] = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class Capsules:
|
|
54
|
+
|
|
55
|
+
client: BaseUrlSession
|
|
56
|
+
|
|
57
|
+
def get_capsule(self, capsule_id: str) -> Capsule:
|
|
58
|
+
res = self.client.get(f"capsules/{capsule_id}")
|
|
59
|
+
|
|
60
|
+
return Capsule.from_dict(res.json())
|
|
61
|
+
|
|
62
|
+
def list_computations(self, capsule_id: str) -> list[Computation]:
|
|
63
|
+
res = self.client.get(f"capsules/{capsule_id}/computations")
|
|
64
|
+
|
|
65
|
+
return [Computation.from_dict(c) for c in res.json()]
|
|
66
|
+
|
|
67
|
+
def attach_data_assets(
|
|
68
|
+
self,
|
|
69
|
+
capsule_id: str,
|
|
70
|
+
attach_params: list[DataAssetAttachParams]) -> list[DataAssetAttachResults]:
|
|
71
|
+
res = self.client.post(
|
|
72
|
+
f"capsules/{capsule_id}/data_assets",
|
|
73
|
+
json=[j.to_dict() for j in attach_params],
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return [DataAssetAttachResults.from_dict(c) for c in res.json()]
|
|
77
|
+
|
|
78
|
+
def detach_data_assets(self, capsule_id: str, data_assets: list[str]):
|
|
79
|
+
self.client.delete(
|
|
80
|
+
f"capsules/{capsule_id}/data_assets/",
|
|
81
|
+
json=data_assets,
|
|
82
|
+
)
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
from requests_toolbelt.sessions import BaseUrlSession
|
|
2
|
-
from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
from codeocean.
|
|
6
|
-
from codeocean.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
self.session
|
|
18
|
-
self.session.
|
|
19
|
-
self.session.
|
|
20
|
-
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
self.
|
|
1
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
2
|
+
from requests_toolbelt.adapters.socket_options import TCPKeepAliveAdapter
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from codeocean.capsule import Capsules
|
|
6
|
+
from codeocean.computation import Computations
|
|
7
|
+
from codeocean.data_asset import DataAssets
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class CodeOcean:
|
|
12
|
+
|
|
13
|
+
domain: str
|
|
14
|
+
token: str
|
|
15
|
+
|
|
16
|
+
def __post_init__(self):
|
|
17
|
+
self.session = BaseUrlSession(base_url=f"{self.domain}/api/v1/")
|
|
18
|
+
self.session.auth = (self.token, "")
|
|
19
|
+
self.session.mount(self.domain, TCPKeepAliveAdapter())
|
|
20
|
+
self.session.headers.update({"Content-Type": "application/json"})
|
|
21
|
+
self.session.hooks["response"] = [
|
|
22
|
+
lambda response, *args, **kwargs: response.raise_for_status()
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
self.capsules = Capsules(client=self.session)
|
|
26
|
+
self.computations = Computations(client=self.session)
|
|
27
|
+
self.data_assets = DataAssets(client=self.session)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from dataclasses_json import dataclass_json
|
|
2
4
|
from dataclasses import dataclass
|
|
3
|
-
from enum import StrEnum
|
|
4
5
|
from typing import Optional
|
|
5
6
|
|
|
7
|
+
from codeocean.enum import StrEnum
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
class UserRole(StrEnum):
|
|
8
11
|
Owner = "owner"
|
|
@@ -1,171 +1,174 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from dataclasses_json import dataclass_json
|
|
5
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from time import sleep
|
|
8
|
+
|
|
9
|
+
from codeocean.enum import StrEnum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ComputationState(StrEnum):
|
|
13
|
+
Initializing = "initializing"
|
|
14
|
+
Running = "running"
|
|
15
|
+
Finalizing = "finalizing"
|
|
16
|
+
Completed = "completed"
|
|
17
|
+
Failed = "failed"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ComputationEndStatus(StrEnum):
|
|
21
|
+
Succeeded = "succeeded"
|
|
22
|
+
Failed = "failed"
|
|
23
|
+
Stopped = "stopped"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass_json
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class Param:
|
|
29
|
+
name: Optional[str] = None
|
|
30
|
+
param_name: Optional[str] = None
|
|
31
|
+
value: Optional[str] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass_json
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class PipelineProcess:
|
|
37
|
+
name: str
|
|
38
|
+
capsule_id: str
|
|
39
|
+
version: Optional[int] = None
|
|
40
|
+
public: Optional[bool] = None
|
|
41
|
+
parameters: Optional[list[Param]] = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass_json
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class InputDataAsset:
|
|
47
|
+
id: str
|
|
48
|
+
mount: Optional[str] = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass_json
|
|
52
|
+
@dataclass(frozen=True)
|
|
53
|
+
class Computation:
|
|
54
|
+
id: str
|
|
55
|
+
created: int
|
|
56
|
+
name: str
|
|
57
|
+
state: ComputationState
|
|
58
|
+
run_time: int
|
|
59
|
+
cloud_workstation: Optional[bool] = None
|
|
60
|
+
data_assets: Optional[list[InputDataAsset]] = None
|
|
61
|
+
end_status: Optional[ComputationEndStatus] = None
|
|
62
|
+
has_results: Optional[bool] = None
|
|
63
|
+
parameters: Optional[list[Param]] = None
|
|
64
|
+
processes: Optional[list[PipelineProcess]] = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass_json
|
|
68
|
+
@dataclass(frozen=True)
|
|
69
|
+
class DataAssetsRunParam:
|
|
70
|
+
id: str
|
|
71
|
+
mount: str
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass_json
|
|
75
|
+
@dataclass(frozen=True)
|
|
76
|
+
class NamedRunParam:
|
|
77
|
+
param_name: str
|
|
78
|
+
value: str
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass_json
|
|
82
|
+
@dataclass(frozen=True)
|
|
83
|
+
class PipelineProcessParams:
|
|
84
|
+
name: str
|
|
85
|
+
parameters: Optional[list[str]] = None
|
|
86
|
+
named_parameters: Optional[list[NamedRunParam]] = None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass_json
|
|
90
|
+
@dataclass(frozen=True)
|
|
91
|
+
class RunParams:
|
|
92
|
+
capsule_id: Optional[str] = None
|
|
93
|
+
pipeline_id: Optional[str] = None
|
|
94
|
+
version: Optional[int] = None
|
|
95
|
+
resume_run_id: Optional[str] = None
|
|
96
|
+
data_assets: Optional[list[DataAssetsRunParam]] = None
|
|
97
|
+
parameters: Optional[list[str]] = None
|
|
98
|
+
named_parameters: Optional[list[NamedRunParam]] = None
|
|
99
|
+
processes: Optional[list[PipelineProcessParams]] = None
|
|
100
|
+
|
|
101
|
+
|
|
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
|
+
@dataclass
|
|
130
|
+
class Computations:
|
|
131
|
+
|
|
132
|
+
client: BaseUrlSession
|
|
133
|
+
|
|
134
|
+
def get_computation(self, computation_id: str) -> Computation:
|
|
135
|
+
res = self.client.get(f"computations/{computation_id}")
|
|
136
|
+
|
|
137
|
+
return Computation.from_dict(res.json())
|
|
138
|
+
|
|
139
|
+
def run_capsule(self, run_params: RunParams) -> Computation:
|
|
140
|
+
res = self.client.post("computations", json=run_params.to_dict())
|
|
141
|
+
|
|
142
|
+
return Computation.from_dict(res.json())
|
|
143
|
+
|
|
144
|
+
def wait_until_completed(self, computation: Computation) -> Computation:
|
|
145
|
+
"""
|
|
146
|
+
Polls the given computation until it reaches the 'Completed' or 'Failed' state.
|
|
147
|
+
"""
|
|
148
|
+
while True:
|
|
149
|
+
comp = self.get_computation(computation.id)
|
|
150
|
+
|
|
151
|
+
if comp.state in [ComputationState.Completed, ComputationState.Failed]:
|
|
152
|
+
return comp
|
|
153
|
+
|
|
154
|
+
sleep(5)
|
|
155
|
+
|
|
156
|
+
def list_computation_results(self, computation_id: str, path: str = "") -> Folder:
|
|
157
|
+
data = {
|
|
158
|
+
"path": path,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
res = self.client.post(f"computations/{computation_id}/results", json=data)
|
|
162
|
+
|
|
163
|
+
return Folder.from_dict(res.json())
|
|
164
|
+
|
|
165
|
+
def get_result_file_download_url(self, computation_id: str, path: str) -> DownloadFileURL:
|
|
166
|
+
res = self.client.get(
|
|
167
|
+
f"computations/{computation_id}/results/download_url",
|
|
168
|
+
params={"path": path},
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
return DownloadFileURL.from_dict(res.json())
|
|
172
|
+
|
|
173
|
+
def delete_computation(self, computation_id: str):
|
|
174
|
+
self.client.delete(f"computations/{computation_id}")
|
|
@@ -1,252 +1,270 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
custom_metadata: Optional[dict] = None
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
@
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
@
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses_json import dataclass_json
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
|
+
from time import sleep
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from codeocean.components import SortOrder, SearchFilter, Permissions
|
|
10
|
+
from codeocean.computation import PipelineProcess, Param
|
|
11
|
+
from codeocean.enum import StrEnum
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DataAssetType(StrEnum):
|
|
15
|
+
Dataset = "dataset"
|
|
16
|
+
Result = "result"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DataAssetState(StrEnum):
|
|
20
|
+
Draft = "draft"
|
|
21
|
+
Ready = "ready"
|
|
22
|
+
Failed = "failed"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass_json
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class Provenance:
|
|
28
|
+
commit: str
|
|
29
|
+
run_script: str
|
|
30
|
+
data_assets: str
|
|
31
|
+
docker_image: str
|
|
32
|
+
capsule: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DataAssetOrigin(StrEnum):
|
|
36
|
+
Local = "local"
|
|
37
|
+
AWS = "aws"
|
|
38
|
+
GCP = "gcp"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass_json
|
|
42
|
+
@dataclass(frozen=True)
|
|
43
|
+
class SourceBucket:
|
|
44
|
+
origin: DataAssetOrigin
|
|
45
|
+
bucket: Optional[str] = None
|
|
46
|
+
prefix: Optional[str] = None
|
|
47
|
+
external: Optional[bool] = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass_json
|
|
51
|
+
@dataclass(frozen=True)
|
|
52
|
+
class AppParameter:
|
|
53
|
+
name: str
|
|
54
|
+
value: str
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass_json
|
|
58
|
+
@dataclass(frozen=True)
|
|
59
|
+
class ResultsInfo:
|
|
60
|
+
capsule_id: Optional[str] = None
|
|
61
|
+
pipeline_id: Optional[str] = None
|
|
62
|
+
version: Optional[int] = None
|
|
63
|
+
commit: Optional[str] = None
|
|
64
|
+
run_script: Optional[str] = None
|
|
65
|
+
data_assets: Optional[list[str]] = None
|
|
66
|
+
parameters: Optional[list[Param]] = None
|
|
67
|
+
processes: Optional[list[PipelineProcess]] = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass_json
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class DataAsset:
|
|
73
|
+
id: str
|
|
74
|
+
created: int
|
|
75
|
+
name: str
|
|
76
|
+
mount: str
|
|
77
|
+
state: DataAssetState
|
|
78
|
+
type: DataAssetType
|
|
79
|
+
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
|
+
files: Optional[int] = None
|
|
85
|
+
provenance: Optional[Provenance] = None
|
|
86
|
+
size: Optional[int] = None
|
|
87
|
+
source_bucket: Optional[SourceBucket] = None
|
|
88
|
+
tags: Optional[list[str]] = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass_json
|
|
92
|
+
@dataclass(frozen=True)
|
|
93
|
+
class DataAssetUpdateParams:
|
|
94
|
+
name: str
|
|
95
|
+
description: str
|
|
96
|
+
tags: list[str]
|
|
97
|
+
mount: str
|
|
98
|
+
custom_metadata: Optional[dict] = None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@dataclass_json
|
|
102
|
+
@dataclass(frozen=True)
|
|
103
|
+
class AWSS3Source:
|
|
104
|
+
bucket: str
|
|
105
|
+
prefix: Optional[str] = None
|
|
106
|
+
keep_on_external_storage: Optional[bool] = None
|
|
107
|
+
public: Optional[bool] = None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclass_json
|
|
111
|
+
@dataclass(frozen=True)
|
|
112
|
+
class GCPCloudStorageSource:
|
|
113
|
+
bucket: str
|
|
114
|
+
client_id: Optional[str] = None
|
|
115
|
+
client_secret: Optional[str] = None
|
|
116
|
+
prefix: Optional[str] = None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass_json
|
|
120
|
+
@dataclass(frozen=True)
|
|
121
|
+
class ComputationSource:
|
|
122
|
+
id: str
|
|
123
|
+
path: Optional[str] = None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@dataclass_json
|
|
127
|
+
@dataclass(frozen=True)
|
|
128
|
+
class Source:
|
|
129
|
+
aws: Optional[AWSS3Source] = None
|
|
130
|
+
gcp: Optional[GCPCloudStorageSource] = None
|
|
131
|
+
computation: Optional[ComputationSource] = None
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@dataclass_json
|
|
135
|
+
@dataclass(frozen=True)
|
|
136
|
+
class AWSS3Target:
|
|
137
|
+
bucket: str
|
|
138
|
+
prefix: Optional[str] = None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass_json
|
|
142
|
+
@dataclass(frozen=True)
|
|
143
|
+
class Target:
|
|
144
|
+
aws: Optional[AWSS3Target] = None
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@dataclass_json
|
|
148
|
+
@dataclass(frozen=True)
|
|
149
|
+
class DataAssetParams:
|
|
150
|
+
name: str
|
|
151
|
+
tags: list[str]
|
|
152
|
+
mount: str
|
|
153
|
+
description: Optional[str] = None
|
|
154
|
+
source: Optional[Source] = None
|
|
155
|
+
target: Optional[Target] = None
|
|
156
|
+
custom_metadata: Optional[dict] = None
|
|
157
|
+
data_asset_ids: Optional[list[str]] = None
|
|
158
|
+
results_info: Optional[ResultsInfo] = None
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@dataclass_json
|
|
162
|
+
@dataclass(frozen=True)
|
|
163
|
+
class DataAssetAttachParams:
|
|
164
|
+
id: str
|
|
165
|
+
mount: Optional[str] = None
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@dataclass_json
|
|
169
|
+
@dataclass(frozen=True)
|
|
170
|
+
class DataAssetAttachResults:
|
|
171
|
+
id: str
|
|
172
|
+
mount: str
|
|
173
|
+
mount_state: str
|
|
174
|
+
job_id: str
|
|
175
|
+
external: bool
|
|
176
|
+
ready: bool
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class DataAssetSortBy(StrEnum):
|
|
180
|
+
Created = "created"
|
|
181
|
+
Type = "type"
|
|
182
|
+
Name = "name"
|
|
183
|
+
Size = "size"
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class DataAssetOwnership(StrEnum):
|
|
187
|
+
Private = "private"
|
|
188
|
+
Shared = "shared"
|
|
189
|
+
Created = "created"
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class DataAssetSearchOrigin(StrEnum):
|
|
193
|
+
Internal = "internal"
|
|
194
|
+
External = "external"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@dataclass_json
|
|
198
|
+
@dataclass(frozen=True)
|
|
199
|
+
class DataAssetSearchParams:
|
|
200
|
+
limit: int
|
|
201
|
+
offset: int
|
|
202
|
+
archived: bool
|
|
203
|
+
favorite: bool
|
|
204
|
+
query: Optional[str] = None
|
|
205
|
+
sort_field: Optional[DataAssetSortBy] = None
|
|
206
|
+
sort_order: Optional[SortOrder] = None
|
|
207
|
+
type: Optional[DataAssetType] = None
|
|
208
|
+
ownership: Optional[DataAssetOwnership] = None
|
|
209
|
+
origin: Optional[DataAssetSearchOrigin] = None
|
|
210
|
+
filters: Optional[list[SearchFilter]] = None
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@dataclass_json
|
|
214
|
+
@dataclass(frozen=True)
|
|
215
|
+
class DataAssetSearchResults:
|
|
216
|
+
has_more: bool
|
|
217
|
+
results: list[DataAsset]
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@dataclass
|
|
221
|
+
class DataAssets:
|
|
222
|
+
|
|
223
|
+
client: BaseUrlSession
|
|
224
|
+
|
|
225
|
+
def get_data_asset(self, data_asset_id: str) -> DataAsset:
|
|
226
|
+
res = self.client.get(f"data_assets/{data_asset_id}")
|
|
227
|
+
|
|
228
|
+
return DataAsset.from_dict(res.json())
|
|
229
|
+
|
|
230
|
+
def update_metadata(self, data_asset_id: str, update_params: DataAssetUpdateParams) -> DataAsset:
|
|
231
|
+
res = self.client.put(f"data_assets/{data_asset_id}", json=update_params.to_dict())
|
|
232
|
+
|
|
233
|
+
return DataAsset.from_dict(res.json())
|
|
234
|
+
|
|
235
|
+
def create_data_asset(self, data_asset_params: DataAssetParams) -> DataAsset:
|
|
236
|
+
res = self.client.post("data_assets", json=data_asset_params.to_dict())
|
|
237
|
+
|
|
238
|
+
return DataAsset.from_dict(res.json())
|
|
239
|
+
|
|
240
|
+
def wait_until_ready(self, data_asset: DataAsset) -> DataAsset:
|
|
241
|
+
"""
|
|
242
|
+
Polls the given data asset until it reaches the 'Ready' or 'Failed' state.
|
|
243
|
+
"""
|
|
244
|
+
while True:
|
|
245
|
+
da = self.get_data_asset(data_asset.id)
|
|
246
|
+
|
|
247
|
+
if da.state in [DataAssetState.Ready, DataAssetState.Failed]:
|
|
248
|
+
return da
|
|
249
|
+
|
|
250
|
+
sleep(5)
|
|
251
|
+
|
|
252
|
+
def delete_data_asset(self, data_asset_id: str):
|
|
253
|
+
self.client.delete(f"data_assets/{data_asset_id}")
|
|
254
|
+
|
|
255
|
+
def update_permissions(self, data_asset_id: str, permissions: Permissions):
|
|
256
|
+
self.client.post(
|
|
257
|
+
f"data_assets/{data_asset_id}/permissions",
|
|
258
|
+
json=permissions.to_dict(),
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
def archive_data_asset(self, data_asset_id: str, archive: bool):
|
|
262
|
+
self.client.patch(
|
|
263
|
+
f"data_assets/{data_asset_id}/archive",
|
|
264
|
+
params={"archive": archive},
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def search_data_assets(self, search_params: DataAssetSearchParams) -> DataAssetSearchResults:
|
|
268
|
+
res = self.client.post("data_assets/search", json=search_params.to_dict())
|
|
269
|
+
|
|
270
|
+
return DataAssetSearchResults.from_dict(res.json())
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import unittest
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TestPackage(unittest.TestCase):
|
|
6
|
+
def test_import_package(self):
|
|
7
|
+
import codeocean # noqa
|
|
8
|
+
|
|
9
|
+
def test_strenum_install(self):
|
|
10
|
+
"""
|
|
11
|
+
Check if the StrEnum backport is installed/not installed as appropriate in the test environment.
|
|
12
|
+
|
|
13
|
+
- the backport can only be installed for Python versions < 3.11 (https://pypi.org/project/backports.strenum/)
|
|
14
|
+
- for >= 3.11, the stdlib StrEnum should be used instead
|
|
15
|
+
"""
|
|
16
|
+
if sys.version_info >= (3, 11):
|
|
17
|
+
with self.assertRaises(ImportError):
|
|
18
|
+
import backports.strenum # noqa
|
|
19
|
+
else:
|
|
20
|
+
try:
|
|
21
|
+
import backports.strenum # noqa
|
|
22
|
+
except ImportError:
|
|
23
|
+
self.fail("Failed to import the backports.strenum module")
|
codeocean-0.1.2/CHANGELOG.md
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|