payi 0.1.0a59__py3-none-any.whl → 0.1.0a61__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.

Files changed (52) hide show
  1. payi/_version.py +1 -1
  2. payi/lib/AnthropicInstrumentor.py +11 -11
  3. payi/lib/BedrockInstrumentor.py +15 -15
  4. payi/lib/OpenAIInstrumentor.py +16 -16
  5. payi/lib/helpers.py +16 -12
  6. payi/lib/instrument.py +180 -39
  7. payi/pagination.py +50 -0
  8. payi/resources/categories/categories.py +108 -23
  9. payi/resources/categories/resources.py +42 -12
  10. payi/resources/experiences/types/types.py +37 -17
  11. payi/resources/limits/limits.py +21 -30
  12. payi/resources/use_cases/__init__.py +14 -0
  13. payi/resources/use_cases/definitions/__init__.py +14 -0
  14. payi/resources/use_cases/definitions/definitions.py +68 -18
  15. payi/resources/use_cases/definitions/kpis.py +584 -0
  16. payi/resources/use_cases/kpis.py +469 -0
  17. payi/resources/use_cases/use_cases.py +32 -0
  18. payi/types/__init__.py +3 -3
  19. payi/types/categories/__init__.py +1 -1
  20. payi/types/categories/resource_list_params.py +17 -0
  21. payi/types/category_list_params.py +15 -0
  22. payi/types/category_list_resources_params.py +15 -0
  23. payi/types/category_response.py +0 -5
  24. payi/types/experiences/__init__.py +0 -1
  25. payi/types/experiences/type_list_params.py +6 -1
  26. payi/types/limit_list_params.py +4 -13
  27. payi/types/limit_list_response.py +30 -0
  28. payi/types/use_cases/__init__.py +4 -1
  29. payi/types/use_cases/definition_list_params.py +6 -1
  30. payi/types/use_cases/definitions/__init__.py +8 -0
  31. payi/types/use_cases/definitions/kpi_create_params.py +17 -0
  32. payi/types/use_cases/definitions/kpi_create_response.py +20 -0
  33. payi/types/use_cases/definitions/kpi_delete_response.py +20 -0
  34. payi/types/use_cases/definitions/kpi_list_params.py +17 -0
  35. payi/types/use_cases/definitions/kpi_list_response.py +20 -0
  36. payi/types/use_cases/definitions/kpi_retrieve_response.py +20 -0
  37. payi/types/use_cases/definitions/kpi_update_params.py +16 -0
  38. payi/types/use_cases/definitions/kpi_update_response.py +20 -0
  39. payi/types/use_cases/kpi_create_params.py +13 -0
  40. payi/types/use_cases/kpi_list_params.py +17 -0
  41. payi/types/use_cases/kpi_list_response.py +21 -0
  42. payi/types/use_cases/kpi_update_params.py +13 -0
  43. {payi-0.1.0a59.dist-info → payi-0.1.0a61.dist-info}/METADATA +91 -28
  44. {payi-0.1.0a59.dist-info → payi-0.1.0a61.dist-info}/RECORD +46 -33
  45. payi/types/categories/resource_list_response.py +0 -10
  46. payi/types/category_list_resources_response.py +0 -10
  47. payi/types/category_list_response.py +0 -10
  48. payi/types/experiences/type_list_response.py +0 -10
  49. payi/types/paged_limit_list.py +0 -52
  50. payi/types/use_cases/definition_list_response.py +0 -10
  51. {payi-0.1.0a59.dist-info → payi-0.1.0a61.dist-info}/WHEEL +0 -0
  52. {payi-0.1.0a59.dist-info → payi-0.1.0a61.dist-info}/licenses/LICENSE +0 -0
payi/lib/instrument.py CHANGED
@@ -21,20 +21,43 @@ from .helpers import PayiCategories
21
21
  from .Stopwatch import Stopwatch
22
22
 
23
23
 
24
- class Context(TypedDict, total=False):
24
+ class PayiInstrumentConfig(TypedDict, total=False):
25
25
  proxy: bool
26
+ limit_ids: Optional["list[str]"]
27
+ request_tags: Optional["list[str]"]
26
28
  experience_name: Optional[str]
27
29
  experience_id: Optional[str]
