unique_toolkit 1.8.1__py3-none-any.whl → 1.9.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.
- unique_toolkit/_common/api_calling/human_verification_manager.py +3 -2
- unique_toolkit/_common/endpoint_requestor.py +200 -9
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.9.0.dist-info}/METADATA +4 -1
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.9.0.dist-info}/RECORD +6 -6
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.9.0.dist-info}/LICENSE +0 -0
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.9.0.dist-info}/WHEEL +0 -0
@@ -15,6 +15,7 @@ from unique_toolkit._common.endpoint_builder import (
|
|
15
15
|
ResponseType,
|
16
16
|
)
|
17
17
|
from unique_toolkit._common.endpoint_requestor import (
|
18
|
+
RequestContext,
|
18
19
|
RequestorType,
|
19
20
|
build_requestor,
|
20
21
|
)
|
@@ -163,7 +164,7 @@ class HumanVerificationManagerForApiCalling(
|
|
163
164
|
def call_api(
|
164
165
|
self,
|
165
166
|
*,
|
166
|
-
|
167
|
+
context: RequestContext,
|
167
168
|
path_params: PathParamsType,
|
168
169
|
payload: PayloadType,
|
169
170
|
) -> ResponseType:
|
@@ -171,7 +172,7 @@ class HumanVerificationManagerForApiCalling(
|
|
171
172
|
params.update(payload.model_dump())
|
172
173
|
|
173
174
|
response = self._requestor.request(
|
174
|
-
|
175
|
+
context=context,
|
175
176
|
**params,
|
176
177
|
)
|
177
178
|
return self._operation.handle_response(response)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from enum import StrEnum
|
2
2
|
from typing import Any, Callable, Generic, Protocol, TypeVar
|
3
|
+
from urllib.parse import urljoin, urlparse
|
3
4
|
|
4
5
|
from pydantic import BaseModel
|
5
6
|
from typing_extensions import ParamSpec
|
@@ -24,11 +25,40 @@ CombinedParamsType = TypeVar("CombinedParamsType", bound=BaseModel)
|
|
24
25
|
ResponseT_co = TypeVar("ResponseT_co", bound=BaseModel, covariant=True)
|
25
26
|
|
26
27
|
|
28
|
+
def _construct_full_url(base_url: str, url: str) -> str:
|
29
|
+
"""
|
30
|
+
Construct full URL from base_url and url.
|
31
|
+
If base_url is provided and url is absolute, strip the scheme/netloc from url.
|
32
|
+
"""
|
33
|
+
if not base_url:
|
34
|
+
return url
|
35
|
+
|
36
|
+
parsed = urlparse(url)
|
37
|
+
if parsed.scheme:
|
38
|
+
# URL is absolute, extract only path + query + fragment
|
39
|
+
url = parsed._replace(scheme="", netloc="").geturl()
|
40
|
+
|
41
|
+
return urljoin(base_url, url)
|
42
|
+
|
43
|
+
|
44
|
+
class RequestContext(BaseModel):
|
45
|
+
base_url: str = ""
|
46
|
+
headers: dict[str, str] | None = None
|
47
|
+
|
48
|
+
|
27
49
|
class EndpointRequestorProtocol(Protocol, Generic[CombinedParamsSpec, ResponseT_co]):
|
28
50
|
@classmethod
|
29
51
|
def request(
|
30
52
|
cls,
|
31
|
-
|
53
|
+
context: RequestContext,
|
54
|
+
*args: CombinedParamsSpec.args,
|
55
|
+
**kwargs: CombinedParamsSpec.kwargs,
|
56
|
+
) -> ResponseT_co: ...
|
57
|
+
|
58
|
+
@classmethod
|
59
|
+
async def request_async(
|
60
|
+
cls,
|
61
|
+
context: RequestContext,
|
32
62
|
*args: CombinedParamsSpec.args,
|
33
63
|
**kwargs: CombinedParamsSpec.kwargs,
|
34
64
|
) -> ResponseT_co: ...
|
@@ -53,7 +83,7 @@ def build_fake_requestor(
|
|
53
83
|
@classmethod
|
54
84
|
def request(
|
55
85
|
cls,
|
56
|
-
|
86
|
+
context: RequestContext,
|
57
87
|
*args: CombinedParamsSpec.args,
|
58
88
|
**kwargs: CombinedParamsSpec.kwargs,
|
59
89
|
) -> ResponseType:
|
@@ -68,6 +98,18 @@ def build_fake_requestor(
|
|
68
98
|
|
69
99
|
return cls._operation.handle_response(return_value)
|
70
100
|
|
101
|
+
@classmethod
|
102
|
+
async def request_async(
|
103
|
+
cls,
|
104
|
+
context: RequestContext,
|
105
|
+
headers: dict[str, str] | None = None,
|
106
|
+
*args: CombinedParamsSpec.args,
|
107
|
+
**kwargs: CombinedParamsSpec.kwargs,
|
108
|
+
) -> ResponseType:
|
109
|
+
raise NotImplementedError(
|
110
|
+
"Async request not implemented for fake requestor"
|
111
|
+
)
|
112
|
+
|
71
113
|
return FakeRequestor
|
72
114
|
|
73
115
|
|
@@ -91,7 +133,7 @@ def build_request_requestor(
|
|
91
133
|
@classmethod
|
92
134
|
def request(
|
93
135
|
cls,
|
94
|
-
|
136
|
+
context: RequestContext,
|
95
137
|
*args: CombinedParamsSpec.args,
|
96
138
|
**kwargs: CombinedParamsSpec.kwargs,
|
97
139
|
) -> ResponseType:
|
@@ -105,18 +147,159 @@ def build_request_requestor(
|
|
105
147
|
|
106
148
|
response = requests.request(
|
107
149
|
method=cls._operation.request_method(),
|
108
|
-
url=url,
|
109
|
-
headers=headers,
|
150
|
+
url=_construct_full_url(context.base_url, url),
|
151
|
+
headers=context.headers,
|
110
152
|
json=payload,
|
111
153
|
)
|
112
154
|
return cls._operation.handle_response(response.json())
|
113
155
|
|
156
|
+
@classmethod
|
157
|
+
async def request_async(
|
158
|
+
cls,
|
159
|
+
base_url: str = "",
|
160
|
+
headers: dict[str, str] | None = None,
|
161
|
+
*args: CombinedParamsSpec.args,
|
162
|
+
**kwargs: CombinedParamsSpec.kwargs,
|
163
|
+
) -> ResponseType:
|
164
|
+
raise NotImplementedError(
|
165
|
+
"Async request not implemented for request requestor"
|
166
|
+
)
|
167
|
+
|
114
168
|
return RequestRequestor
|
115
169
|
|
116
170
|
|
171
|
+
def build_httpx_requestor(
|
172
|
+
operation_type: type[
|
173
|
+
ApiOperationProtocol[
|
174
|
+
PathParamsSpec,
|
175
|
+
PathParamsType,
|
176
|
+
PayloadParamSpec,
|
177
|
+
PayloadType,
|
178
|
+
ResponseType,
|
179
|
+
]
|
180
|
+
],
|
181
|
+
combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
|
182
|
+
) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
|
183
|
+
import httpx
|
184
|
+
|
185
|
+
class HttpxRequestor(EndpointRequestorProtocol):
|
186
|
+
_operation = operation_type
|
187
|
+
|
188
|
+
@classmethod
|
189
|
+
def request(
|
190
|
+
cls,
|
191
|
+
context: RequestContext,
|
192
|
+
*args: CombinedParamsSpec.args,
|
193
|
+
**kwargs: CombinedParamsSpec.kwargs,
|
194
|
+
) -> ResponseType:
|
195
|
+
headers = context.headers or {}
|
196
|
+
|
197
|
+
path_params, payload_model = cls._operation.models_from_combined(
|
198
|
+
combined=kwargs
|
199
|
+
)
|
200
|
+
|
201
|
+
with httpx.Client() as client:
|
202
|
+
response = client.request(
|
203
|
+
method=cls._operation.request_method(),
|
204
|
+
url=_construct_full_url(
|
205
|
+
base_url=context.base_url,
|
206
|
+
url=cls._operation.create_url_from_model(path_params),
|
207
|
+
),
|
208
|
+
headers=headers,
|
209
|
+
json=cls._operation.create_payload_from_model(payload_model),
|
210
|
+
)
|
211
|
+
return cls._operation.handle_response(response.json())
|
212
|
+
|
213
|
+
@classmethod
|
214
|
+
async def request_async(
|
215
|
+
cls,
|
216
|
+
context: RequestContext,
|
217
|
+
*args: CombinedParamsSpec.args,
|
218
|
+
**kwargs: CombinedParamsSpec.kwargs,
|
219
|
+
) -> ResponseType:
|
220
|
+
headers = context.headers or {}
|
221
|
+
|
222
|
+
path_params, payload_model = cls._operation.models_from_combined(
|
223
|
+
combined=kwargs
|
224
|
+
)
|
225
|
+
|
226
|
+
async with httpx.AsyncClient() as client:
|
227
|
+
response = await client.request(
|
228
|
+
method=cls._operation.request_method(),
|
229
|
+
url=_construct_full_url(
|
230
|
+
base_url=context.base_url,
|
231
|
+
url=cls._operation.create_url_from_model(path_params),
|
232
|
+
),
|
233
|
+
headers=headers,
|
234
|
+
json=cls._operation.create_payload_from_model(payload_model),
|
235
|
+
)
|
236
|
+
return cls._operation.handle_response(response.json())
|
237
|
+
|
238
|
+
return HttpxRequestor
|
239
|
+
|
240
|
+
|
241
|
+
def build_aiohttp_requestor(
|
242
|
+
operation_type: type[
|
243
|
+
ApiOperationProtocol[
|
244
|
+
PathParamsSpec,
|
245
|
+
PathParamsType,
|
246
|
+
PayloadParamSpec,
|
247
|
+
PayloadType,
|
248
|
+
ResponseType,
|
249
|
+
]
|
250
|
+
],
|
251
|
+
combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
|
252
|
+
) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
|
253
|
+
import aiohttp
|
254
|
+
|
255
|
+
class AiohttpRequestor(EndpointRequestorProtocol):
|
256
|
+
_operation = operation_type
|
257
|
+
|
258
|
+
@classmethod
|
259
|
+
def request(
|
260
|
+
cls,
|
261
|
+
context: RequestContext,
|
262
|
+
*args: CombinedParamsSpec.args,
|
263
|
+
**kwargs: CombinedParamsSpec.kwargs,
|
264
|
+
) -> ResponseType:
|
265
|
+
raise NotImplementedError(
|
266
|
+
"Sync request not implemented for aiohttp requestor"
|
267
|
+
)
|
268
|
+
|
269
|
+
@classmethod
|
270
|
+
async def request_async(
|
271
|
+
cls,
|
272
|
+
context: RequestContext,
|
273
|
+
headers: dict[str, str] | None = None,
|
274
|
+
*args: CombinedParamsSpec.args,
|
275
|
+
**kwargs: CombinedParamsSpec.kwargs,
|
276
|
+
) -> ResponseType:
|
277
|
+
headers = context.headers or {}
|
278
|
+
|
279
|
+
path_params, payload_model = cls._operation.models_from_combined(
|
280
|
+
combined=kwargs
|
281
|
+
)
|
282
|
+
|
283
|
+
async with aiohttp.ClientSession() as session:
|
284
|
+
response = await session.request(
|
285
|
+
method=cls._operation.request_method(),
|
286
|
+
url=_construct_full_url(
|
287
|
+
base_url=context.base_url,
|
288
|
+
url=cls._operation.create_url_from_model(path_params),
|
289
|
+
),
|
290
|
+
headers=headers,
|
291
|
+
json=cls._operation.create_payload_from_model(payload_model),
|
292
|
+
)
|
293
|
+
return cls._operation.handle_response(await response.json())
|
294
|
+
|
295
|
+
return AiohttpRequestor
|
296
|
+
|
297
|
+
|
117
298
|
class RequestorType(StrEnum):
|
118
299
|
REQUESTS = "requests"
|
119
300
|
FAKE = "fake"
|
301
|
+
HTTPIX = "httpx"
|
302
|
+
AIOHTTP = "aiohttp"
|
120
303
|
|
121
304
|
|
122
305
|
def build_requestor(
|
@@ -147,6 +330,14 @@ def build_requestor(
|
|
147
330
|
combined_model=combined_model,
|
148
331
|
return_value=return_value,
|
149
332
|
)
|
333
|
+
case RequestorType.HTTPIX:
|
334
|
+
return build_httpx_requestor(
|
335
|
+
operation_type=operation_type, combined_model=combined_model
|
336
|
+
)
|
337
|
+
case RequestorType.AIOHTTP:
|
338
|
+
return build_aiohttp_requestor(
|
339
|
+
operation_type=operation_type, combined_model=combined_model
|
340
|
+
)
|
150
341
|
|
151
342
|
|
152
343
|
if __name__ == "__main__":
|
@@ -183,19 +374,19 @@ if __name__ == "__main__":
|
|
183
374
|
|
184
375
|
# Note that the return value is a pydantic UserResponse object
|
185
376
|
response = FakeUserRequestor().request(
|
186
|
-
headers={"a": "b"},
|
377
|
+
context=RequestContext(headers={"a": "b"}),
|
187
378
|
user_id=123,
|
188
379
|
include_profile=True,
|
189
380
|
)
|
190
381
|
|
191
|
-
|
382
|
+
RequestRequestor = build_request_requestor(
|
192
383
|
operation_type=UserEndpoint,
|
193
384
|
combined_model=CombinedParams,
|
194
385
|
)
|
195
386
|
|
196
387
|
# Check type hints
|
197
|
-
response =
|
198
|
-
headers={"a": "b"}, user_id=123, include_profile=True
|
388
|
+
response = RequestRequestor().request(
|
389
|
+
context=RequestContext(headers={"a": "b"}), user_id=123, include_profile=True
|
199
390
|
)
|
200
391
|
|
201
392
|
print(response.model_dump())
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: unique_toolkit
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.9.0
|
4
4
|
Summary:
|
5
5
|
License: Proprietary
|
6
6
|
Author: Cedric Klinkert
|
@@ -118,6 +118,9 @@ All notable changes to this project will be documented in this file.
|
|
118
118
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
119
119
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
120
120
|
|
121
|
+
## [1.9.0] - 2026-10-04
|
122
|
+
- Define the RequestContext and add aihttp/httpx requestors
|
123
|
+
|
121
124
|
## [1.8.1] - 2026-10-03
|
122
125
|
- Fix bug where sub agent evaluation config variable `include_evaluation` did not include aliases for previous names.
|
123
126
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
unique_toolkit/__init__.py,sha256=nbOYPIKERt-ITsgifrnJhatn1YNR38Ntumw-dCn_tsA,714
|
2
2
|
unique_toolkit/_common/_base_service.py,sha256=S8H0rAebx7GsOldA7xInLp3aQJt9yEPDQdsGSFRJsGg,276
|
3
3
|
unique_toolkit/_common/_time_utils.py,sha256=ztmTovTvr-3w71Ns2VwXC65OKUUh-sQlzbHdKTQWm-w,135
|
4
|
-
unique_toolkit/_common/api_calling/human_verification_manager.py,sha256=
|
4
|
+
unique_toolkit/_common/api_calling/human_verification_manager.py,sha256=wgK0hefTh3pdrs8kH26Pba46ROQoFihEhT4r6h189wo,7819
|
5
5
|
unique_toolkit/_common/base_model_type_attribute.py,sha256=7rzVqjXa0deYEixeo_pJSJcQ7nKXpWK_UGpOiEH3yZY,10382
|
6
6
|
unique_toolkit/_common/chunk_relevancy_sorter/config.py,sha256=kDSEcXeIWGvzK4IXT3pBofTXeUnq3a9qRWaPllweR-s,1817
|
7
7
|
unique_toolkit/_common/chunk_relevancy_sorter/exception.py,sha256=1mY4zjbvnXsd5oIxwiVsma09bS2XRnHrxW8KJBGtgCM,126
|
@@ -10,7 +10,7 @@ unique_toolkit/_common/chunk_relevancy_sorter/service.py,sha256=ZX1pxcy53zh3Ha0_
|
|
10
10
|
unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py,sha256=UhDllC40Y1OUQvkU6pe3nu6NR7v0d25yldE6FyozuZI,8926
|
11
11
|
unique_toolkit/_common/default_language_model.py,sha256=tmHSqg6e8G7RmKqmdE_tmLxkSN0x-aGoyUdy6Pl2oAE,334
|
12
12
|
unique_toolkit/_common/endpoint_builder.py,sha256=WzJrJ7azUQhvQRd-vsFFoyj6omJpHiVYrh1UFxNQvVg,8242
|
13
|
-
unique_toolkit/_common/endpoint_requestor.py,sha256=
|
13
|
+
unique_toolkit/_common/endpoint_requestor.py,sha256=7rDpeEvmQbLtn3iNW8NftyvAqDkLFGHoYN1h5AFDxho,12319
|
14
14
|
unique_toolkit/_common/exception.py,sha256=hwh60UUawHDyPFNs-Wom-Gc6Yb09gPelftAuW1tXE6o,779
|
15
15
|
unique_toolkit/_common/feature_flags/schema.py,sha256=F1NdVJFNU8PKlS7bYzrIPeDu2LxRqHSM9pyw622a1Kk,547
|
16
16
|
unique_toolkit/_common/pydantic/rjsf_tags.py,sha256=T3AZIF8wny3fFov66s258nEl1GqfKevFouTtG6k9PqU,31219
|
@@ -144,7 +144,7 @@ unique_toolkit/short_term_memory/schemas.py,sha256=OhfcXyF6ACdwIXW45sKzjtZX_gkcJ
|
|
144
144
|
unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBuE9sI2o9Aajqjxg,8884
|
145
145
|
unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
146
146
|
unique_toolkit/smart_rules/compile.py,sha256=cxWjb2dxEI2HGsakKdVCkSNi7VK9mr08w5sDcFCQyWI,9553
|
147
|
-
unique_toolkit-1.
|
148
|
-
unique_toolkit-1.
|
149
|
-
unique_toolkit-1.
|
150
|
-
unique_toolkit-1.
|
147
|
+
unique_toolkit-1.9.0.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
|
148
|
+
unique_toolkit-1.9.0.dist-info/METADATA,sha256=93QwMegTzGuio7DAZx1G75b02h0mD90HidVNGM2jx1A,35098
|
149
|
+
unique_toolkit-1.9.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
150
|
+
unique_toolkit-1.9.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|