"""A class for iterating over paginated API endpoints, collecting anyiterated type T into a python Iterator."""from__future__importannotationsfromtypingimportAny,Callable,Dict,Generic,Iterator,List,TypeVarimporthttpximportpandasaspdimportqnexus.exceptionsasqnx_excfromqnexus.models.referencesimportDataframable,DataframableListT=TypeVar("T",bound=Dataframable)
[docs]classNexusIterator(Generic[T],Iterator[T]):"""An object that can be used to summarize or iterate through a filter query made to the Nexus database."""def__init__(self,resource_type:str,nexus_url:str,params:Dict[str,Any],wrapper_method:Callable[[dict[str,Any]],List[T]],nexus_client:httpx.Client,)->None:self.nexus_client=nexus_clientself.resource_type=resource_typeself.nexus_url=nexus_urlself.wrapper=wrapper_methodself.current_page:int=0self.params=paramsself._cached_list:DataframableList[T]|None=Noneself._current_page_subiterator:Iterator[T]=iter([])def__iter__(self)->Iterator[T]:"""Return the Iterator."""returnselfdef__next__(self)->T:"""Get the next element of the Iterator."""try:returnnext(self._current_page_subiterator)exceptStopIterationasexc:self.params["page[number]"]=(self.current_page,)res=self.nexus_client.get(url=self.nexus_url,params=self.params)self._handle_errors(res)self.current_page+=1ifres.json()["data"]:self._current_page_subiterator=iter(self.wrapper(res.json()))returnnext(self._current_page_subiterator)raiseStopIterationfromexc
[docs]deflist(self)->DataframableList[T]:"""Collapse into RefList."""ifnotself._cached_list:self._cached_list=DataframableList([])foriteminself:self._cached_list.append(item)returnself._cached_list
[docs]defdf(self)->pd.DataFrame:"""List and present in a pandas DataFrame."""returnself.list().df()
[docs]defcount(self)->int:"""Count the items that match the filter."""res=self.nexus_client.get(url=self.nexus_url+"/meta/count",params=self.params)self._handle_errors(res)res_dict=res.json()returnint(res_dict["count"])
[docs]defsummarize(self)->pd.DataFrame:"""Present in a pandas DataFrame."""returnpd.DataFrame({"resource":self.resource_type,"total_count":self.count()},index=[0])
[docs]deftry_unique_match(self)->T:"""Utility function for expecting a single match on the filter."""match_count=self.count()ifmatch_count>1:raiseqnx_exc.NoUniqueMatch()ifmatch_count==0:raiseqnx_exc.ZeroMatches()returnself.list()[0]