30
+ use_case_name: Optional[str]
31
+ use_case_id: Optional[str]
32
+ use_case_version: Optional[int]
33
+ user_id: Optional[str]
34
+
35
+ class _Context(TypedDict, total=False):
36
+ proxy: bool
37
+ experience_name: Optional[str]
38
+ experience_id: Optional[str]
39
+ use_case_name: Optional[str]
40
+ use_case_id: Optional[str]
41
+ use_case_version: Optional[int]
28
42
  limit_ids: Optional['list[str]']
29
43
  request_tags: Optional['list[str]']
30
44
  user_id: Optional[str]
31
45
 
32
- class IsStreaming(Enum):
46
+ class _ParentState(TypedDict, total=False):
47
+ experience_name: Optional[str]
48
+ experience_id: Optional[str]
49
+ use_case_name: Optional[str]
50
+ use_case_id: Optional[str]
51
+ use_case_version: Optional[int]
52
+ limit_ids: Optional['list[str]']
53
+ request_tags: Optional['list[str]']
54
+
55
+ class _IsStreaming(Enum):
33
56
  false = 0
34
57
  true = 1
35
58
  kwargs = 2
36
59
 
37
- class PayiInstrumentor:
60
+ class _PayiInstrumentor:
38
61
  estimated_prompt_tokens: str = "estimated_prompt_tokens"
39
62
 
40
63
  def __init__(
@@ -49,7 +72,12 @@ class PayiInstrumentor:
49
72
  ):
50
73
  self._payi: Optional[Payi] = payi
51
74
  self._apayi: Optional[AsyncPayi] = apayi
52
- self._context_stack: list[Context] = [] # Stack of context dictionaries
75
+
76
+ if not self._payi and not self._apayi:
77
+ self._payi = Payi()
78
+ self._apayi = AsyncPayi()
79
+
80
+ self._context_stack: list[_Context] = [] # Stack of context dictionaries
53
81
  self._log_prompt_and_response: bool = log_prompt_and_response
54
82
  self._prompt_and_response_logger: Optional[Callable[[str, dict[str, str]], None]] = prompt_and_response_logger
55
83
 
@@ -221,40 +249,51 @@ class PayiInstrumentor:
221
249
 
222
250
  def _setup_call_func(
223
251
  self
224
- ) -> 'tuple[Context, Optional[str], Optional[str]]':
225
- context: Context = {}
252
+ ) -> 'tuple[_Context, _ParentState]':
253
+ context: _Context = {}
254
+ parentState: _ParentState = {}
226
255
 
227
256
  if len(self._context_stack) > 0:
228
257
  # copy current context into the upcoming context
229
258
  context = self._context_stack[-1].copy()
230
259
  context.pop("proxy")
231
- previous_experience_name = context.get("experience_name", None)
232
- previous_experience_id = context.get("experience_id", None)
233
- else:
234
- previous_experience_name = None
235
- previous_experience_id = None
236
- return (context, previous_experience_name, previous_experience_id)
260
+ parentState["experience_name"] = context.get("experience_name", None)
261
+ parentState["experience_id"] = context.get("experience_id", None)
262
+ parentState["use_case_name"] = context.get("use_case_name", None)
263
+ parentState["use_case_id"] = context.get("use_case_id", None)
264
+ parentState["use_case_version"] = context.get("use_case_version", None)
265
+ parentState["limit_ids"] = context.get("limit_ids", None)
266
+ parentState["request_tags"] = context.get("request_tags", None)
267
+
268
+ return (context, parentState)
237
269
 
238
270
  def _init_context(
239
271
  self,
240
- context: Context,
241
- previous_experience_name: Optional[str],
242
- previous_experience_id: Optional[str],
272
+ context: _Context,
273
+ parentState: _ParentState,
243
274
  proxy: bool,
244
275
  limit_ids: Optional["list[str]"],
245
276
  request_tags: Optional["list[str]"],
246
277
  experience_name: Optional[str],
247
278
  experience_id: Optional[str],
279
+ use_case_name: Optional[str],
280
+ use_case_id: Optional[str],
281
+ use_case_version: Optional[int],
248
282
  user_id: Optional[str],
249
283
  ) -> None:
250
284
  context["proxy"] = proxy
251
285
 
286
+ # TODO use case what if caller specified epxerience / use_case ID and no name?
287
+
252
288
  # Handle experience name and ID logic
253
289
  if not experience_name:
254
290
  # If no experience_name specified, use previous values
255
- context["experience_name"] = previous_experience_name
256
- context["experience_id"] = previous_experience_id
291
+ context["experience_name"] = parentState.get("experience_name", None)
292
+ context["experience_id"] = parentState.get("experience_id", None)
257
293
  else:
