subspacecomputing 0.1.1__tar.gz → 0.1.2__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 (20) hide show
  1. {subspacecomputing-0.1.1/subspacecomputing.egg-info → subspacecomputing-0.1.2}/PKG-INFO +12 -1
  2. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/README.md +11 -0
  3. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/pyproject.toml +2 -1
  4. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/setup.py +1 -1
  5. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing/__init__.py +1 -1
  6. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing/client.py +35 -2
  7. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing/errors.py +15 -3
  8. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2/subspacecomputing.egg-info}/PKG-INFO +12 -1
  9. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/LICENSE +0 -0
  10. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/MANIFEST.in +0 -0
  11. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/setup.cfg +0 -0
  12. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing/utils/__init__.py +0 -0
  13. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing/utils/pandas_integration.py +0 -0
  14. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing.egg-info/SOURCES.txt +0 -0
  15. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing.egg-info/dependency_links.txt +0 -0
  16. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing.egg-info/requires.txt +0 -0
  17. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/subspacecomputing.egg-info/top_level.txt +0 -0
  18. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/tests/test_client_integration.py +0 -0
  19. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/tests/test_client_unit.py +0 -0
  20. {subspacecomputing-0.1.1 → subspacecomputing-0.1.2}/tests/test_pandas_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: subspacecomputing
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Python SDK for Subspace Computing Engine API (by Beausoft)
5
5
  Home-page: https://www.subspacecomputing.com/developer
6
6
  Author: Beausoft
@@ -49,6 +49,17 @@ bsce = BSCE(api_key='your-api-key-here')
49
49
  # bsce = BSCE(api_key='your-api-key-here', base_url='http://localhost:8000')
50
50
  ```
51
51
 
52
+ ### Teams (`X-Team-Id`)
53
+
54
+ Keys can carry a `default_team_id` from the portal. If the user is in **several** teams, some endpoints require an explicit team: pass `team_id=...` or call `set_team_id` so the SDK sends `X-Team-Id`.
55
+
56
+ If you omit it when required, the API returns **400** with `error.reason` **`team_context_required`**. Use `ValidationError` and read `exc.reason`.
57
+
58
+ ```python
59
+ bsce = BSCE(api_key="...", team_id="00000000-0000-0000-0000-000000000000")
60
+ bsce.set_team_id(None) # clear override for following requests
61
+ ```
62
+
52
63
  ### Simple Projection (1 scenario)
53
64
 
54
65
  ```python
@@ -22,6 +22,17 @@ bsce = BSCE(api_key='your-api-key-here')
22
22
  # bsce = BSCE(api_key='your-api-key-here', base_url='http://localhost:8000')
23
23
  ```
24
24
 
25
+ ### Teams (`X-Team-Id`)
26
+
27
+ Keys can carry a `default_team_id` from the portal. If the user is in **several** teams, some endpoints require an explicit team: pass `team_id=...` or call `set_team_id` so the SDK sends `X-Team-Id`.
28
+
29
+ If you omit it when required, the API returns **400** with `error.reason` **`team_context_required`**. Use `ValidationError` and read `exc.reason`.
30
+
31
+ ```python
32
+ bsce = BSCE(api_key="...", team_id="00000000-0000-0000-0000-000000000000")
33
+ bsce.set_team_id(None) # clear override for following requests
34
+ ```
35
+
25
36
  ### Simple Projection (1 scenario)
26
37
 
27
38
  ```python
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "subspacecomputing"
9
- version = "0.1.1"
9
+ version = "0.1.2"
10
10
  description = "Python SDK for Subspace Computing Engine API (by Beausoft)"
11
11
  authors = [{name = "Beausoft", email = "contact@beausoft.ca"}]
12
12
  readme = "README.md"
@@ -25,6 +25,7 @@ dev = [
25
25
  "fastapi>=0.100.0", # Pour tests d'intégration
26
26
  ]
27
27
 
28
+ # No Git repository URL: built from a private monorepo; only public product URLs are published on PyPI.
28
29
  [project.urls]
29
30
  Documentation = "https://www.subspacecomputing.com/developer"
30
31
  Homepage = "https://www.subspacecomputing.com/developer"
@@ -13,7 +13,7 @@ except FileNotFoundError:
13
13
 
