enkryptai-sdk 1.0.23__py3-none-any.whl → 1.0.25__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.
@@ -0,0 +1,384 @@
1
+ """
2
+ Pagination utilities for Enkrypt AI SDK.
3
+
4
+ This module provides helper functions for handling pagination in API requests and responses.
5
+ """
6
+
7
+ from typing import Dict, Any, List, Optional, Union, Tuple
8
+ from urllib.parse import urlencode, parse_qs, urlparse, urlunparse
9
+ from ..response import PaginationInfo, PaginatedResponse
10
+
11
+
12
+ def parse_pagination_params(
13
+ query_string: str = "",
14
+ default_page: int = 1,
15
+ default_per_page: int = 10
16
+ ) -> PaginationInfo:
17
+ """
18
+ Parse pagination parameters from a query string.
19
+
20
+ Args:
21
+ query_string (str): URL query string (e.g., "page=2&per_page=20")
22
+ default_page (int): Default page number if not specified
23
+ default_per_page (int): Default items per page if not specified
24
+
25
+ Returns:
26
+ PaginationInfo: Parsed pagination information
27
+
28
+ Example:
29
+ >>> parse_pagination_params("page=2&per_page=20")
30
+ PaginationInfo(page=2, per_page=20, total_count=0)
31
+ """
32
+ if not query_string:
33
+ return PaginationInfo(default_page, default_per_page)
34
+
35
+ # Parse query string
36
+ params = parse_qs(query_string)
37
+
38
+ # Extract pagination parameters
39
+ page = params.get("page", [str(default_page)])[0]
40
+ per_page = params.get("per_page", [str(default_per_page)])[0]
41
+
42
+ try:
43
+ page_num = int(page)
44
+ per_page_num = int(per_page)
45
+ except (ValueError, TypeError):
46
+ page_num = default_page
47
+ per_page_num = default_per_page
48
+
49
+ # Validate and create PaginationInfo
50
+ return PaginationInfo(
51
+ page=max(1, page_num),
52
+ per_page=max(1, min(100, per_page_num)),
53
+ total_count=0
54
+ )
55
+
56
+
57
+ def build_pagination_url(
58
+ base_url: str,
59
+ page: int,
60
+ per_page: int,
61
+ **additional_params
62
+ ) -> str:
63
+ """
64
+ Build a URL with pagination parameters.
65
+
66
+ Args:
67
+ base_url (str): Base URL without query parameters
68
+ page (int): Page number
69
+ per_page (int): Items per page
70
+ **additional_params: Additional query parameters
71
+
72
+ Returns:
73
+ str: Complete URL with pagination parameters
74
+
75
+ Example:
76
+ >>> build_pagination_url("https://api.example.com/users", 2, 20, status="active")
77
+ 'https://api.example.com/users?page=2&per_page=20&status=active'
78
+ """
79
+ params = {
80
+ "page": page,
81
+ "per_page": per_page,
82
+ **additional_params
83
+ }
84
+
85
+ # Filter out None values
86
+ params = {k: v for k, v in params.items() if v is not None}
87
+
88
+ query_string = urlencode(params)
89
+ return f"{base_url}?{query_string}" if query_string else base_url
90
+
91
+
92
+ def create_paginated_response(
93
+ data: List[Any],
94
+ total_count: int,
95
+ page: int = 1,
96
+ per_page: int = 10,
97
+ **additional_data
98
+ ) -> PaginatedResponse:
99
+ """
100
+ Create a paginated response object.
101
+
102
+ Args:
103
+ data (List[Any]): List of items for the current page
104
+ total_count (int): Total number of items across all pages
105
+ page (int): Current page number
106
+ per_page (int): Items per page
107
+ **additional_data: Additional data to include in the response
108
+
109
+ Returns:
110
+ PaginatedResponse: Paginated response object
111
+
112
+ Example:
113
+ >>> users = [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]
114
+ >>> response = create_paginated_response(users, 100, 1, 10)
115
+ >>> response.get_page()
116
+ 1
117
+ >>> response.get_total_count()
118
+ 100
119
+ """
120
+ pagination = PaginationInfo(page, per_page, total_count)
121
+ return PaginatedResponse(data, pagination, **additional_data)
122
+
123
+
124
+ def validate_pagination_params(
125
+ page: Union[str, int, None],
126
+ per_page: Union[str, int, None]
127
+ ) -> Tuple[int, int]:
128
+ """
129
+ Validate pagination parameters and return validated values.
130
+
131
+ Args:
132
+ page: Page number (can be string, int, or None)
133
+ per_page: Items per page (can be string, int, or None)
134
+
135
+ Returns:
136
+ Tuple[int, int]: Validated (page, per_page) values
137
+
138
+ Raises:
139
+ ValueError: If parameters are invalid
140
+
141
+ Example:
142
+ >>> validate_pagination_params("2", "20")
143
+ (2, 20)
144
+ >>> validate_pagination_params(None, None)
145
+ (1, 10)
146
+ """
147
+ try:
148
+ page_num = int(page) if page is not None else 1
149
+ per_page_num = int(per_page) if per_page is not None else 10
150
+ except (ValueError, TypeError):
151
+ raise ValueError("Page and per_page must be valid integers")
152
+
153
+ if page_num < 1:
154
+ raise ValueError("Page must be >= 1")
155
+ if per_page_num < 1 or per_page_num > 100:
156
+ raise ValueError("Per_page must be between 1 and 100")
157
+
158
+ return page_num, per_page_num
159
+
160
+
161
+ def get_pagination_metadata(
162
+ total_count: int,
163
+ page: int,
164
+ per_page: int
165
+ ) -> Dict[str, Any]:
166
+ """
167
+ Generate pagination metadata for API responses.
168
+
169
+ Args:
170
+ total_count (int): Total number of items
171
+ page (int): Current page number
172
+ per_page (int): Items per page
173
+
174
+ Returns:
175
+ Dict[str, Any]: Pagination metadata dictionary
176
+
177
+ Example:
178
+ >>> get_pagination_metadata(100, 2, 20)
179
+ {
180
+ 'page': 2,
181
+ 'per_page': 20,
182
+ 'total_count': 100,
183
+ 'total_pages': 5,
184
+ 'has_next': True,
185
+ 'has_previous': True
186
+ }
187
+ """
188
+ pagination = PaginationInfo(page, per_page, total_count)
189
+ return pagination.to_dict()
190
+
191
+
192
+ def calculate_page_info(
193
+ total_count: int,
194
+ page: int,
195
+ per_page: int
196
+ ) -> Dict[str, Any]:
197
+ """
198
+ Calculate detailed pagination information.
199
+
200
+ Args:
201
+ total_count (int): Total number of items
202
+ page (int): Current page number
203
+ per_page (int): Items per page
204
+
205
+ Returns:
206
+ Dict[str, Any]: Detailed pagination information
207
+
208
+ Example:
209
+ >>> calculate_page_info(100, 2, 20)
210
+ {
211
+ 'current_page': 2,
212
+ 'per_page': 20,
213
+ 'total_count': 100,
214
+ 'total_pages': 5,
215
+ 'has_next': True,
216
+ 'has_previous': True,
217
+ 'offset': 20,
218
+ 'limit': 20,
219
+ 'start_item': 21,
220
+ 'end_item': 40
221
+ }
222
+ """
223
+ pagination = PaginationInfo(page, per_page, total_count)
224
+
225
+ start_item = (page - 1) * per_page + 1
226
+ end_item = min(page * per_page, total_count)
227
+
228
+ return {
229
+ 'current_page': pagination.page,
230
+ 'per_page': pagination.per_page,
231
+ 'total_count': pagination.total_count,
232
+ 'total_pages': pagination.total_pages,
233
+ 'has_next': pagination.has_next,
234
+ 'has_previous': pagination.has_previous,
235
+ 'offset': pagination.offset,
236
+ 'limit': pagination.limit,
237
+ 'start_item': start_item if total_count > 0 else 0,
238
+ 'end_item': end_item if total_count > 0 else 0
239
+ }
240
+
241
+
242
+ def create_pagination_links(
243
+ base_url: str,
244
+ current_page: int,
245
+ total_pages: int,
246
+ per_page: int,
247
+ **additional_params
248
+ ) -> Dict[str, Optional[str]]:
249
+ """
250
+ Create pagination links for navigation.
251
+
252
+ Args:
253
+ base_url (str): Base URL for the endpoint
254
+ current_page (int): Current page number
255
+ total_pages (int): Total number of pages
256
+ per_page (int): Items per page
257
+ **additional_params: Additional query parameters
258
+
259
+ Returns:
260
+ Dict[str, Optional[str]]: Dictionary with pagination links
261
+
262
+ Example:
263
+ >>> links = create_pagination_links("https://api.example.com/users", 2, 5, 20)
264
+ >>> links
265
+ {
266
+ 'first': 'https://api.example.com/users?page=1&per_page=20',
267
+ 'previous': 'https://api.example.com/users?page=1&per_page=20',
268
+ 'current': 'https://api.example.com/users?page=2&per_page=20',
269
+ 'next': 'https://api.example.com/users?page=3&per_page=20',
270
+ 'last': 'https://api.example.com/users?page=5&per_page=20'
271
+ }
272
+ """
273
+ links = {}
274
+
275
+ # First page
276
+ links['first'] = build_pagination_url(base_url, 1, per_page, **additional_params)
277
+
278
+ # Previous page
279
+ if current_page > 1:
280
+ links['previous'] = build_pagination_url(base_url, current_page - 1, per_page, **additional_params)
281
+ else:
282
+ links['previous'] = None
283
+
284
+ # Current page
285
+ links['current'] = build_pagination_url(base_url, current_page, per_page, **additional_params)
286
+
287
+ # Next page
288
+ if current_page < total_pages:
289
+ links['next'] = build_pagination_url(base_url, current_page + 1, per_page, **additional_params)
290
+ else:
291
+ links['next'] = None
292
+
293
+ # Last page
294
+ if total_pages > 0:
295
+ links['last'] = build_pagination_url(base_url, total_pages, per_page, **additional_params)
296
+ else:
297
+ links['last'] = None
298
+
299
+ return links
300
+
301
+
302
+ def apply_pagination_to_list(
303
+ data: List[Any],
304
+ page: int,
305
+ per_page: int
306
+ ) -> Tuple[List[Any], int]:
307
+ """
308
+ Apply pagination to a list of data.
309
+
310
+ Args:
311
+ data (List[Any]): Complete list of data
312
+ page (int): Page number (1-based)
313
+ per_page (int): Items per page
314
+
315
+ Returns:
316
+ Tuple[List[Any], int]: (paginated_data, total_count)
317
+
318
+ Example:
319
+ >>> all_users = [{"id": i, "name": f"User{i}"} for i in range(1, 101)]
320
+ >>> page_data, total = apply_pagination_to_list(all_users, 2, 20)
321
+ >>> len(page_data)
322
+ 20
323
+ >>> total
324
+ 100
325
+ """
326
+ total_count = len(data)
327
+ start_index = (page - 1) * per_page
328
+ end_index = start_index + per_page
329
+
330
+ paginated_data = data[start_index:end_index]
331
+ return paginated_data, total_count
332
+
333
+
334
+ def format_pagination_response(
335
+ data: List[Any],
336
+ total_count: int,
337
+ page: int,
338
+ per_page: int,
339
+ include_links: bool = True,
340
+ base_url: str = "",
341
+ **additional_data
342
+ ) -> Dict[str, Any]:
343
+ """
344
+ Format a complete paginated response.
345
+
346
+ Args:
347
+ data (List[Any]): List of items for the current page
348
+ total_count (int): Total number of items
349
+ page (int): Current page number
350
+ per_page (int): Items per page
351
+ include_links (bool): Whether to include pagination links
352
+ base_url (str): Base URL for generating pagination links
353
+ **additional_data: Additional data to include
354
+
355
+ Returns:
356
+ Dict[str, Any]: Formatted paginated response
357
+
358
+ Example:
359
+ >>> response = format_pagination_response(
360
+ ... [{"id": 1, "name": "John"}],
361
+ ... 100, 1, 10,
362
+ ... base_url="https://api.example.com/users"
363
+ ... )
364
+ >>> response.keys()
365
+ dict_keys(['data', 'pagination', 'links'])
366
+ """
367
+ # Create pagination metadata
368
+ pagination = get_pagination_metadata(total_count, page, per_page)
369
+
370
+ # Build response
371
+ response = {
372
+ "data": data,
373
+ "pagination": pagination,
374
+ **additional_data
375
+ }
376
+
377
+ # Add pagination links if requested
378
+ if include_links and base_url:
379
+ links = create_pagination_links(
380
+ base_url, page, pagination['total_pages'], per_page
381
+ )
382
+ response["links"] = links
383
+
384
+ return response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: enkryptai-sdk
3
- Version: 1.0.23
3
+ Version: 1.0.25
4
4
  Summary: A Python SDK with guardrails and red teaming functionality for API interactions