294
+ previous_experience_name = parentState.get("experience_name", None)
295
+ previous_experience_id = parentState.get("experience_id", None)
296
+
258
297
  # If experience_name is specified
259
298
  if experience_name == previous_experience_name:
260
299
  # Same experience name, use previous ID unless new one specified
@@ -265,6 +304,29 @@ class PayiInstrumentor:
265
304
  context["experience_name"] = experience_name
266
305
  context["experience_id"] = experience_id if experience_id else str(uuid.uuid4())
267
306
 
307
+ # Handle use case name and ID logic
308
+ if not use_case_name: # TODO use case
309
+ # If no use_case_name specified, use previous values
310
+ context["use_case_name"] = parentState.get("use_case_name", None)
311
+ context["use_case_id"] = parentState.get("use_case_id", None)
312
+ context["use_case_version"] = parentState.get("use_case_version", None)
313
+ else:
314
+ previous_use_case_name = parentState.get("use_case_name", None)
315
+ previous_use_case_id = parentState.get("use_case_id", None)
316
+ previous_use_case_version = parentState.get("use_case_version", None)
317
+
318
+ # If use_case_name is specified
319
+ if use_case_name == previous_use_case_name:
320
+ # Same use case name, use previous ID unless new one specified
321
+ context["use_case_name"] = use_case_name
322
+ context["use_case_id"] = use_case_id if use_case_id else previous_use_case_id
323
+ context["use_case_version"] = use_case_version if use_case_version else previous_use_case_version
324
+ else:
325
+ # Different experience name, use specified ID or generate one
326
+ context["use_case_name"] = use_case_name
327
+ context["use_case_id"] = use_case_id if use_case_id else str(uuid.uuid4())
328
+ context["use_case_version"] = use_case_version
329
+
268
330
  # set any values explicitly passed by the caller, otherwise use what is already in the context
269
331
  if limit_ids:
270
332
  context["limit_ids"] = limit_ids
@@ -283,22 +345,27 @@ class PayiInstrumentor:
283
345
  request_tags: Optional["list[str]"],
284
346
  experience_name: Optional[str],
285
347
  experience_id: Optional[str],
348
+ use_case_name: Optional[str],
349
+ use_case_id: Optional[str],
350
+ use_case_version: Optional[int],
286
351
  user_id: Optional[str],
287
352
  *args: Any,
288
353
  **kwargs: Any,
289
354
  ) -> Any:
290
- context, previous_experience_name, previous_experience_id = self._setup_call_func()
355
+ context, parentState = self._setup_call_func()
291
356
 
292
357
  with self:
293
358
  self._init_context(
294
359
  context,
295
- previous_experience_name,
296
- previous_experience_id,
360
+ parentState,
297
361
  proxy,
298
362
  limit_ids,
299
363
  request_tags,
300
364
  experience_name,
301
365
  experience_id,
366
+ use_case_name,
367
+ use_case_id,
368
+ use_case_version,
302
369
  user_id)
303
370
  return await func(*args, **kwargs)
304
371
 
@@ -310,22 +377,27 @@ class PayiInstrumentor:
310
377
  request_tags: Optional["list[str]"],
311
378
  experience_name: Optional[str],
312
379
  experience_id: Optional[str],
380
+ use_case_name: Optional[str],
381
+ use_case_id: Optional[str],
382
+ use_case_version: Optional[int],
313
383
  user_id: Optional[str],
314
384
  *args: Any,
315
385
  **kwargs: Any,
316
386
  ) -> Any:
317
- context, previous_experience_name, previous_experience_id = self._setup_call_func()
387
+ context, parentState = self._setup_call_func()
318
388
 
319
389
  with self:
320
390
  self._init_context(
321
391
  context,
322
- previous_experience_name,
323
- previous_experience_id,
392
+ parentState,
324
393
  proxy,
325
394
  limit_ids,
326
395
  request_tags,
327
396
  experience_name,
328
397
  experience_id,
398
+ use_case_name,
399
+ use_case_id,
400
+ use_case_version,
329
401
  user_id)
330
402
  return func(*args, **kwargs)
331
403
 
@@ -339,16 +411,15 @@ class PayiInstrumentor:
339
411
  if self._context_stack:
340
412
  self._context_stack.pop()
341
413
 
342
- def set_context(self, context: Context) -> None:
414
+ def set_context(self, context: _Context) -> None:
343
415
  # Update the current top of the stack with the provided context
344
416
  if self._context_stack:
