xenfra-sdk 0.1.0__py3-none-any.whl → 0.1.1__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.
- xenfra_sdk/client.py +19 -2
- xenfra_sdk/client_with_hooks.py +30 -7
- xenfra_sdk/config.py +2 -2
- xenfra_sdk/privacy.py +41 -8
- xenfra_sdk/resources/deployments.py +11 -9
- xenfra_sdk/resources/intelligence.py +7 -4
- xenfra_sdk/resources/projects.py +17 -8
- xenfra_sdk/utils.py +51 -0
- {xenfra_sdk-0.1.0.dist-info → xenfra_sdk-0.1.1.dist-info}/METADATA +1 -1
- {xenfra_sdk-0.1.0.dist-info → xenfra_sdk-0.1.1.dist-info}/RECORD +11 -11
- {xenfra_sdk-0.1.0.dist-info → xenfra_sdk-0.1.1.dist-info}/WHEEL +0 -0
xenfra_sdk/client.py
CHANGED
|
@@ -6,10 +6,15 @@ from .exceptions import AuthenticationError, XenfraAPIError, XenfraError
|
|
|
6
6
|
from .resources.deployments import DeploymentsManager
|
|
7
7
|
from .resources.intelligence import IntelligenceManager
|
|
8
8
|
from .resources.projects import ProjectsManager
|
|
9
|
+
from .utils import safe_json_parse
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class XenfraClient:
|
|
12
|
-
def __init__(self, token: str = None, api_url: str =
|
|
13
|
+
def __init__(self, token: str = None, api_url: str = None):
|
|
14
|
+
# Use provided URL, or fall back to env var, or default to production
|
|
15
|
+
if api_url is None:
|
|
16
|
+
api_url = os.getenv("XENFRA_API_URL", "https://api.xenfra.tech")
|
|
17
|
+
|
|
13
18
|
self.api_url = api_url
|
|
14
19
|
self._token = token or os.getenv("XENFRA_TOKEN")
|
|
15
20
|
if not self._token:
|
|
@@ -42,7 +47,19 @@ class XenfraClient:
|
|
|
42
47
|
return response
|
|
43
48
|
except httpx.HTTPStatusError as e:
|
|
44
49
|
# Convert httpx error to our custom SDK error
|
|
45
|
-
|
|
50
|
+
# Safe JSON parsing with fallback
|
|
51
|
+
try:
|
|
52
|
+
content_type = e.response.headers.get("content-type", "")
|
|
53
|
+
if "application/json" in content_type:
|
|
54
|
+
try:
|
|
55
|
+
error_data = e.response.json()
|
|
56
|
+
detail = error_data.get("detail", e.response.text[:500] if e.response.text else "Unknown error")
|
|
57
|
+
except (ValueError, TypeError):
|
|
58
|
+
detail = e.response.text[:500] if e.response.text else "Unknown error"
|
|
59
|
+
else:
|
|
60
|
+
detail = e.response.text[:500] if e.response.text else "Unknown error"
|
|
61
|
+
except Exception:
|
|
62
|
+
detail = "Unknown error"
|
|
46
63
|
raise XenfraAPIError(status_code=e.response.status_code, detail=detail) from e
|
|
47
64
|
except httpx.RequestError as e:
|
|
48
65
|
# Handle connection errors, timeouts, etc.
|
xenfra_sdk/client_with_hooks.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Enhanced XenfraClient with context management and lifecycle hooks.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import logging
|
|
5
6
|
import os
|
|
6
|
-
from typing import
|
|
7
|
+
from typing import Callable
|
|
7
8
|
|
|
8
9
|
import httpx
|
|
9
10
|
|
|
@@ -11,6 +12,7 @@ from .exceptions import AuthenticationError, XenfraAPIError, XenfraError
|
|
|
11
12
|
from .resources.deployments import DeploymentsManager
|
|
12
13
|
from .resources.intelligence import IntelligenceManager
|
|
13
14
|
from .resources.projects import ProjectsManager
|
|
15
|
+
from .utils import safe_json_parse
|
|
14
16
|
|
|
15
17
|
logger = logging.getLogger(__name__)
|
|
16
18
|
|
|
@@ -102,7 +104,7 @@ class XenfraClient:
|
|
|
102
104
|
headers={
|
|
103
105
|
"Authorization": f"Bearer {self._token}",
|
|
104
106
|
"Content-Type": "application/json",
|
|
105
|
-
"User-Agent": "Xenfra-SDK/0.2.
|
|
107
|
+
"User-Agent": "Xenfra-SDK/0.2.4",
|
|
106
108
|
},
|
|
107
109
|
timeout=timeout,
|
|
108
110
|
transport=transport,
|
|
@@ -178,7 +180,22 @@ class XenfraClient:
|
|
|
178
180
|
|
|
179
181
|
except httpx.HTTPStatusError as e:
|
|
180
182
|
# API error (4xx, 5xx)
|
|
181
|
-
|
|
183
|
+
# Safe JSON parsing with fallback
|
|
184
|
+
if e.response:
|
|
185
|
+
try:
|
|
186
|
+
content_type = e.response.headers.get("content-type", "")
|
|
187
|
+
if "application/json" in content_type:
|
|
188
|
+
try:
|
|
189
|
+
error_data = e.response.json()
|
|
190
|
+
detail = error_data.get("detail", e.response.text[:500] if e.response.text else "Unknown error")
|
|
191
|
+
except (ValueError, TypeError):
|
|
192
|
+
detail = e.response.text[:500] if e.response.text else "Unknown error"
|
|
193
|
+
else:
|
|
194
|
+
detail = e.response.text[:500] if e.response.text else "Unknown error"
|
|
195
|
+
except Exception:
|
|
196
|
+
detail = "Unknown error"
|
|
197
|
+
else:
|
|
198
|
+
detail = str(e)
|
|
182
199
|
|
|
183
200
|
# Run error hooks
|
|
184
201
|
error_context = {**request_context, "error": e, "response": e.response}
|
|
@@ -189,11 +206,12 @@ class XenfraClient:
|
|
|
189
206
|
logger.warning(f"on_error hook failed: {hook_error}")
|
|
190
207
|
|
|
191
208
|
# Log error
|
|
192
|
-
logger.error(
|
|
209
|
+
logger.error(
|
|
210
|
+
f"{method} {path} failed: {e.response.status_code if e.response else 'unknown'}"
|
|
211
|
+
)
|
|
193
212
|
|
|
194
213
|
raise XenfraAPIError(
|
|
195
|
-
status_code=e.response.status_code if e.response else 500,
|
|
196
|
-
detail=detail
|
|
214
|
+
status_code=e.response.status_code if e.response else 500, detail=detail
|
|
197
215
|
) from e
|
|
198
216
|
|
|
199
217
|
except httpx.RequestError as e:
|
|
@@ -227,7 +245,9 @@ class XenfraClient:
|
|
|
227
245
|
def __del__(self):
|
|
228
246
|
"""Destructor - cleanup if not already closed."""
|
|
229
247
|
if not self._closed:
|
|
230
|
-
logger.warning(
|
|
248
|
+
logger.warning(
|
|
249
|
+
"XenfraClient was not properly closed. Use 'with' statement or call close()."
|
|
250
|
+
)
|
|
231
251
|
self.close()
|
|
232
252
|
|
|
233
253
|
def __repr__(self):
|
|
@@ -238,6 +258,7 @@ class XenfraClient:
|
|
|
238
258
|
|
|
239
259
|
# Example hooks for common use cases
|
|
240
260
|
|
|
261
|
+
|
|
241
262
|
def logging_hook_before(request_context):
|
|
242
263
|
"""Example: Log all requests."""
|
|
243
264
|
print(f"→ {request_context['method']} {request_context['url']}")
|
|
@@ -264,12 +285,14 @@ def rate_limit_tracker_hook(request_context, response):
|
|
|
264
285
|
def request_timing_hook(request_context):
|
|
265
286
|
"""Example: Track request timing."""
|
|
266
287
|
import time
|
|
288
|
+
|
|
267
289
|
request_context["start_time"] = time.time()
|
|
268
290
|
|
|
269
291
|
|
|
270
292
|
def response_timing_hook(request_context, response):
|
|
271
293
|
"""Example: Calculate request duration."""
|
|
272
294
|
import time
|
|
295
|
+
|
|
273
296
|
if "start_time" in request_context:
|
|
274
297
|
duration = time.time() - request_context["start_time"]
|
|
275
298
|
print(f"Request took {duration:.3f}s")
|
xenfra_sdk/config.py
CHANGED
xenfra_sdk/privacy.py
CHANGED
|
@@ -5,12 +5,16 @@ before it is sent to diagnostic endpoints, upholding privacy-first principles.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
8
10
|
import re
|
|
9
11
|
from pathlib import Path
|
|
10
12
|
from typing import List, Optional
|
|
11
13
|
|
|
12
14
|
import httpx # For fetching patterns from URL
|
|
13
15
|
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
14
18
|
# Path to the patterns file within the SDK
|
|
15
19
|
_PATTERNS_FILE_PATH = Path(__file__).parent / "patterns.json"
|
|
16
20
|
_REDACTION_PLACEHOLDER = "[REDACTED]"
|
|
@@ -20,8 +24,8 @@ _CACHED_PATTERNS: List[re.Pattern] = []
|
|
|
20
24
|
def _load_patterns_from_file(file_path: Path) -> List[str]:
|
|
21
25
|
"""Loads raw regex patterns from a JSON file."""
|
|
22
26
|
if not file_path.exists():
|
|
23
|
-
|
|
24
|
-
f"
|
|
27
|
+
logger.warning(
|
|
28
|
+
f"Patterns file not found at {file_path}. No patterns will be used for scrubbing."
|
|
25
29
|
)
|
|
26
30
|
return []
|
|
27
31
|
try:
|
|
@@ -29,7 +33,7 @@ def _load_patterns_from_file(file_path: Path) -> List[str]:
|
|
|
29
33
|
config = json.load(f)
|
|
30
34
|
return config.get("redaction_patterns", [])
|
|
31
35
|
except json.JSONDecodeError as e:
|
|
32
|
-
|
|
36
|
+
logger.error(f"Error decoding patterns.json: {e}. Falling back to empty patterns.")
|
|
33
37
|
return []
|
|
34
38
|
|
|
35
39
|
|
|
@@ -38,16 +42,45 @@ async def _refresh_patterns_from_url(url: str) -> Optional[List[str]]:
|
|
|
38
42
|
Fetches updated patterns from a URL asynchronously.
|
|
39
43
|
"""
|
|
40
44
|
try:
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
# Configure timeout from environment or default to 30 seconds
|
|
46
|
+
timeout_seconds = float(os.getenv("XENFRA_SDK_TIMEOUT", "30.0"))
|
|
47
|
+
timeout = httpx.Timeout(timeout_seconds, connect=10.0)
|
|
48
|
+
|
|
49
|
+
async with httpx.AsyncClient(timeout=timeout) as client:
|
|
50
|
+
response = await client.get(url)
|
|
43
51
|
response.raise_for_status()
|
|
44
|
-
|
|
52
|
+
|
|
53
|
+
# Safe JSON parsing with content-type check
|
|
54
|
+
content_type = response.headers.get("content-type", "")
|
|
55
|
+
if "application/json" not in content_type:
|
|
56
|
+
logger.warning(
|
|
57
|
+
f"Expected JSON response from {url}, got {content_type}. "
|
|
58
|
+
"Skipping pattern refresh."
|
|
59
|
+
)
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
config = response.json()
|
|
64
|
+
except (ValueError, TypeError) as e:
|
|
65
|
+
logger.error(f"Failed to parse JSON from patterns URL {url}: {e}")
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
if not isinstance(config, dict):
|
|
69
|
+
logger.error(f"Expected dictionary from patterns URL {url}, got {type(config).__name__}")
|
|
70
|
+
return None
|
|
71
|
+
|
|
45
72
|
return config.get("redaction_patterns", [])
|
|
73
|
+
except httpx.TimeoutException as e:
|
|
74
|
+
logger.warning(f"Timeout fetching patterns from {url}: {e}")
|
|
75
|
+
return None
|
|
46
76
|
except httpx.RequestError as e:
|
|
47
|
-
|
|
77
|
+
logger.warning(f"Error fetching patterns from {url}: {e}")
|
|
48
78
|
return None
|
|
49
79
|
except json.JSONDecodeError as e:
|
|
50
|
-
|
|
80
|
+
logger.error(f"Error decoding JSON from patterns URL {url}: {e}")
|
|
81
|
+
return None
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logger.error(f"Unexpected error fetching patterns from {url}: {e}")
|
|
51
84
|
return None
|
|
52
85
|
|
|
53
86
|
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
# Import Deployment model when it's defined in models.py
|
|
4
4
|
# from ..models import Deployment
|
|
5
5
|
from ..exceptions import XenfraAPIError, XenfraError # Add XenfraError
|
|
6
|
+
from ..utils import safe_get_json_field, safe_json_parse
|
|
6
7
|
from .base import BaseManager
|
|
7
8
|
|
|
8
9
|
logger = logging.getLogger(__name__)
|
|
@@ -19,9 +20,8 @@ class DeploymentsManager(BaseManager):
|
|
|
19
20
|
"framework": framework,
|
|
20
21
|
}
|
|
21
22
|
response = self._client._request("POST", "/deployments", json=payload)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return response.json()
|
|
23
|
+
# Safe JSON parsing
|
|
24
|
+
return safe_json_parse(response)
|
|
25
25
|
except XenfraAPIError:
|
|
26
26
|
raise
|
|
27
27
|
except Exception as e:
|
|
@@ -43,8 +43,8 @@ class DeploymentsManager(BaseManager):
|
|
|
43
43
|
try:
|
|
44
44
|
response = self._client._request("GET", f"/deployments/{deployment_id}/status")
|
|
45
45
|
logger.debug(f"DeploymentsManager.get_status({deployment_id}) response: {response.status_code}")
|
|
46
|
-
|
|
47
|
-
return response
|
|
46
|
+
# Safe JSON parsing - _request() already handles status codes
|
|
47
|
+
return safe_json_parse(response)
|
|
48
48
|
except XenfraAPIError:
|
|
49
49
|
raise # Re-raise API errors
|
|
50
50
|
except Exception as e:
|
|
@@ -66,11 +66,13 @@ class DeploymentsManager(BaseManager):
|
|
|
66
66
|
try:
|
|
67
67
|
response = self._client._request("GET", f"/deployments/{deployment_id}/logs")
|
|
68
68
|
logger.debug(f"DeploymentsManager.get_logs({deployment_id}) response: {response.status_code}")
|
|
69
|
-
response.raise_for_status()
|
|
70
69
|
|
|
71
|
-
#
|
|
72
|
-
data = response
|
|
73
|
-
|
|
70
|
+
# Safe JSON parsing with structure validation - _request() already handles status codes
|
|
71
|
+
data = safe_json_parse(response)
|
|
72
|
+
if not isinstance(data, dict):
|
|
73
|
+
raise XenfraError(f"Expected dictionary response, got {type(data).__name__}")
|
|
74
|
+
|
|
75
|
+
logs = safe_get_json_field(data, "logs", "")
|
|
74
76
|
|
|
75
77
|
if not logs:
|
|
76
78
|
logger.warning(f"No logs found for deployment {deployment_id}")
|
|
@@ -6,6 +6,7 @@ import logging
|
|
|
6
6
|
|
|
7
7
|
from ..exceptions import XenfraAPIError, XenfraError
|
|
8
8
|
from ..models import CodebaseAnalysisResponse, DiagnosisResponse
|
|
9
|
+
from ..utils import safe_json_parse
|
|
9
10
|
from .base import BaseManager
|
|
10
11
|
|
|
11
12
|
logger = logging.getLogger(__name__)
|
|
@@ -61,8 +62,9 @@ class IntelligenceManager(BaseManager):
|
|
|
61
62
|
f"IntelligenceManager.diagnose response: status={response.status_code}"
|
|
62
63
|
)
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
# Safe JSON parsing
|
|
66
|
+
data = safe_json_parse(response)
|
|
67
|
+
return DiagnosisResponse(**data)
|
|
66
68
|
except XenfraAPIError:
|
|
67
69
|
raise
|
|
68
70
|
except Exception as e:
|
|
@@ -94,8 +96,9 @@ class IntelligenceManager(BaseManager):
|
|
|
94
96
|
f"IntelligenceManager.analyze_codebase response: status={response.status_code}"
|
|
95
97
|
)
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
# Safe JSON parsing
|
|
100
|
+
data = safe_json_parse(response)
|
|
101
|
+
return CodebaseAnalysisResponse(**data)
|
|
99
102
|
except XenfraAPIError:
|
|
100
103
|
raise
|
|
101
104
|
except Exception as e:
|
xenfra_sdk/resources/projects.py
CHANGED
|
@@ -2,6 +2,7 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
from ..exceptions import XenfraAPIError, XenfraError # Add XenfraError
|
|
4
4
|
from ..models import ProjectRead
|
|
5
|
+
from ..utils import safe_get_json_field, safe_json_parse
|
|
5
6
|
from .base import BaseManager
|
|
6
7
|
|
|
7
8
|
logger = logging.getLogger(__name__)
|
|
@@ -18,8 +19,14 @@ class ProjectsManager(BaseManager):
|
|
|
18
19
|
f"body={response.text[:200]}..." # Truncate long responses
|
|
19
20
|
)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
# Safe JSON parsing with structure validation
|
|
23
|
+
data = safe_json_parse(response)
|
|
24
|
+
projects = safe_get_json_field(data, "projects", [])
|
|
25
|
+
|
|
26
|
+
if not isinstance(projects, list):
|
|
27
|
+
raise XenfraError(f"Expected 'projects' to be a list, got {type(projects).__name__}")
|
|
28
|
+
|
|
29
|
+
return [ProjectRead(**p) for p in projects]
|
|
23
30
|
except XenfraAPIError:
|
|
24
31
|
raise # Re-raise API errors
|
|
25
32
|
except Exception as e:
|
|
@@ -42,8 +49,9 @@ class ProjectsManager(BaseManager):
|
|
|
42
49
|
try:
|
|
43
50
|
response = self._client._request("GET", f"/projects/{project_id}")
|
|
44
51
|
logger.debug(f"ProjectsManager.show({project_id}) response: {response.status_code}")
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
# Safe JSON parsing
|
|
53
|
+
data = safe_json_parse(response)
|
|
54
|
+
return ProjectRead(**data)
|
|
47
55
|
except XenfraAPIError:
|
|
48
56
|
raise # Re-raise API errors
|
|
49
57
|
except Exception as e:
|
|
@@ -77,8 +85,9 @@ class ProjectsManager(BaseManager):
|
|
|
77
85
|
}
|
|
78
86
|
logger.debug(f"ProjectsManager.create payload: {payload}")
|
|
79
87
|
response = self._client._request("POST", "/projects/", json=payload)
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
# Safe JSON parsing
|
|
89
|
+
data = safe_json_parse(response)
|
|
90
|
+
return ProjectRead(**data)
|
|
82
91
|
except XenfraAPIError:
|
|
83
92
|
raise
|
|
84
93
|
except Exception as e:
|
|
@@ -87,8 +96,8 @@ class ProjectsManager(BaseManager):
|
|
|
87
96
|
def delete(self, project_id: str) -> None:
|
|
88
97
|
"""Deletes a project."""
|
|
89
98
|
try:
|
|
90
|
-
|
|
91
|
-
|
|
99
|
+
# _request() already handles status codes and raises XenfraAPIError for non-2xx
|
|
100
|
+
self._client._request("DELETE", f"/projects/{project_id}")
|
|
92
101
|
except XenfraAPIError:
|
|
93
102
|
raise
|
|
94
103
|
except Exception as e:
|
xenfra_sdk/utils.py
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import tomllib # Python 3.11+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from .exceptions import XenfraError
|
|
3
8
|
|
|
4
9
|
|
|
5
10
|
def get_project_context():
|
|
@@ -68,3 +73,49 @@ def get_project_context():
|
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
return context
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def safe_json_parse(response: httpx.Response) -> Dict[str, Any]:
|
|
79
|
+
"""
|
|
80
|
+
Safely parse JSON from HTTP response with content-type validation and error handling.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
response: HTTP response object
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Parsed JSON dictionary
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
XenfraError: If response is not JSON or parsing fails
|
|
90
|
+
"""
|
|
91
|
+
content_type = response.headers.get("content-type", "")
|
|
92
|
+
if "application/json" not in content_type:
|
|
93
|
+
# Try to get error text for better error messages
|
|
94
|
+
error_text = response.text[:500] if response.text else "Unknown error"
|
|
95
|
+
raise XenfraError(
|
|
96
|
+
f"Expected JSON response, got {content_type}. Response: {error_text}"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
return response.json()
|
|
101
|
+
except (ValueError, TypeError) as e:
|
|
102
|
+
error_text = response.text[:500] if response.text else "Unknown error"
|
|
103
|
+
raise XenfraError(f"Failed to parse JSON response: {e}. Response: {error_text}")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def safe_get_json_field(data: Dict[str, Any], field: str, default: Any = None) -> Any:
|
|
107
|
+
"""
|
|
108
|
+
Safely get a field from JSON data with validation.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
data: JSON dictionary
|
|
112
|
+
field: Field name to retrieve
|
|
113
|
+
default: Default value if field is missing
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Field value or default
|
|
117
|
+
"""
|
|
118
|
+
if not isinstance(data, dict):
|
|
119
|
+
raise XenfraError(f"Expected dictionary, got {type(data).__name__}")
|
|
120
|
+
|
|
121
|
+
return data.get(field, default)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
xenfra_sdk/__init__.py,sha256=lk9xo2msYvs_JgBePTIuxRb2sBW-egJS_EAOq4w4xQo,467
|
|
2
2
|
xenfra_sdk/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
xenfra_sdk/cli/main.py,sha256=541nlIUYFFeu4h1sCXivaHMC7SqpskazI0YocM8ylh4,7958
|
|
4
|
-
xenfra_sdk/client.py,sha256=
|
|
5
|
-
xenfra_sdk/client_with_hooks.py,sha256=
|
|
6
|
-
xenfra_sdk/config.py,sha256=
|
|
4
|
+
xenfra_sdk/client.py,sha256=pnmdmmTtECyV7MmT2_DViXeaQP0q1W1eOhcqOTdmi80,3495
|
|
5
|
+
xenfra_sdk/client_with_hooks.py,sha256=5mKIF3rbN1hlZKCCNOlMyFBbuwugBeCU9_8ZcQ_8uOs,9986
|
|
6
|
+
xenfra_sdk/config.py,sha256=gaT4k5iJgW9guNVmlnYkCFGDSU1_er4LRZA2CgfKmJ0,588
|
|
7
7
|
xenfra_sdk/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
xenfra_sdk/db/models.py,sha256=H29uHzXizkim5KnEAdmfMO8mytkCDCQl2NPzTgMMD7w,874
|
|
9
9
|
xenfra_sdk/db/session.py,sha256=LoTKFO3FTsx5AtZ-0ZsplxXjAdzOgcr3Yk-dkeJsz5U,823
|
|
@@ -14,18 +14,18 @@ xenfra_sdk/exceptions.py,sha256=aMVtDVlzG7-FT2G_b-pJSuuey22B4YvC-b-L37GaImM,477
|
|
|
14
14
|
xenfra_sdk/mcp_client.py,sha256=NZtQz_qK_8i504rVPXlE1vPdzt75hg8Lkp4d8BA8dk0,5777
|
|
15
15
|
xenfra_sdk/models.py,sha256=73rZMHP2iPRcX9PC8KUgkmNEVgDozD4Tj09UneQhYJU,6923
|
|
16
16
|
xenfra_sdk/patterns.json,sha256=xHxbc0ogHDwysMczi30_hW1Ylfdsf-nsQdAom7RZ4KI,446
|
|
17
|
-
xenfra_sdk/privacy.py,sha256
|
|
17
|
+
xenfra_sdk/privacy.py,sha256=XXNLCrPZzqbYj8qrcootygE2WiDYyMVdMO7h0ow7vBQ,5527
|
|
18
18
|
xenfra_sdk/recipes.py,sha256=J6-7tDWVXv8IelkdBta5pDRhD0o5VgAM_jWDKvPvm5g,852
|
|
19
19
|
xenfra_sdk/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
20
|
xenfra_sdk/resources/base.py,sha256=5n-HTKAnIX2lTgXwio0xtwoaBn-nksjdm8qRTpe3iDk,81
|
|
21
|
-
xenfra_sdk/resources/deployments.py,sha256=
|
|
22
|
-
xenfra_sdk/resources/intelligence.py,sha256=
|
|
23
|
-
xenfra_sdk/resources/projects.py,sha256=
|
|
21
|
+
xenfra_sdk/resources/deployments.py,sha256=ybIV4ViNhnjWRkPaynp0wQjEKBjKby0GkAPd3_ohu-w,3291
|
|
22
|
+
xenfra_sdk/resources/intelligence.py,sha256=W1J2tr4W3xKB1v8Wya0edXB07Vr3zO0JZ7mIDk_dU1w,3470
|
|
23
|
+
xenfra_sdk/resources/projects.py,sha256=ZMox7siqSXWuXHsUBYkUb10Qik7wNvgPBZWN3C4gQnA,3760
|
|
24
24
|
xenfra_sdk/security.py,sha256=6vMZpbglhkRGBVVj4RCTu45-MCnQ15wt94-996zmaT8,1199
|
|
25
25
|
xenfra_sdk/templates/Dockerfile.j2,sha256=apWts895OOoUYwj_fOa6OiylFB5m8zFEYvJ1Nki32YM,664
|
|
26
26
|
xenfra_sdk/templates/cloud-init.sh.j2,sha256=QCWG8hL1V05bAQ7BQ70QfuhIvS4tnsL8ZTCVtyi9F0A,2222
|
|
27
27
|
xenfra_sdk/templates/docker-compose.yml.j2,sha256=zKUT2cd_FrxXvRxE-vAAjuQk3-nLNQjRe-StkhAWRQA,860
|
|
28
|
-
xenfra_sdk/utils.py,sha256=
|
|
29
|
-
xenfra_sdk-0.1.
|
|
30
|
-
xenfra_sdk-0.1.
|
|
31
|
-
xenfra_sdk-0.1.
|
|
28
|
+
xenfra_sdk/utils.py,sha256=uLlDb-kNRlr6RJvU8vJ6vXfgUEZeWZDfN2UtlrQoxfs,3930
|
|
29
|
+
xenfra_sdk-0.1.1.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
|
|
30
|
+
xenfra_sdk-0.1.1.dist-info/METADATA,sha256=jg_JTeKLR_SzyMovzvjYub641lc3nSObkPy7-V9GEe0,3889
|
|
31
|
+
xenfra_sdk-0.1.1.dist-info/RECORD,,
|
|
File without changes
|