codeocean 0.7.0__tar.gz → 0.8.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.7.0 → codeocean-0.8.0}/CHANGELOG.md +4 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/PKG-INFO +1 -1
- {codeocean-0.7.0 → codeocean-0.8.0}/pyproject.toml +1 -1
- codeocean-0.8.0/src/codeocean/client.py +55 -0
- codeocean-0.8.0/tests/test_client.py +83 -0
- codeocean-0.7.0/src/codeocean/client.py +0 -32
- {codeocean-0.7.0 → codeocean-0.8.0}/.flake8 +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/.gitignore +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/LICENSE +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/README.md +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/RELEASE.md +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/examples/create_data_asset.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/examples/run_capsule.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/examples/run_pipeline.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/src/codeocean/__init__.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/src/codeocean/capsule.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/src/codeocean/components.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/src/codeocean/computation.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/src/codeocean/data_asset.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/src/codeocean/enum.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/src/codeocean/folder.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/tests/__init__.py +0 -0
- {codeocean-0.7.0 → codeocean-0.8.0}/tests/test_package.py +0 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## 0.8.0 (2025-07-11)
|
|
5
|
+
- [#50](https://github.com/codeocean/codeocean-sdk-python/pull/50) feat: Add Min-Server-Version header support
|
|
6
|
+
- [#49](https://github.com/codeocean/codeocean-sdk-python/pull/49) feat: Identify AI agents in API requests
|
|
7
|
+
|
|
4
8
|
## 0.7.0 (2025-06-24)
|
|
5
9
|
- [#46](https://github.com/codeocean/codeocean-sdk-python/pull/46) feat: Add API documentation
|
|
6
10
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from requests_toolbelt.adapters.socket_options import TCPKeepAliveAdapter
|
|
5
|
+
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from urllib3.util import Retry
|
|
8
|
+
|
|
9
|
+
from codeocean.capsule import Capsules
|
|
10
|
+
from codeocean.computation import Computations
|
|
11
|
+
from codeocean.data_asset import DataAssets
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class CodeOcean:
|
|
16
|
+
"""
|
|
17
|
+
Code Ocean API client.
|
|
18
|
+
|
|
19
|
+
This class provides a unified interface to access Code Ocean's API endpoints
|
|
20
|
+
for managing capsules, pipelines, computations, and data assets.
|
|
21
|
+
|
|
22
|
+
Fields:
|
|
23
|
+
domain: The Code Ocean domain URL (e.g., 'https://codeocean.acme.com')
|
|
24
|
+
token: Code Ocean API access token
|
|
25
|
+
retries: Optional retry configuration for failed HTTP requests. Can be an integer
|
|
26
|
+
(number of retries) or a urllib3.util.Retry object for advanced
|
|
27
|
+
retry configuration. Defaults to 0 (no retries)
|
|
28
|
+
agent_id: Optional agent identifier for tracking AI agent API usage on behalf of users
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
domain: str
|
|
32
|
+
token: str
|
|
33
|
+
retries: Optional[Retry | int] = 0
|
|
34
|
+
agent_id: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
# Minimum server version required by this SDK
|
|
37
|
+
MIN_SERVER_VERSION = "3.6.0"
|
|
38
|
+
|
|
39
|
+
def __post_init__(self):
|
|
40
|
+
self.session = BaseUrlSession(base_url=f"{self.domain}/api/v1/")
|
|
41
|
+
self.session.auth = (self.token, "")
|
|
42
|
+
self.session.headers.update({
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
"Min-Server-Version": CodeOcean.MIN_SERVER_VERSION,
|
|
45
|
+
})
|
|
46
|
+
if self.agent_id:
|
|
47
|
+
self.session.headers.update({"Agent-Id": self.agent_id})
|
|
48
|
+
self.session.hooks["response"] = [
|
|
49
|
+
lambda response, *args, **kwargs: response.raise_for_status()
|
|
50
|
+
]
|
|
51
|
+
self.session.mount(self.domain, TCPKeepAliveAdapter(max_retries=self.retries))
|
|
52
|
+
|
|
53
|
+
self.capsules = Capsules(client=self.session)
|
|
54
|
+
self.computations = Computations(client=self.session)
|
|
55
|
+
self.data_assets = DataAssets(client=self.session)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
from urllib3.util import Retry
|
|
4
|
+
|
|
5
|
+
from codeocean.client import CodeOcean
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestClient(unittest.TestCase):
|
|
9
|
+
"""Test cases for the CodeOcean client class."""
|
|
10
|
+
|
|
11
|
+
def setUp(self):
|
|
12
|
+
"""Set up test fixtures."""
|
|
13
|
+
self.test_domain = "https://codeocean.acme.com"
|
|
14
|
+
self.test_token = "test_token_123"
|
|
15
|
+
self.test_agent_id = "test_agent_456"
|
|
16
|
+
|
|
17
|
+
def test_basic_init(self):
|
|
18
|
+
"""Test a basic client initialization."""
|
|
19
|
+
client = CodeOcean(
|
|
20
|
+
domain=self.test_domain,
|
|
21
|
+
token=self.test_token,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Verify base URL is set correctly
|
|
25
|
+
self.assertEqual(client.session.base_url, f"{self.test_domain}/api/v1/")
|
|
26
|
+
|
|
27
|
+
# Verify auth is correctly set
|
|
28
|
+
self.assertEqual(client.session.auth, (self.test_token, ""))
|
|
29
|
+
|
|
30
|
+
# Verify the session headers are correctly configured
|
|
31
|
+
headers = client.session.headers
|
|
32
|
+
self.assertIn("Content-Type", headers)
|
|
33
|
+
self.assertEqual(headers["Content-Type"], "application/json")
|
|
34
|
+
self.assertIn("Min-Server-Version", headers)
|
|
35
|
+
self.assertEqual(headers["Min-Server-Version"], CodeOcean.MIN_SERVER_VERSION)
|
|
36
|
+
|
|
37
|
+
@patch("codeocean.client.TCPKeepAliveAdapter")
|
|
38
|
+
def test_retry_configuration_types(self, mock_adapter):
|
|
39
|
+
"""Test that both integer and Retry object work for retries parameter."""
|
|
40
|
+
# Test with integer
|
|
41
|
+
CodeOcean(
|
|
42
|
+
domain=self.test_domain,
|
|
43
|
+
token=self.test_token,
|
|
44
|
+
retries=5,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Test with Retry object
|
|
48
|
+
retry_obj = Retry(total=3, backoff_factor=0.3)
|
|
49
|
+
CodeOcean(
|
|
50
|
+
domain=self.test_domain,
|
|
51
|
+
token=self.test_token,
|
|
52
|
+
retries=retry_obj,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Assert both configurations work
|
|
56
|
+
self.assertEqual(mock_adapter.call_count, 2)
|
|
57
|
+
mock_adapter.assert_any_call(max_retries=5)
|
|
58
|
+
mock_adapter.assert_any_call(max_retries=retry_obj)
|
|
59
|
+
|
|
60
|
+
def test_agent_id_header_set_when_provided(self):
|
|
61
|
+
"""Test that Agent-Id header is set when agent_id is provided."""
|
|
62
|
+
client = CodeOcean(
|
|
63
|
+
domain=self.test_domain,
|
|
64
|
+
token=self.test_token,
|
|
65
|
+
agent_id=self.test_agent_id,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Verify the session headers are correctly configured
|
|
69
|
+
headers = client.session.headers
|
|
70
|
+
self.assertIn("Agent-Id", headers)
|
|
71
|
+
self.assertEqual(headers["Agent-Id"], self.test_agent_id)
|
|
72
|
+
|
|
73
|
+
def test_agent_id_header_not_set_when_none(self):
|
|
74
|
+
"""Test that Agent-Id header is not set when agent_id is None."""
|
|
75
|
+
client = CodeOcean(
|
|
76
|
+
domain=self.test_domain,
|
|
77
|
+
token=self.test_token,
|
|
78
|
+
agent_id=None,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Verify the session headers are correctly configured
|
|
82
|
+
headers = client.session.headers
|
|
83
|
+
self.assertNotIn("Agent-Id", headers)
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from requests_toolbelt.adapters.socket_options import TCPKeepAliveAdapter
|
|
5
|
-
from requests_toolbelt.sessions import BaseUrlSession
|
|
6
|
-
from typing import Optional
|
|
7
|
-
from urllib3.util import Retry
|
|
8
|
-
|
|
9
|
-
from codeocean.capsule import Capsules
|
|
10
|
-
from codeocean.computation import Computations
|
|
11
|
-
from codeocean.data_asset import DataAssets
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class CodeOcean:
|
|
16
|
-
|
|
17
|
-
domain: str
|
|
18
|
-
token: str
|
|
19
|
-
retries: Optional[Retry | int] = 0
|
|
20
|
-
|
|
21
|
-
def __post_init__(self):
|
|
22
|
-
self.session = BaseUrlSession(base_url=f"{self.domain}/api/v1/")
|
|
23
|
-
self.session.auth = (self.token, "")
|
|
24
|
-
self.session.headers.update({"Content-Type": "application/json"})
|
|
25
|
-
self.session.hooks["response"] = [
|
|
26
|
-
lambda response, *args, **kwargs: response.raise_for_status()
|
|
27
|
-
]
|
|
28
|
-
self.session.mount(self.domain, TCPKeepAliveAdapter(max_retries=self.retries))
|
|
29
|
-
|
|
30
|
-
self.capsules = Capsules(client=self.session)
|
|
31
|
-
self.computations = Computations(client=self.session)
|
|
32
|
-
self.data_assets = DataAssets(client=self.session)
|
|
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
|