5
5
  Home-page: https://github.com/enkryptai/enkryptai-sdk
6
6
  Author: Enkrypt AI Team
@@ -1,4 +1,4 @@
1
- enkryptai_sdk/__init__.py,sha256=8H5tznmjirTVdrTmrsyU6fNVRj3-UC0nrTGkzfFp0h0,845
1
+ enkryptai_sdk/__init__.py,sha256=uwIMVg_MDFmp7khURZt4nSOPVdZlwqK_s4pGhv8yzCw,2111
2
2
  enkryptai_sdk/ai_proxy.py,sha256=ot1lqKk2LjcvlpnFm2kSA51vFThfquVlx86BhSbAzBo,3823
3
3
  enkryptai_sdk/base.py,sha256=KonezvdjVzIr3gw75grzcCNyhzI_sHXi-Cb9tRJgSDE,3277
4
4
  enkryptai_sdk/coc.py,sha256=5rq9LhZX-uvCmX8fM6JEndIEvd8rSzsSfDFnTvSvTQE,7396
@@ -9,9 +9,9 @@ enkryptai_sdk/evals.py,sha256=BywyEgIT7xdJ58svO_sDNOMVowdB0RTGoAZPEbCnDVo,2595
9
9
  enkryptai_sdk/guardrails.py,sha256=iEngSpkzZBB3EkJGxUxUgYF0Av4N2XWMN-BlAkRDle4,19856
