1
1
from abc import ABC , abstractmethod
2
+ from collections import namedtuple
2
3
3
4
4
5
class PageIterator :
5
- def __init__ (self , paginator ):
6
+ def __init__ (self , paginator , yield_first_page = False ):
6
7
self .paginator = paginator
8
+ self .yield_first_page = yield_first_page
9
+ # If yielding the first page, set started to False
10
+ self .started = not yield_first_page
7
11
8
12
def __iter__ (self ):
9
13
return self
10
14
11
15
def __next__ (self ):
16
+ if not self .started :
17
+ self .started = True
18
+ return self .paginator
19
+
12
20
if self .paginator .has_next_page :
13
21
return self .paginator .next_page ()
14
22
else :
@@ -113,32 +121,118 @@ async def _initialize(cls, sinch, endpoint):
113
121
return cls (sinch , endpoint , result )
114
122
115
123
116
- class TokenBasedPaginator (Paginator ):
117
- __doc__ = Paginator .__doc__
124
+ class TokenBasedPaginatorBase (Paginator ):
125
+ """Base paginator for token-based pagination."""
126
+
127
+ def __init__ (self , sinch , endpoint , yield_first_page = False , result = None ):
128
+ self ._sinch = sinch
129
+ self .endpoint = endpoint
130
+ # Determines if the first page should be included
131
+ self .yield_first_page = yield_first_page
132
+ self .result = result or self ._sinch .configuration .transport .request (self .endpoint )
133
+ self .has_next_page = bool (self .result .next_page_token )
134
+
135
+ def __repr__ (self ):
136
+ pass
118
137
119
138
def _calculate_next_page (self ):
120
- if self .result .next_page_token :
121
- self .has_next_page = True
122
- else :
123
- self .has_next_page = False
139
+ self .has_next_page = bool (self .result .next_page_token )
124
140
125
141
def next_page (self ):
142
+ """Fetches the next page and updates pagination state."""
126
143
self .endpoint .request_data .page_token = self .result .next_page_token
127
144
self .result = self ._sinch .configuration .transport .request (self .endpoint )
128
145
self ._calculate_next_page ()
129
146
return self
130
147
131
148
def auto_paging_iter (self ):
132
- return PageIterator (self )
149
+ """Returns an iterator for automatic pagination."""
150
+ return PageIterator (self , yield_first_page = self .yield_first_page )
133
151
134
152
@classmethod
135
153
def _initialize (cls , sinch , endpoint ):
154
+ """Creates an instance of the paginator skipping first page."""
136
155
result = sinch .configuration .transport .request (endpoint )
137
- return cls (sinch , endpoint , result )
156
+ return cls (sinch , endpoint , yield_first_page = False , result = result )
138
157
139
158
140
- class AsyncTokenBasedPaginator (TokenBasedPaginator ):
141
- __doc__ = TokenBasedPaginator .__doc__
159
+ class TokenBasedPaginator (TokenBasedPaginatorBase ):
160
+ """Paginator that skips the first page."""
161
+ pass
162
+
163
+
164
+ class TokenBasedPaginatorNumbers (TokenBasedPaginatorBase ):
165
+ """
166
+ Paginator for handling token-based pagination specifically for phone numbers.
167
+
168
+ This paginator is designed to iterate through phone numbers automatically or manually, fetching new pages as needed.
169
+ It extends the TokenBasedPaginatorBase class and provides additional methods for number-specific pagination.
170
+ """
171
+
172
+ def __init__ (self , sinch , endpoint ):
173
+ super ().__init__ (sinch , endpoint , yield_first_page = True )
174
+
175
+ def numbers_iterator (self ):
176
+ """Iterates through numbers individually, fetching new pages as needed."""
177
+ while True :
178
+ if self .result and self .result .active_numbers :
179
+ yield from self .result .active_numbers
180
+
181
+ if not self .has_next_page :
182
+ break
183
+
184
+ self .next_page ()
185
+
186
+ def list (self ):
187
+ """Returns the first page's numbers along with pagination metadata."""
188
+
189
+ PagedListResponse = namedtuple (
190
+ "PagedResponse" , ["result" , "has_next_page" , "next_page_info" , "next_page" ]
191
+ )
192
+
193
+ next_page_result = self ._get_next_page_result ()
194
+
195
+ return PagedListResponse (
196
+ result = self .result .active_numbers ,
197
+ has_next_page = self .has_next_page ,
198
+ next_page_info = self ._build_next_pagination_info (next_page_result ),
199
+ next_page = self ._next_page_wrapper ()
200
+ )
201
+
202
+ def _get_next_page_result (self ):
203
+ """Fetches the next page result."""
204
+ if not self .has_next_page :
205
+ return None
206
+
207
+ current_state = self .result
208
+ self .next_page ()
209
+ next_page_result = self .result
210
+ self .result = current_state
211
+
212
+ return next_page_result
213
+
214
+ def _build_next_pagination_info (self , next_page_result ):
215
+ """Constructs and returns structured pagination metadata."""
216
+ return {
217
+ "result" : self .result .active_numbers ,
218
+ "result.next" : (
219
+ self .result .active_numbers + next_page_result .active_numbers
220
+ if next_page_result else self .result .active_numbers
221
+ ),
222
+ "has_next_page" : self .has_next_page ,
223
+ "has_next_page.next" : bool (next_page_result and next_page_result .next_page_token ),
224
+ }
225
+
226
+ def _next_page_wrapper (self ):
227
+ """Fetches and returns the next page as a formatted PagedListResponse object."""
228
+ def wrapper ():
229
+ self .next_page ()
230
+ return self .list ()
231
+ return wrapper
232
+
233
+
234
+ class AsyncTokenBasedPaginator (TokenBasedPaginatorBase ):
235
+ """Asynchronous token-based paginator."""
142
236
143
237
async def next_page (self ):
144
238
self .endpoint .request_data .page_token = self .result .next_page_token
@@ -152,4 +246,4 @@ def auto_paging_iter(self):
152
246
@classmethod
153
247
async def _initialize (cls , sinch , endpoint ):
154
248
result = await sinch .configuration .transport .request (endpoint )
155
- return cls (sinch , endpoint , result )
249
+ return cls (sinch , endpoint , result = result )
0 commit comments