payi 0.1.0a88__py3-none-any.whl → 0.1.0a90__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.
Potentially problematic release.
This version of payi might be problematic. Click here for more details.
- payi/__init__.py +2 -1
- payi/_base_client.py +38 -2
- payi/_version.py +1 -1
- payi/lib/instrument.py +34 -5
- {payi-0.1.0a88.dist-info → payi-0.1.0a90.dist-info}/METADATA +41 -3
- {payi-0.1.0a88.dist-info → payi-0.1.0a90.dist-info}/RECORD +8 -8
- {payi-0.1.0a88.dist-info → payi-0.1.0a90.dist-info}/WHEEL +0 -0
- {payi-0.1.0a88.dist-info → payi-0.1.0a90.dist-info}/licenses/LICENSE +0 -0
payi/__init__.py
CHANGED
|
@@ -26,7 +26,7 @@ from ._exceptions import (
|
|
|
26
26
|
UnprocessableEntityError,
|
|
27
27
|
APIResponseValidationError,
|
|
28
28
|
)
|
|
29
|
-
from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
|
|
29
|
+
from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
|
|
30
30
|
from ._utils._logs import setup_logging as _setup_logging
|
|
31
31
|
|
|
32
32
|
__all__ = [
|
|
@@ -68,6 +68,7 @@ __all__ = [
|
|
|
68
68
|
"DEFAULT_CONNECTION_LIMITS",
|
|
69
69
|
"DefaultHttpxClient",
|
|
70
70
|
"DefaultAsyncHttpxClient",
|
|
71
|
+
"DefaultAioHttpClient",
|
|
71
72
|
]
|
|
72
73
|
|
|
73
74
|
if not _t.TYPE_CHECKING:
|
payi/_base_client.py
CHANGED
|
@@ -1071,7 +1071,14 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
|
|
|
1071
1071
|
) -> ResponseT:
|
|
1072
1072
|
origin = get_origin(cast_to) or cast_to
|
|
1073
1073
|
|
|
1074
|
-
if
|
|
1074
|
+
if (
|
|
1075
|
+
inspect.isclass(origin)
|
|
1076
|
+
and issubclass(origin, BaseAPIResponse)
|
|
1077
|
+
# we only want to actually return the custom BaseAPIResponse class if we're
|
|
1078
|
+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
|
1079
|
+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
|
1080
|
+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
|
1081
|
+
):
|
|
1075
1082
|
if not issubclass(origin, APIResponse):
|
|
1076
1083
|
raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
|
|
1077
1084
|
|
|
@@ -1282,6 +1289,24 @@ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
|
|
|
1282
1289
|
super().__init__(**kwargs)
|
|
1283
1290
|
|
|
1284
1291
|
|
|
1292
|
+
try:
|
|
1293
|
+
import httpx_aiohttp
|
|
1294
|
+
except ImportError:
|
|
1295
|
+
|
|
1296
|
+
class _DefaultAioHttpClient(httpx.AsyncClient):
|
|
1297
|
+
def __init__(self, **_kwargs: Any) -> None:
|
|
1298
|
+
raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
|
|
1299
|
+
else:
|
|
1300
|
+
|
|
1301
|
+
class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
|
|
1302
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
1303
|
+
kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
|
|
1304
|
+
kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
|
|
1305
|
+
kwargs.setdefault("follow_redirects", True)
|
|
1306
|
+
|
|
1307
|
+
super().__init__(**kwargs)
|
|
1308
|
+
|
|
1309
|
+
|
|
1285
1310
|
if TYPE_CHECKING:
|
|
1286
1311
|
DefaultAsyncHttpxClient = httpx.AsyncClient
|
|
1287
1312
|
"""An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
|
|
@@ -1290,8 +1315,12 @@ if TYPE_CHECKING:
|
|
|
1290
1315
|
This is useful because overriding the `http_client` with your own instance of
|
|
1291
1316
|
`httpx.AsyncClient` will result in httpx's defaults being used, not ours.
|
|
1292
1317
|
"""
|
|
1318
|
+
|
|
1319
|
+
DefaultAioHttpClient = httpx.AsyncClient
|
|
1320
|
+
"""An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
|
|
1293
1321
|
else:
|
|
1294
1322
|
DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
|
|
1323
|
+
DefaultAioHttpClient = _DefaultAioHttpClient
|
|
1295
1324
|
|
|
1296
1325
|
|
|
1297
1326
|
class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
|
|
@@ -1574,7 +1603,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
|
|
|
1574
1603
|
) -> ResponseT:
|
|
1575
1604
|
origin = get_origin(cast_to) or cast_to
|
|
1576
1605
|
|
|
1577
|
-
if
|
|
1606
|
+
if (
|
|
1607
|
+
inspect.isclass(origin)
|
|
1608
|
+
and issubclass(origin, BaseAPIResponse)
|
|
1609
|
+
# we only want to actually return the custom BaseAPIResponse class if we're
|
|
1610
|
+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
|
1611
|
+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
|
1612
|
+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
|
1613
|
+
):
|
|
1578
1614
|
if not issubclass(origin, AsyncAPIResponse):
|
|
1579
1615
|
raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
|
|
1580
1616
|
|
payi/_version.py
CHANGED
payi/lib/instrument.py
CHANGED
|
@@ -138,6 +138,7 @@ class PayiInstrumentConfig(TypedDict, total=False):
|
|
|
138
138
|
use_case_id: Optional[str]
|
|
139
139
|
use_case_version: Optional[int]
|
|
140
140
|
user_id: Optional[str]
|
|
141
|
+
request_tags: Optional["list[str]"]
|
|
141
142
|
|
|
142
143
|
class _Context(TypedDict, total=False):
|
|
143
144
|
proxy: Optional[bool]
|
|
@@ -246,8 +247,17 @@ class _PayiInstrumentor:
|
|
|
246
247
|
self._logger.error(f"Error creating default use case definition based on file name {caller_filename}: {e}")
|
|
247
248
|
|
|
248
249
|
self.__enter__()
|
|
250
|
+
|
|
249
251
|
# _init_current_context will update the currrent context stack location
|
|
250
|
-
|
|
252
|
+
context: _Context = {}
|
|
253
|
+
# Copy allowed keys from global_config into context
|
|
254
|
+
# Dynamically use keys from _Context TypedDict
|
|
255
|
+
context_keys = list(_Context.__annotations__.keys()) if hasattr(_Context, '__annotations__') else []
|
|
256
|
+
for key in context_keys:
|
|
257
|
+
if key in global_config:
|
|
258
|
+
context[key] = global_config[key] # type: ignore
|
|
259
|
+
|
|
260
|
+
self._init_current_context(**context)
|
|
251
261
|
|
|
252
262
|
def _instrument_all(self) -> None:
|
|
253
263
|
self._instrument_openai()
|
|
@@ -567,10 +577,22 @@ class _PayiInstrumentor:
|
|
|
567
577
|
else:
|
|
568
578
|
context["user_id"] = user_id
|
|
569
579
|
|
|
580
|
+
parent_request_tags = parent_context.get("request_tags", None)
|
|
581
|
+
if request_tags is not None:
|
|
582
|
+
if len(request_tags) == 0:
|
|
583
|
+
context["request_tags"] = None
|
|
584
|
+
else:
|
|
585
|
+
if parent_request_tags:
|
|
586
|
+
# union of new and parent lists if the parent context contains request tags
|
|
587
|
+
context["request_tags"] = list(set(request_tags) | set(parent_request_tags))
|
|
588
|
+
else:
|
|
589
|
+
context["request_tags"] = request_tags
|
|
590
|
+
elif parent_request_tags:
|
|
591
|
+
# use the parent request_tags if it exists
|
|
592
|
+
context["request_tags"] = parent_request_tags
|
|
593
|
+
|
|
570
594
|
if use_case_step and (context["use_case_name"] or context["use_case_id"]):
|
|
571
595
|
context["use_case_step"] = use_case_step
|
|
572
|
-
if request_tags:
|
|
573
|
-
context["request_tags"] = request_tags
|
|
574
596
|
if price_as_category:
|
|
575
597
|
context["price_as_category"] = price_as_category
|
|
576
598
|
if price_as_resource:
|
|
@@ -587,6 +609,7 @@ class _PayiInstrumentor:
|
|
|
587
609
|
use_case_id: Optional[str],
|
|
588
610
|
use_case_version: Optional[int],
|
|
589
611
|
user_id: Optional[str],
|
|
612
|
+
request_tags: Optional["list[str]"] = None,
|
|
590
613
|
*args: Any,
|
|
591
614
|
**kwargs: Any,
|
|
592
615
|
) -> Any:
|
|
@@ -597,7 +620,8 @@ class _PayiInstrumentor:
|
|
|
597
620
|
use_case_name=use_case_name,
|
|
598
621
|
use_case_id=use_case_id,
|
|
599
622
|
use_case_version=use_case_version,
|
|
600
|
-
user_id=user_id
|
|
623
|
+
user_id=user_id,
|
|
624
|
+
request_tags=request_tags)
|
|
601
625
|
return await func(*args, **kwargs)
|
|
602
626
|
|
|
603
627
|
def _call_func(
|
|
@@ -609,6 +633,7 @@ class _PayiInstrumentor:
|
|
|
609
633
|
use_case_id: Optional[str],
|
|
610
634
|
use_case_version: Optional[int],
|
|
611
635
|
user_id: Optional[str],
|
|
636
|
+
request_tags: Optional["list[str]"] = None,
|
|
612
637
|
*args: Any,
|
|
613
638
|
**kwargs: Any,
|
|
614
639
|
) -> Any:
|
|
@@ -619,7 +644,8 @@ class _PayiInstrumentor:
|
|
|
619
644
|
use_case_name=use_case_name,
|
|
620
645
|
use_case_id=use_case_id,
|
|
621
646
|
use_case_version=use_case_version,
|
|
622
|
-
user_id=user_id
|
|
647
|
+
user_id=user_id,
|
|
648
|
+
request_tags=request_tags)
|
|
623
649
|
return func(*args, **kwargs)
|
|
624
650
|
|
|
625
651
|
def __enter__(self) -> Any:
|
|
@@ -1475,6 +1501,7 @@ def track(
|
|
|
1475
1501
|
use_case_id: Optional[str] = None,
|
|
1476
1502
|
use_case_version: Optional[int] = None,
|
|
1477
1503
|
user_id: Optional[str] = None,
|
|
1504
|
+
request_tags: Optional["list[str]"] = None,
|
|
1478
1505
|
proxy: Optional[bool] = None,
|
|
1479
1506
|
) -> Any:
|
|
1480
1507
|
|
|
@@ -1496,6 +1523,7 @@ def track(
|
|
|
1496
1523
|
use_case_id,
|
|
1497
1524
|
use_case_version,
|
|
1498
1525
|
user_id,
|
|
1526
|
+
request_tags,
|
|
1499
1527
|
*args,
|
|
1500
1528
|
**kwargs,
|
|
1501
1529
|
)
|
|
@@ -1516,6 +1544,7 @@ def track(
|
|
|
1516
1544
|
use_case_id,
|
|
1517
1545
|
use_case_version,
|
|
1518
1546
|
user_id,
|
|
1547
|
+
request_tags,
|
|
1519
1548
|
*args,
|
|
1520
1549
|
**kwargs,
|
|
1521
1550
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: payi
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0a90
|
|
4
4
|
Summary: The official Python library for the payi API
|
|
5
5
|
Project-URL: Homepage, https://github.com/Pay-i/pay-i-python
|
|
6
6
|
Project-URL: Repository, https://github.com/Pay-i/pay-i-python
|
|
@@ -30,11 +30,14 @@ Requires-Dist: sniffio
|
|
|
30
30
|
Requires-Dist: tiktoken>=0.8.0
|
|
31
31
|
Requires-Dist: typing-extensions<5,>=4.10
|
|
32
32
|
Requires-Dist: wrapt>=1.17.2
|
|
33
|
+
Provides-Extra: aiohttp
|
|
34
|
+
Requires-Dist: aiohttp; extra == 'aiohttp'
|
|
35
|
+
Requires-Dist: httpx-aiohttp>=0.1.6; extra == 'aiohttp'
|
|
33
36
|
Description-Content-Type: text/markdown
|
|
34
37
|
|
|
35
38
|
# Payi Python API library
|
|
36
39
|
|
|
37
|
-
[](https://pypi.org/project/payi/)
|
|
40
|
+
[>)](https://pypi.org/project/payi/)
|
|
38
41
|
|
|
39
42
|
The Payi Python library provides convenient access to the Payi REST API from any Python 3.8+
|
|
40
43
|
application. The library includes type definitions for all request params and response fields,
|
|
@@ -104,6 +107,41 @@ asyncio.run(main())
|
|
|
104
107
|
|
|
105
108
|
Functionality between the synchronous and asynchronous clients is otherwise identical.
|
|
106
109
|
|
|
110
|
+
### With aiohttp
|
|
111
|
+
|
|
112
|
+
By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
|
|
113
|
+
|
|
114
|
+
You can enable this by installing `aiohttp`:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
# install from PyPI
|
|
118
|
+
pip install --pre payi[aiohttp]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
import os
|
|
125
|
+
import asyncio
|
|
126
|
+
from payi import DefaultAioHttpClient
|
|
127
|
+
from payi import AsyncPayi
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
async def main() -> None:
|
|
131
|
+
async with AsyncPayi(
|
|
132
|
+
api_key=os.environ.get("PAYI_API_KEY"), # This is the default and can be omitted
|
|
133
|
+
http_client=DefaultAioHttpClient(),
|
|
134
|
+
) as client:
|
|
135
|
+
use_case_definition = await client.use_cases.definitions.create(
|
|
136
|
+
description="Sample Use Case Definition Description",
|
|
137
|
+
name="SampleUseCaseDefinition",
|
|
138
|
+
)
|
|
139
|
+
print(use_case_definition.request_id)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
asyncio.run(main())
|
|
143
|
+
```
|
|
144
|
+
|
|
107
145
|
## Using types
|
|
108
146
|
|
|
109
147
|
Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
|
|
@@ -264,7 +302,7 @@ client.with_options(max_retries=5).use_cases.definitions.create(
|
|
|
264
302
|
### Timeouts
|
|
265
303
|
|
|
266
304
|
By default requests time out after 1 minute. You can configure this with a `timeout` option,
|
|
267
|
-
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
|
|
305
|
+
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
|
|
268
306
|
|
|
269
307
|
```python
|
|
270
308
|
from payi import Payi
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
payi/__init__.py,sha256=
|
|
2
|
-
payi/_base_client.py,sha256=
|
|
1
|
+
payi/__init__.py,sha256=D0Hb0f0CuE6t648U7C0qOOKez56wyNcIndIYcNuamlU,2560
|
|
2
|
+
payi/_base_client.py,sha256=Euo_HnDuz_74WmLbzSJZe5mBIbXNQIixMiOvCSRZFiI,66713
|
|
3
3
|
payi/_client.py,sha256=NoznzJFIQsFjEcPZWGJpHr94mOTMaQBuH-U_WGdjB10,17882
|
|
4
4
|
payi/_compat.py,sha256=VWemUKbj6DDkQ-O4baSpHVLJafotzeXmCQGJugfVTIw,6580
|
|
5
5
|
payi/_constants.py,sha256=S14PFzyN9-I31wiV7SmIlL5Ga0MLHxdvegInGdXH7tM,462
|
|
@@ -11,7 +11,7 @@ payi/_resource.py,sha256=j2jIkTr8OIC8sU6-05nxSaCyj4MaFlbZrwlyg4_xJos,1088
|
|
|
11
11
|
payi/_response.py,sha256=rh9oJAvCKcPwQFm4iqH_iVrmK8bNx--YP_A2a4kN1OU,28776
|
|
12
12
|
payi/_streaming.py,sha256=Z_wIyo206T6Jqh2rolFg2VXZgX24PahLmpURp0-NssU,10092
|
|
13
13
|
payi/_types.py,sha256=7jE5MoQQFVoVxw5vVzvZ2Ao0kcjfNOGsBgyJfLBEnMo,6195
|
|
14
|
-
payi/_version.py,sha256=
|
|
14
|
+
payi/_version.py,sha256=tXFgPEeKbWMp7R7RIanP0VvZ88LuzOsIwp2Fn20klHs,165
|
|
15
15
|
payi/pagination.py,sha256=k2356QGPOUSjRF2vHpwLBdF6P-2vnQzFfRIJQAHGQ7A,1258
|
|
16
16
|
payi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
payi/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
|
|
@@ -33,7 +33,7 @@ payi/lib/Stopwatch.py,sha256=7OJlxvr2Jyb6Zr1LYCYKczRB7rDVKkIR7gc4YoleNdE,764
|
|
|
33
33
|
payi/lib/VertexInstrumentor.py,sha256=IdahkOgB6ReBGpdgGCrBHplAFwK3KZ_XaRgFXVTodRU,7136
|
|
34
34
|
payi/lib/VertexRequest.py,sha256=xKBURJHx4_bXMM8AijtRAjH8t-QukRLx6AIwsCw33Y0,9986
|
|
35
35
|
payi/lib/helpers.py,sha256=FPzNSSHGf9bgD6CanB7yVx_U8t4lm2c0jlZKrsziYlc,4242
|
|
36
|
-
payi/lib/instrument.py,sha256=
|
|
36
|
+
payi/lib/instrument.py,sha256=FB0X4y7Fc5q9gtOxkX4FomNiCLP7e7SOioDztX16lEk,62040
|
|
37
37
|
payi/resources/__init__.py,sha256=1rtrPLWbNt8oJGOp6nwPumKLJ-ftez0B6qwLFyfcoP4,2972
|
|
38
38
|
payi/resources/ingest.py,sha256=Z4WHv-INZoIlBzFw4o1j_PHykDsNACpkkF42Kik0UMg,23758
|
|
39
39
|
payi/resources/categories/__init__.py,sha256=WeotN_d-0Ri8ohsrNPbve7RyViD9_N0NA9DrV3WYg3w,1701
|
|
@@ -145,7 +145,7 @@ payi/types/use_cases/definitions/kpi_retrieve_response.py,sha256=uQXliSvS3k-yDYw
|
|
|
145
145
|
payi/types/use_cases/definitions/kpi_update_params.py,sha256=jbawdWAdMnsTWVH0qfQGb8W7_TXe3lq4zjSRu44d8p8,373
|
|
146
146
|
payi/types/use_cases/definitions/kpi_update_response.py,sha256=zLyEoT0S8d7XHsnXZYT8tM7yDw0Aze0Mk-_Z6QeMtc8,459
|
|
147
147
|
payi/types/use_cases/definitions/limit_config_create_params.py,sha256=pzQza_16N3z8cFNEKr6gPbFvuGFrwNuGxAYb--Kbo2M,449
|
|
148
|
-
payi-0.1.
|
|
149
|
-
payi-0.1.
|
|
150
|
-
payi-0.1.
|
|
151
|
-
payi-0.1.
|
|
148
|
+
payi-0.1.0a90.dist-info/METADATA,sha256=gyCugCALPCJppx1mvByADB01sZ2mbBFbWJTEynnccjg,16333
|
|
149
|
+
payi-0.1.0a90.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
150
|
+
payi-0.1.0a90.dist-info/licenses/LICENSE,sha256=CQt03aM-P4a3Yg5qBg3JSLVoQS3smMyvx7tYg_6V7Gk,11334
|
|
151
|
+
payi-0.1.0a90.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|