gentic-sdk 0.1.0__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.
gentic_sdk/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from gentic_sdk.client import GenticHub
2
+ from gentic_sdk.exceptions import GenticHubError
3
+
4
+ __all__ = ["GenticHub", "GenticHubError"]
gentic_sdk/client.py ADDED
@@ -0,0 +1,116 @@
1
+ import json
2
+ from collections.abc import Callable
3
+ from functools import lru_cache
4
+ from typing import Any, TypeVar
5
+ from urllib.parse import quote
6
+
7
+ import httpx
8
+ from pydantic import BaseModel, TypeAdapter
9
+
10
+ from gentic_sdk import models
11
+ from gentic_sdk.exceptions import GenticHubError
12
+ from gentic_sdk.resources.account import AccountApi
13
+ from gentic_sdk.resources.activity import ActivityApi
14
+ from gentic_sdk.resources.auth import AuthApi
15
+ from gentic_sdk.resources.categories import CategoriesApi
16
+ from gentic_sdk.resources.cli import CliApi
17
+ from gentic_sdk.resources.health import HealthApi
18
+ from gentic_sdk.resources.library import LibraryApi
19
+ from gentic_sdk.resources.oauth import OauthApi
20
+ from gentic_sdk.resources.notifications import NotificationsApi
21
+ from gentic_sdk.resources.profiles import ProfilesApi
22
+ from gentic_sdk.resources.projects import ProjectsApi
23
+ from gentic_sdk.resources.recommend import RecommendApi
24
+ from gentic_sdk.resources.skills import SkillsApi
25
+ from gentic_sdk.resources.subscriptions import SubscriptionsApi
26
+
27
+ Result = TypeVar("Result")
28
+ TokenSource = str | Callable[[], str | None]
29
+
30
+
31
+ @lru_cache
32
+ def adapter_for(result_type: Any) -> TypeAdapter[Any]:
33
+ return TypeAdapter(result_type)
34
+
35
+
36
+ class GenticHub:
37
+ def __init__(self, base_url: str, token: TokenSource | None = None, timeout: float = 30.0, http_client: httpx.Client | None = None) -> None:
38
+ self.token = token
39
+ self.http_client = http_client or httpx.Client(base_url=base_url.rstrip("/"), timeout=timeout)
40
+ self.health = HealthApi(self)
41
+ self.auth = AuthApi(self)
42
+ self.skills = SkillsApi(self)
43
+ self.categories = CategoriesApi(self)
44
+ self.cli = CliApi(self)
45
+ self.library = LibraryApi(self)
46
+ self.account = AccountApi(self)
47
+ self.activity = ActivityApi(self)
48
+ self.notifications = NotificationsApi(self)
49
+ self.profiles = ProfilesApi(self)
50
+ self.projects = ProjectsApi(self)
51
+ self.oauth = OauthApi(self)
52
+ self.subscriptions = SubscriptionsApi(self)
53
+ self.recommend = RecommendApi(self)
54
+
55
+ def __enter__(self) -> "GenticHub":
56
+ return self
57
+
58
+ def __exit__(self, *_exception: object) -> None:
59
+ self.close()
60
+
61
+ def close(self) -> None:
62
+ self.http_client.close()
63
+
64
+ def sign_in(self, email: str, password: str) -> models.TokenResponse:
65
+ token = self.auth.token(models.TokenRequest(email=email, password=password))
66
+ if not isinstance(token, models.TokenResponse):
67
+ raise GenticHubError(500, "unexpected_answer")
68
+ self.token = token.access_token
69
+ return token
70
+
71
+ def sign_out(self) -> None:
72
+ self.auth.sign_out()
73
+ self.token = None
74
+
75
+ def request(
76
+ self,
77
+ method: str,
78
+ path: str,
79
+ result_type: type[Result] | Any = None,
80
+ *,
81
+ path_parameters: dict[str, Any] | None = None,
82
+ query: dict[str, Any] | None = None,
83
+ body: BaseModel | dict[str, Any] | None = None,
84
+ ) -> Any:
85
+ headers = {"accept": "application/json"}
86
+ token = self.token() if callable(self.token) else self.token
87
+ if token:
88
+ headers["authorization"] = f"Bearer {token}"
89
+ filled_path = path.format(**{name: quote(str(value), safe="") for name, value in (path_parameters or {}).items()})
90
+ content = None
91
+ if body is not None:
92
+ headers["content-type"] = "application/json"
93
+ payload = body.model_dump(mode="json", exclude_unset=True) if isinstance(body, BaseModel) else body
94
+ content = json.dumps(payload)
95
+ response = self.http_client.request(
96
+ method,
97
+ filled_path,
98
+ params={name: value for name, value in (query or {}).items() if value is not None},
99
+ headers=headers,
100
+ content=content,
101
+ )
102
+ if response.is_error:
103
+ raise GenticHubError(response.status_code, self.error_detail(response))
104
+ if response.status_code == 204 or result_type is None:
105
+ return None
106
+ return adapter_for(result_type).validate_python(response.json())
107
+
108
+ @staticmethod
109
+ def error_detail(response: httpx.Response) -> str:
110
+ try:
111
+ detail = response.json().get("detail")
112
+ except (ValueError, AttributeError):
113
+ detail = None
114
+ if detail is None:
115
+ return response.reason_phrase
116
+ return detail if isinstance(detail, str) else json.dumps(detail)
@@ -0,0 +1,5 @@
1
+ class GenticHubError(Exception):
2
+ def __init__(self, status: int, detail: str) -> None:
3
+ super().__init__(detail)
4
+ self.status = status
5
+ self.detail = detail