dataspace-sdk 0.4.2__py3-none-any.whl
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.
- dataspace_sdk/__init__.py +18 -0
- dataspace_sdk/__version__.py +3 -0
- dataspace_sdk/auth.py +470 -0
- dataspace_sdk/base.py +160 -0
- dataspace_sdk/client.py +206 -0
- dataspace_sdk/exceptions.py +36 -0
- dataspace_sdk/resources/__init__.py +8 -0
- dataspace_sdk/resources/aimodels.py +989 -0
- dataspace_sdk/resources/datasets.py +233 -0
- dataspace_sdk/resources/sectors.py +128 -0
- dataspace_sdk/resources/usecases.py +248 -0
- dataspace_sdk-0.4.2.dist-info/METADATA +551 -0
- dataspace_sdk-0.4.2.dist-info/RECORD +15 -0
- dataspace_sdk-0.4.2.dist-info/WHEEL +5 -0
- dataspace_sdk-0.4.2.dist-info/top_level.txt +1 -0
dataspace_sdk/client.py
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"""Main DataSpace SDK client."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from dataspace_sdk.auth import AuthClient
|
|
6
|
+
from dataspace_sdk.resources.aimodels import AIModelClient
|
|
7
|
+
from dataspace_sdk.resources.datasets import DatasetClient
|
|
8
|
+
from dataspace_sdk.resources.sectors import SectorClient
|
|
9
|
+
from dataspace_sdk.resources.usecases import UseCaseClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DataSpaceClient:
|
|
13
|
+
"""
|
|
14
|
+
Main client for interacting with DataSpace API.
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
>>> from dataspace_sdk import DataSpaceClient
|
|
18
|
+
>>>
|
|
19
|
+
>>> # Initialize client
|
|
20
|
+
>>> client = DataSpaceClient(base_url="https://api.dataspace.example.com")
|
|
21
|
+
>>>
|
|
22
|
+
>>> # Login with Keycloak token
|
|
23
|
+
>>> client.login(keycloak_token="your_keycloak_token")
|
|
24
|
+
>>>
|
|
25
|
+
>>> # Search for datasets
|
|
26
|
+
>>> datasets = client.datasets.search(query="health", tags=["public-health"])
|
|
27
|
+
>>>
|
|
28
|
+
>>> # Get a specific dataset
|
|
29
|
+
>>> dataset = client.datasets.get_by_id("dataset-uuid")
|
|
30
|
+
>>>
|
|
31
|
+
>>> # Get organization's resources
|
|
32
|
+
>>> org_datasets = client.datasets.get_organization_datasets("org-uuid")
|
|
33
|
+
>>> org_models = client.aimodels.get_organization_models("org-uuid")
|
|
34
|
+
>>> org_usecases = client.usecases.get_organization_usecases("org-uuid")
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
base_url: str,
|
|
40
|
+
keycloak_url: Optional[str] = None,
|
|
41
|
+
keycloak_realm: Optional[str] = None,
|
|
42
|
+
keycloak_client_id: Optional[str] = None,
|
|
43
|
+
keycloak_client_secret: Optional[str] = None,
|
|
44
|
+
):
|
|
45
|
+
"""
|
|
46
|
+
Initialize the DataSpace client.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
base_url: Base URL of the DataSpace API (e.g., "https://api.dataspace.example.com")
|
|
50
|
+
keycloak_url: Keycloak server URL (e.g., "https://opub-kc.civicdatalab.in")
|
|
51
|
+
keycloak_realm: Keycloak realm name (e.g., "DataSpace")
|
|
52
|
+
keycloak_client_id: Keycloak client ID (e.g., "dataspace")
|
|
53
|
+
keycloak_client_secret: Optional client secret for confidential clients
|
|
54
|
+
"""
|
|
55
|
+
self.base_url = base_url.rstrip("/")
|
|
56
|
+
self._auth = AuthClient(
|
|
57
|
+
self.base_url,
|
|
58
|
+
keycloak_url=keycloak_url,
|
|
59
|
+
keycloak_realm=keycloak_realm,
|
|
60
|
+
keycloak_client_id=keycloak_client_id,
|
|
61
|
+
keycloak_client_secret=keycloak_client_secret,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Initialize resource clients
|
|
65
|
+
self.datasets = DatasetClient(self.base_url, self._auth)
|
|
66
|
+
self.aimodels = AIModelClient(self.base_url, self._auth)
|
|
67
|
+
self.usecases = UseCaseClient(self.base_url, self._auth)
|
|
68
|
+
self.sectors = SectorClient(self.base_url, self._auth)
|
|
69
|
+
|
|
70
|
+
def login(self, username: str, password: str) -> dict:
|
|
71
|
+
"""
|
|
72
|
+
Login using username and password.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
username: User's username or email
|
|
76
|
+
password: User's password
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Dictionary containing user info and tokens
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
DataSpaceAuthError: If authentication fails
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
>>> client = DataSpaceClient(
|
|
86
|
+
... base_url="https://api.dataspace.example.com",
|
|
87
|
+
... keycloak_url="https://opub-kc.civicdatalab.in",
|
|
88
|
+
... keycloak_realm="DataSpace",
|
|
89
|
+
... keycloak_client_id="dataspace"
|
|
90
|
+
... )
|
|
91
|
+
>>> user_info = client.login(username="user@example.com", password="secret")
|
|
92
|
+
>>> print(user_info["user"]["username"])
|
|
93
|
+
"""
|
|
94
|
+
return self._auth.login(username, password)
|
|
95
|
+
|
|
96
|
+
def login_as_service_account(self) -> dict:
|
|
97
|
+
"""
|
|
98
|
+
Login using client credentials (service account).
|
|
99
|
+
|
|
100
|
+
This method authenticates the client itself using client_id and client_secret.
|
|
101
|
+
The Keycloak client must have "Service Accounts Enabled" turned ON.
|
|
102
|
+
|
|
103
|
+
This is the recommended approach for backend services and automated tasks.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Dictionary containing user info and tokens
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
DataSpaceAuthError: If authentication fails
|
|
110
|
+
|
|
111
|
+
Example:
|
|
112
|
+
>>> client = DataSpaceClient(
|
|
113
|
+
... base_url="https://api.dataspace.example.com",
|
|
114
|
+
... keycloak_url="https://opub-kc.civicdatalab.in",
|
|
115
|
+
... keycloak_realm="DataSpace",
|
|
116
|
+
... keycloak_client_id="dataspace",
|
|
117
|
+
... keycloak_client_secret="your-secret"
|
|
118
|
+
... )
|
|
119
|
+
>>> info = client.login_as_service_account()
|
|
120
|
+
>>> print("Authenticated as service account")
|
|
121
|
+
"""
|
|
122
|
+
return self._auth.login_as_service_account()
|
|
123
|
+
|
|
124
|
+
def login_with_token(self, keycloak_token: str) -> dict:
|
|
125
|
+
"""
|
|
126
|
+
Login using a pre-obtained Keycloak token.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
keycloak_token: Valid Keycloak access token
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Dictionary containing user info and tokens
|
|
133
|
+
|
|
134
|
+
Raises:
|
|
135
|
+
DataSpaceAuthError: If authentication fails
|
|
136
|
+
|
|
137
|
+
Example:
|
|
138
|
+
>>> client = DataSpaceClient(base_url="https://api.dataspace.example.com")
|
|
139
|
+
>>> user_info = client.login_with_token(keycloak_token="your_token")
|
|
140
|
+
>>> print(user_info["user"]["username"])
|
|
141
|
+
"""
|
|
142
|
+
return self._auth._login_with_keycloak_token(keycloak_token)
|
|
143
|
+
|
|
144
|
+
def refresh_token(self) -> str:
|
|
145
|
+
"""
|
|
146
|
+
Refresh the access token using the refresh token.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
New access token
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
DataSpaceAuthError: If token refresh fails
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
>>> client.refresh_token()
|
|
156
|
+
"""
|
|
157
|
+
return self._auth.refresh_access_token()
|
|
158
|
+
|
|
159
|
+
def get_user_info(self) -> dict:
|
|
160
|
+
"""
|
|
161
|
+
Get current user information.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
Dictionary containing user information including organizations
|
|
165
|
+
|
|
166
|
+
Raises:
|
|
167
|
+
DataSpaceAuthError: If not authenticated or request fails
|
|
168
|
+
|
|
169
|
+
Example:
|
|
170
|
+
>>> user_info = client.get_user_info()
|
|
171
|
+
>>> print(user_info["organizations"])
|
|
172
|
+
"""
|
|
173
|
+
return self._auth.get_user_info()
|
|
174
|
+
|
|
175
|
+
def is_authenticated(self) -> bool:
|
|
176
|
+
"""
|
|
177
|
+
Check if the client is authenticated.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
True if authenticated, False otherwise
|
|
181
|
+
|
|
182
|
+
Example:
|
|
183
|
+
>>> if client.is_authenticated():
|
|
184
|
+
... datasets = client.datasets.search()
|
|
185
|
+
"""
|
|
186
|
+
return self._auth.is_authenticated()
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def user(self) -> Optional[dict]:
|
|
190
|
+
"""
|
|
191
|
+
Get cached user information.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
User information dictionary or None if not authenticated
|
|
195
|
+
"""
|
|
196
|
+
return self._auth.user_info
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def access_token(self) -> Optional[str]:
|
|
200
|
+
"""
|
|
201
|
+
Get the current access token.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Access token string or None if not authenticated
|
|
205
|
+
"""
|
|
206
|
+
return self._auth.access_token
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Custom exceptions for DataSpace SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DataSpaceAPIError(Exception):
|
|
7
|
+
"""Base exception for DataSpace API errors."""
|
|
8
|
+
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
message: str,
|
|
12
|
+
status_code: Optional[int] = None,
|
|
13
|
+
response: Optional[dict[str, Any]] = None,
|
|
14
|
+
):
|
|
15
|
+
self.message = message
|
|
16
|
+
self.status_code = status_code
|
|
17
|
+
self.response = response
|
|
18
|
+
super().__init__(self.message)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DataSpaceAuthError(DataSpaceAPIError):
|
|
22
|
+
"""Exception raised for authentication errors."""
|
|
23
|
+
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DataSpaceNotFoundError(DataSpaceAPIError):
|
|
28
|
+
"""Exception raised when a resource is not found."""
|
|
29
|
+
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class DataSpaceValidationError(DataSpaceAPIError):
|
|
34
|
+
"""Exception raised for validation errors."""
|
|
35
|
+
|
|
36
|
+
pass
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Resource clients for DataSpace SDK."""
|
|
2
|
+
|
|
3
|
+
from dataspace_sdk.resources.aimodels import AIModelClient
|
|
4
|
+
from dataspace_sdk.resources.datasets import DatasetClient
|
|
5
|
+
from dataspace_sdk.resources.sectors import SectorClient
|
|
6
|
+
from dataspace_sdk.resources.usecases import UseCaseClient
|
|
7
|
+
|
|
8
|
+
__all__ = ["DatasetClient", "AIModelClient", "UseCaseClient", "SectorClient"]
|