10
10
  enkryptai_sdk/guardrails_old.py,sha256=SgzPZkTzbAPD9XfmYNG6M1-TrzbhDHpAkI3FjnVWS_s,6434
11
11
  enkryptai_sdk/models.py,sha256=0R0I4KOq0aDNi5utabANot-E8dT9GqiSsgrcI9RULHM,8932
12
- enkryptai_sdk/red_team.py,sha256=w52gPteGaH6iEBThjIYxLAV1bXXTorgxST_TOnGMT88,20917
13
- enkryptai_sdk/response.py,sha256=43JRubzgGCpoVxYNzBZY0AlUgLbfcXD_AwD7wU3qY9o,4086
14
- enkryptai_sdk/dto/__init__.py,sha256=wHgIv_OCnVMJOys-vqImF59ifogDrMcgxVRmfNayVvc,2761
12
+ enkryptai_sdk/red_team.py,sha256=BbL_GRbkU_zqJuF6tPgXHhLGhq4Ri_RQmxzyO2X8wQ0,28756
13
+ enkryptai_sdk/response.py,sha256=2WOyejMYK7lA7I3fyebd0oYhP4js5Q1favJAV_h9pmo,13604
14
+ enkryptai_sdk/dto/__init__.py,sha256=hBN523YIkuHCvLTrkPu9ipGwAyLDnhV9sb3rKNpRajg,3061
15
15
  enkryptai_sdk/dto/ai_proxy.py,sha256=clwMN4xdH8Zr55dnhilHbs-qaHRlCOrLPrij0Zd1Av0,11283
