@@ -112,27 +112,39 @@ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
112112 )
113113 if isinstance (self .url_base , str ):
114114 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
116124
117125 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 ,
119131 ) -> 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 ,
122137 )
123- if self . _token :
124- return {"next_page_token" : self . _token }
138+ if next_page_token :
139+ return {"next_page_token" : next_page_token }
125140 else :
126141 return None
127142
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 ):
134146 # 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__
136148 else :
137149 return None
138150
@@ -143,7 +155,7 @@ def get_request_params(
143155 stream_slice : Optional [StreamSlice ] = None ,
144156 next_page_token : Optional [Mapping [str , Any ]] = None ,
145157 ) -> MutableMapping [str , Any ]:
146- return self ._get_request_options (RequestOptionType .request_parameter )
158+ return self ._get_request_options (RequestOptionType .request_parameter , next_page_token )
147159
148160 def get_request_headers (
149161 self ,
@@ -152,7 +164,7 @@ def get_request_headers(
152164 stream_slice : Optional [StreamSlice ] = None ,
153165 next_page_token : Optional [Mapping [str , Any ]] = None ,
154166 ) -> Mapping [str , str ]:
155- return self ._get_request_options (RequestOptionType .header )
167+ return self ._get_request_options (RequestOptionType .header , next_page_token )
156168
157169 def get_request_body_data (
158170 self ,
@@ -161,7 +173,7 @@ def get_request_body_data(
161173 stream_slice : Optional [StreamSlice ] = None ,
162174 next_page_token : Optional [Mapping [str , Any ]] = None ,
163175 ) -> Mapping [str , Any ]:
164- return self ._get_request_options (RequestOptionType .body_data )
176+ return self ._get_request_options (RequestOptionType .body_data , next_page_token )
165177
166178 def get_request_body_json (
167179 self ,
@@ -170,25 +182,21 @@ def get_request_body_json(
170182 stream_slice : Optional [StreamSlice ] = None ,
171183 next_page_token : Optional [Mapping [str , Any ]] = None ,
172184 ) -> 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 )
181186
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 ]:
183190 options = {}
184191
192+ token = next_page_token .get ("next_page_token" ) if next_page_token else None
185193 if (
186194 self .page_token_option
187- and self . _token is not None
195+ and token is not None
188196 and isinstance (self .page_token_option , RequestOption )
189197 and self .page_token_option .inject_into == option_type
190198 ):
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
192200 if (
193201 self .page_size_option
194202 and self .pagination_strategy .get_page_size ()
@@ -204,6 +212,9 @@ class PaginatorTestReadDecorator(Paginator):
204212 """
205213 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
206214 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
207218 """
208219
209220 _PAGE_COUNT_BEFORE_FIRST_NEXT_CALL = 1
@@ -217,17 +228,27 @@ def __init__(self, decorated: Paginator, maximum_number_of_pages: int = 5) -> No
217228 self ._decorated = decorated
218229 self ._page_count = self ._PAGE_COUNT_BEFORE_FIRST_NEXT_CALL
219230
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+
220235 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 ,
222241 ) -> Optional [Mapping [str , Any ]]:
223242 if self ._page_count >= self ._maximum_number_of_pages :
224243 return None
225244
226245 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+ )
228249
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 )
231252
232253 def get_request_params (
233254 self ,
@@ -272,7 +293,3 @@ def get_request_body_json(
272293 return self ._decorated .get_request_body_json (
273294 stream_state = stream_state , stream_slice = stream_slice , next_page_token = next_page_token
274295 )
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