@@ -640,7 +640,7 @@ def _query_resource(
640640 use_document_model: if None, will defer to the self.use_document_model attribute
641641 num_chunks: Maximum number of chunks of data to yield. None will yield all possible.
642642 chunk_size: Number of data entries per chunk.
643- timeout : Time in seconds to wait until a request timeout error is thrown
643+ timeout (float or None) : Time in seconds to wait until a request timeout error is thrown
644644
645645 Returns:
646646 A Resource, a dict with two keys, "data" containing a list of documents, and
@@ -786,27 +786,32 @@ def _query_resource(
786786 except RequestException as ex :
787787 raise MPRestError (str (ex ))
788788
789- def _submit_requests ( # noqa
789+ def _submit_requests (
790790 self ,
791- url ,
792- criteria ,
793- use_document_model ,
794- chunk_size ,
795- num_chunks = None ,
796- timeout = None ,
791+ url : str ,
792+ criteria : dict [str , Any ],
793+ use_document_model : bool ,
794+ chunk_size : int | None ,
795+ num_chunks : int | None = None ,
796+ timeout : int | None = None ,
797+ max_batch_size : int = 100 ,
798+ norecur : bool = False ,
797799 ) -> dict :
798800 """Handle submitting requests sequentially with pagination.
799801
800802 If criteria contains comma-separated parameters (except those that are naturally comma-separated),
801803 split them into multiple sequential requests and combine results.
802804
803805 Arguments:
804- criteria: dictionary of criteria to filter down
805- url: url used to make request
806- use_document_model: if None, will defer to the self.use_document_model attribute
807- num_chunks: Maximum number of chunks of data to yield. None will yield all possible.
808- chunk_size: Number of data entries per chunk.
809- timeout: Time in seconds to wait until a request timeout error is thrown
806+ url (str): url used to make request
807+ criteria (dict of str): dictionary of criteria to filter down
808+ use_document_model (bool): whether to use the document model
809+ num_chunks (int or None): Maximum number of chunks of data to yield. None will yield all possible.
810+ chunk_size (int or None): Number of data entries per chunk.
811+ timeout (int or None): Time in seconds to wait until a request timeout error is thrown
812+ max_batch_size (int) : Maximum size of a batch when retrieving batches in parallel
813+ norecur (bool) : Whether to forbid recursive splitting of a query field
814+ when a direct query fails
810815
811816 Returns:
812817 Dictionary containing data and metadata
@@ -865,14 +870,6 @@ def _submit_requests( # noqa
865870 timeout = timeout ,
866871 )
867872
868- # Check if we got 0 results - some parameters are silently ignored by the API
869- # when passed as comma-separated values, so we need to split them anyway
870- if total_num_docs == 0 and len (split_values ) > 1 :
871- # Treat this the same as a 422 error - split into batches
872- raise MPRestError (
873- "Got 0 results for comma-separated parameter, will try splitting"
874- )
875-
876873 # If successful, continue with normal pagination
877874 data_chunks = [data ["data" ]]
878875 total_data : dict [str , Any ] = {"data" : []}
@@ -884,18 +881,26 @@ def _submit_requests( # noqa
884881 # Continue with pagination if needed (handled below)
885882
886883 except MPRestError as e :
887- # If we get 422 or 414 error, or 0 results for comma-separated params, split into batches
888- if any (trace in str (e ) for trace in ("422" , "414" , "Got 0 results" )):
884+ # If we get 422 or 414 error, split into batches
885+ if not norecur and any (
886+ trace in str (e )
887+ for trace in (
888+ "422" ,
889+ "414" ,
890+ )
891+ ):
889892 total_data = {"data" : []}
890893 total_num_docs = 0
891894 data_chunks = []
892895
893896 # Batch the split values to reduce number of requests
894897 # Use batches of up to 100 values to balance URL length and request count
895- batch_size = min (100 , max (1 , len (split_values ) // 10 ))
898+ num_batches = min (
899+ max_batch_size , max (1 , len (split_values ) // max_batch_size )
900+ )
901+ batch_size = min (len (split_values ), max_batch_size )
896902
897903 # Setup progress bar for split parameter requests
898- num_batches = ceil (len (split_values ) / batch_size )
899904 pbar_message = f"Retrieving { len (split_values )} { split_param } values in { num_batches } batches"
900905 pbar = (
901906 tqdm (
@@ -919,6 +924,7 @@ def _submit_requests( # noqa
919924 chunk_size = chunk_size ,
920925 num_chunks = num_chunks ,
921926 timeout = timeout ,
927+ norecur = len (batch ) <= max_batch_size ,
922928 )
923929
924930 data_chunks .append (result ["data" ])
@@ -960,6 +966,12 @@ def _submit_requests( # noqa
960966 if "meta" in data :
961967 total_data ["meta" ] = data ["meta" ]
962968
969+ # otherwise, paginate sequentially
970+ if chunk_size is None or chunk_size < 1 :
971+ raise ValueError (
972+ "A positive chunk size must be provided to enable pagination"
973+ )
974+
963975 # Get max number of response pages
964976 max_pages = (
965977 num_chunks if num_chunks is not None else ceil (total_num_docs / chunk_size )
@@ -979,7 +991,7 @@ def _submit_requests( # noqa
979991 desc = pbar_message ,
980992 total = num_docs_needed ,
981993 )
982- if not self .mute_progress_bars
994+ if not self .mute_progress_bars and total_num_docs > 0
983995 else None
984996 )
985997
@@ -999,10 +1011,6 @@ def _submit_requests( # noqa
9991011 pbar .close ()
10001012 return new_total_data
10011013
1002- # otherwise, paginate sequentially
1003- if chunk_size is None :
1004- raise ValueError ("A chunk size must be provided to enable pagination" )
1005-
10061014 # Warning to select specific fields only for many results
10071015 if criteria .get ("_all_fields" , False ) and (total_num_docs / chunk_size > 10 ):
10081016 warnings .warn (
0 commit comments