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.
Files changed (32) hide show
  1. {codeocean-0.15.0 → codeocean-0.16.0}/CHANGELOG.md +4 -0
  2. {codeocean-0.15.0 → codeocean-0.16.0}/PKG-INFO +1 -1
  3. {codeocean-0.15.0 → codeocean-0.16.0}/pyproject.toml +1 -1
  4. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/capsule.py +7 -0
  5. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/client.py +1 -1
  6. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/capsule.py +19 -0
  7. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/pipeline.py +5 -0
  8. codeocean-0.16.0/tests/test_git_sync.py +46 -0
  9. {codeocean-0.15.0 → codeocean-0.16.0}/.flake8 +0 -0
  10. {codeocean-0.15.0 → codeocean-0.16.0}/.gitignore +0 -0
  11. {codeocean-0.15.0 → codeocean-0.16.0}/LICENSE +0 -0
  12. {codeocean-0.15.0 → codeocean-0.16.0}/README.md +0 -0
  13. {codeocean-0.15.0 → codeocean-0.16.0}/RELEASE.md +0 -0
  14. {codeocean-0.15.0 → codeocean-0.16.0}/examples/create_data_asset.py +0 -0
  15. {codeocean-0.15.0 → codeocean-0.16.0}/examples/run_capsule.py +0 -0
  16. {codeocean-0.15.0 → codeocean-0.16.0}/examples/run_pipeline.py +0 -0
  17. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/__init__.py +0 -0
  18. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/components.py +0 -0
  19. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/computation.py +0 -0
  20. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/custom_metadata.py +0 -0
  21. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/data_asset.py +0 -0
  22. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/enum.py +0 -0
  23. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/error.py +0 -0
  24. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/__init__.py +0 -0
  25. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/components.py +0 -0
  26. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/computation.py +0 -0
  27. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/data_asset.py +0 -0
  28. {codeocean-0.15.0 → codeocean-0.16.0}/src/codeocean/models/folder.py +0 -0
  29. {codeocean-0.15.0 → codeocean-0.16.0}/tests/__init__.py +0 -0
  30. {codeocean-0.15.0 → codeocean-0.16.0}/tests/test_client.py +0 -0
  31. {codeocean-0.15.0 → codeocean-0.16.0}/tests/test_error.py +0 -0
  32. {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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeocean
3
- Version: 0.15.0
3
+ Version: 0.16.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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "codeocean"
7
- version = "0.15.0"
7
+ version = "0.16.0"
8
8
  authors = [
9
9
  { name="Code Ocean", email="dev@codeocean.com" },
10
10
  ]
@@ -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.3.0"
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