autonomize-core 0.1.4__py3-none-any.whl → 0.1.5__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.
- autonomize/core/__init__.py +14 -0
- autonomize/core/base_client.py +471 -0
- autonomize/core/credential.py +11 -4
- autonomize/exceptions/core/credentials.py +28 -0
- autonomize/types/__init__.py +0 -0
- autonomize/types/core/__init__.py +0 -0
- autonomize/types/core/base_client.py +8 -0
- {autonomize_core-0.1.4.dist-info → autonomize_core-0.1.5.dist-info}/METADATA +2 -2
- autonomize_core-0.1.5.dist-info/RECORD +17 -0
- autonomize_core-0.1.4.dist-info/RECORD +0 -13
- {autonomize_core-0.1.4.dist-info → autonomize_core-0.1.5.dist-info}/LICENSE +0 -0
- {autonomize_core-0.1.4.dist-info → autonomize_core-0.1.5.dist-info}/WHEEL +0 -0
autonomize/core/__init__.py
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
"""
|
2
|
+
This module provides the core functionality for the ModelHub SDK.
|
3
|
+
|
4
|
+
Classes:
|
5
|
+
- BaseClient: The base client class for interacting with the ModelHub API.
|
6
|
+
- ModelHubException: Custom exception class for ModelHub-related errors.
|
7
|
+
|
8
|
+
Functions:
|
9
|
+
- handle_response: Helper function for handling API responses.
|
10
|
+
"""
|
11
|
+
|
12
|
+
from .base_client import BaseClient, ahandle_response, handle_response
|
13
|
+
|
14
|
+
__all__ = ["BaseClient", "handle_response", "ahandle_response"]
|
@@ -0,0 +1,471 @@
|
|
1
|
+
"""
|
2
|
+
This module contains the BaseClient class for handling common HTTP operations
|
3
|
+
and token management using a simplified, credential-focused approach.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import os
|
7
|
+
from typing import Any, Dict, Optional
|
8
|
+
|
9
|
+
import httpx
|
10
|
+
|
11
|
+
from autonomize.core.credential import ModelhubCredential
|
12
|
+
from autonomize.exceptions.core.credentials import (
|
13
|
+
ModelHubAPIException,
|
14
|
+
ModelHubBadRequestException,
|
15
|
+
ModelHubConflictException,
|
16
|
+
ModelhubMissingCredentialsException,
|
17
|
+
ModelHubResourceNotFoundException,
|
18
|
+
ModelhubUnauthorizedException,
|
19
|
+
)
|
20
|
+
from autonomize.types.core.base_client import VerifySSLTypes
|
21
|
+
from autonomize.utils.logger import setup_logger
|
22
|
+
|
23
|
+
logger = setup_logger(__name__)
|
24
|
+
|
25
|
+
|
26
|
+
class BaseClient:
|
27
|
+
"""Base client for handling common HTTP operations with ModelhubCredential integration."""
|
28
|
+
|
29
|
+
def __init__(
|
30
|
+
self,
|
31
|
+
credential: ModelhubCredential,
|
32
|
+
client_id: Optional[str] = None,
|
33
|
+
copilot_id: Optional[str] = None,
|
34
|
+
timeout: int = 10,
|
35
|
+
verify_ssl: VerifySSLTypes = True,
|
36
|
+
):
|
37
|
+
"""
|
38
|
+
Initialize a new instance of the BaseClient class.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
credential (ModelhubCredential): Credential object for token management and base URL.
|
42
|
+
client_id (Optional[str]): Client ID for API URL construction.
|
43
|
+
Defaults to CLIENT_ID env var if not provided.
|
44
|
+
copilot_id (Optional[str]): Copilot ID for API URL construction.
|
45
|
+
Defaults to COPILOT_ID env var if not provided.
|
46
|
+
timeout (int, optional): Request timeout in seconds. Defaults to 10.
|
47
|
+
verify_ssl (VerifySSLTypes): Whether to verify SSL certificates. Defaults to True.
|
48
|
+
|
49
|
+
Raises:
|
50
|
+
ModelhubMissingCredentialsException: If required credential information is missing.
|
51
|
+
"""
|
52
|
+
# Store the credential
|
53
|
+
self.credential = credential
|
54
|
+
|
55
|
+
# Get client and copilot IDs from args or environment
|
56
|
+
self.client_id = client_id or os.getenv("CLIENT_ID")
|
57
|
+
self.copilot_id = copilot_id or os.getenv("COPILOT_ID")
|
58
|
+
|
59
|
+
# Other configuration
|
60
|
+
self.timeout = timeout
|
61
|
+
self.verify_ssl = verify_ssl
|
62
|
+
|
63
|
+
# Create HTTP clients with retry configured
|
64
|
+
self.client = self._setup_client()
|
65
|
+
self.async_client = self._setup_async_client()
|
66
|
+
|
67
|
+
# Validate we can construct API URL
|
68
|
+
try:
|
69
|
+
api_url = self.api_url
|
70
|
+
logger.debug("Initializing client with API URL: %s", api_url)
|
71
|
+
except Exception as e:
|
72
|
+
logger.error("Failed to construct API URL: %s", str(e))
|
73
|
+
raise ModelhubMissingCredentialsException(
|
74
|
+
"Unable to construct API URL. Ensure ModelhubCredential has a valid modelhub_url."
|
75
|
+
) from e
|
76
|
+
|
77
|
+
@property
|
78
|
+
def api_url(self) -> str:
|
79
|
+
"""
|
80
|
+
Get the complete API URL by combining the base URL with client and copilot IDs.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
str: The complete API URL.
|
84
|
+
|
85
|
+
Raises:
|
86
|
+
ModelhubMissingCredentialsException: If required IDs are missing.
|
87
|
+
"""
|
88
|
+
# Get the base URL from the credential
|
89
|
+
base_url = getattr(self.credential, "_modelhub_url", None)
|
90
|
+
if not base_url:
|
91
|
+
raise ModelhubMissingCredentialsException(
|
92
|
+
"ModelhubCredential must have a valid modelhub_url."
|
93
|
+
)
|
94
|
+
|
95
|
+
# Check if we have client and copilot IDs
|
96
|
+
if not self.client_id or not self.copilot_id:
|
97
|
+
raise ModelhubMissingCredentialsException(
|
98
|
+
"Client ID and Copilot ID are required for API URL construction."
|
99
|
+
)
|
100
|
+
|
101
|
+
# Construct the full API URL
|
102
|
+
return (
|
103
|
+
f"{base_url}/modelhub/api/v1/client/{self.client_id}/"
|
104
|
+
f"copilot/{self.copilot_id}"
|
105
|
+
)
|
106
|
+
|
107
|
+
def _setup_client(self) -> httpx.Client:
|
108
|
+
"""
|
109
|
+
Set up a synchronous HTTPX client with retry configuration.
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
httpx.Client: Configured client object.
|
113
|
+
"""
|
114
|
+
transport = httpx.HTTPTransport(
|
115
|
+
retries=3, # Total number of retries
|
116
|
+
)
|
117
|
+
|
118
|
+
return httpx.Client(
|
119
|
+
transport=transport,
|
120
|
+
timeout=self.timeout,
|
121
|
+
follow_redirects=True,
|
122
|
+
verify=self.verify_ssl,
|
123
|
+
)
|
124
|
+
|
125
|
+
def _setup_async_client(self) -> httpx.AsyncClient:
|
126
|
+
"""
|
127
|
+
Set up an asynchronous HTTPX client with retry configuration.
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
httpx.AsyncClient: Configured async client object.
|
131
|
+
"""
|
132
|
+
transport = httpx.AsyncHTTPTransport(
|
133
|
+
retries=3, # Total number of retries
|
134
|
+
)
|
135
|
+
|
136
|
+
return httpx.AsyncClient(
|
137
|
+
transport=transport,
|
138
|
+
timeout=self.timeout,
|
139
|
+
follow_redirects=True,
|
140
|
+
verify=self.verify_ssl,
|
141
|
+
)
|
142
|
+
|
143
|
+
def _get_auth_headers(self) -> Dict[str, str]:
|
144
|
+
"""
|
145
|
+
Get authentication headers using the credential.
|
146
|
+
|
147
|
+
Returns:
|
148
|
+
Dict[str, str]: Headers dictionary with authorization token.
|
149
|
+
"""
|
150
|
+
token = self.credential.get_token()
|
151
|
+
return {"Content-Type": "application/json", "Authorization": f"Bearer {token}"}
|
152
|
+
|
153
|
+
async def _aget_auth_headers(self) -> Dict[str, str]:
|
154
|
+
"""
|
155
|
+
Asynchronously get authentication headers using the credential.
|
156
|
+
|
157
|
+
Returns:
|
158
|
+
Dict[str, str]: Headers dictionary with authorization token.
|
159
|
+
"""
|
160
|
+
token = await self.credential.aget_token()
|
161
|
+
return {"Content-Type": "application/json", "Authorization": f"Bearer {token}"}
|
162
|
+
|
163
|
+
def _handle_error_status(self, response: httpx.Response) -> None:
|
164
|
+
"""
|
165
|
+
Handle common HTTP error status codes.
|
166
|
+
|
167
|
+
Args:
|
168
|
+
response (httpx.Response): The HTTP response.
|
169
|
+
|
170
|
+
Raises:
|
171
|
+
ModelHubResourceNotFoundException: For 404 errors.
|
172
|
+
ModelHubBadRequestException: For 400 errors.
|
173
|
+
ModelhubUnauthorizedException: For 401/403 errors.
|
174
|
+
ModelHubConflictException: For 409 errors.
|
175
|
+
ModelHubAPIException: For other HTTP errors.
|
176
|
+
"""
|
177
|
+
if response.status_code == 404:
|
178
|
+
raise ModelHubResourceNotFoundException(
|
179
|
+
f"Resource not found: {response.url}"
|
180
|
+
)
|
181
|
+
if response.status_code == 400:
|
182
|
+
raise ModelHubBadRequestException(f"Bad request: {response.text}")
|
183
|
+
if response.status_code in (401, 403):
|
184
|
+
raise ModelhubUnauthorizedException(f"Unauthorized: {response.text}")
|
185
|
+
if response.status_code == 409:
|
186
|
+
raise ModelHubConflictException(f"Conflict: {response.text}")
|
187
|
+
if response.status_code >= 400:
|
188
|
+
raise ModelHubAPIException(
|
189
|
+
f"API error {response.status_code}: {response.text}"
|
190
|
+
)
|
191
|
+
|
192
|
+
def request(
|
193
|
+
self,
|
194
|
+
method: str,
|
195
|
+
endpoint: str,
|
196
|
+
retry_auth: bool = True,
|
197
|
+
headers: Optional[Dict[str, str]] = None,
|
198
|
+
**kwargs: Any,
|
199
|
+
) -> Dict[str, Any]:
|
200
|
+
"""
|
201
|
+
Send a request with automatic token handling and optional retry.
|
202
|
+
|
203
|
+
Args:
|
204
|
+
method (str): The HTTP method for the request.
|
205
|
+
endpoint (str): The endpoint to send the request to.
|
206
|
+
retry_auth (bool, optional): Whether to retry on auth failure. Defaults to True.
|
207
|
+
headers (Optional[Dict[str, str]], optional): Additional headers. Defaults to None.
|
208
|
+
**kwargs: Additional keyword arguments for the request.
|
209
|
+
|
210
|
+
Returns:
|
211
|
+
Dict[str, Any]: The response data.
|
212
|
+
|
213
|
+
Raises:
|
214
|
+
ModelHubResourceNotFoundException: If the resource is not found.
|
215
|
+
ModelHubBadRequestException: If the request is invalid.
|
216
|
+
ModelhubUnauthorizedException: If unauthorized.
|
217
|
+
ModelHubAPIException: For other API errors.
|
218
|
+
"""
|
219
|
+
url = f"{self.api_url}/{endpoint.lstrip('/')}"
|
220
|
+
logger.debug("Making %s request to: %s", method, url)
|
221
|
+
|
222
|
+
# Prepare headers with auth token
|
223
|
+
request_headers = headers or {}
|
224
|
+
auth_headers = self._get_auth_headers()
|
225
|
+
|
226
|
+
# If files are being uploaded, don't include Content-Type in auth_headers
|
227
|
+
if "files" in kwargs:
|
228
|
+
auth_headers = {"Authorization": auth_headers["Authorization"]}
|
229
|
+
|
230
|
+
merged_headers = {**auth_headers, **request_headers}
|
231
|
+
|
232
|
+
try:
|
233
|
+
# Make the initial request
|
234
|
+
response = self.client.request(
|
235
|
+
method, url, headers=merged_headers, **kwargs
|
236
|
+
)
|
237
|
+
|
238
|
+
# If we get a 401, retry with a fresh token
|
239
|
+
if response.status_code == 401 and retry_auth:
|
240
|
+
logger.debug("Received 401, refreshing token and retrying")
|
241
|
+
# Force credential to get a new token
|
242
|
+
self.credential.reset_token() # Use the proper method instead of direct access
|
243
|
+
auth_headers = self._get_auth_headers()
|
244
|
+
merged_headers = {**auth_headers, **request_headers}
|
245
|
+
|
246
|
+
# Retry the request with the new token
|
247
|
+
response = self.client.request(
|
248
|
+
method, url, headers=merged_headers, **kwargs
|
249
|
+
)
|
250
|
+
|
251
|
+
# If still unauthorized, handle the error
|
252
|
+
if response.status_code == 401:
|
253
|
+
self._handle_error_status(response)
|
254
|
+
|
255
|
+
# Handle any error status codes
|
256
|
+
if response.status_code >= 400:
|
257
|
+
self._handle_error_status(response)
|
258
|
+
|
259
|
+
# Parse and return the response
|
260
|
+
return handle_response(response)
|
261
|
+
|
262
|
+
except httpx.HTTPError as e:
|
263
|
+
logger.error("Request failed: %s", str(e))
|
264
|
+
if isinstance(e, httpx.HTTPStatusError):
|
265
|
+
self._handle_error_status(e.response)
|
266
|
+
raise ModelHubAPIException(f"Request failed: {str(e)}") from e
|
267
|
+
|
268
|
+
async def arequest(
|
269
|
+
self,
|
270
|
+
method: str,
|
271
|
+
endpoint: str,
|
272
|
+
retry_auth: bool = True,
|
273
|
+
headers: Optional[Dict[str, str]] = None,
|
274
|
+
**kwargs: Any,
|
275
|
+
) -> Dict[str, Any]:
|
276
|
+
"""
|
277
|
+
Send an asynchronous request with automatic token handling and optional retry.
|
278
|
+
|
279
|
+
Args:
|
280
|
+
method (str): The HTTP method for the request.
|
281
|
+
endpoint (str): The endpoint to send the request to.
|
282
|
+
retry_auth (bool, optional): Whether to retry on auth failure. Defaults to True.
|
283
|
+
headers (Optional[Dict[str, str]], optional): Additional headers. Defaults to None.
|
284
|
+
**kwargs: Additional keyword arguments for the request.
|
285
|
+
|
286
|
+
Returns:
|
287
|
+
Dict[str, Any]: The response data.
|
288
|
+
|
289
|
+
Raises:
|
290
|
+
ModelHubResourceNotFoundException: If the resource is not found.
|
291
|
+
ModelHubBadRequestException: If the request is invalid.
|
292
|
+
ModelhubUnauthorizedException: If unauthorized.
|
293
|
+
ModelHubAPIException: For other API errors.
|
294
|
+
"""
|
295
|
+
url = f"{self.api_url}/{endpoint.lstrip('/')}"
|
296
|
+
logger.debug("Making async %s request to: %s", method, url)
|
297
|
+
|
298
|
+
# Prepare headers with auth token
|
299
|
+
request_headers = headers or {}
|
300
|
+
auth_headers = await self._aget_auth_headers()
|
301
|
+
merged_headers = {**auth_headers, **request_headers}
|
302
|
+
|
303
|
+
try:
|
304
|
+
# Make the initial request
|
305
|
+
response = await self.async_client.request(
|
306
|
+
method, url, headers=merged_headers, **kwargs
|
307
|
+
)
|
308
|
+
|
309
|
+
# If we get a 401, retry with a fresh token
|
310
|
+
if response.status_code == 401 and retry_auth:
|
311
|
+
logger.debug("Received 401, refreshing token and retrying (async)")
|
312
|
+
# Force credential to get a new token
|
313
|
+
self.credential.reset_token() # Use the proper method instead of direct access
|
314
|
+
auth_headers = await self._aget_auth_headers()
|
315
|
+
merged_headers = {**auth_headers, **request_headers}
|
316
|
+
|
317
|
+
# Retry the request with the new token
|
318
|
+
response = await self.async_client.request(
|
319
|
+
method, url, headers=merged_headers, **kwargs
|
320
|
+
)
|
321
|
+
|
322
|
+
# If still unauthorized, handle the error
|
323
|
+
if response.status_code == 401:
|
324
|
+
self._handle_error_status(response)
|
325
|
+
|
326
|
+
# Handle any error status codes
|
327
|
+
if response.status_code >= 400:
|
328
|
+
self._handle_error_status(response)
|
329
|
+
|
330
|
+
# Parse and return the response
|
331
|
+
return await ahandle_response(response)
|
332
|
+
|
333
|
+
except httpx.HTTPError as e:
|
334
|
+
logger.error("Async request failed: %s", str(e))
|
335
|
+
if isinstance(e, httpx.HTTPStatusError):
|
336
|
+
self._handle_error_status(e.response)
|
337
|
+
raise ModelHubAPIException(f"Request failed: {str(e)}") from e
|
338
|
+
|
339
|
+
# Convenience methods for common HTTP operations
|
340
|
+
|
341
|
+
def get(
|
342
|
+
self, endpoint: str, params: Optional[Dict[str, Any]] = None, **kwargs: Any
|
343
|
+
) -> Dict[str, Any]:
|
344
|
+
"""Send a GET request to the specified endpoint."""
|
345
|
+
return self.request("GET", endpoint, params=params, **kwargs)
|
346
|
+
|
347
|
+
def post(
|
348
|
+
self,
|
349
|
+
endpoint: str,
|
350
|
+
json: Optional[Dict[str, Any]] = None,
|
351
|
+
data: Optional[Any] = None,
|
352
|
+
files: Optional[Dict[str, Any]] = None,
|
353
|
+
**kwargs: Any,
|
354
|
+
) -> Dict[str, Any]:
|
355
|
+
"""Send a POST request to the specified endpoint."""
|
356
|
+
return self.request(
|
357
|
+
"POST", endpoint, json=json, data=data, files=files, **kwargs
|
358
|
+
)
|
359
|
+
|
360
|
+
def put(
|
361
|
+
self, endpoint: str, json: Optional[Dict[str, Any]] = None, **kwargs: Any
|
362
|
+
) -> Dict[str, Any]:
|
363
|
+
"""Send a PUT request to the specified endpoint."""
|
364
|
+
return self.request("PUT", endpoint, json=json, **kwargs)
|
365
|
+
|
366
|
+
def patch(
|
367
|
+
self, endpoint: str, json: Optional[Dict[str, Any]] = None, **kwargs: Any
|
368
|
+
) -> Dict[str, Any]:
|
369
|
+
"""Send a PATCH request to the specified endpoint."""
|
370
|
+
return self.request("PATCH", endpoint, json=json, **kwargs)
|
371
|
+
|
372
|
+
def delete(self, endpoint: str, **kwargs: Any) -> Dict[str, Any]:
|
373
|
+
"""Send a DELETE request to the specified endpoint."""
|
374
|
+
return self.request("DELETE", endpoint, **kwargs)
|
375
|
+
|
376
|
+
# Asynchronous convenience methods
|
377
|
+
|
378
|
+
async def aget(
|
379
|
+
self, endpoint: str, params: Optional[Dict[str, Any]] = None, **kwargs: Any
|
380
|
+
) -> Dict[str, Any]:
|
381
|
+
"""Send an asynchronous GET request to the specified endpoint."""
|
382
|
+
return await self.arequest("GET", endpoint, params=params, **kwargs)
|
383
|
+
|
384
|
+
async def apost(
|
385
|
+
self,
|
386
|
+
endpoint: str,
|
387
|
+
json: Optional[Dict[str, Any]] = None,
|
388
|
+
data: Optional[Any] = None,
|
389
|
+
files: Optional[Dict[str, Any]] = None,
|
390
|
+
**kwargs: Any,
|
391
|
+
) -> Dict[str, Any]:
|
392
|
+
"""Send an asynchronous POST request to the specified endpoint."""
|
393
|
+
return await self.arequest(
|
394
|
+
"POST", endpoint, json=json, data=data, files=files, **kwargs
|
395
|
+
)
|
396
|
+
|
397
|
+
async def aput(
|
398
|
+
self, endpoint: str, json: Optional[Dict[str, Any]] = None, **kwargs: Any
|
399
|
+
) -> Dict[str, Any]:
|
400
|
+
"""Send an asynchronous PUT request to the specified endpoint."""
|
401
|
+
return await self.arequest("PUT", endpoint, json=json, **kwargs)
|
402
|
+
|
403
|
+
async def apatch(
|
404
|
+
self, endpoint: str, json: Optional[Dict[str, Any]] = None, **kwargs: Any
|
405
|
+
) -> Dict[str, Any]:
|
406
|
+
"""Send an asynchronous PATCH request to the specified endpoint."""
|
407
|
+
return await self.arequest("PATCH", endpoint, json=json, **kwargs)
|
408
|
+
|
409
|
+
async def adelete(self, endpoint: str, **kwargs: Any) -> Dict[str, Any]:
|
410
|
+
"""Send an asynchronous DELETE request to the specified endpoint."""
|
411
|
+
return await self.arequest("DELETE", endpoint, **kwargs)
|
412
|
+
|
413
|
+
def close(self) -> None:
|
414
|
+
"""Close the HTTPX clients when done."""
|
415
|
+
self.client.close()
|
416
|
+
|
417
|
+
async def aclose(self) -> None:
|
418
|
+
"""Asynchronously close the HTTPX async client when done."""
|
419
|
+
await self.async_client.aclose()
|
420
|
+
|
421
|
+
|
422
|
+
def handle_response(response: httpx.Response) -> Dict[str, Any]:
|
423
|
+
"""
|
424
|
+
Synchronously handle the response from an HTTP request.
|
425
|
+
|
426
|
+
Args:
|
427
|
+
response (httpx.Response): The response object from the HTTP request.
|
428
|
+
|
429
|
+
Returns:
|
430
|
+
dict: The JSON response from the HTTP request.
|
431
|
+
|
432
|
+
Raises:
|
433
|
+
httpx.HTTPError: If the HTTP response status code is an error.
|
434
|
+
ValueError: If the response is not a valid JSON.
|
435
|
+
"""
|
436
|
+
try:
|
437
|
+
response.raise_for_status()
|
438
|
+
return response.json()
|
439
|
+
except httpx.HTTPError as e:
|
440
|
+
logger.error("HTTP error: %s", str(e))
|
441
|
+
raise
|
442
|
+
except ValueError as e:
|
443
|
+
logger.error("Invalid JSON response: %s", str(e))
|
444
|
+
raise
|
445
|
+
|
446
|
+
|
447
|
+
async def ahandle_response(response: httpx.Response) -> Dict[str, Any]:
|
448
|
+
"""
|
449
|
+
Asynchronously handles the response from an HTTP request.
|
450
|
+
|
451
|
+
Args:
|
452
|
+
response (httpx.Response): The response object from the HTTP request.
|
453
|
+
|
454
|
+
Returns:
|
455
|
+
dict: The JSON response from the HTTP request.
|
456
|
+
|
457
|
+
Raises:
|
458
|
+
httpx.HTTPError: If the HTTP response status code is an error.
|
459
|
+
ValueError: If the response is not a valid JSON.
|
460
|
+
"""
|
461
|
+
try:
|
462
|
+
response.raise_for_status()
|
463
|
+
# Use sync version for simplicity - httpx.Response.json()
|
464
|
+
# is not a coroutine in current versions
|
465
|
+
return response.json()
|
466
|
+
except httpx.HTTPError as e:
|
467
|
+
logger.error("HTTP error: %s", str(e))
|
468
|
+
raise
|
469
|
+
except ValueError as e:
|
470
|
+
logger.error("Invalid JSON response: %s", str(e))
|
471
|
+
raise
|
autonomize/core/credential.py
CHANGED
@@ -16,6 +16,7 @@ from autonomize.exceptions.core import (
|
|
16
16
|
ModelhubTokenRetrievalException,
|
17
17
|
ModelhubUnauthorizedException,
|
18
18
|
)
|
19
|
+
from autonomize.types.core.base_client import VerifySSLTypes
|
19
20
|
from autonomize.utils.logger import setup_logger
|
20
21
|
|
21
22
|
logger = setup_logger(__name__)
|
@@ -30,7 +31,7 @@ class ModelhubCredential:
|
|
30
31
|
Example:
|
31
32
|
.. code-block:: python
|
32
33
|
|
33
|
-
from autonomize.core import ModelhubCredential
|
34
|
+
from autonomize.core.credential import ModelhubCredential
|
34
35
|
|
35
36
|
# Using modelhub_url (recommended)
|
36
37
|
modelhub_credential = ModelhubCredential(
|
@@ -52,6 +53,7 @@ class ModelhubCredential:
|
|
52
53
|
client_secret: Optional[str] = None,
|
53
54
|
token: Optional[str] = None,
|
54
55
|
auth_url: Optional[str] = None, # Kept for backward compatibility
|
56
|
+
verify_ssl: VerifySSLTypes = True,
|
55
57
|
):
|
56
58
|
"""
|
57
59
|
Initialize the ModelhubCredential instance.
|
@@ -62,6 +64,7 @@ class ModelhubCredential:
|
|
62
64
|
client_secret (Optional[str]): The client secret for authentication.
|
63
65
|
token (Optional[str]): An existing JWT token for authentication.
|
64
66
|
auth_url (Optional[str]): The direct authentication URL (legacy parameter).
|
67
|
+
verify_ssl (VerifySSLTypes): Either `True` to use an SSL context with the default CA bundle, False to disable verification, or an instance of `ssl.SSLContext` to use a custom context.
|
65
68
|
|
66
69
|
Raises:
|
67
70
|
ModelhubMissingCredentialsException: If neither (client_id and client_secret) nor token is provided.
|
@@ -91,6 +94,9 @@ class ModelhubCredential:
|
|
91
94
|
# Default URL as a fallback
|
92
95
|
self._auth_url = "https://auth.sprint.autonomize.dev/realms/autonomize/protocol/openid-connect/token"
|
93
96
|
|
97
|
+
# SSL Config
|
98
|
+
self.verify_ssl = verify_ssl
|
99
|
+
|
94
100
|
# Validate credentials
|
95
101
|
if self._client_id is None or self._client_secret is None:
|
96
102
|
if self._token is None:
|
@@ -164,8 +170,7 @@ class ModelhubCredential:
|
|
164
170
|
"client_id and client_secret must be provided to fetch JWT token."
|
165
171
|
)
|
166
172
|
|
167
|
-
|
168
|
-
with httpx.Client(verify=False, timeout=None) as client:
|
173
|
+
with httpx.Client(timeout=None, verify=self.verify_ssl) as client:
|
169
174
|
response = client.post(
|
170
175
|
self.auth_url,
|
171
176
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
@@ -219,7 +224,9 @@ class ModelhubCredential:
|
|
219
224
|
"client_id and client_secret must be provided to fetch JWT token."
|
220
225
|
)
|
221
226
|
|
222
|
-
async with httpx.AsyncClient(
|
227
|
+
async with httpx.AsyncClient(
|
228
|
+
timeout=None, verify=self.verify_ssl
|
229
|
+
) as client:
|
223
230
|
response = await client.post(
|
224
231
|
self.auth_url,
|
225
232
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""Exceptions for the modelhub module."""
|
2
2
|
|
3
3
|
|
4
|
+
# Original Exceptions
|
4
5
|
class ModelhubCredentialException(Exception):
|
5
6
|
"""Base exception for ModelhubCredential exceptions."""
|
6
7
|
|
@@ -19,3 +20,30 @@ class ModelhubTokenRetrievalException(ModelhubCredentialException):
|
|
19
20
|
|
20
21
|
class ModelhubUnauthorizedException(ModelhubCredentialException):
|
21
22
|
"""Raised when the modelhub credentials are invalid."""
|
23
|
+
|
24
|
+
|
25
|
+
# Base exception for ModelHub client
|
26
|
+
class ModelHubException(Exception):
|
27
|
+
"""Base exception for all ModelHub client exceptions."""
|
28
|
+
|
29
|
+
|
30
|
+
# API exceptions
|
31
|
+
class ModelHubAPIException(ModelHubException):
|
32
|
+
"""Base exception for API-related errors."""
|
33
|
+
|
34
|
+
|
35
|
+
class ModelHubResourceNotFoundException(ModelHubAPIException):
|
36
|
+
"""Raised when a requested resource is not found."""
|
37
|
+
|
38
|
+
|
39
|
+
class ModelHubBadRequestException(ModelHubAPIException):
|
40
|
+
"""Raised when the API request is malformed or invalid."""
|
41
|
+
|
42
|
+
|
43
|
+
class ModelHubConflictException(ModelHubAPIException):
|
44
|
+
"""Raised when there's a conflict with the current state of the resource."""
|
45
|
+
|
46
|
+
|
47
|
+
# Parsing exceptions
|
48
|
+
class ModelHubParsingException(ModelHubException):
|
49
|
+
"""Raised when response parsing fails."""
|
File without changes
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: autonomize-core
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.5
|
4
4
|
Summary: Autonomize Core contains the unified authentication source to access platform.
|
5
5
|
License: Proprietary
|
6
6
|
Author: Varun Prakash
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
19
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
20
20
|
Classifier: Topic :: Text Processing
|
21
21
|
Classifier: Typing :: Typed
|
22
|
-
Requires-Dist: httpx (>=0.
|
22
|
+
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
23
23
|
Project-URL: Documentation, https://github.com/autonomize-ai/autonomize-core
|
24
24
|
Project-URL: Homepage, https://github.com/autonomize-ai/autonomize-core
|
25
25
|
Project-URL: Repository, https://github.com/autonomize-ai/autonomize-core
|
@@ -0,0 +1,17 @@
|
|
1
|
+
autonomize/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
autonomize/core/__init__.py,sha256=Bc5MrXUgBLjByMP-iW1yCsFgQyNPgKxCvAKjogfdHgY,444
|
3
|
+
autonomize/core/base_client.py,sha256=q2DWt8EwDH9ftXgzIyaSVh5cDUMFGlC0Qg2YGMHggD0,17475
|
4
|
+
autonomize/core/credential.py,sha256=YICDNRfG_GTvjMaeQCDVAXHL34OUu8QpwT6PSXtGewQ,10210
|
5
|
+
autonomize/exceptions/__init__.py,sha256=LS0jVRjHWYuIeFuSi7SNg5dwHmH9U3kvFWByiYSV7Hw,401
|
6
|
+
autonomize/exceptions/core/__init__.py,sha256=5flhl7JoAxV-3ofkWxpW7Am0mrdZDB3RfmAKv5XhuXc,408
|
7
|
+
autonomize/exceptions/core/credentials.py,sha256=2kPp10ktbZFnZEaEL8jU2a-BECwkZzPpS8d56fx6g_0,1451
|
8
|
+
autonomize/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
autonomize/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
autonomize/types/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
autonomize/types/core/base_client.py,sha256=DcJPT9GJuvGoUoCu3xS63qZoCZaG97Iwc7pOmN0q_6w,223
|
12
|
+
autonomize/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
autonomize/utils/logger.py,sha256=oQLM9pmQkHBQRN9c4hCXDBOf2BqHB06JjizIaWbNFfw,2168
|
14
|
+
autonomize_core-0.1.5.dist-info/LICENSE,sha256=1BOgDsbiPB_RVAQMpdx88RIvXmu5u5X5bSd4aVhxUok,170
|
15
|
+
autonomize_core-0.1.5.dist-info/METADATA,sha256=np04CQ8-JpVGumjxi7ezk9mY0T-QHLLtHE_Olh_obi0,3641
|
16
|
+
autonomize_core-0.1.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
17
|
+
autonomize_core-0.1.5.dist-info/RECORD,,
|
@@ -1,13 +0,0 @@
|
|
1
|
-
autonomize/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
autonomize/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
autonomize/core/credential.py,sha256=YSPjyGdqKmDY4A6KEB-tI_0etxhdhjvQb0Uj3SU3tVU,9875
|
4
|
-
autonomize/exceptions/__init__.py,sha256=LS0jVRjHWYuIeFuSi7SNg5dwHmH9U3kvFWByiYSV7Hw,401
|
5
|
-
autonomize/exceptions/core/__init__.py,sha256=5flhl7JoAxV-3ofkWxpW7Am0mrdZDB3RfmAKv5XhuXc,408
|
6
|
-
autonomize/exceptions/core/credentials.py,sha256=GzBUKyEdNH4ORXMpy0y19WXkX1VRwWIBARhEg46NuRk,676
|
7
|
-
autonomize/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
autonomize/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
autonomize/utils/logger.py,sha256=oQLM9pmQkHBQRN9c4hCXDBOf2BqHB06JjizIaWbNFfw,2168
|
10
|
-
autonomize_core-0.1.4.dist-info/LICENSE,sha256=1BOgDsbiPB_RVAQMpdx88RIvXmu5u5X5bSd4aVhxUok,170
|
11
|
-
autonomize_core-0.1.4.dist-info/METADATA,sha256=DT5VTdkWlTgDVETjs71Wf60ypI3SJX9pjYgGwglxYuo,3641
|
12
|
-
autonomize_core-0.1.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
13
|
-
autonomize_core-0.1.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|