16
16
  enkryptai_sdk/dto/base.py,sha256=y77kQL1X7389ifSVNc0E7CUFNxACh5AM3ml9YPon1KY,2822
17
17
  enkryptai_sdk/dto/coc.py,sha256=9D5mmSdmC_guV75ml48PPLZD_zFa5FjxRwlTqHrmdak,5071
@@ -19,10 +19,12 @@ enkryptai_sdk/dto/common.py,sha256=lrWMu4FKUGCN2dbS9fT4yNtfiPm1cNN16J4eCe4_tBM,1
19
19
  enkryptai_sdk/dto/datasets.py,sha256=FiVwbEZ04jPajnlBfgw1Aj83iAhup3Ut7GOymq73OMg,5073
20
20
  enkryptai_sdk/dto/deployments.py,sha256=v--UrwkuXP4xTsPbmVruYj-g3JEQXepBRQfr-Gsv3aA,11744
21
21
  enkryptai_sdk/dto/guardrails.py,sha256=n73uPmK9fCIqqxv1rNecYUX4v5ePdIjxSBD4jIhwDe8,55966
22
- enkryptai_sdk/dto/models.py,sha256=AwqYMBZckJ0RdeU89I-3CYJ03c-VLdHf5zD5PSbU3JQ,14585
23
- enkryptai_sdk/dto/red_team.py,sha256=rV7bYVb5YSxnrhLwNiTlKWy0ZTXK4zhmPgVoLJQMMoo,28802
24
- enkryptai_sdk-1.0.23.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- enkryptai_sdk-1.0.23.dist-info/METADATA,sha256=CMSsEyEBXxGhIciL2JgGg2slVeEbxw9OeLRpVtUp1qM,1644
26
- enkryptai_sdk-1.0.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- enkryptai_sdk-1.0.23.dist-info/top_level.txt,sha256=s2X9UJJwvJamNmr6ZXWyyQe60sXtQGWFuaBYfhgHI_4,14
28
- enkryptai_sdk-1.0.23.dist-info/RECORD,,
22
+ enkryptai_sdk/dto/models.py,sha256=upzoQlyA7-isf0DsuabDw1CfqzZXLOhkcj7jV5cnj4Q,16175
23
+ enkryptai_sdk/dto/red_team.py,sha256=NwE6Ed7dpSvcx3ioin6B8iCglQWD5rtKFJwDVfKQnLM,38456
24
+ enkryptai_sdk/utils/__init__.py,sha256=SII0dz9SesrXt2zOR1xXErPYZGj3WyC9A9Pn_eOLsOg,710
25
+ enkryptai_sdk/utils/pagination.py,sha256=5t9qiDdxRA4uQywU4I4pp9OScqNBrEPmzKlPG-b-eVE,11149
26
+ enkryptai_sdk-1.0.25.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ enkryptai_sdk-1.0.25.dist-info/METADATA,sha256=tdfbJ017FU2zkAS1nSN8-l8h2Ve1E_pk8KNxOZH1tSw,1644
28
+ enkryptai_sdk-1.0.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
+ enkryptai_sdk-1.0.25.dist-info/top_level.txt,sha256=s2X9UJJwvJamNmr6ZXWyyQe60sXtQGWFuaBYfhgHI_4,14
30
+ enkryptai_sdk-1.0.25.dist-info/RECORD,,