logion-client 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.
- logion/__init__.py +32 -0
- logion/_client.py +61 -0
- logion/_config.py +56 -0
- logion/_errors.py +74 -0
- logion/_http.py +187 -0
- logion/_types/__init__.py +2 -0
- logion/_version.py +19 -0
- logion/_versioning.py +22 -0
- logion/py.typed +0 -0
- logion/v1/__init__.py +36 -0
- logion/v1/_generated/__init__.py +2 -0
- logion/v1/_generated/operations.py +1085 -0
- logion/v1/_operation_map.py +90 -0
- logion/v1/_resources/__init__.py +2 -0
- logion/v1/_resources/admin/__init__.py +24 -0
- logion/v1/_resources/admin/courses.py +51 -0
- logion/v1/_resources/admin/payments.py +2 -0
- logion/v1/_resources/admin/reports.py +74 -0
- logion/v1/_resources/admin/shared.py +12 -0
- logion/v1/_resources/admin/users_agents.py +78 -0
- logion/v1/_resources/bounties/__init__.py +19 -0
- logion/v1/_resources/bounties/core.py +97 -0
- logion/v1/_resources/bounties/shared.py +14 -0
- logion/v1/_resources/bounties/submissions.py +108 -0
- logion/v1/_resources/course_reviews.py +141 -0
- logion/v1/_resources/courses/__init__.py +24 -0
- logion/v1/_resources/courses/core.py +181 -0
- logion/v1/_resources/courses/publication.py +40 -0
- logion/v1/_resources/courses/reviews.py +99 -0
- logion/v1/_resources/courses/shared.py +34 -0
- logion/v1/_resources/credits.py +40 -0
- logion/v1/_resources/health.py +24 -0
- logion/v1/_resources/identity.py +113 -0
- logion/v1/_resources/listings.py +77 -0
- logion/v1/_resources/notifications.py +53 -0
- logion/v1/_resources/payments.py +80 -0
- logion/v1/_resources/referrals.py +38 -0
- logion/v1/_resources/reports.py +72 -0
- logion/v1/_types/__init__.py +6 -0
- logion/v1/_types/generated/__init__.py +7 -0
- logion/v1/_types/generated/v1.py +2026 -0
- logion_client-0.1.0.dist-info/METADATA +194 -0
- logion_client-0.1.0.dist-info/RECORD +45 -0
- logion_client-0.1.0.dist-info/WHEEL +4 -0
- logion_client-0.1.0.dist-info/licenses/LICENSE +21 -0
logion/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Logion Python client SDK."""
|
|
3
|
+
|
|
4
|
+
from logion._client import LogionClient
|
|
5
|
+
from logion._errors import (
|
|
6
|
+
APIError,
|
|
7
|
+
AuthenticationError,
|
|
8
|
+
ClientError,
|
|
9
|
+
ConflictError,
|
|
10
|
+
ForbiddenError,
|
|
11
|
+
LogionError,
|
|
12
|
+
NotFoundError,
|
|
13
|
+
RateLimitError,
|
|
14
|
+
ServerError,
|
|
15
|
+
TransportError,
|
|
16
|
+
ValidationError,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"APIError",
|
|
21
|
+
"AuthenticationError",
|
|
22
|
+
"ClientError",
|
|
23
|
+
"ConflictError",
|
|
24
|
+
"ForbiddenError",
|
|
25
|
+
"LogionClient",
|
|
26
|
+
"LogionError",
|
|
27
|
+
"NotFoundError",
|
|
28
|
+
"RateLimitError",
|
|
29
|
+
"ServerError",
|
|
30
|
+
"TransportError",
|
|
31
|
+
"ValidationError",
|
|
32
|
+
]
|
logion/_client.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Logion client — entry point for the SDK."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from logion._config import resolve_config
|
|
7
|
+
from logion._http import HttpClient
|
|
8
|
+
from logion._versioning import VersionedNamespaces
|
|
9
|
+
from logion.v1 import V1Namespace
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LogionClient:
|
|
13
|
+
"""Python client for the Logion API.
|
|
14
|
+
|
|
15
|
+
Configuration can be provided via constructor arguments or
|
|
16
|
+
environment variables (``LOGION_API_KEY``, ``LOGION_BASE_URL``).
|
|
17
|
+
Omitted arguments fall back to the corresponding environment
|
|
18
|
+
variable, then to built-in defaults.
|
|
19
|
+
|
|
20
|
+
Usage::
|
|
21
|
+
|
|
22
|
+
from logion import LogionClient
|
|
23
|
+
|
|
24
|
+
client = LogionClient(api_key="lgk_...")
|
|
25
|
+
client.v1.health.check()
|
|
26
|
+
client.v1.listings.search(query="rag")
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
api_key: str | None = None,
|
|
33
|
+
base_url: str | None = None,
|
|
34
|
+
timeout: float | None = None,
|
|
35
|
+
max_retries: int | None = None,
|
|
36
|
+
extra_headers: dict[str, str] | None = None,
|
|
37
|
+
) -> None:
|
|
38
|
+
config = resolve_config(
|
|
39
|
+
api_key=api_key,
|
|
40
|
+
base_url=base_url,
|
|
41
|
+
timeout=timeout,
|
|
42
|
+
max_retries=max_retries,
|
|
43
|
+
extra_headers=extra_headers,
|
|
44
|
+
)
|
|
45
|
+
self._http = HttpClient(config)
|
|
46
|
+
self._namespaces = VersionedNamespaces(self._http)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def v1(self) -> V1Namespace:
|
|
50
|
+
"""Access the v1 API namespace."""
|
|
51
|
+
return self._namespaces.v1
|
|
52
|
+
|
|
53
|
+
def close(self) -> None:
|
|
54
|
+
"""Close the underlying HTTP connection."""
|
|
55
|
+
self._http.close()
|
|
56
|
+
|
|
57
|
+
def __enter__(self) -> LogionClient:
|
|
58
|
+
return self
|
|
59
|
+
|
|
60
|
+
def __exit__(self, *args: object) -> None:
|
|
61
|
+
self.close()
|
logion/_config.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Client configuration."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
|
|
9
|
+
DEFAULT_BASE_URL = "https://api.logion.sh"
|
|
10
|
+
DEFAULT_TIMEOUT = 30.0
|
|
11
|
+
DEFAULT_MAX_RETRIES = 3
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def resolve_env_or(key: str, default: str) -> str:
|
|
15
|
+
"""Return *os.environ[key]* if set, otherwise *default*."""
|
|
16
|
+
return os.environ.get(key, default)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ClientConfig:
|
|
21
|
+
"""Resolved configuration for the Logion HTTP client."""
|
|
22
|
+
|
|
23
|
+
base_url: str = DEFAULT_BASE_URL
|
|
24
|
+
api_key: str = ""
|
|
25
|
+
timeout: float = DEFAULT_TIMEOUT
|
|
26
|
+
max_retries: int = DEFAULT_MAX_RETRIES
|
|
27
|
+
extra_headers: dict[str, str] = field(default_factory=dict)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def resolve_config(
|
|
31
|
+
*,
|
|
32
|
+
api_key: str | None = None,
|
|
33
|
+
base_url: str | None = None,
|
|
34
|
+
timeout: float | None = None,
|
|
35
|
+
max_retries: int | None = None,
|
|
36
|
+
extra_headers: dict[str, str] | None = None,
|
|
37
|
+
) -> ClientConfig:
|
|
38
|
+
"""Resolve SDK configuration from explicit values, env vars, or
|
|
39
|
+
defaults — in that priority order."""
|
|
40
|
+
return ClientConfig(
|
|
41
|
+
base_url=(
|
|
42
|
+
base_url
|
|
43
|
+
if base_url is not None
|
|
44
|
+
else resolve_env_or("LOGION_BASE_URL", DEFAULT_BASE_URL)
|
|
45
|
+
),
|
|
46
|
+
api_key=(
|
|
47
|
+
api_key
|
|
48
|
+
if api_key is not None
|
|
49
|
+
else resolve_env_or("LOGION_API_KEY", "")
|
|
50
|
+
),
|
|
51
|
+
timeout=timeout if timeout is not None else DEFAULT_TIMEOUT,
|
|
52
|
+
max_retries=(
|
|
53
|
+
max_retries if max_retries is not None else DEFAULT_MAX_RETRIES
|
|
54
|
+
),
|
|
55
|
+
extra_headers=extra_headers if extra_headers is not None else {},
|
|
56
|
+
)
|
logion/_errors.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Error hierarchy for the Logion SDK."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class LogionError(Exception):
|
|
8
|
+
"""Base exception for all SDK errors."""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class APIError(LogionError):
|
|
12
|
+
"""Error returned by the Logion API."""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
status_code: int,
|
|
17
|
+
detail: str | list[dict[str, object]],
|
|
18
|
+
request_id: str | None = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
self.status_code = status_code
|
|
21
|
+
self.detail = detail
|
|
22
|
+
self.request_id = request_id
|
|
23
|
+
msg = f"{status_code}"
|
|
24
|
+
if request_id:
|
|
25
|
+
msg += f" (request_id={request_id})"
|
|
26
|
+
msg += f": {detail}"
|
|
27
|
+
super().__init__(msg)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ClientError(APIError):
|
|
31
|
+
"""4xx response that isn't mapped to a specific error class."""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AuthenticationError(APIError):
|
|
35
|
+
"""401 — Invalid or missing API key."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ForbiddenError(APIError):
|
|
39
|
+
"""403 — Insufficient permissions."""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class NotFoundError(APIError):
|
|
43
|
+
"""404 — Resource not found."""
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ConflictError(APIError):
|
|
47
|
+
"""409 — Resource already exists."""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ValidationError(APIError):
|
|
51
|
+
"""422 — Request body or parameters invalid."""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class RateLimitError(APIError):
|
|
55
|
+
"""429 — Too many requests."""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ServerError(APIError):
|
|
59
|
+
"""5xx — Server-side error."""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TransportError(LogionError):
|
|
63
|
+
"""Network-level failure (DNS, connection, timeout, etc.).
|
|
64
|
+
|
|
65
|
+
Wraps an ``httpx.TransportError`` after retries are exhausted.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
message: str,
|
|
71
|
+
original: Exception | None = None,
|
|
72
|
+
) -> None:
|
|
73
|
+
self.original = original
|
|
74
|
+
super().__init__(message)
|
logion/_http.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""HTTP transport wrapper with retry and auth."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import time
|
|
7
|
+
import uuid
|
|
8
|
+
from typing import Any, TypeVar, cast
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
from logion._config import ClientConfig
|
|
14
|
+
from logion._errors import (
|
|
15
|
+
APIError,
|
|
16
|
+
AuthenticationError,
|
|
17
|
+
ClientError,
|
|
18
|
+
ConflictError,
|
|
19
|
+
ForbiddenError,
|
|
20
|
+
NotFoundError,
|
|
21
|
+
RateLimitError,
|
|
22
|
+
ServerError,
|
|
23
|
+
TransportError,
|
|
24
|
+
ValidationError,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
_RETRYABLE_STATUS_CODES = {429, 502, 503, 504}
|
|
28
|
+
_RETRYABLE_METHODS = {"GET", "HEAD", "OPTIONS"}
|
|
29
|
+
_STATUS_ERROR_MAP: dict[int, type[APIError]] = {
|
|
30
|
+
401: AuthenticationError,
|
|
31
|
+
403: ForbiddenError,
|
|
32
|
+
404: NotFoundError,
|
|
33
|
+
409: ConflictError,
|
|
34
|
+
422: ValidationError,
|
|
35
|
+
429: RateLimitError,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
T = TypeVar("T", bound=BaseModel)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _raise_for_status(response: httpx.Response) -> None:
|
|
42
|
+
"""Raise a typed SDK error for non-2xx responses."""
|
|
43
|
+
if response.is_success:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
status_code = response.status_code
|
|
47
|
+
request_id: str | None = response.headers.get("x-request-id")
|
|
48
|
+
detail: str | list[dict[str, object]] = response.text
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
body = response.json()
|
|
52
|
+
detail = body.get("detail", detail)
|
|
53
|
+
except Exception: # nosec B110 — intentional: non-JSON responses are fine as plain text
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
error_cls = _STATUS_ERROR_MAP.get(status_code)
|
|
57
|
+
if error_cls is None:
|
|
58
|
+
error_cls = ServerError if status_code >= 500 else ClientError
|
|
59
|
+
|
|
60
|
+
raise error_cls(
|
|
61
|
+
status_code=status_code,
|
|
62
|
+
detail=detail,
|
|
63
|
+
request_id=request_id,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class HttpClient:
|
|
68
|
+
"""Wraps httpx.Client with retry, auth, and error mapping."""
|
|
69
|
+
|
|
70
|
+
def __init__(self, config: ClientConfig) -> None:
|
|
71
|
+
self._config = config
|
|
72
|
+
self._client = httpx.Client(
|
|
73
|
+
base_url=config.base_url,
|
|
74
|
+
timeout=config.timeout,
|
|
75
|
+
headers=self._build_headers(config),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def _build_headers(config: ClientConfig) -> dict[str, str]:
|
|
80
|
+
headers: dict[str, str] = {
|
|
81
|
+
"Accept": "application/json",
|
|
82
|
+
**config.extra_headers,
|
|
83
|
+
}
|
|
84
|
+
if config.api_key:
|
|
85
|
+
headers["Authorization"] = f"Bearer {config.api_key}"
|
|
86
|
+
return headers
|
|
87
|
+
|
|
88
|
+
def request(
|
|
89
|
+
self,
|
|
90
|
+
method: str,
|
|
91
|
+
path: str,
|
|
92
|
+
*,
|
|
93
|
+
params: dict[str, Any] | None = None,
|
|
94
|
+
json: dict[str, Any] | None = None,
|
|
95
|
+
) -> dict[str, Any]:
|
|
96
|
+
"""Send a request and return raw JSON dict."""
|
|
97
|
+
if self._config.max_retries < 0:
|
|
98
|
+
msg = f"max_retries must be >= 0, got {self._config.max_retries}"
|
|
99
|
+
raise ValueError(msg)
|
|
100
|
+
can_retry = method.upper() in _RETRYABLE_METHODS
|
|
101
|
+
last_exc: httpx.TransportError | None = None
|
|
102
|
+
max_attempts = self._config.max_retries + 1 if can_retry else 1
|
|
103
|
+
|
|
104
|
+
for attempt in range(max_attempts):
|
|
105
|
+
request_id = str(uuid.uuid4())
|
|
106
|
+
headers = {"X-Request-ID": request_id}
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
response = self._client.request(
|
|
110
|
+
method,
|
|
111
|
+
path,
|
|
112
|
+
params=params,
|
|
113
|
+
json=json,
|
|
114
|
+
headers=headers,
|
|
115
|
+
)
|
|
116
|
+
except httpx.TransportError as exc:
|
|
117
|
+
last_exc = exc
|
|
118
|
+
if can_retry and attempt < max_attempts - 1:
|
|
119
|
+
backoff = 0.5 * (2**attempt)
|
|
120
|
+
time.sleep(backoff)
|
|
121
|
+
continue
|
|
122
|
+
raise TransportError(
|
|
123
|
+
f"Request failed after {attempt + 1} attempt(s): {exc}",
|
|
124
|
+
original=exc,
|
|
125
|
+
) from exc
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
response.status_code in _RETRYABLE_STATUS_CODES
|
|
129
|
+
and can_retry
|
|
130
|
+
and attempt < max_attempts - 1
|
|
131
|
+
):
|
|
132
|
+
backoff = 0.5 * (2**attempt)
|
|
133
|
+
time.sleep(backoff)
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
_raise_for_status(response)
|
|
137
|
+
return response.json()
|
|
138
|
+
|
|
139
|
+
assert last_exc is not None # for type checker
|
|
140
|
+
raise TransportError(
|
|
141
|
+
f"Request failed after {max_attempts} attempts",
|
|
142
|
+
original=last_exc,
|
|
143
|
+
) from last_exc
|
|
144
|
+
|
|
145
|
+
def request_model(
|
|
146
|
+
self,
|
|
147
|
+
method: str,
|
|
148
|
+
path: str,
|
|
149
|
+
model_type: type[T],
|
|
150
|
+
*,
|
|
151
|
+
params: dict[str, Any] | None = None,
|
|
152
|
+
json: dict[str, Any] | None = None,
|
|
153
|
+
) -> T:
|
|
154
|
+
"""Send a request and parse the response into a Pydantic model."""
|
|
155
|
+
data = self.request(
|
|
156
|
+
method,
|
|
157
|
+
path,
|
|
158
|
+
params=params,
|
|
159
|
+
json=json,
|
|
160
|
+
)
|
|
161
|
+
return cast(T, model_type.model_validate(data))
|
|
162
|
+
|
|
163
|
+
def request_list(
|
|
164
|
+
self,
|
|
165
|
+
method: str,
|
|
166
|
+
path: str,
|
|
167
|
+
*,
|
|
168
|
+
params: dict[str, Any] | None = None,
|
|
169
|
+
json: dict[str, Any] | None = None,
|
|
170
|
+
) -> list[dict[str, Any]]:
|
|
171
|
+
"""Send a request and return raw JSON as a list of dicts.
|
|
172
|
+
|
|
173
|
+
Use this for endpoints whose OpenAPI contract defines an array
|
|
174
|
+
response (``[...]``) rather than a JSON object.
|
|
175
|
+
"""
|
|
176
|
+
data = self.request(method, path, params=params, json=json)
|
|
177
|
+
if not isinstance(data, list):
|
|
178
|
+
msg = (
|
|
179
|
+
f"Expected a JSON array from "
|
|
180
|
+
f"{method} {path}, got {type(data).__name__}"
|
|
181
|
+
)
|
|
182
|
+
raise TypeError(msg)
|
|
183
|
+
return data
|
|
184
|
+
|
|
185
|
+
def close(self) -> None:
|
|
186
|
+
"""Close the underlying httpx client."""
|
|
187
|
+
self._client.close()
|
logion/_version.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Runtime-accessible package version."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from importlib.metadata import PackageNotFoundError
|
|
7
|
+
from importlib.metadata import version as _pkg_version
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
__version__: str = _pkg_version("logion-client")
|
|
11
|
+
except PackageNotFoundError: # local checkout / sdist
|
|
12
|
+
import tomllib
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
_pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
16
|
+
with _pyproject.open("rb") as _f:
|
|
17
|
+
__version__ = tomllib.load(_f)["project"]["version"]
|
|
18
|
+
|
|
19
|
+
__all__ = ["__version__"]
|
logion/_versioning.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Versioned namespace factory."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from logion._http import HttpClient
|
|
7
|
+
from logion.v1 import V1Namespace
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class VersionedNamespaces:
|
|
11
|
+
"""Lazy namespace accessors for each API version."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, http: HttpClient) -> None:
|
|
14
|
+
self._http = http
|
|
15
|
+
self._v1: V1Namespace | None = None
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def v1(self) -> V1Namespace:
|
|
19
|
+
"""Access the v1 API namespace."""
|
|
20
|
+
if self._v1 is None:
|
|
21
|
+
self._v1 = V1Namespace(self._http)
|
|
22
|
+
return self._v1
|
logion/py.typed
ADDED
|
File without changes
|
logion/v1/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""V1 API namespace."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from logion._http import HttpClient
|
|
7
|
+
from logion.v1._resources.admin import AdminResource
|
|
8
|
+
from logion.v1._resources.bounties import BountiesResource
|
|
9
|
+
from logion.v1._resources.course_reviews import CourseReviewsResource
|
|
10
|
+
from logion.v1._resources.courses import CoursesResource
|
|
11
|
+
from logion.v1._resources.credits import CreditsResource
|
|
12
|
+
from logion.v1._resources.health import HealthResource
|
|
13
|
+
from logion.v1._resources.identity import IdentityResource
|
|
14
|
+
from logion.v1._resources.listings import ListingsResource
|
|
15
|
+
from logion.v1._resources.notifications import NotificationsResource
|
|
16
|
+
from logion.v1._resources.payments import PaymentsResource
|
|
17
|
+
from logion.v1._resources.referrals import ReferralsResource
|
|
18
|
+
from logion.v1._resources.reports import ReportsResource
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class V1Namespace:
|
|
22
|
+
"""Namespace for v1 API endpoints."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, http: HttpClient) -> None:
|
|
25
|
+
self.health = HealthResource(http)
|
|
26
|
+
self.identity = IdentityResource(http)
|
|
27
|
+
self.listings = ListingsResource(http)
|
|
28
|
+
self.courses = CoursesResource(http)
|
|
29
|
+
self.credits = CreditsResource(http)
|
|
30
|
+
self.payments = PaymentsResource(http)
|
|
31
|
+
self.course_reviews = CourseReviewsResource(http)
|
|
32
|
+
self.notifications = NotificationsResource(http)
|
|
33
|
+
self.reports = ReportsResource(http)
|
|
34
|
+
self.admin = AdminResource(http)
|
|
35
|
+
self.bounties = BountiesResource(http)
|
|
36
|
+
self.referrals = ReferralsResource(http)
|