Skip to content

Commit 06d3675

Browse files
committed
refactors the code based from doc blocks perspective
1 parent 6b082e6 commit 06d3675

9 files changed

Lines changed: 288 additions & 56 deletions

File tree

apimatic_core/pagination/configuration/cursor_pagination.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,29 @@
33

44

55
class CursorPagination(PaginationStrategy):
6+
"""
7+
Implements a cursor-based pagination strategy for API responses.
8+
9+
This class manages the extraction and injection of cursor values between API requests and responses,
10+
enabling seamless traversal of paginated data. It validates required pointers, updates the request builder
11+
with the appropriate cursor, and applies a metadata wrapper to paged responses.
12+
"""
613

714
def __init__(self, output, input_, metadata_wrapper):
15+
"""
16+
Initializes a CursorPagination instance with the specified output and input pointers and a metadata wrapper.
17+
18+
Validates that both input and output pointers are provided,
19+
and sets up internal state for cursor-based pagination.
20+
21+
Args:
22+
output: JSON pointer to extract the cursor from the API response.
23+
input_: JSON pointer indicating where to set the cursor in the request.
24+
metadata_wrapper: Function to wrap paged responses with additional metadata.
25+
26+
Raises:
27+
ValueError: If either input_ or output is None.
28+
"""
829
super().__init__(metadata_wrapper)
930

1031
if input_ is None:
@@ -17,6 +38,19 @@ def __init__(self, output, input_, metadata_wrapper):
1738
self._cursor_value = None
1839

1940
def apply(self, paginated_data):
41+
"""
42+
Advances the pagination by updating the request builder with the next cursor value.
43+
44+
If there is no previous response, initializes the cursor from the request builder.
45+
Otherwise, extracts the cursor from the last response using the configured output pointer,
46+
and updates the request builder for the next page. Returns None if no further pages are available.
47+
48+
Args:
49+
paginated_data: An object containing the last response and the current request builder.
50+
51+
Returns:
52+
A new request builder for the next page, or None if pagination is complete.
53+
"""
2054
last_response = paginated_data.last_response
2155
request_builder = paginated_data.request_builder
2256

@@ -36,10 +70,29 @@ def apply(self, paginated_data):
3670
return self.get_updated_request_builder(request_builder, self._input, self._cursor_value)
3771

3872
def apply_metadata_wrapper(self, paged_response):
73+
"""
74+
Applies the configured metadata wrapper to the paged response, including the current cursor value.
75+
76+
Args:
77+
paged_response: The response object from the current page.
78+
79+
Returns:
80+
The result of the metadata wrapper applied to the paged response and cursor value.
81+
"""
3982
return self._metadata_wrapper(paged_response, self._cursor_value)
4083

4184
@staticmethod
4285
def _get_initial_cursor_value(request_builder, input_pointer):
86+
"""
87+
Retrieves the initial cursor value from the request builder using the specified input pointer.
88+
89+
Args:
90+
request_builder: The request builder containing request parameters.
91+
input_pointer (str): The JSON pointer indicating the location of the cursor value.
92+
93+
Returns:
94+
The initial cursor value if found, otherwise None.
95+
"""
4396
path_prefix, field_path = ApiHelper.split_into_parts(input_pointer)
4497

4598
if path_prefix == "$request.path":

apimatic_core/pagination/configuration/link_pagination.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,24 @@
44

55

66
class LinkPagination(PaginationStrategy):
7-
"""Pagination manager implementation for link-based pagination."""
7+
"""
8+
Implements a pagination strategy that extracts the next page link from API responses using a JSON pointer.
9+
10+
This class updates the request builder with query parameters from the next page link and applies a metadata
11+
wrapper to the paged response.
12+
"""
813

914
def __init__(self, next_link_pointer, metadata_wrapper):
15+
"""
16+
Initializes a LinkPagination instance with the given next link pointer and metadata wrapper.
17+
18+
Args:
19+
next_link_pointer: JSON pointer to extract the next page link from the API response.
20+
metadata_wrapper: Callable to wrap the paged response metadata.
21+
22+
Raises:
23+
ValueError: If next_link_pointer is None.
24+
"""
1025
super().__init__(metadata_wrapper)
1126

1227
if next_link_pointer is None:
@@ -16,6 +31,17 @@ def __init__(self, next_link_pointer, metadata_wrapper):
1631
self._next_link = None
1732

1833
def apply(self, paginated_data):
34+
"""
35+
Updates the request builder with query parameters from the next page
36+
link extracted from the last API response.
37+
38+
Args:
39+
paginated_data: An object containing the last API response and the current request builder.
40+
41+
Returns:
42+
A new request builder instance with updated query parameters for the next page,
43+
or None if no next link is found.
44+
"""
1945
last_response = paginated_data.last_response
2046
request_builder = paginated_data.request_builder
2147

@@ -40,4 +66,13 @@ def apply(self, paginated_data):
4066
)
4167