345
417
  self._context_stack[-1].update(context)
346
418
 
347
- def get_context(self) -> Optional[Context]:
419
+ def get_context(self) -> Optional[_Context]:
348
420
  # Return the current top of the stack
349
421
  return self._context_stack[-1] if self._context_stack else None
350
422
 
351
-
352
423
  def _prepare_ingest(
353
424
  self,
354
425
  ingest: IngestUnitsParams,
@@ -359,6 +430,9 @@ class PayiInstrumentor:
359
430
  request_tags = ingest_extra_headers.pop(PayiHeaderNames.request_tags, None)
360
431
  experience_name = ingest_extra_headers.pop(PayiHeaderNames.experience_name, None)
361
432
  experience_id = ingest_extra_headers.pop(PayiHeaderNames.experience_id, None)
433
+ use_case_name = ingest_extra_headers.pop(PayiHeaderNames.use_case_name, None)
434
+ use_case_id = ingest_extra_headers.pop(PayiHeaderNames.use_case_id, None)
435
+ use_case_version = ingest_extra_headers.pop(PayiHeaderNames.use_case_version, None)
362
436
  user_id = ingest_extra_headers.pop(PayiHeaderNames.user_id, None)
363
437
 
364
438
  if limit_ids:
@@ -369,6 +443,12 @@ class PayiInstrumentor:
369
443
  ingest["experience_name"] = experience_name
370
444
  if experience_id:
371
445
  ingest["experience_id"] = experience_id
446
+ if use_case_name:
447
+ ingest["use_case_name"] = use_case_name
448
+ if use_case_id:
449
+ ingest["use_case_id"] = use_case_id
450
+ if use_case_version:
451
+ ingest["use_case_version"] = int(use_case_version)
372
452
  if user_id:
373
453
  ingest["user_id"] = user_id
374
454
 
@@ -397,7 +477,7 @@ class PayiInstrumentor:
397
477
  process_chunk: Optional[Callable[[Any, IngestUnitsParams], None]],
398
478
  process_request: Optional[Callable[[IngestUnitsParams, Any, Any], None]],
399
479
  process_synchronous_response: Any,
400
- is_streaming: IsStreaming,
480
+ is_streaming: _IsStreaming,
401
481
  wrapped: Any,
402
482
  instance: Any,
403
483
  args: Any,
@@ -459,9 +539,9 @@ class PayiInstrumentor:
459
539
  sw = Stopwatch()
460
540
  stream: bool = False
461
541
 
462
- if is_streaming == IsStreaming.kwargs:
542
+ if is_streaming == _IsStreaming.kwargs:
463
543
  stream = kwargs.get("stream", False)
464
- elif is_streaming == IsStreaming.true:
544
+ elif is_streaming == _IsStreaming.true:
465
545
  stream = True
466
546
  else:
467
547
  stream = False
@@ -517,7 +597,7 @@ class PayiInstrumentor:
517
597
  process_chunk: Optional[Callable[[Any, IngestUnitsParams], None]],
518
598
  process_request: Optional[Callable[[IngestUnitsParams, Any, Any], None]],
519
599
  process_synchronous_response: Any,
520
- is_streaming: IsStreaming,
600
+ is_streaming: _IsStreaming,
521
601
  wrapped: Any,
522
602
  instance: Any,
523
603
  args: Any,
@@ -588,9 +668,9 @@ class PayiInstrumentor:
588
668
  sw = Stopwatch()
589
669
  stream: bool = False
590
670
 
591
- if is_streaming == IsStreaming.kwargs:
671
+ if is_streaming == _IsStreaming.kwargs:
592
672
  stream = kwargs.get("stream", False)
593
- elif is_streaming == IsStreaming.true:
673
+ elif is_streaming == _IsStreaming.true:
594
674
  stream = True
595
675
  else:
596
676
  stream = False
@@ -649,13 +729,16 @@ class PayiInstrumentor:
649
729
 
650
730
  @staticmethod
651
731
  def _update_headers(
652
- context: Context,
732
+ context: _Context,
653
733
  extra_headers: "dict[str, str]",
654
734
  ) -> None:
655
735
  limit_ids: Optional[list[str]] = context.get("limit_ids")
656
736
  request_tags: Optional[list[str]] = context.get("request_tags")
657
737
  experience_name: Optional[str] = context.get("experience_name")
658
738
  experience_id: Optional[str] = context.get("experience_id")
739
+ use_case_name: Optional[str] = context.get("use_case_name")
740
+ use_case_id: Optional[str] = context.get("use_case_id")
741
+ use_case_version: Optional[int] = context.get("use_case_version")
659
742
  user_id: Optional[str] = context.get("user_id")
660
743
 
661
744
  # Merge limits from the decorator and extra headers
@@ -703,10 +786,35 @@ class PayiInstrumentor:
703
786
  # use the inner experience name and id as-is
704
787
  ...
705
788
 
789
+ # inner extra_headers use_casee_name and use_case_id take precedence over outer decorator use_case_name and use_case_id
790
+ # if either inner value is specified, ignore outer decorator values
791
+ if PayiHeaderNames.use_case_name not in extra_headers and PayiHeaderNames.use_case_id not in extra_headers:
792
+
793
+ # use decorator values
794
+ if use_case_name is not None:
795
+ extra_headers[PayiHeaderNames.use_case_name] = use_case_name
796
+ if use_case_id is not None:
797
+ extra_headers[PayiHeaderNames.use_case_id] = use_case_id
798
+ if use_case_version is not None:
799
+ extra_headers[PayiHeaderNames.use_case_version] = str(use_case_version)
800
+
801
+ elif PayiHeaderNames.use_case_id in extra_headers and PayiHeaderNames.use_case_name not in extra_headers:
802
+ # use the decorator experience name and the inner experience id
803
+ if use_case_name is not None:
804
+ extra_headers[PayiHeaderNames.use_case_name] = use_case_name
805
+
806
+ # use the decorator experience version and the inner experience id
807
+ if use_case_version is not None:
808
+ extra_headers[PayiHeaderNames.use_case_version] = str(use_case_version) # TODO use case
809
+
810
+ else:
811
+ # use the inner experience name and id as-is
812
+ ...
813
+
706
814
  @staticmethod
707
815
  def update_for_vision(input: int, units: 'dict[str, Units]') -> int:
708
- if PayiInstrumentor.estimated_prompt_tokens in units:
709
- prompt_token_estimate: int = units.pop(PayiInstrumentor.estimated_prompt_tokens)["input"] # type: ignore
816
+ if _PayiInstrumentor.estimated_prompt_tokens in units:
817
+ prompt_token_estimate: int = units.pop(_PayiInstrumentor.estimated_prompt_tokens)["input"] # type: ignore
710
818
  vision = input - prompt_token_estimate
711
819
  if (vision > 0):
712
820
  units["vision"] = Units(input=vision, output=0)
@@ -751,7 +859,7 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
751
859
  self,
752
860
  response: Any,
753
861
  instance: Any,
754
- instrumentor: PayiInstrumentor,
862
+ instrumentor: _PayiInstrumentor,
755
863
  ingest: IngestUnitsParams,
756
864
  stopwatch: Stopwatch,
757
865
  process_chunk: Optional[Callable[[Any, IngestUnitsParams], None]] = None,
@@ -885,13 +993,14 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
885
993
  return json.dumps(chunk)
886
994
 
887
995
  global _instrumentor
888
- _instrumentor: Optional[PayiInstrumentor] = None
996
+ _instrumentor: Optional[_PayiInstrumentor] = None
889
997
 
890
998
  def payi_instrument(
891
999
  payi: Optional[Union[Payi, AsyncPayi, 'list[Union[Payi, AsyncPayi]]']] = None,
892
1000
  instruments: Optional[Set[str]] = None,
893
1001
  log_prompt_and_response: bool = True,
894
1002
  prompt_and_response_logger: Optional[Callable[[str, "dict[str, str]"], None]] = None,
1003
+ config: Optional[PayiInstrumentConfig] = None,
895
1004
  ) -> None:
896
1005
  global _instrumentor
897
1006
  if _instrumentor:
@@ -910,10 +1019,21 @@ def payi_instrument(
910
1019
  payi_param = p
911
1020
  elif isinstance(p, AsyncPayi): # type: ignore
912
1021
  apayi_param = p
1022
+
1023
+ global_context: _Context = {}
913
1024
 
914
- # allow for both payi and apayi to be None for the @proxy case
1025
+ if config and len(config) > 0:
1026
+ if "proxy" not in config:
1027
+ config["proxy"] = False
1028
+ global_context = {**config}
1029
+
1030
+ # create the clients on their behalf if not provided for global ingest instrumentation
1031
+ if not payi_param and not apayi_param and len(global_context) > 0 and global_context.get("proxy", False):
1032
+ payi_param = Payi()
1033
+ apayi_param = AsyncPayi()
915
1034
 
916
- _instrumentor = PayiInstrumentor(
1035
+ # allow for both payi and apayi to be None for the @proxy case
1036
+ _instrumentor = _PayiInstrumentor(
917
1037
  payi=payi_param,
918
1038
  apayi=apayi_param,
919
1039
  instruments=instruments,
@@ -921,11 +1041,17 @@ def payi_instrument(
921
1041
  prompt_and_response_logger=prompt_and_response_logger,
922
1042
  )
923
1043
 
1044
+ if len(global_context) > 0:
1045
+ _instrumentor._context_stack.append(global_context)
1046
+
924
1047
  def ingest(
925
1048
  limit_ids: Optional["list[str]"] = None,
926
1049
  request_tags: Optional["list[str]"] = None,
927
1050
  experience_name: Optional[str] = None,
928
1051
  experience_id: Optional[str] = None,
1052
+ use_case_name: Optional[str] = None,
1053
+ use_case_id: Optional[str] = None,
1054
+ use_case_version: Optional[int] = None,
929
1055
  user_id: Optional[str] = None,
930
1056
  ) -> Any:
931
1057
  def _ingest(func: Any) -> Any:
@@ -942,6 +1068,9 @@ def ingest(
942
1068
  request_tags,
943
1069
  experience_name,
944
1070
  experience_id,
1071
+ use_case_name,
1072
+ use_case_id,
1073
+ use_case_version,
945
1074
  user_id,
946
1075
  *args,
947
1076
  **kwargs,
@@ -958,6 +1087,9 @@ def ingest(
958
1087
  request_tags,
959
1088
  experience_name,
960
1089
  experience_id,
1090
+ use_case_name,
1091
+ use_case_id,
1092
+ use_case_version,
961
1093
  user_id,
962
1094
  *args,
963
1095
  **kwargs,
@@ -970,6 +1102,9 @@ def proxy(
970
1102
  request_tags: Optional["list[str]"] = None,
971
1103
  experience_name: Optional[str] = None,
972
1104
  experience_id: Optional[str] = None,
1105
+ use_case_id: Optional[str] = None,
1106
+ use_case_name: Optional[str] = None,
1107
+ use_case_version: Optional[int] = None,
973
1108
  user_id: Optional[str] = None,
974
1109
  ) -> Any:
975
1110
  def _proxy(func: Any) -> Any:
@@ -985,6 +1120,9 @@ def proxy(
985
1120
  request_tags,
986
1121
  experience_name,
987
1122
  experience_id,
1123
+ use_case_name,
1124
+ use_case_id,
1125
+ use_case_version,
988
1126
  user_id,
989
1127
  *args,
990
1128
  **kwargs
@@ -1002,6 +1140,9 @@ def proxy(
1002
1140
  request_tags,
1003
1141
  experience_name,
1004
1142
  experience_id,
1143
+ use_case_name,
1144
+ use_case_id,
1145
+ use_case_version,
1005
1146
  user_id,
1006
1147
  *args,
1007
1148
  **kwargs
payi/pagination.py ADDED
@@ -0,0 +1,50 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ from typing import List, Generic, TypeVar, Optional
4
+ from typing_extensions import override
5
+
6
+ from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage
7
+
8
+ __all__ = ["SyncCursorPage", "AsyncCursorPage"]
9
+
10
+ _T = TypeVar("_T")
11
+
12
+
13
+ class SyncCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
14
+ items: List[_T]
15
+ cursor: Optional[str] = None
16
+
17
+ @override
18
+ def _get_page_items(self) -> List[_T]:
19
+ items = self.items
20
+ if not items:
21
+ return []
22
+ return items
23
+
24
+ @override
25
+ def next_page_info(self) -> Optional[PageInfo]:
26
+ cursor = self.cursor
27
+ if not cursor:
28
+ return None
29
+
30
+ return PageInfo(params={"cursor": cursor})
31
+
32
+
33
+ class AsyncCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
34
+ items: List[_T]
35
+ cursor: Optional[str] = None
36
+
37
+ @override
38
+ def _get_page_items(self) -> List[_T]:
39
+ items = self.items
40
+ if not items:
41
+ return []
42
+ return items
43
+
44
+ @override
45
+ def next_page_info(self) -> Optional[PageInfo]:
46
+ cursor = self.cursor
47
+ if not cursor:
48
+ return None
49
+
50
+ return PageInfo(params={"cursor": cursor})