diff --git a/CHANGES.rst b/CHANGES.rst index 4188d3c0dd..44b4040f56 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -30,6 +30,11 @@ esa.euclid sourcepatch_id. [#3543] - The ``source_id`` kwarg in the ``get_spectrum`` method has been renamed to ``ids``. [#3543] +gemini +^^^^^^ + +- Added ``get_query_payload`` kwarg to allow inspection of the query payload to aid in debugging. [#3568] + vizier ^^^^^^ diff --git a/astroquery/gemini/core.py b/astroquery/gemini/core.py index dbe7c8d38a..b38ff4bb7c 100644 --- a/astroquery/gemini/core.py +++ b/astroquery/gemini/core.py @@ -132,7 +132,7 @@ def _login(self, username, password): return True @class_or_instance - def query_region(self, coordinates, *, radius=0.3*units.deg): + def query_region(self, coordinates, *, radius=0.3*units.deg, get_query_payload=False): """ search for Gemini observations by target on the sky. @@ -148,15 +148,20 @@ def query_region(self, coordinates, *, radius=0.3*units.deg): The string must be parsable by `~astropy.coordinates.Angle`. The appropriate `~astropy.units.Quantity` object from `~astropy.units` may also be used. Defaults to 0.3 deg. + get_query_payload : bool, optional + If set to `True` then returns the URL and method that would be used for the + request. Defaults to `False`. Returns ------- - response : `~astropy.table.Table` + response : `~astropy.table.Table` or dict + The response from the query as an `~astropy.table.Table`, or if get_query_payload + is True, a dictionary containing the URL and HTTP method that would be used. """ - return self.query_criteria(coordinates=coordinates, radius=radius) + return self.query_criteria(coordinates=coordinates, radius=radius, get_query_payload=get_query_payload) @class_or_instance - def query_object(self, objectname, *, radius=0.3*units.deg): + def query_object(self, objectname, *, radius=0.3*units.deg, get_query_payload=False): """ search for Gemini observations by target on the sky. @@ -173,18 +178,23 @@ def query_object(self, objectname, *, radius=0.3*units.deg): The string must be parsable by `~astropy.coordinates.Angle`. The appropriate `~astropy.units.Quantity` object from `~astropy.units` may also be used. Defaults to 0.3 deg. + get_query_payload : bool, optional + If set to `True` then returns the URL and method that would be used for the + request. Defaults to `False`. Returns ------- - response : `~astropy.table.Table` + response : `~astropy.table.Table` or dict + The response from the query as an `~astropy.table.Table`, or if get_query_payload + is True, a dictionary containing the URL and HTTP method that would be used. """ - return self.query_criteria(objectname=objectname, radius=radius) + return self.query_criteria(objectname=objectname, radius=radius, get_query_payload=get_query_payload) @class_or_instance def query_criteria(self, *rawqueryargs, coordinates=None, radius=None, pi_name=None, program_id=None, utc_date=None, instrument=None, observation_class=None, observation_type=None, mode=None, adaptive_optics=None, program_text=None, objectname=None, raw_reduced=None, - orderby=None, **rawquerykwargs): + orderby=None, get_query_payload=False, **rawquerykwargs): """ search a variety of known parameters against the Gemini observations. @@ -294,7 +304,9 @@ def query_criteria(self, *rawqueryargs, coordinates=None, radius=None, pi_name=N Returns ------- - response : `~astropy.table.Table` + response : `~astropy.table.Table` or dict + The response from the query as an `~astropy.table.Table`, or if get_query_payload + is True, a dictionary containing the URL and HTTP method that would be used. Raises ------ @@ -316,7 +328,8 @@ def query_criteria(self, *rawqueryargs, coordinates=None, radius=None, pi_name=N args.append(arg) if rawquerykwargs: for (k, v) in rawquerykwargs.items(): - kwargs[k] = v + if k != 'get_query_payload': + kwargs[k] = v # If coordinates is set but we have no radius, set a default if (coordinates or objectname) and radius is None: @@ -370,6 +383,8 @@ def query_criteria(self, *rawqueryargs, coordinates=None, radius=None, pi_name=N if orderby is not None: kwargs["orderby"] = orderby + if get_query_payload: + kwargs['get_query_payload'] = get_query_payload return self.query_raw(*args, **kwargs) @class_or_instance @@ -380,7 +395,7 @@ def query_raw(self, *args, **kwargs): This is a more flexible query method. This method will do special handling for coordinates and radius if present in kwargs. However, for the remaining arguments it assumes all of args are useable as query path elements. For kwargs, it assumes - all of the elements can be passed as name=value within the query path to Gemini. + all of the elements can be passed as name=value within the query path to the webserver. This method does not do any validation checking or attempt to interperet the values being passed, aside from coordinates and radius. @@ -406,11 +421,24 @@ def query_raw(self, *args, **kwargs): path to the webserver. The ``orderby`` key value pair has a special intepretation and is appended as a query parameter like the one used in the archive website for sorting results. + get_query_payload : bool, optional + If set to `True` then returns the URL and method that would be used for the + request. Defaults to `False`. Returns ------- - response : `~astropy.table.Table` + response : `~astropy.table.Table` or dict + The response from the query as an `~astropy.table.Table`, or if get_query_payload + is True, a dictionary containing the URL and HTTP method that would be used. """ + if kwargs.pop('get_query_payload', False): + url = self.url_helper.build_url(*args, **kwargs) + return { + 'url': url, + 'method': 'GET', + 'data': {} + } + url = self.url_helper.build_url(*args, **kwargs) response = self._request(method="GET", url=url, data={}, timeout=180, cache=False) diff --git a/astroquery/gemini/tests/test_gemini.py b/astroquery/gemini/tests/test_gemini.py index a3a36a7f9b..afaf290a11 100644 --- a/astroquery/gemini/tests/test_gemini.py +++ b/astroquery/gemini/tests/test_gemini.py @@ -171,3 +171,74 @@ def test_url_helper_eng_fail(test_arg): urlsplit = url.split('/') assert (('notengineering' in urlsplit) == should_have_noteng) assert (('NotFail' in urlsplit) == should_have_notfail) + + +def test_observations_query_region_get_query_payload(): + coords = SkyCoord(210.80242917, 54.34875, unit="deg") + result = gemini.Observations.query_region( + coords, + radius=0.3 * units.deg, + get_query_payload=True + ) + assert isinstance(result, dict) + assert 'url' in result + assert 'method' in result + assert result['method'] == 'GET' + assert 'data' in result + assert result['data'] == {} + assert 'ra=210.802429' in result['url'] + assert 'dec=54.348750' in result['url'] + assert 'sr=0.300000d' in result['url'] + + +def test_observations_query_object_get_query_payload(): + result = gemini.Observations.query_object( + 'M101', + radius=0.3 * units.deg, + get_query_payload=True + ) + assert isinstance(result, dict) + assert 'url' in result + assert 'method' in result + assert result['method'] == 'GET' + assert 'data' in result + assert result['data'] == {} + assert 'object=M101' in result['url'] + assert 'sr=0.300000d' in result['url'] + + +def test_observations_query_criteria_get_query_payload(): + result = gemini.Observations.query_criteria( + instrument='GMOS-N', + program_id='GN-CAL20191122', + observation_type='BIAS', + utc_date=(date(2019, 10, 1), date(2019, 11, 25)), + get_query_payload=True + ) + assert isinstance(result, dict) + assert 'url' in result + assert 'method' in result + assert result['method'] == 'GET' + assert 'data' in result + assert result['data'] == {} + assert 'GMOS-N' in result['url'] + assert 'BIAS' in result['url'] + assert '20191001-20191125' in result['url'] + assert 'GN-CAL20191122' in result['url'] + + +def test_observations_query_raw_get_query_payload(): + result = gemini.Observations.query_raw( + 'GMOS-N', 'BIAS', + progid='GN-CAL20191122', + get_query_payload=True + ) + assert isinstance(result, dict) + assert 'url' in result + assert 'method' in result + assert result['method'] == 'GET' + assert 'data' in result + assert result['data'] == {} + assert 'GMOS-N' in result['url'] + assert 'BIAS' in result['url'] + assert 'progid=GN-CAL20191122' in result['url'] diff --git a/docs/gemini/gemini.rst b/docs/gemini/gemini.rst index 6778243dac..56f392fa2b 100644 --- a/docs/gemini/gemini.rst +++ b/docs/gemini/gemini.rst @@ -129,6 +129,25 @@ the *NotFail* or *notengineering* terms respectively. 0.0 Full Frame -- ... 2019-11-22 -- +Inspecting Query Payloads +------------------------- + +All query methods accept an optional ``get_query_payload`` keyword argument. When set to +``True``, no network request is made and a dictionary is returned instead of an +`~astropy.table.Table`. The dictionary contains the URL, HTTP method, and any data that +would have been sent to the Gemini archive. This is useful for debugging and verifying +the query that will be executed. + +.. doctest-skip:: + + >>> from astroquery.gemini import Observations + >>> payload = Observations.query_criteria(instrument='GMOS-N', + ... observation_type='BIAS', + ... get_query_payload=True) + >>> print(payload) + {'url': 'https://archive.gemini.edu/jsonsummary/notengineering/NotFail/GMOS-N/BIAS', 'method': 'GET', 'data': {}} + + Authenticated Sessions ----------------------