@@ -1121,6 +1121,63 @@ def service_request_async(self, service, params, *, pagesize=None, page=None, **
11211121
11221122 return self ._portal_api_connection .service_request_async (service , params , pagesize , page , ** kwargs )
11231123
1124+ def _normalize_filter_value (self , key : str , val ) -> list :
1125+ """
1126+ Normalize a filter value into a list suitable for MAST filters.
1127+
1128+ Parameters
1129+ ----------
1130+ key : str
1131+ Parameter name (used for error messages).
1132+ val : any
1133+ Raw filter value.
1134+
1135+ Returns
1136+ -------
1137+ list
1138+ Normalized filter values.
1139+ """
1140+ # Range filters must be dicts with 'min' and 'max'
1141+ if isinstance (val , dict ):
1142+ if not {"min" , "max" }.issubset (val .keys ()):
1143+ raise InvalidQueryError (
1144+ f'Range filter for "{ key } " must be a dictionary with "min" and "max" keys.'
1145+ )
1146+ return [val ]
1147+
1148+ # Convert numpy arrays to lists
1149+ if isinstance (val , np .ndarray ):
1150+ val = val .tolist ()
1151+
1152+ # Convert numpy arrays, sets, or tuples to lists
1153+ if isinstance (val , (set , tuple )):
1154+ val = list (val )
1155+
1156+ # Wrap scalars into a list
1157+ return val if isinstance (val , list ) else [val ]
1158+
1159+ def _build_filters (self , service_params ):
1160+ """
1161+ Construct filters for filtered services.
1162+
1163+ Parameters
1164+ ----------
1165+ service_params : dict
1166+ Parameters not classified as request/position keys.
1167+
1168+ Returns
1169+ -------
1170+ list of dict
1171+ Filters suitable for a MAST filtered query.
1172+ """
1173+ filters = []
1174+ for key , val in service_params .items ():
1175+ filters .append ({
1176+ "paramName" : key ,
1177+ "values" : self ._normalize_filter_value (key , val )
1178+ })
1179+ return filters
1180+
11241181 def mast_query (self , service , columns = None , ** kwargs ):
11251182 """
11261183 Given a Mashup service and parameters as keyword arguments, builds and excecutes a Mashup query.
@@ -1129,53 +1186,57 @@ def mast_query(self, service, columns=None, **kwargs):
11291186 ----------
11301187 service : str
11311188 The Mashup service to query.
1132- columns : str, optional
1189+ columns : str or list , optional
11331190 Specifies the columns to be returned as a comma-separated list, e.g. "ID, ra, dec".
11341191 **kwargs :
11351192 Service-specific parameters and MashupRequest properties. See the
11361193 `service documentation <https://mast.stsci.edu/api/v0/_services.html>`__ and the
11371194 `MashupRequest Class Reference <https://mast.stsci.edu/api/v0/class_mashup_1_1_mashup_request.html>`__
11381195 for valid keyword arguments.
11391196
1197+ For filtered services (i.e. those with "filtered" in the service name),
1198+ parameters that are not related to position or MashupRequest properties
1199+ are treated as filters. If the column has discrete values, the parameter value should be a
1200+ single value or list of values, and values will be matched exactly. If the column is continuous,
1201+ you can filter by a single value, a list of values, or a range of values. If filtering by a range of values,
1202+ the parameter value should be a dict in the form ``{'min': minVal, 'max': maxVal}``.
1203+
11401204 Returns
11411205 -------
11421206 response : `~astropy.table.Table`
11431207 """
11441208 # Specific keywords related to positional and MashupRequest parameters.
1145- position_keys = [ 'ra' , 'dec' , 'radius' , 'position' ]
1146- request_keys = [ 'format' , 'data' , 'filename' , 'timeout' , 'clearcache' ,
1147- 'removecache' , 'removenullcolumns' , 'page' , 'pagesize' ]
1209+ position_keys = { 'ra' , 'dec' , 'radius' , 'position' }
1210+ request_keys = { 'format' , 'data' , 'filename' , 'timeout' , 'clearcache' ,
1211+ 'removecache' , 'removenullcolumns' , 'page' , 'pagesize' }
11481212
1149- # Explicit formatting for Mast's filtered services
1150- if 'filtered' in service .lower ():
1213+ # Split params into categories
1214+ position_params = {k : v for k , v in kwargs .items () if k .lower () in position_keys }
1215+ request_params = {k : v for k , v in kwargs .items () if k .lower () in request_keys }
1216+ service_params = {k : v for k , v in kwargs .items () if k .lower () not in position_keys | request_keys }
11511217
1152- # Separating the filter params from the positional and service_request method params.
1153- filters = [{'paramName' : k , 'values' : kwargs [k ]} for k in kwargs
1154- if k .lower () not in position_keys + request_keys ]
1155- position_params = {k : v for k , v in kwargs .items () if k .lower () in position_keys }
1156- request_params = {k : v for k , v in kwargs .items () if k .lower () in request_keys }
1218+ # Handle filtered vs. non-filtered services
1219+ if 'filtered' in service .lower ():
1220+ filters = self ._build_filters (service_params )
11571221
1158- # Mast's filtered services require at least one filter
1159- if filters == []:
1160- raise InvalidQueryError ("Please provide at least one filter." )
1222+ if not filters :
1223+ raise InvalidQueryError ('Please provide at least one filter.' )
11611224
1162- # Building 'params' for Mast.service_request
1163- if columns is None :
1164- columns = '*'
1225+ if columns is not None and isinstance (columns , list ):
1226+ columns = ',' .join (columns )
11651227
1166- params = {'columns' : columns ,
1167- 'filters' : filters ,
1168- ** position_params
1169- }
1228+ params = {
1229+ 'columns' : columns or '*' ,
1230+ 'filters' : filters ,
1231+ ** position_params ,
1232+ }
11701233 else :
1171-
1172- # Separating service specific params from service_request method params
1173- params = {k : v for k , v in kwargs .items () if k .lower () not in request_keys }
1174- request_params = {k : v for k , v in kwargs .items () if k .lower () in request_keys }
1175-
1176- # Warning for wrong input
11771234 if columns is not None :
1178- warnings .warn ("'columns' parameter will not mask non-filtered services" , InputWarning )
1235+ warnings .warn (
1236+ "'columns' parameter is ignored for non-filtered services." ,
1237+ InputWarning
1238+ )
1239+ params = {** service_params , ** position_params }
11791240
11801241 return self .service_request (service , params , ** request_params )
11811242
0 commit comments