4268
def apply_metadata_wrapper(self, paged_response):
69+
"""
70+
Applies the metadata wrapper to the paged response, including the next page link.
71+
72+
Args:
73+
paged_response: The API response object for the current page.
74+
75+
Returns:
76+
The result of the metadata wrapper, typically containing the response and next link information.
77+
"""
4378
return self._metadata_wrapper(paged_response, self._next_link)

apimatic_core/pagination/configuration/offset_pagination.py

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,24 @@
44

55

66
class OffsetPagination(PaginationStrategy):
7-
"""Pagination manager implementation for offset-based pagination."""
7+
"""
8+
Implements offset-based pagination strategy for API responses.
9+
10+
This class manages pagination by updating an offset parameter in the request builder,
11+
allowing sequential retrieval of paginated data. It extracts and updates the offset
12+
based on a configurable JSON pointer and applies a metadata wrapper to each page response.
13+
"""
814

915
def __init__(self, input_, metadata_wrapper):
1016
"""
11-
Initializes a new instance of the OffsetPagination class.
17+
Initializes an OffsetPagination instance with the given input pointer and metadata wrapper.
1218
1319
Args:
14-
input_ (str): JSON pointer to the request field representing the offset.
20+
input_: JSON pointer indicating the pagination parameter to update.
21+
metadata_wrapper: Callable for handling pagination metadata.
22+
23+
Raises:
24+
ValueError: If input_ is None.
1525
"""
1626
super().__init__(metadata_wrapper)
1727

@@ -22,6 +32,18 @@ def __init__(self, input_, metadata_wrapper):
2232
self._offset = 0
2333

2434
def apply(self, paginated_data):
35+
"""
36+
Updates the request builder to fetch the next page of results using offset-based pagination.
37+
38+
If this is the first page, initializes the offset from the request builder. Otherwise,
39+
increments the offset by the previous page size and updates the pagination parameter.
40+
41+
Args:
42+
paginated_data: The PaginatedData instance containing the last response, request builder, and page size.
43+
44+
Returns:
45+
An updated request builder configured for the next page request.
46+
"""
2547
last_response = paginated_data.last_response
2648
request_builder = paginated_data.request_builder
2749
last_page_size = paginated_data.page_size
@@ -35,9 +57,28 @@ def apply(self, paginated_data):
3557
return self.get_updated_request_builder(request_builder, self._input, self._offset)
3658

3759
def apply_metadata_wrapper(self, page_response):
60+
"""
61+
Applies the metadata wrapper to the given page response, passing the current offset.
62+
63+
Args:
64+
page_response: The response object for the current page.
65+
66+
Returns:
67+
The result of the metadata wrapper callable with the page response and offset.
68+
"""
3869
return self._metadata_wrapper(page_response, self._offset)
3970

4071
def _get_initial_offset(self, request_builder):
72+
"""
73+
Determines the initial offset value for pagination by extracting it from the request builder
74+
based on the configured JSON pointer input.
75+
76+
Args:
77+
request_builder: The request builder containing path, query, and header parameters.
78+
79+
Returns:
80+
int: The initial offset value extracted from the appropriate request parameter, or 0 if not found.
81+
"""
4182
path_prefix, field_path = ApiHelper.split_into_parts(self._input)
4283

4384
if path_prefix == "$request.path":

apimatic_core/pagination/configuration/page_pagination.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,25 @@
22
from apimatic_core.utilities.api_helper import ApiHelper
33

44
class PagePagination(PaginationStrategy):
5+
"""
6+
Implements a page-based pagination strategy for API requests.
7+
8+
This class manages pagination by updating the request builder with the appropriate page number,
9+
using a JSON pointer to identify the pagination parameter. It also applies a metadata wrapper
10+
to each paged response, including the current page number.
11+
"""
512

613
def __init__(self, input_, metadata_wrapper):
14+
"""
15+
Initializes a PagePagination instance with the given input pointer and metadata wrapper.
16+
17+
Args:
18+
input_: The JSON pointer indicating the pagination parameter in the request.
19+
metadata_wrapper: A callable for wrapping pagination metadata.
20+
21+
Raises:
22+
ValueError: If input_ is None.
23+
"""
724
super().__init__(metadata_wrapper)
825

926
if input_ is None:
@@ -13,6 +30,15 @@ def __init__(self, input_, metadata_wrapper):
1330
self._page_number = 1
1431

1532
def apply(self, paginated_data):
33+
"""
34+
Updates the request builder to fetch the next page of results based on the current paginated data.
35+
36+
Args:
37+
paginated_data: An object containing the last response, request builder, and page size.
38+
39+
Returns:
40+
The updated request builder configured for the next page request.
41+
"""
1642
last_response = paginated_data.last_response
1743
request_builder = paginated_data.request_builder
1844
last_page_size = paginated_data.page_size
@@ -25,9 +51,28 @@ def apply(self, paginated_data):
2551
return self.get_updated_request_builder(request_builder, self._input, self._page_number)
2652