14
14
  setup(
15
15
  name="subspacecomputing",
16
- version="0.1.1",
16
+ version="0.1.2",
17
17
  description="Python SDK for Subspace Computing Engine API (by Beausoft)",
18
18
  long_description=long_description,
19
19
  long_description_content_type="text/markdown",
@@ -13,7 +13,7 @@ from .errors import (
13
13
  ValidationError,
14
14
  )
15
15
 
16
- __version__ = "0.1.1"
16
+ __version__ = "0.1.2"
17
17
  __all__ = [
18
18
  "BSCE",
19
19
  "BSCEError",
@@ -26,6 +26,8 @@ class BSCE:
26
26
  api_key: str,
27
27
  base_url: Optional[str] = None,
28
28
  timeout: Optional[int] = None,
29
+ *,
30
+ team_id: Optional[str] = None,
29
31
  ):
30
32
  """
31
33
  Initialize the BSCE client.
@@ -36,6 +38,7 @@ class BSCE:
36
38
  base_url: API base URL (optional, defaults to https://api.subspacecomputing.com).
37
39
  Only useful for local testing or custom environments.
38
40
  timeout: Request timeout in seconds (optional, defaults to 60).
41
+ team_id: Optional team UUID for header ``X-Team-Id`` (override default_team_id on the key).
39
42
 
40
43
  Raises:
41
44
  ValueError: If api_key is empty or None.
@@ -47,13 +50,25 @@ class BSCE:
47
50
  self.api_key = api_key.strip()
48
51
  self.base_url = (base_url or "https://api.subspacecomputing.com").rstrip("/")
49
52
  self.timeout = timeout if timeout is not None else DEFAULT_TIMEOUT
53
+ self._team_id = (team_id or "").strip() or None
50
54
  self.session = requests.Session()
51
- self.session.headers.update({
55
+ headers = {
52
56
  "X-API-Key": self.api_key,
53
57
  "Content-Type": "application/json",
54
- })
58
+ }
59
+ if self._team_id:
60
+ headers["X-Team-Id"] = self._team_id
61
+ self.session.headers.update(headers)
55
62
  self.last_response = None # Store last response for header access
56
63
 
64
+ def set_team_id(self, team_id: Optional[str] = None) -> None:
65
+ """Set or clear ``X-Team-Id`` for subsequent requests."""
66
+ self._team_id = (team_id or "").strip() or None
67
+ if self._team_id:
68
+ self.session.headers["X-Team-Id"] = self._team_id
69
+ else:
70
+ self.session.headers.pop("X-Team-Id", None)
71
+
57
72
  def _handle_response(self, response: requests.Response):
58
73
  """
59
74
  Handle HTTP errors and raise appropriate exceptions.
@@ -445,6 +460,24 @@ class BSCE:
445
460
  self._handle_response(response)
446
461
  # 204 No Content, no body
447
462
 
463
+ def get_run_artifact(self, artifact_id: str) -> Dict[str, Any]:
464
+ """
465
+ Fetch a run artifact by id (authZ: view on parent projection).
466
+
467
+ Args:
468
+ artifact_id: run_artifacts.id
469
+
470
+ Returns:
471
+ Artifact payload (may include final_values or url).
472
+ """
473
+ response = self.session.get(
474
+ f"{self.base_url}/run-artifacts/{artifact_id}",
475
+ timeout=self.timeout,
476
+ )
477
+ self.last_response = response
478
+ self._handle_response(response)
479
+ return response.json()
480
+
448
481
  # Helper methods for accessing rate limit and quota info
449
482
 
450
483
  @staticmethod
@@ -3,7 +3,7 @@ Custom exceptions for the Subspace Computing SDK.
3
3
  """
4
4
 
5
5
  import requests
6
- from typing import Optional
6
+ from typing import Any, Optional
7
7
 
8
8
 
9
9
  class BSCEError(Exception):
@@ -13,19 +13,31 @@ class BSCEError(Exception):
13
13
  self.message = message
14
14
  self.response = response
15
15
  self.status_code = response.status_code if response else None
16
- self.detail = None
16
+ self.detail: Any = None
17
+ self._body: Optional[dict] = None
17
18
 
18
- # Try to extract error details from the response
19
19
  if response is not None:
20
20
  try:
21
21
  error_data = response.json()
22
22
  if isinstance(error_data, dict):
23
+ self._body = error_data
23
24
  self.detail = error_data.get("detail", error_data.get("message"))
24
25
  except ValueError:
25
26
  self.detail = response.text
26
27
 
27
28
  super().__init__(self.message)
28
29
 
30
+ @property
31
+ def reason(self) -> Optional[str]:
32
+ """Clé stable contrat §6.8 si le corps est ``{\"error\": {\"reason\": ...}}``."""
33
+ if not self._body:
34
+ return None
35
+ err = self._body.get("error")
36
+ if isinstance(err, dict):
37
+ r = err.get("reason")
38
+ return str(r) if r is not None else None
39
+ return None
40
+
29
41
  def __str__(self):
30
42
  if self.detail:
31
43
  return f"{self.message}: {self.detail}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: subspacecomputing
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Python SDK for Subspace Computing Engine API (by Beausoft)
5
5
  Home-page: https://www.subspacecomputing.com/developer
6
6
  Author: Beausoft
@@ -49,6 +49,17 @@ bsce = BSCE(api_key='your-api-key-here')
49
49
  # bsce = BSCE(api_key='your-api-key-here', base_url='http://localhost:8000')
50
50
  ```
51
51
 
52
+ ### Teams (`X-Team-Id`)
53
+
54
+ Keys can carry a `default_team_id` from the portal. If the user is in **several** teams, some endpoints require an explicit team: pass `team_id=...` or call `set_team_id` so the SDK sends `X-Team-Id`.
55
+
56
+ If you omit it when required, the API returns **400** with `error.reason` **`team_context_required`**. Use `ValidationError` and read `exc.reason`.
57
+
58
+ ```python
59
+ bsce = BSCE(api_key="...", team_id="00000000-0000-0000-0000-000000000000")
60
+ bsce.set_team_id(None) # clear override for following requests
61
+ ```
62
+
52
63
  ### Simple Projection (1 scenario)
53
64
 
54
65
  ```python