1010import uuid
1111import json
1212import time
13+ import re
1314
1415import numpy as np
1516
1819from astropy .table import Table , vstack , MaskedColumn
1920from astropy .utils import deprecated
2021
21- from ..query import BaseQuery , QueryWithLogin
22+ from ..query import BaseQuery , QueryWithLogin , AstroQuery , to_cache
2223from ..utils import async_to_sync
2324from ..utils .class_or_instance import class_or_instance
2425from ..exceptions import InputWarning , NoResultsWarning , RemoteServiceError
@@ -211,7 +212,39 @@ def _request(self, method, url, params=None, data=None, headers=None,
211212
212213 return all_responses
213214
214- def _get_col_config (self , service , fetch_name = None ):
215+ def _request_w_cache (self , method , url , data = None , headers = None , retrieve_all = True ,
216+ cache = False , cache_opts = None ):
217+ # Note: the method only exposes 4 parameters of the underlying _request() function
218+ # to play nice with existing mocks
219+ # Caching: follow BaseQuery._request()'s pattern, which uses an AstroQuery object
220+ if not cache :
221+ response = self ._request (method , url , data = data , headers = headers , retrieve_all = retrieve_all )
222+ else :
223+ cacher = self ._get_cacher (method , url , data , headers , retrieve_all )
224+ response = cacher .from_cache (self .cache_location )
225+ if not response :
226+ response = self ._request (method , url , data = data , headers = headers , retrieve_all = retrieve_all )
227+ to_cache (response , cacher .request_file (self .cache_location ))
228+ return response
229+
230+ def _get_cacher (self , method , url , data , headers , retrieve_all ):
231+ """
232+ Return an object that can cache the HTTP request based on the supplied arguments
233+ """
234+
235+ # cacheBreaker parameter (to underlying MAST service) is not relevant (and breaks) local caching
236+ # remove it from part of the cache key
237+ data_no_cache_breaker = re .sub (r'^(.+)cacheBreaker%22%3A%20%22.+%22' , r'\1' , data )
238+ # include retrieve_all as part of the cache key by appending it to data
239+ # it cannot be added as part of req_kwargs dict, as it will be rejected by AstroQuery
240+ data_w_retrieve_all = data_no_cache_breaker + " retrieve_all={}" .format (retrieve_all )
241+ req_kwargs = dict (
242+ data = data_no_cache_breaker ,
243+ headers = headers
244+ )
245+ return AstroQuery (method , url , ** req_kwargs )
246+
247+ def _get_col_config (self , service , fetch_name = None , cache = False ):
215248 """
216249 Gets the columnsConfig entry for given service and stores it in `self._column_configs`.
217250
@@ -247,7 +280,7 @@ def _get_col_config(self, service, fetch_name=None):
247280 if more :
248281 mashup_request = {'service' : all_name , 'params' : {}, 'format' : 'extjs' }
249282 req_string = _prepare_service_request_string (mashup_request )
250- response = self ._request ("POST" , self .MAST_REQUEST_URL , data = req_string , headers = headers )
283+ response = self ._request_w_cache ("POST" , self .MAST_REQUEST_URL , data = req_string , headers = headers , cache = cache )
251284 json_response = response [0 ].json ()
252285
253286 self ._column_configs [service ].update (json_response ['data' ]['Tables' ][0 ]
@@ -301,7 +334,7 @@ def _parse_result(self, responses, verbose=False):
301334 return all_results
302335
303336 @class_or_instance
304- def service_request_async (self , service , params , pagesize = None , page = None , ** kwargs ):
337+ def service_request_async (self , service , params , pagesize = None , page = None , cache = False , cache_opts = None , ** kwargs ):
305338 """
306339 Given a Mashup service and parameters, builds and excecutes a Mashup query.
307340 See documentation `here <https://mast.stsci.edu/api/v0/class_mashup_1_1_mashup_request.html>`__
@@ -321,6 +354,10 @@ def service_request_async(self, service, params, pagesize=None, page=None, **kwa
321354 Default None.
322355 Can be used to override the default behavior of all results being returned to obtain
323356 a specific page of results.
357+ cache : Boolean, optional
358+ try to use cached the query result if set to True
359+ cache_opts : dict, optional
360+ cache options, details TBD, e.g., cache expiration policy, etc.
324361 **kwargs :
325362 See MashupRequest properties
326363 `here <https://mast.stsci.edu/api/v0/class_mashup_1_1_mashup_request.html>`__
@@ -334,7 +371,7 @@ def service_request_async(self, service, params, pagesize=None, page=None, **kwa
334371 # setting self._current_service
335372 if service not in self ._column_configs .keys ():
336373 fetch_name = kwargs .pop ('fetch_name' , None )
337- self ._get_col_config (service , fetch_name )
374+ self ._get_col_config (service , fetch_name , cache )
338375 self ._current_service = service
339376
340377 # setting up pagination
@@ -360,12 +397,12 @@ def service_request_async(self, service, params, pagesize=None, page=None, **kwa
360397 mashup_request [prop ] = value
361398
362399 req_string = _prepare_service_request_string (mashup_request )
363- response = self ._request ("POST" , self .MAST_REQUEST_URL , data = req_string , headers = headers ,
364- retrieve_all = retrieve_all )
400+ response = self ._request_w_cache ("POST" , self .MAST_REQUEST_URL , data = req_string , headers = headers ,
401+ retrieve_all = retrieve_all , cache = cache , cache_opts = cache_opts )
365402
366403 return response
367404
368- def build_filter_set (self , column_config_name , service_name = None , ** filters ):
405+ def build_filter_set (self , column_config_name , service_name = None , cache = False , ** filters ):
369406 """
370407 Takes user input dictionary of filters and returns a filterlist that the Mashup can understand.
371408
@@ -393,7 +430,7 @@ def build_filter_set(self, column_config_name, service_name=None, **filters):
393430 service_name = column_config_name
394431
395432 if not self ._column_configs .get (service_name ):
396- self ._get_col_config (service_name , fetch_name = column_config_name )
433+ self ._get_col_config (service_name , fetch_name = column_config_name , cache = cache )
397434
398435 caom_col_config = self ._column_configs [service_name ]
399436
0 commit comments