@@ -112,27 +112,39 @@ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
112
112
)
113
113
if isinstance (self .url_base , str ):
114
114
self .url_base = InterpolatedString (string = self .url_base , parameters = parameters )
115
- self ._token : Optional [Any ] = self .pagination_strategy .initial_token
115
+
116
+ def get_initial_token (self ) -> Optional [Any ]:
117
+ """
118
+ Return the page token that should be used for the first request of a stream
119
+
120
+ WARNING: get_initial_token() should not be used by streams that use RFR that perform checkpointing
121
+ of state using page numbers. Because paginators are stateless
122
+ """
123
+ return self .pagination_strategy .initial_token
116
124
117
125
def next_page_token (
118
- self , response : requests .Response , last_page_size : int , last_record : Optional [Record ]
126
+ self ,
127
+ response : requests .Response ,
128
+ last_page_size : int ,
129
+ last_record : Optional [Record ],
130
+ last_page_token_value : Optional [Any ] = None ,
119
131
) -> Optional [Mapping [str , Any ]]:
120
- self ._token = self .pagination_strategy .next_page_token (
121
- response , last_page_size , last_record
132
+ next_page_token = self .pagination_strategy .next_page_token (
133
+ response = response ,
134
+ last_page_size = last_page_size ,
135
+ last_record = last_record ,
136
+ last_page_token_value = last_page_token_value ,
122
137
)
123
- if self . _token :
124
- return {"next_page_token" : self . _token }
138
+ if next_page_token :
139
+ return {"next_page_token" : next_page_token }
125
140
else :
126
141
return None
127
142
128
- def path (self ) -> Optional [str ]:
129
- if (
130
- self ._token
131
- and self .page_token_option
132
- and isinstance (self .page_token_option , RequestPath )
133
- ):
143
+ def path (self , next_page_token : Optional [Mapping [str , Any ]]) -> Optional [str ]:
144
+ token = next_page_token .get ("next_page_token" ) if next_page_token else None
145
+ if token and self .page_token_option and isinstance (self .page_token_option , RequestPath ):
134
146
# Replace url base to only return the path
135
- return str (self . _token ).replace (self .url_base .eval (self .config ), "" ) # type: ignore # url_base is casted to a InterpolatedString in __post_init__
147
+ return str (token ).replace (self .url_base .eval (self .config ), "" ) # type: ignore # url_base is casted to a InterpolatedString in __post_init__
136
148
else :
137
149
return None
138
150
@@ -143,7 +155,7 @@ def get_request_params(
143
155
stream_slice : Optional [StreamSlice ] = None ,
144
156
next_page_token : Optional [Mapping [str , Any ]] = None ,
145
157
) -> MutableMapping [str , Any ]:
146
- return self ._get_request_options (RequestOptionType .request_parameter )
158
+ return self ._get_request_options (RequestOptionType .request_parameter , next_page_token )
147
159
148
160
def get_request_headers (
149
161
self ,
@@ -152,7 +164,7 @@ def get_request_headers(
152
164
stream_slice : Optional [StreamSlice ] = None ,
153
165
next_page_token : Optional [Mapping [str , Any ]] = None ,
154
166
) -> Mapping [str , str ]:
155
- return self ._get_request_options (RequestOptionType .header )
167
+ return self ._get_request_options (RequestOptionType .header , next_page_token )
156
168
157
169
def get_request_body_data (
158
170
self ,
@@ -161,7 +173,7 @@ def get_request_body_data(
161
173
stream_slice : Optional [StreamSlice ] = None ,
162
174
next_page_token : Optional [Mapping [str , Any ]] = None ,
163
175
) -> Mapping [str , Any ]:
164
- return self ._get_request_options (RequestOptionType .body_data )
176
+ return self ._get_request_options (RequestOptionType .body_data , next_page_token )
165
177
166
178
def get_request_body_json (
167
179
self ,
@@ -170,25 +182,21 @@ def get_request_body_json(
170
182
stream_slice : Optional [StreamSlice ] = None ,
171
183
next_page_token : Optional [Mapping [str , Any ]] = None ,
172
184
) -> Mapping [str , Any ]:
173
- return self ._get_request_options (RequestOptionType .body_json )
174
-
175
- def reset (self , reset_value : Optional [Any ] = None ) -> None :
176
- if reset_value :
177
- self .pagination_strategy .reset (reset_value = reset_value )
178
- else :
179
- self .pagination_strategy .reset ()
180
- self ._token = self .pagination_strategy .initial_token
185
+ return self ._get_request_options (RequestOptionType .body_json , next_page_token )
181
186
182
- def _get_request_options (self , option_type : RequestOptionType ) -> MutableMapping [str , Any ]:
187
+ def _get_request_options (
188
+ self , option_type : RequestOptionType , next_page_token : Optional [Mapping [str , Any ]]
189
+ ) -> MutableMapping [str , Any ]:
183
190
options = {}
184
191
192
+ token = next_page_token .get ("next_page_token" ) if next_page_token else None
185
193
if (
186
194
self .page_token_option
187
- and self . _token is not None
195
+ and token is not None
188
196
and isinstance (self .page_token_option , RequestOption )
189
197
and self .page_token_option .inject_into == option_type
190
198
):
191
- options [self .page_token_option .field_name .eval (config = self .config )] = self . _token # type: ignore # field_name is always cast to an interpolated string
199
+ options [self .page_token_option .field_name .eval (config = self .config )] = token # type: ignore # field_name is always cast to an interpolated string
192
200
if (
193
201
self .page_size_option
194
202
and self .pagination_strategy .get_page_size ()
@@ -204,6 +212,9 @@ class PaginatorTestReadDecorator(Paginator):
204
212
"""
205
213
In some cases, we want to limit the number of requests that are made to the backend source. This class allows for limiting the number of
206
214
pages that are queried throughout a read command.
215
+
216
+ WARNING: This decorator is not currently thread-safe like the rest of the low-code framework because it has
217
+ an internal state to track the current number of pages counted so that it can exit early during a test read
207
218
"""
208
219
209
220
_PAGE_COUNT_BEFORE_FIRST_NEXT_CALL = 1
@@ -217,17 +228,27 @@ def __init__(self, decorated: Paginator, maximum_number_of_pages: int = 5) -> No
217
228
self ._decorated = decorated
218
229
self ._page_count = self ._PAGE_COUNT_BEFORE_FIRST_NEXT_CALL
219
230
231
+ def get_initial_token (self ) -> Optional [Any ]:
232
+ self ._page_count = self ._PAGE_COUNT_BEFORE_FIRST_NEXT_CALL
233
+ return self ._decorated .get_initial_token ()
234
+
220
235
def next_page_token (
221
- self , response : requests .Response , last_page_size : int , last_record : Optional [Record ]
236
+ self ,
237
+ response : requests .Response ,
238
+ last_page_size : int ,
239
+ last_record : Optional [Record ],
240
+ last_page_token_value : Optional [Any ] = None ,
222
241
) -> Optional [Mapping [str , Any ]]:
223
242
if self ._page_count >= self ._maximum_number_of_pages :
224
243
return None
225
244
226
245
self ._page_count += 1
227
- return self ._decorated .next_page_token (response , last_page_size , last_record )
246
+ return self ._decorated .next_page_token (
247
+ response , last_page_size , last_record , last_page_token_value
248
+ )
228
249
229
- def path (self ) -> Optional [str ]:
230
- return self ._decorated .path ()
250
+ def path (self , next_page_token : Optional [ Mapping [ str , Any ]] ) -> Optional [str ]:
251
+ return self ._decorated .path (next_page_token )
231
252
232
253
def get_request_params (
233
254
self ,
@@ -272,7 +293,3 @@ def get_request_body_json(
272
293
return self ._decorated .get_request_body_json (
273
294
stream_state = stream_state , stream_slice = stream_slice , next_page_token = next_page_token
274
295
)
275
-
276
- def reset (self , reset_value : Optional [Any ] = None ) -> None :
277
- self ._decorated .reset ()
278
- self ._page_count = self ._PAGE_COUNT_BEFORE_FIRST_NEXT_CALL
0 commit comments