2753
def apply_metadata_wrapper(self, paged_response):
54+
"""
55+
Applies the metadata wrapper to the paged response, including the current page number.
56+
57+
Args:
58+
paged_response: The response object for the current page.
59+
60+
Returns:
61+
The result of the metadata wrapper with the paged response and current page number.
62+
"""
2863
return self._metadata_wrapper(paged_response, self._page_number)
2964

3065
def _get_initial_page_offset(self, request_builder):
66+
"""
67+
Determines the initial page offset for pagination by extracting the value from the request builder
68+
based on the configured JSON pointer. Returns 1 if the value is missing or invalid.
69+
70+
Args:
71+
request_builder: The request builder containing path, query, and header parameters.
72+
73+
Returns:
74+
int: The initial page offset value.
75+
"""
3176
path_prefix, field_path = ApiHelper.split_into_parts(self._input)
3277

3378
try:

apimatic_core/pagination/paginated_data.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,49 @@
33
import copy
44

55
class PaginatedData(Iterator):
6+
"""
7+
Iterator class for handling paginated API responses.
8+
9+
Provides methods to iterate over items and pages, fetch next pages using defined pagination strategies,
10+
and access the latest HTTP response and request builder. Supports independent iterators for concurrent traversals.
11+
"""
612

713
@property
814
def last_response(self):
15+
"""
16+
Returns the most recent HTTP response received during pagination.
17+
"""
918
return self._http_call_context.response
1019

1120
@property
1221
def request_builder(self):
22+
"""
23+
Returns the appropriate request builder for the current pagination state.
24+
"""
1325
if self.last_response is None:
1426
return self._initial_request_builder
1527

1628
return self._api_call.request_builder
1729

1830
@property
1931
def page_size(self):
32+
"""
33+
Returns the number of items in the current page of paginated results.
34+
"""
2035
return self._page_size
2136

2237
def __init__(self, api_call, paginated_items_converter):
38+
"""
39+
Initializes a PaginatedData instance with the given API call and item converter.
40+
41+
Deep copies the API call, sets up pagination strategies, HTTP call context, and global configuration.
42+
Raises:
43+
ValueError: If paginated_items_converter is None.
2344
45+
Args:
46+
api_call: The API call object to paginate.
47+
paginated_items_converter: Function to convert paginated response bodies into items.
48+
"""
2449
if paginated_items_converter is None:
2550
raise ValueError('paginated_items_converter cannot be None')
2651

@@ -40,9 +65,17 @@ def __init__(self, api_call, paginated_items_converter):
4065
self._current_index = 0
4166

4267
def __iter__(self):
68+
"""
69+
Returns a new independent iterator instance for paginated data traversal.
70+
"""
4371
return self._get_new_self_instance()
4472

4573
def __next__(self):
74+
"""
75+
Returns the next item in the paginated data sequence.
76+
77+
Fetches the next page if the current page is exhausted. Raises StopIteration when no more items are available.
78+
"""
4679
if self._current_index < self.page_size:
4780
item = self._items[self._current_index]
4881
self._current_index += 1
@@ -59,7 +92,10 @@ def __next__(self):
5992

6093
def pages(self):
6194
"""
62-
Generator to iterate over pages instead of items.
95+
Yields each page of the paginated response as an independent generator.
96+
97+
Returns:
98+
Generator yielding HTTP response objects for each page.
6399
"""
64100
# Create a new instance so the page iteration is independent
65101
paginated_data = self._get_new_self_instance()
@@ -73,6 +109,19 @@ def pages(self):
73109
yield paginated_data._paged_response
74110

75111
def _fetch_next_page(self):
112+
"""
113+
Fetches the next page of paginated data using available pagination strategies.
114+
115+
Attempts each strategy to build the next request, executes the API call,
116+
and applies any response metadata wrappers.
117+
Returns an empty list if no further pages are available.
118+
119+
Returns:
120+
The processed response object for the next page, or an empty list if pagination is complete.
121+
122+
Raises:
123+
Exception: Propagates any exceptions encountered during the API call execution.
124+
"""
76125
for pagination_strategy in self._pagination_strategies:
77126
request_builder = pagination_strategy.apply(self)
78127
if request_builder is None:
@@ -87,6 +136,13 @@ def _fetch_next_page(self):
87136
return []
88137

89138
def _get_new_self_instance(self):
139+
"""
140+
Creates and returns a new independent PaginatedData instance with the initial
141+
request builder and item converter.
142+
143+
Returns:
144+
PaginatedData: A fresh iterator instance for independent pagination traversal.
145+
"""
90146
return PaginatedData(
91147
self._api_call.clone(request_builder=self._initial_request_builder),
92148
self._paginated_items_converter

0 commit comments

Comments
 (0)