codeocean 0.15.0__tar.gz → 0.16.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.15.0 → codeocean-0.16.0}/CHANGELOG.md +4 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/PKG-INFO +1 -1
- {codeocean-0.15.0 → codeocean-0.16.0}/pyproject.toml +1 -1
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/capsule.py +7 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/client.py +1 -1
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/capsule.py +19 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/pipeline.py +5 -0
- codeocean-0.16.0/tests/test_git_sync.py +46 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/.flake8 +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/.gitignore +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/LICENSE +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/README.md +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/RELEASE.md +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/examples/create_data_asset.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/examples/run_capsule.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/examples/run_pipeline.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/__init__.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/components.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/computation.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/custom_metadata.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/data_asset.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/enum.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/error.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/__init__.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/components.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/computation.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/data_asset.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/folder.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/tests/__init__.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/tests/test_client.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/tests/test_error.py +0 -0
- {codeocean-0.15.0 → codeocean-0.16.0}/tests/test_package.py +0 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## 0.16.0 (2026-06-08)
|
|
5
|
+
- [#71](https://github.com/codeocean/codeocean-sdk-python/pull/71) feat: add Git sync support for capsules and pipelines
|
|
6
|
+
- **Minimum Code Ocean platform version updated to `4.6.0`.**
|
|
7
|
+
|
|
4
8
|
## 0.15.0 (2026-04-10)
|
|
5
9
|
- [#69](https://github.com/codeocean/codeocean-sdk-python/pull/69) feat: Code Ocean version 4.3 functionality
|
|
6
10
|
- [#68](https://github.com/codeocean/codeocean-sdk-python/pull/68) feat: add get_permissions method for capsules, pipelines, data assets
|
|
@@ -9,6 +9,7 @@ from codeocean.models.capsule import (
|
|
|
9
9
|
CapsuleSearchParams,
|
|
10
10
|
CapsuleSearchResults,
|
|
11
11
|
AppPanel,
|
|
12
|
+
GitSyncResults,
|
|
12
13
|
)
|
|
13
14
|
# Re-exports for backward compatibility
|
|
14
15
|
from codeocean.models.capsule import ( # noqa: F401
|
|
@@ -91,6 +92,12 @@ class Capsules:
|
|
|
91
92
|
json=data_assets,
|
|
92
93
|
)
|
|
93
94
|
|
|
95
|
+
def sync_capsule(self, capsule_id: str) -> GitSyncResults:
|
|
96
|
+
"""Sync a capsule with its linked external Git repository."""
|
|
97
|
+
res = self.client.post(f"{self._route}/{capsule_id}/sync")
|
|
98
|
+
|
|
99
|
+
return GitSyncResults.from_dict(res.json())
|
|
100
|
+
|
|
94
101
|
def archive_capsule(self, capsule_id: str, archive: bool):
|
|
95
102
|
"""Archive or unarchive a capsule to control its visibility and accessibility."""
|
|
96
103
|
self.client.patch(
|
|
@@ -38,7 +38,7 @@ class CodeOcean:
|
|
|
38
38
|
agent_id: Optional[str] = None
|
|
39
39
|
|
|
40
40
|
# Minimum server version required by this SDK
|
|
41
|
-
MIN_SERVER_VERSION = "4.
|
|
41
|
+
MIN_SERVER_VERSION = "4.6.0"
|
|
42
42
|
|
|
43
43
|
def __post_init__(self):
|
|
44
44
|
self.session = BaseUrlSession(base_url=f"{self.domain}/api/v1/")
|
|
@@ -159,6 +159,25 @@ class Capsule:
|
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
|
|
162
|
+
@dataclass_json
|
|
163
|
+
@dataclass(frozen=True)
|
|
164
|
+
class GitSyncResults:
|
|
165
|
+
"""Results of syncing a capsule or pipeline with its external Git remote."""
|
|
166
|
+
|
|
167
|
+
pushed: int = dataclass_field(
|
|
168
|
+
default=0,
|
|
169
|
+
metadata={"description": "Number of commits pushed to the external Git remote"},
|
|
170
|
+
)
|
|
171
|
+
pulled: int = dataclass_field(
|
|
172
|
+
default=0,
|
|
173
|
+
metadata={"description": "Number of commits pulled from the external Git remote"},
|
|
174
|
+
)
|
|
175
|
+
new_branch: bool = dataclass_field(
|
|
176
|
+
default=False,
|
|
177
|
+
metadata={"description": "Whether the current branch was newly created on the external remote by this sync"},
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
162
181
|
@dataclass_json
|
|
163
182
|
@dataclass(frozen=True)
|
|
164
183
|
class CapsuleSearchParams:
|
|
@@ -10,6 +10,7 @@ from codeocean.models.capsule import (
|
|
|
10
10
|
CapsuleSearchParams,
|
|
11
11
|
CapsuleSearchResults,
|
|
12
12
|
AppPanel,
|
|
13
|
+
GitSyncResults,
|
|
13
14
|
)
|
|
14
15
|
from codeocean.models.components import Permissions
|
|
15
16
|
from codeocean.models.computation import Computation
|
|
@@ -62,6 +63,10 @@ class Pipelines:
|
|
|
62
63
|
"""Detach one or more data assets from a pipeline by their IDs."""
|
|
63
64
|
return self._capsules.detach_data_assets(pipeline_id, data_assets)
|
|
64
65
|
|
|
66
|
+
def sync_pipeline(self, pipeline_id: str) -> GitSyncResults:
|
|
67
|
+
"""Sync a pipeline with its linked external Git repository."""
|
|
68
|
+
return self._capsules.sync_capsule(pipeline_id)
|
|
69
|
+
|
|
65
70
|
def archive_pipeline(self, pipeline_id: str, archive: bool):
|
|
66
71
|
"""Archive or unarchive a pipeline to control its visibility and accessibility."""
|
|
67
72
|
return self._capsules.archive_capsule(pipeline_id, archive)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import MagicMock
|
|
3
|
+
|
|
4
|
+
from codeocean.capsule import Capsules, GitSyncResults
|
|
5
|
+
from codeocean.pipeline import Pipelines
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestGitSync(unittest.TestCase):
|
|
9
|
+
"""Test cases for capsule and pipeline Git sync."""
|
|
10
|
+
|
|
11
|
+
def _mock_session(self, body):
|
|
12
|
+
"""Build a mock session whose post() returns a response with the given JSON body."""
|
|
13
|
+
session = MagicMock()
|
|
14
|
+
response = MagicMock()
|
|
15
|
+
response.json.return_value = body
|
|
16
|
+
session.post.return_value = response
|
|
17
|
+
return session
|
|
18
|
+
|
|
19
|
+
def test_sync_capsule_returns_results(self):
|
|
20
|
+
"""sync_capsule posts to the capsule sync route and parses the results."""
|
|
21
|
+
session = self._mock_session({"pushed": 2, "pulled": 1, "new_branch": True})
|
|
22
|
+
capsules = Capsules(client=session)
|
|
23
|
+
|
|
24
|
+
result = capsules.sync_capsule("cap-123")
|
|
25
|
+
|
|
26
|
+
session.post.assert_called_once_with("capsules/cap-123/sync")
|
|
27
|
+
self.assertEqual(result, GitSyncResults(pushed=2, pulled=1, new_branch=True))
|
|
28
|
+
|
|
29
|
+
def test_sync_capsule_empty_body_defaults(self):
|
|
30
|
+
"""An empty body (all fields omitempty on the server) deserializes to zero defaults."""
|
|
31
|
+
session = self._mock_session({})
|
|
32
|
+
capsules = Capsules(client=session)
|
|
33
|
+
|
|
34
|
+
result = capsules.sync_capsule("cap-123")
|
|
35
|
+
|
|
36
|
+
self.assertEqual(result, GitSyncResults(pushed=0, pulled=0, new_branch=False))
|
|
37
|
+
|
|
38
|
+
def test_sync_pipeline_returns_results(self):
|
|
39
|
+
"""sync_pipeline posts to the pipeline sync route and parses the results."""
|
|
40
|
+
session = self._mock_session({"pushed": 0, "pulled": 3, "new_branch": False})
|
|
41
|
+
pipelines = Pipelines(client=session)
|
|
42
|
+
|
|
43
|
+
result = pipelines.sync_pipeline("pipe-456")
|
|
44
|
+
|
|
45
|
+
session.post.assert_called_once_with("pipelines/pipe-456/sync")
|
|
46
|
+
self.assertEqual(result, GitSyncResults(pushed=0, pulled=3, new_branch=False))
|
|
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
|
|
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
|