sdkrouter 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.
- sdkrouter/__init__.py +110 -0
- sdkrouter/_api/__init__.py +28 -0
- sdkrouter/_api/client.py +204 -0
- sdkrouter/_api/generated/__init__.py +21 -0
- sdkrouter/_api/generated/cdn/__init__.py +209 -0
- sdkrouter/_api/generated/cdn/cdn__api__cdn/__init__.py +7 -0
- sdkrouter/_api/generated/cdn/cdn__api__cdn/client.py +133 -0
- sdkrouter/_api/generated/cdn/cdn__api__cdn/models.py +163 -0
- sdkrouter/_api/generated/cdn/cdn__api__cdn/sync_client.py +132 -0
- sdkrouter/_api/generated/cdn/client.py +75 -0
- sdkrouter/_api/generated/cdn/logger.py +256 -0
- sdkrouter/_api/generated/cdn/pyproject.toml +55 -0
- sdkrouter/_api/generated/cdn/retry.py +272 -0
- sdkrouter/_api/generated/cdn/sync_client.py +58 -0
- sdkrouter/_api/generated/cleaner/__init__.py +212 -0
- sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/__init__.py +7 -0
- sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/client.py +83 -0
- sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/models.py +117 -0
- sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/sync_client.py +82 -0
- sdkrouter/_api/generated/cleaner/client.py +75 -0
- sdkrouter/_api/generated/cleaner/enums.py +55 -0
- sdkrouter/_api/generated/cleaner/logger.py +256 -0
- sdkrouter/_api/generated/cleaner/pyproject.toml +55 -0
- sdkrouter/_api/generated/cleaner/retry.py +272 -0
- sdkrouter/_api/generated/cleaner/sync_client.py +58 -0
- sdkrouter/_api/generated/keys/__init__.py +212 -0
- sdkrouter/_api/generated/keys/client.py +75 -0
- sdkrouter/_api/generated/keys/enums.py +64 -0
- sdkrouter/_api/generated/keys/keys__api__keys/__init__.py +7 -0
- sdkrouter/_api/generated/keys/keys__api__keys/client.py +150 -0
- sdkrouter/_api/generated/keys/keys__api__keys/models.py +152 -0
- sdkrouter/_api/generated/keys/keys__api__keys/sync_client.py +149 -0
- sdkrouter/_api/generated/keys/logger.py +256 -0
- sdkrouter/_api/generated/keys/pyproject.toml +55 -0
- sdkrouter/_api/generated/keys/retry.py +272 -0
- sdkrouter/_api/generated/keys/sync_client.py +58 -0
- sdkrouter/_api/generated/models/__init__.py +209 -0
- sdkrouter/_api/generated/models/client.py +75 -0
- sdkrouter/_api/generated/models/logger.py +256 -0
- sdkrouter/_api/generated/models/models__api__llm_models/__init__.py +7 -0
- sdkrouter/_api/generated/models/models__api__llm_models/client.py +99 -0
- sdkrouter/_api/generated/models/models__api__llm_models/models.py +206 -0
- sdkrouter/_api/generated/models/models__api__llm_models/sync_client.py +99 -0
- sdkrouter/_api/generated/models/pyproject.toml +55 -0
- sdkrouter/_api/generated/models/retry.py +272 -0
- sdkrouter/_api/generated/models/sync_client.py +58 -0
- sdkrouter/_api/generated/shortlinks/__init__.py +209 -0
- sdkrouter/_api/generated/shortlinks/client.py +75 -0
- sdkrouter/_api/generated/shortlinks/logger.py +256 -0
- sdkrouter/_api/generated/shortlinks/pyproject.toml +55 -0
- sdkrouter/_api/generated/shortlinks/retry.py +272 -0
- sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/__init__.py +7 -0
- sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/client.py +137 -0
- sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/models.py +153 -0
- sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/sync_client.py +136 -0
- sdkrouter/_api/generated/shortlinks/sync_client.py +58 -0
- sdkrouter/_api/generated/vision/__init__.py +212 -0
- sdkrouter/_api/generated/vision/client.py +75 -0
- sdkrouter/_api/generated/vision/enums.py +40 -0
- sdkrouter/_api/generated/vision/logger.py +256 -0
- sdkrouter/_api/generated/vision/pyproject.toml +55 -0
- sdkrouter/_api/generated/vision/retry.py +272 -0
- sdkrouter/_api/generated/vision/sync_client.py +58 -0
- sdkrouter/_api/generated/vision/vision__api__vision/__init__.py +7 -0
- sdkrouter/_api/generated/vision/vision__api__vision/client.py +65 -0
- sdkrouter/_api/generated/vision/vision__api__vision/models.py +138 -0
- sdkrouter/_api/generated/vision/vision__api__vision/sync_client.py +65 -0
- sdkrouter/_client.py +432 -0
- sdkrouter/_config.py +74 -0
- sdkrouter/_constants.py +21 -0
- sdkrouter/_internal/__init__.py +1 -0
- sdkrouter/_types/__init__.py +30 -0
- sdkrouter/_types/cdn.py +27 -0
- sdkrouter/_types/models.py +26 -0
- sdkrouter/_types/ocr.py +24 -0
- sdkrouter/_types/parsed.py +101 -0
- sdkrouter/_types/shortlinks.py +27 -0
- sdkrouter/_types/vision.py +29 -0
- sdkrouter/_version.py +3 -0
- sdkrouter/helpers/__init__.py +13 -0
- sdkrouter/helpers/formatting.py +15 -0
- sdkrouter/helpers/html.py +100 -0
- sdkrouter/helpers/json_cleaner.py +53 -0
- sdkrouter/tools/__init__.py +129 -0
- sdkrouter/tools/cdn.py +285 -0
- sdkrouter/tools/cleaner.py +186 -0
- sdkrouter/tools/keys.py +215 -0
- sdkrouter/tools/models.py +196 -0
- sdkrouter/tools/shortlinks.py +165 -0
- sdkrouter/tools/vision.py +173 -0
- sdkrouter/utils/__init__.py +27 -0
- sdkrouter/utils/parsing.py +109 -0
- sdkrouter/utils/tokens.py +375 -0
- sdkrouter-0.1.1.dist-info/METADATA +411 -0
- sdkrouter-0.1.1.dist-info/RECORD +96 -0
- sdkrouter-0.1.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from .models import *
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ShortlinksShortlinksAPI:
|
|
9
|
+
"""API endpoints for Shortlinks."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, client: httpx.AsyncClient):
|
|
12
|
+
"""Initialize sub-client with shared httpx client."""
|
|
13
|
+
self._client = client
|
|
14
|
+
|
|
15
|
+
async def list(self, page: int | None = None, page_size: int | None = None) -> list[PaginatedShortLinkListList]:
|
|
16
|
+
"""
|
|
17
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
18
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
19
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
20
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
21
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
22
|
+
"""
|
|
23
|
+
url = "/api/shortlinks/"
|
|
24
|
+
response = await self._client.get(url, params={"page": page if page is not None else None, "page_size": page_size if page_size is not None else None})
|
|
25
|
+
if not response.is_success:
|
|
26
|
+
try:
|
|
27
|
+
error_body = response.json()
|
|
28
|
+
except Exception:
|
|
29
|
+
error_body = response.text
|
|
30
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
31
|
+
return PaginatedShortLinkListList.model_validate(response.json())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def create(self, data: ShortLinkCreateRequest) -> ShortLinkCreate:
|
|
35
|
+
"""
|
|
36
|
+
Create a new short link.
|
|
37
|
+
"""
|
|
38
|
+
url = "/api/shortlinks/"
|
|
39
|
+
response = await self._client.post(url, json=data.model_dump(exclude_unset=True))
|
|
40
|
+
if not response.is_success:
|
|
41
|
+
try:
|
|
42
|
+
error_body = response.json()
|
|
43
|
+
except Exception:
|
|
44
|
+
error_body = response.text
|
|
45
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
46
|
+
return ShortLinkCreate.model_validate(response.json())
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async def retrieve(self, code: str) -> ShortLinkDetail:
|
|
50
|
+
"""
|
|
51
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
52
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
53
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
54
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
55
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
56
|
+
"""
|
|
57
|
+
url = f"/api/shortlinks/{code}/"
|
|
58
|
+
response = await self._client.get(url)
|
|
59
|
+
if not response.is_success:
|
|
60
|
+
try:
|
|
61
|
+
error_body = response.json()
|
|
62
|
+
except Exception:
|
|
63
|
+
error_body = response.text
|
|
64
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
65
|
+
return ShortLinkDetail.model_validate(response.json())
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
async def update(self, code: str) -> ShortLinkList:
|
|
69
|
+
"""
|
|
70
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
71
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
72
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
73
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
74
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
75
|
+
"""
|
|
76
|
+
url = f"/api/shortlinks/{code}/"
|
|
77
|
+
response = await self._client.put(url)
|
|
78
|
+
if not response.is_success:
|
|
79
|
+
try:
|
|
80
|
+
error_body = response.json()
|
|
81
|
+
except Exception:
|
|
82
|
+
error_body = response.text
|
|
83
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
84
|
+
return ShortLinkList.model_validate(response.json())
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def partial_update(self, code: str) -> ShortLinkList:
|
|
88
|
+
"""
|
|
89
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
90
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
91
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
92
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
93
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
94
|
+
"""
|
|
95
|
+
url = f"/api/shortlinks/{code}/"
|
|
96
|
+
response = await self._client.patch(url)
|
|
97
|
+
if not response.is_success:
|
|
98
|
+
try:
|
|
99
|
+
error_body = response.json()
|
|
100
|
+
except Exception:
|
|
101
|
+
error_body = response.text
|
|
102
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
103
|
+
return ShortLinkList.model_validate(response.json())
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
async def destroy(self, code: str) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Deactivate a short link.
|
|
109
|
+
"""
|
|
110
|
+
url = f"/api/shortlinks/{code}/"
|
|
111
|
+
response = await self._client.delete(url)
|
|
112
|
+
if not response.is_success:
|
|
113
|
+
try:
|
|
114
|
+
error_body = response.json()
|
|
115
|
+
except Exception:
|
|
116
|
+
error_body = response.text
|
|
117
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def stats_retrieve(self) -> ShortLinkStats:
|
|
122
|
+
"""
|
|
123
|
+
Get shortlink statistics
|
|
124
|
+
|
|
125
|
+
Get shortlink statistics for the current user.
|
|
126
|
+
"""
|
|
127
|
+
url = "/api/shortlinks/stats/"
|
|
128
|
+
response = await self._client.get(url)
|
|
129
|
+
if not response.is_success:
|
|
130
|
+
try:
|
|
131
|
+
error_body = response.json()
|
|
132
|
+
except Exception:
|
|
133
|
+
error_body = response.text
|
|
134
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
135
|
+
return ShortLinkStats.model_validate(response.json())
|
|
136
|
+
|
|
137
|
+
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Auto-generated by DjangoCFG - see CLAUDE.md
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ShortLinkList(BaseModel):
|
|
11
|
+
"""
|
|
12
|
+
Serializer for listing short links.
|
|
13
|
+
|
|
14
|
+
Response model (includes read-only fields).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
model_config = ConfigDict(
|
|
18
|
+
validate_assignment=True,
|
|
19
|
+
extra="allow",
|
|
20
|
+
frozen=False,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
id: Any = ...
|
|
24
|
+
code: Any = Field(description='Short code for the URL')
|
|
25
|
+
custom_slug: Any | None = Field(None, description='Custom slug (optional)')
|
|
26
|
+
target_url: Any = Field(description='Target URL to redirect to')
|
|
27
|
+
short_url: Any = ...
|
|
28
|
+
is_active: bool = Field(description='Whether the link is active')
|
|
29
|
+
is_expired: bool = ...
|
|
30
|
+
is_valid: bool = ...
|
|
31
|
+
hit_count: int = Field(description='Number of times the link was accessed')
|
|
32
|
+
max_hits: int | None = Field(None, description='Maximum number of redirects (null = unlimited)')
|
|
33
|
+
expires_at: Any | None = Field(None, description='When the link expires (null = never)')
|
|
34
|
+
created_at: Any = ...
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PaginatedShortLinkListList(BaseModel):
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
Response model (includes read-only fields).
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
model_config = ConfigDict(
|
|
45
|
+
validate_assignment=True,
|
|
46
|
+
extra="allow",
|
|
47
|
+
frozen=False,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
count: int = Field(description='Total number of items across all pages')
|
|
51
|
+
page: int = Field(description='Current page number (1-based)')
|
|
52
|
+
pages: int = Field(description='Total number of pages')
|
|
53
|
+
page_size: int = Field(description='Number of items per page')
|
|
54
|
+
has_next: bool = Field(description='Whether there is a next page')
|
|
55
|
+
has_previous: bool = Field(description='Whether there is a previous page')
|
|
56
|
+
next_page: int | None = Field(None, description='Next page number (null if no next page)')
|
|
57
|
+
previous_page: int | None = Field(None, description='Previous page number (null if no previous page)')
|
|
58
|
+
results: list[ShortLinkList] = Field(description='Array of items for current page')
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ShortLinkCreateRequest(BaseModel):
|
|
63
|
+
"""
|
|
64
|
+
Serializer for creating short links.
|
|
65
|
+
|
|
66
|
+
Request model (no read-only fields).
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
model_config = ConfigDict(
|
|
70
|
+
validate_assignment=True,
|
|
71
|
+
extra="allow",
|
|
72
|
+
frozen=False,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
target_url: str = Field(min_length=1, max_length=2000)
|
|
76
|
+
custom_slug: str | None = Field(None, min_length=1, max_length=50)
|
|
77
|
+
expires_at: str | None = None
|
|
78
|
+
max_hits: int | None = Field(None, ge=1)
|
|
79
|
+
metadata: dict[str, Any] | None = None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class ShortLinkCreate(BaseModel):
|
|
84
|
+
"""
|
|
85
|
+
Serializer for creating short links.
|
|
86
|
+
|
|
87
|
+
Response model (includes read-only fields).
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
model_config = ConfigDict(
|
|
91
|
+
validate_assignment=True,
|
|
92
|
+
extra="allow",
|
|
93
|
+
frozen=False,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
target_url: str = Field(max_length=2000)
|
|
97
|
+
custom_slug: str | None = Field(None, max_length=50)
|
|
98
|
+
expires_at: str | None = None
|
|
99
|
+
max_hits: int | None = Field(None, ge=1)
|
|
100
|
+
metadata: dict[str, Any] | None = None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class ShortLinkDetail(BaseModel):
|
|
105
|
+
"""
|
|
106
|
+
Serializer for short link details.
|
|
107
|
+
|
|
108
|
+
Response model (includes read-only fields).
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
model_config = ConfigDict(
|
|
112
|
+
validate_assignment=True,
|
|
113
|
+
extra="allow",
|
|
114
|
+
frozen=False,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
id: Any = ...
|
|
118
|
+
code: Any = Field(description='Short code for the URL')
|
|
119
|
+
custom_slug: Any | None = Field(None, description='Custom slug (optional)')
|
|
120
|
+
target_url: Any = Field(description='Target URL to redirect to')
|
|
121
|
+
short_url: Any = ...
|
|
122
|
+
is_active: bool = Field(description='Whether the link is active')
|
|
123
|
+
is_expired: bool = ...
|
|
124
|
+
is_valid: bool = ...
|
|
125
|
+
hit_count: int = Field(description='Number of times the link was accessed')
|
|
126
|
+
max_hits: int | None = Field(None, description='Maximum number of redirects (null = unlimited)')
|
|
127
|
+
expires_at: Any | None = Field(None, description='When the link expires (null = never)')
|
|
128
|
+
created_at: Any = ...
|
|
129
|
+
last_hit_at: str | None = Field(None, description='Last time the link was accessed')
|
|
130
|
+
metadata: dict[str, Any] | None = Field(None, description='Additional metadata (e.g., title, description)')
|
|
131
|
+
updated_at: Any = ...
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class ShortLinkStats(BaseModel):
|
|
136
|
+
"""
|
|
137
|
+
Serializer for shortlink statistics.
|
|
138
|
+
|
|
139
|
+
Response model (includes read-only fields).
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
model_config = ConfigDict(
|
|
143
|
+
validate_assignment=True,
|
|
144
|
+
extra="allow",
|
|
145
|
+
frozen=False,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
total_links: int = Field(description='Total number of short links')
|
|
149
|
+
active_links: int = Field(description='Number of active links')
|
|
150
|
+
total_hits: int = Field(description='Total hit count across all links')
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from .models import *
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SyncShortlinksShortlinksAPI:
|
|
9
|
+
"""Synchronous API endpoints for Shortlinks."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, client: httpx.Client):
|
|
12
|
+
"""Initialize sync sub-client with shared httpx client."""
|
|
13
|
+
self._client = client
|
|
14
|
+
|
|
15
|
+
def list(self, page: int | None = None, page_size: int | None = None) -> list[PaginatedShortLinkListList]:
|
|
16
|
+
"""
|
|
17
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
18
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
19
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
20
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
21
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
22
|
+
"""
|
|
23
|
+
url = "/api/shortlinks/"
|
|
24
|
+
response = self._client.get(url, params={"page": page if page is not None else None, "page_size": page_size if page_size is not None else None})
|
|
25
|
+
if not response.is_success:
|
|
26
|
+
try:
|
|
27
|
+
error_body = response.json()
|
|
28
|
+
except Exception:
|
|
29
|
+
error_body = response.text
|
|
30
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
31
|
+
return PaginatedShortLinkListList.model_validate(response.json())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def create(self, data: ShortLinkCreateRequest) -> ShortLinkCreate:
|
|
35
|
+
"""
|
|
36
|
+
Create a new short link.
|
|
37
|
+
"""
|
|
38
|
+
url = "/api/shortlinks/"
|
|
39
|
+
response = self._client.post(url, json=data.model_dump(exclude_unset=True))
|
|
40
|
+
if not response.is_success:
|
|
41
|
+
try:
|
|
42
|
+
error_body = response.json()
|
|
43
|
+
except Exception:
|
|
44
|
+
error_body = response.text
|
|
45
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
46
|
+
return ShortLinkCreate.model_validate(response.json())
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def retrieve(self, code: str) -> ShortLinkDetail:
|
|
50
|
+
"""
|
|
51
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
52
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
53
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
54
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
55
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
56
|
+
"""
|
|
57
|
+
url = f"/api/shortlinks/{code}/"
|
|
58
|
+
response = self._client.get(url)
|
|
59
|
+
if not response.is_success:
|
|
60
|
+
try:
|
|
61
|
+
error_body = response.json()
|
|
62
|
+
except Exception:
|
|
63
|
+
error_body = response.text
|
|
64
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
65
|
+
return ShortLinkDetail.model_validate(response.json())
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def update(self, code: str) -> ShortLinkList:
|
|
69
|
+
"""
|
|
70
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
71
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
72
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
73
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
74
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
75
|
+
"""
|
|
76
|
+
url = f"/api/shortlinks/{code}/"
|
|
77
|
+
response = self._client.put(url)
|
|
78
|
+
if not response.is_success:
|
|
79
|
+
try:
|
|
80
|
+
error_body = response.json()
|
|
81
|
+
except Exception:
|
|
82
|
+
error_body = response.text
|
|
83
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
84
|
+
return ShortLinkList.model_validate(response.json())
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def partial_update(self, code: str) -> ShortLinkList:
|
|
88
|
+
"""
|
|
89
|
+
ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
|
|
90
|
+
List user's short links - POST /api/shortlinks/ - Create a new short
|
|
91
|
+
link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
|
|
92
|
+
/api/shortlinks/{code}/ - Deactivate short link - GET
|
|
93
|
+
/api/shortlinks/stats/ - Get link statistics
|
|
94
|
+
"""
|
|
95
|
+
url = f"/api/shortlinks/{code}/"
|
|
96
|
+
response = self._client.patch(url)
|
|
97
|
+
if not response.is_success:
|
|
98
|
+
try:
|
|
99
|
+
error_body = response.json()
|
|
100
|
+
except Exception:
|
|
101
|
+
error_body = response.text
|
|
102
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
103
|
+
return ShortLinkList.model_validate(response.json())
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def destroy(self, code: str) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Deactivate a short link.
|
|
109
|
+
"""
|
|
110
|
+
url = f"/api/shortlinks/{code}/"
|
|
111
|
+
response = self._client.delete(url)
|
|
112
|
+
if not response.is_success:
|
|
113
|
+
try:
|
|
114
|
+
error_body = response.json()
|
|
115
|
+
except Exception:
|
|
116
|
+
error_body = response.text
|
|
117
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def stats_retrieve(self) -> ShortLinkStats:
|
|
121
|
+
"""
|
|
122
|
+
Get shortlink statistics
|
|
123
|
+
|
|
124
|
+
Get shortlink statistics for the current user.
|
|
125
|
+
"""
|
|
126
|
+
url = "/api/shortlinks/stats/"
|
|
127
|
+
response = self._client.get(url)
|
|
128
|
+
if not response.is_success:
|
|
129
|
+
try:
|
|
130
|
+
error_body = response.json()
|
|
131
|
+
except Exception:
|
|
132
|
+
error_body = response.text
|
|
133
|
+
raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
|
|
134
|
+
return ShortLinkStats.model_validate(response.json())
|
|
135
|
+
|
|
136
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from .shortlinks__api__shortlinks.sync_client import SyncShortlinksShortlinksAPI
|
|
8
|
+
from .logger import APILogger, LoggerConfig
|
|
9
|
+
from .retry import RetryConfig, RetryAsyncClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SyncAPIClient:
|
|
13
|
+
"""
|
|
14
|
+
Synchronous API client for SDKRouter API.
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
>>> with SyncAPIClient(base_url='https://api.example.com') as client:
|
|
18
|
+
... users = client.users.list()
|
|
19
|
+
... post = client.posts.create(data=new_post)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
base_url: str,
|
|
25
|
+
logger_config: Optional[LoggerConfig] = None,
|
|
26
|
+
**kwargs: Any,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Initialize sync API client.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
base_url: Base API URL (e.g., 'https://api.example.com')
|
|
33
|
+
logger_config: Logger configuration (None to disable logging)
|
|
34
|
+
**kwargs: Additional httpx.Client kwargs
|
|
35
|
+
"""
|
|
36
|
+
self.base_url = base_url.rstrip('/')
|
|
37
|
+
self._client = httpx.Client(
|
|
38
|
+
base_url=self.base_url,
|
|
39
|
+
**kwargs,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Initialize logger
|
|
43
|
+
self.logger: Optional[APILogger] = None
|
|
44
|
+
if logger_config is not None:
|
|
45
|
+
self.logger = APILogger(logger_config)
|
|
46
|
+
|
|
47
|
+
# Initialize sub-clients
|
|
48
|
+
self.shortlinks_shortlinks = SyncShortlinksShortlinksAPI(self._client)
|
|
49
|
+
|
|
50
|
+
def __enter__(self) -> 'SyncAPIClient':
|
|
51
|
+
return self
|
|
52
|
+
|
|
53
|
+
def __exit__(self, *args: Any) -> None:
|
|
54
|
+
self._client.close()
|
|
55
|
+
|
|
56
|
+
def close(self) -> None:
|
|
57
|
+
"""Close HTTP client."""
|
|
58
|
+
self._client.close()
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Auto-generated by DjangoCFG - see CLAUDE.md
|
|
2
|
+
"""
|
|
3
|
+
SDKRouter API - API Client with JWT Management
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
>>> from api import API
|
|
7
|
+
>>>
|
|
8
|
+
>>> api = API('https://api.example.com')
|
|
9
|
+
>>>
|
|
10
|
+
>>> # Set JWT token
|
|
11
|
+
>>> api.set_token('your-jwt-token', 'refresh-token')
|
|
12
|
+
>>>
|
|
13
|
+
>>> # Use API
|
|
14
|
+
>>> async with api:
|
|
15
|
+
... posts = await api.posts.list()
|
|
16
|
+
... user = await api.users.retrieve(1)
|
|
17
|
+
>>>
|
|
18
|
+
>>> # Check authentication
|
|
19
|
+
>>> if api.is_authenticated():
|
|
20
|
+
... # ...
|
|
21
|
+
>>>
|
|
22
|
+
>>> # Get OpenAPI schema path
|
|
23
|
+
>>> schema_path = api.get_schema_path()
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import threading
|
|
29
|
+
from typing import Any
|
|
30
|
+
|
|
31
|
+
import httpx
|
|
32
|
+
|
|
33
|
+
from .client import APIClient
|
|
34
|
+
from .logger import LoggerConfig
|
|
35
|
+
from .retry import RetryConfig
|
|
36
|
+
from .vision__api__vision import VisionVisionAPI
|
|
37
|
+
from . import enums
|
|
38
|
+
# NOTE: Individual enum imports commented out due to invalid Python syntax with dotted names
|
|
39
|
+
# from .enums import OCRRequestRequest.mode, VisionAnalyzeRequestRequest.model_quality
|
|
40
|
+
|
|
41
|
+
TOKEN_KEY = "auth_token"
|
|
42
|
+
REFRESH_TOKEN_KEY = "refresh_token"
|
|
43
|
+
|
|
44
|
+
# Auto-generated by DjangoCFG - see CLAUDE.md
|
|
45
|
+
class API:
|
|
46
|
+
"""
|
|
47
|
+
API Client wrapper with JWT token management.
|
|
48
|
+
|
|
49
|
+
This class provides:
|
|
50
|
+
- Thread-safe JWT token storage
|
|
51
|
+
- Automatic Authorization header injection
|
|
52
|
+
- Context manager support for async operations
|
|
53
|
+
- Optional retry and logging configuration
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
>>> api = API('https://api.example.com')
|
|
57
|
+
>>> api.set_token('jwt-token')
|
|
58
|
+
>>> async with api:
|
|
59
|
+
... users = await api.users.list()
|
|
60
|
+
>>>
|
|
61
|
+
>>> # With retry and logging
|
|
62
|
+
>>> api = API(
|
|
63
|
+
... 'https://api.example.com',
|
|
64
|
+
... retry_config=RetryConfig(max_attempts=5),
|
|
65
|
+
... logger_config=LoggerConfig(enabled=True)
|
|
66
|
+
... )
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
base_url: str,
|
|
72
|
+
logger_config: LoggerConfig | None = None,
|
|
73
|
+
retry_config: RetryConfig | None = None,
|
|
74
|
+
**kwargs: Any
|
|
75
|
+
):
|
|
76
|
+
"""
|
|
77
|
+
Initialize API client.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
base_url: Base API URL (e.g., 'https://api.example.com')
|
|
81
|
+
logger_config: Logger configuration (None to disable logging)
|
|
82
|
+
retry_config: Retry configuration (None to disable retry)
|
|
83
|
+
**kwargs: Additional httpx.AsyncClient kwargs
|
|
84
|
+
"""
|
|
85
|
+
self.base_url = base_url.rstrip('/')
|
|
86
|
+
self._kwargs = kwargs
|
|
87
|
+
self._logger_config = logger_config
|
|
88
|
+
self._retry_config = retry_config
|
|
89
|
+
self._token: str | None = None
|
|
90
|
+
self._refresh_token: str | None = None
|
|
91
|
+
self._lock = threading.Lock()
|
|
92
|
+
self._client: APIClient | None = None
|
|
93
|
+
self._init_clients()
|
|
94
|
+
|
|
95
|
+
def _init_clients(self) -> None:
|
|
96
|
+
"""Initialize API client with current token."""
|
|
97
|
+
# Create httpx client with auth header if token exists
|
|
98
|
+
headers = {}
|
|
99
|
+
if self._token:
|
|
100
|
+
headers['Authorization'] = f'Bearer {self._token}'
|
|
101
|
+
|
|
102
|
+
kwargs = {**self._kwargs}
|
|
103
|
+
if headers:
|
|
104
|
+
kwargs['headers'] = headers
|
|
105
|
+
|
|
106
|
+
# Create new APIClient
|
|
107
|
+
self._client = APIClient(
|
|
108
|
+
self.base_url,
|
|
109
|
+
logger_config=self._logger_config,
|
|
110
|
+
retry_config=self._retry_config,
|
|
111
|
+
**kwargs
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def vision_vision(self) -> VisionVisionAPI:
|
|
116
|
+
"""Access vision endpoints."""
|
|
117
|
+
return self._client.vision_vision
|
|
118
|
+
|
|
119
|
+
def get_token(self) -> str | None:
|
|
120
|
+
"""Get current JWT token."""
|
|
121
|
+
with self._lock:
|
|
122
|
+
return self._token
|
|
123
|
+
|
|
124
|
+
def get_refresh_token(self) -> str | None:
|
|
125
|
+
"""Get current refresh token."""
|
|
126
|
+
with self._lock:
|
|
127
|
+
return self._refresh_token
|
|
128
|
+
|
|
129
|
+
def set_token(self, token: str, refresh_token: str | None = None) -> None:
|
|
130
|
+
"""
|
|
131
|
+
Set JWT token and refresh token.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
token: JWT access token
|
|
135
|
+
refresh_token: JWT refresh token (optional)
|
|
136
|
+
"""
|
|
137
|
+
with self._lock:
|
|
138
|
+
self._token = token
|
|
139
|
+
if refresh_token:
|
|
140
|
+
self._refresh_token = refresh_token
|
|
141
|
+
|
|
142
|
+
# Reinitialize clients with new token
|
|
143
|
+
self._init_clients()
|
|
144
|
+
|
|
145
|
+
def clear_tokens(self) -> None:
|
|
146
|
+
"""Clear all tokens."""
|
|
147
|
+
with self._lock:
|
|
148
|
+
self._token = None
|
|
149
|
+
self._refresh_token = None
|
|
150
|
+
|
|
151
|
+
# Reinitialize clients without token
|
|
152
|
+
self._init_clients()
|
|
153
|
+
|
|
154
|
+
def is_authenticated(self) -> bool:
|
|
155
|
+
"""Check if user is authenticated."""
|
|
156
|
+
return self.get_token() is not None
|
|
157
|
+
|
|
158
|
+
def set_base_url(self, url: str) -> None:
|
|
159
|
+
"""
|
|
160
|
+
Update base URL and reinitialize clients.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
url: New base URL
|
|
164
|
+
"""
|
|
165
|
+
self.base_url = url.rstrip('/')
|
|
166
|
+
self._init_clients()
|
|
167
|
+
|
|
168
|
+
def get_base_url(self) -> str:
|
|
169
|
+
"""Get current base URL."""
|
|
170
|
+
return self.base_url
|
|
171
|
+
|
|
172
|
+
def get_schema_path(self) -> str:
|
|
173
|
+
"""
|
|
174
|
+
Get OpenAPI schema path.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Path to the OpenAPI schema JSON file
|
|
178
|
+
|
|
179
|
+
Note:
|
|
180
|
+
The OpenAPI schema is available in the schema.json file.
|
|
181
|
+
You can load it dynamically using:
|
|
182
|
+
```python
|
|
183
|
+
import json
|
|
184
|
+
from pathlib import Path
|
|
185
|
+
|
|
186
|
+
schema_path = Path(__file__).parent / 'schema.json'
|
|
187
|
+
with open(schema_path) as f:
|
|
188
|
+
schema = json.load(f)
|
|
189
|
+
```
|
|
190
|
+
"""
|
|
191
|
+
return './schema.json'
|
|
192
|
+
|
|
193
|
+
async def __aenter__(self) -> 'API':
|
|
194
|
+
"""Async context manager entry."""
|
|
195
|
+
if self._client:
|
|
196
|
+
await self._client.__aenter__()
|
|
197
|
+
return self
|
|
198
|
+
|
|
199
|
+
async def __aexit__(self, *args: Any) -> None:
|
|
200
|
+
"""Async context manager exit."""
|
|
201
|
+
if self._client:
|
|
202
|
+
await self._client.__aexit__(*args)
|
|
203
|
+
|
|
204
|
+
async def close(self) -> None:
|
|
205
|
+
"""Close HTTP client."""
|
|
206
|
+
if self._client:
|
|
207
|
+
await self._client.close()
|
|
208
|
+
|
|
209
|
+
__all__ = [
|
|
210
|
+
"API",
|
|
211
|
+
"APIClient",
|
|
212
|
+
]
|