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 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 inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
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 inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
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
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "payi"
4
- __version__ = "0.1.0-alpha.88" # x-release-please-version
4
+ __version__ = "0.1.0-alpha.90" # x-release-please-version
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
- self._init_current_context(**global_config) # type: ignore
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.0a88
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
- [![PyPI version](https://img.shields.io/pypi/v/payi.svg)](https://pypi.org/project/payi/)
40
+ [![PyPI version](https://github.com/Pay-i/pay-i-python/tree/main/<https://img.shields.io/pypi/v/payi.svg?label=pypi%20(stable)>)](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=4FRZqYbTvadWzWaSOtI2PmlFVjY4Z-jAi-T0DZAqR8c,2510
2
- payi/_base_client.py,sha256=b8EliKyjMXslDv4v36gTGE_tIg3h9wi8eQmwAJ2xaBg,65090
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=mmvzpz5jsTtAwZFRR8dHHIZK4kUAk5zC7Amkz0uWBAQ,165
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=qGTnLEppOsuGU8G0mQRwfoosBIJ_sZP-b1FabCmI5wc,60696
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.0a88.dist-info/METADATA,sha256=1Ya6iDmjt5mh2Kfhd9h3sPYTOO0NLKhC_RZ2tuCJatQ,15180
149
- payi-0.1.0a88.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
150
- payi-0.1.0a88.dist-info/licenses/LICENSE,sha256=CQt03aM-P4a3Yg5qBg3JSLVoQS3smMyvx7tYg_6V7Gk,11334
151
- payi-0.1.0a88.dist-info/RECORD,,
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,,