[docs]classAPIIterator:""" The API iterator provides a scalable way to work through result sets of any size. The iterator will walk through each page of data, returning one record at a time. If it reaches the end of a page of records, then it will request the next page of information and then continue to return records from the next page (and the next, and the next) until the counter reaches the total number of records that the API has reported. Note that this Iterator is used as a base model for all of the iterators, and while the mechanics of each iterator may vary, they should all behave to the user in a similar manner. Attributes: _api (restfly.session.APISession): The APISession object that will be used for querying for the data. count (int): The current number of records that have been returned max_items (int): The maximum number of items to return before stopping iteration. max_pages (int): The maximum number of pages to request before throwing stopping iteration. num_pages (int): The number of pages that have been requested. page (list): The current page of data being walked through. pages will be cycled through as the iterator requests more information from the API. page_count (int): The number of record returned from the current page. total (int): The total number of records that exist for the current request. """count=0page_count=0num_pages=0max_pages=Nonemax_items=Nonetotal=Nonepage=[]_api=Nonedef__init__(self,api,**kw):""" Args: api (restfly.session.APISession): The APISession object to use for this iterator. **kw (dict): The various attributes to add/overload in the iterator. Example: >>> i = APIIterator(api, max_pages=1, max_items=100) """self._api=apiself.__dict__.update(kw)# Create the logging facilityself._log=logging.getLogger(f'{self.__module__}.{self.__class__.__name__}')
[docs]def_increment_counters(self)->None:""" Handles incrementing all of the counters that are controlling the next item to be retreived. """self.count+=1self.page_count+=1
[docs]def_get_next_item(self)->Any:""" Returns the next item in the page """returnself[self.page_count]
[docs]def_get_page(self)->None:""" A method to be overloaded in order to instruct the iterator how to retrieve the next page of data. Example: >>> class ExampleIterator(APIIterator): ... def _get_page(self): ... self.total = 100 ... items = range(10) ... self.page = [{'id': i + self._offset} for i in items] ... self._offset += self._limit """
[docs]defget(self,key:int,default:Optional[Any]=None)->Any:""" Retrieves an item from the the current page based off of the key. Args: key (int): The index of the item to retrieve. default (obj): The returned object if the item does not exist. Examples: >>> a = APIIterator() >>> a.get(2) None """try:returnself[key]exceptIndexError:returndefault
[docs]defnext(self)->Any:""" Ask for the next record """# If there are no more records to return, then we should raise a# StopIteration exception to break the iterator out.if((self.totalandself.count+1>self.total)# noqa: PLR0916or(self.max_itemsandself.count>=self.max_items)):raiseStopIteration()# If we have worked through the current page of records and we still# haven't hit to the total number of available records, then we should# query the next page of records.ifself.page_count>=len(self.page)and(notself.totalorself.count+1<=self.total):# If the number of pages requested reaches the total number of# pages that should be requested, then stop iteration.ifself.max_pagesandself.num_pages+1>self.max_pages:raiseStopIteration()# Perform the _get_page call.self._get_page()self.page_count=0self.num_pages+=1# If the length of the page is 0, then we don't have anything# further to do and should stop iteration.iflen(self.page)==0:raiseStopIteration()# Get the relevant record, increment the counters, and return the# record.item=self._get_next_item()self._increment_counters()returnitem