-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.py
More file actions
254 lines (214 loc) · 9.71 KB
/
client.py
File metadata and controls
254 lines (214 loc) · 9.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
import requests
import json
from typing import Optional, Dict, Any, List
from .exceptions import (
SysMLV2Error,
SysMLV2AuthError,
SysMLV2APIError,
SysMLV2NotFoundError,
SysMLV2BadRequestError,
SysMLV2ConflictError,
)
class SysMLV2Client:
def __init__(self, base_url: str, bearer_token: str):
if not base_url:
raise ValueError("base_url cannot be empty.")
if not bearer_token or not bearer_token.lower().startswith("bearer "):
raise ValueError("bearer_token must be provided and start with 'Bearer '.")
self.base_url = base_url.rstrip('/')
self._bearer_token = bearer_token
self._headers = {
"Authorization": self._bearer_token,
"Content-Type": "application/json",
"Accept": "application/json",
}
self._session = requests.Session()
self._session.headers.update(self._headers)
def _request(
self,
method: str,
endpoint: str,
params: Optional[Dict[str, Any]] = None,
data: Optional[Dict[str, Any]] = None,
expected_status: int = 200,
) -> Dict[str, Any]:
url = f"{self.base_url}{endpoint}"
json_data = data
try:
response = self._session.request(
method=method,
url=url,
params=params,
json=json_data,
)
# Check for specific error codes first
if response.status_code == 401 or response.status_code == 403:
raise SysMLV2AuthError(f"Authentication failed: {response.status_code} - {response.text}")
if response.status_code == 404:
raise SysMLV2NotFoundError(f"Resource not found at {endpoint}: {response.text}")
if response.status_code == 400:
try:
error_details = response.json()
except json.JSONDecodeError:
error_details = response.text
raise SysMLV2BadRequestError(f"Bad request for {endpoint}: {error_details}")
if response.status_code == 409:
raise SysMLV2ConflictError(f"Conflict detected for {endpoint}: {response.text}")
# Check if the status code matches the expected one
if response.status_code != expected_status:
raise SysMLV2APIError(
status_code=response.status_code,
message=f"Unexpected status code for {method} {endpoint}. Response: {response.text}"
)
# Handle successful responses with no content (e.g., DELETE)
if response.status_code == 204 or not response.content:
return {}
# Parse successful JSON response
return response.json()
except requests.exceptions.RequestException as e:
raise SysMLV2Error(f"Network error during request to {url}: {e}") from e
except json.JSONDecodeError as e:
raise SysMLV2Error(f"Failed to decode JSON response from {url}: {e}. Response text: {response.text}") from e
# --- Core API Methods ---
def get_projects(self) -> List[Dict[str, Any]]:
response_data = self._request(method="GET", endpoint="/projects", expected_status=200)
if isinstance(response_data, list):
return response_data
elif isinstance(response_data, dict):
return response_data.get('elements', [])
else:
return []
def create_project(self, project_data: Dict[str, Any]) -> Dict[str, Any]:
return self._request(
method="POST",
endpoint="/projects",
data=project_data,
expected_status=200
)
def delete_project(self, project_id: str):
return self._request(
method="DELETE",
endpoint=f"/projects/{project_id}",
expected_status=200
)
def get_project_by_id(self, project_id: str) -> Dict[str, Any]:
endpoint = f"/projects/{project_id}"
return self._request(method="GET", endpoint=endpoint, expected_status=200)
def get_element(self, project_id: str, element_id: str, commit_id: str = "main") -> Dict[str, Any]:
endpoint = f"/projects/{project_id}/commits/{commit_id}/elements/{element_id}"
return self._request(method="GET", endpoint=endpoint, expected_status=200)
def get_owned_elements(self, project_id: str, element_id: str, commit_id: str = "main") -> List[Dict[str, Any]]:
endpoint = f"/projects/{project_id}/commits/{commit_id}/elements/{element_id}/owned"
response_data = self._request(method="GET", endpoint=endpoint, expected_status=200)
if isinstance(response_data, list):
return response_data
elif isinstance(response_data, dict):
return response_data.get('elements', [])
else:
return []
def create_commit(self, project_id: str, commit_data: Dict[str, Any], branch_id:str = None, replace:bool = False) -> Dict[str, Any]:
params = []
if replace:
params.append("replace=true")
if branch_id is not None:
params.append(f"branchId={branch_id}")
endpoint = f"/projects/{project_id}/commits"
if params:
endpoint += "?" + "&".join(params)
#print (">>> DEBUG create_commit")
#print (endpoint)
#print (commit_data)
return self._request(
method="POST",
endpoint=endpoint,
data=commit_data,
expected_status=200
)
def get_commit_by_id(self, project_id: str, commit_id: str) -> Dict[str, Any]:
endpoint = f"/projects/{project_id}/commits/{commit_id}"
return self._request(method="GET", endpoint=endpoint, expected_status=200)
def list_commits(self, project_id: str) -> List[Dict[str, Any]]:
endpoint = f"/projects/{project_id}/commits"
response_data = self._request(method="GET", endpoint=endpoint, expected_status=200)
if isinstance(response_data, list):
return response_data
elif isinstance(response_data, dict):
return response_data.get('elements', [])
else:
return []
# --- Branch Management ---
def list_branches(self, project_id: str) -> List[Dict[str, Any]]:
endpoint = f"/projects/{project_id}/branches"
response_data = self._request(method="GET", endpoint=endpoint, expected_status=200)
if isinstance(response_data, list):
return response_data
elif isinstance(response_data, dict):
return response_data.get('elements', [])
else:
return []
def create_branch(self, project_id: str, branch_data: Dict[str, Any]) -> Dict[str, Any]:
endpoint = f"/projects/{project_id}/branches"
return self._request(
method="POST",
endpoint=endpoint,
data=branch_data,
expected_status=200
)
def get_branch_by_id(self, project_id: str, branch_id: str) -> Dict[str, Any]:
endpoint = f"/projects/{project_id}/branches/{branch_id}"
return self._request(method="GET", endpoint=endpoint, expected_status=200)
def delete_branch(self, project_id: str, branch_id: str) -> None:
endpoint = f"/projects/{project_id}/branches/{branch_id}"
self._request(method="DELETE", endpoint=endpoint, expected_status=204)
return None
# --- Tag Management ---
def list_tags(self, project_id: str) -> List[Dict[str, Any]]:
endpoint = f"/projects/{project_id}/tags"
response_data = self._request(method="GET", endpoint=endpoint, expected_status=200)
if isinstance(response_data, list):
return response_data
elif isinstance(response_data, dict):
return response_data.get('elements', [])
else:
return []
def create_tag(self, project_id: str, tag_data: Dict[str, Any]) -> Dict[str, Any]:
endpoint = f"/projects/{project_id}/tags"
return self._request(
method="POST",
endpoint=endpoint,
data=tag_data,
expected_status=200
)
def get_tag_by_id(self, project_id: str, tag_id: str) -> Dict[str, Any]:
endpoint = f"/projects/{project_id}/tags/{tag_id}"
return self._request(method="GET", endpoint=endpoint, expected_status=200)
def delete_tag(self, project_id: str, tag_id: str) -> None:
endpoint = f"/projects/{project_id}/tags/{tag_id}"
self._request(method="DELETE", endpoint=endpoint, expected_status=204)
return None
# --- Element/Relationship Listing ---
def list_elements(self, project_id: str, commit_id: str = "main") -> List[Dict[str, Any]]:
endpoint = f"/projects/{project_id}/commits/{commit_id}/elements"
response_data = self._request(method="GET", endpoint=endpoint, expected_status=200)
if isinstance(response_data, list):
return response_data
elif isinstance(response_data, dict):
return response_data.get('elements', [])
else:
return []
def list_relationships(
self,
project_id: str,
related_element_id: str,
commit_id: str = "main",
direction: str = "both"
) -> List[Dict[str, Any]]:
endpoint = f"/projects/{project_id}/commits/{commit_id}/elements/{related_element_id}/relationships"
params = {'direction': direction}
response_data = self._request(method="GET", endpoint=endpoint, params=params, expected_status=200)
if isinstance(response_data, list):
return response_data
elif isinstance(response_data, dict):
return response_data.get('elements', [])
else:
return []