Skip to content

Commit 9fce901

Browse files
committed
consolidate some methods
1 parent 12c557a commit 9fce901

5 files changed

Lines changed: 160 additions & 163 deletions

File tree

astroquery/noirlab/core.py

Lines changed: 50 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,16 @@ def _fields_url(self, hdu=False, aux=False):
8181
core = 'aux' if aux else 'core'
8282
return f'{self.NAT_URL}/api/adv_search/{core}_{file}_fields'
8383

84-
def _response_to_table(self, response_json, rectype=None):
84+
def _response_to_table(self, response_json, sia=False):
8585
"""Convert a JSON response to a :class:`~astropy.table.Table`.
8686
8787
Parameters
8888
----------
8989
response_json : :class:`list`
9090
A query response formatted as a list of objects. The query
9191
metadata is the first item in the list.
92-
rectype : :class:`str`, optional
93-
Expect response keys to be prepended with this string,
94-
*e.g.* ``file:`` or ``hdu:``. The default is no qualifier.
92+
sia : :class:`bool`, optional
93+
If ``True``, `response_json` came from a SIA query.
9594
9695
Returns
9796
-------
@@ -103,18 +102,20 @@ def _response_to_table(self, response_json, rectype=None):
103102
-----
104103
* Metadata queries return columns that are qualified with ``file:`` or ``hdu:``,
105104
however SIA queries to not.
105+
* HDU queries will label HDU-specific fields with ``hdu:`` but other
106+
fields will be qualified with ``file:``.
106107
"""
107-
if rectype is None:
108+
if sia:
108109
raw_names = [k for k in response_json[0]['HEADER'].keys()]
109110
names = raw_names
110111
else:
111112
raw_names = [k for k in response_json[0]['HEADER'].keys()
112-
if k.startswith(f"{rectype}:")]
113+
if k.startswith('file:') or k.startswith('hdu:')]
113114
names = [n.split(':')[1] for n in raw_names]
114115
rows = [[row[n] for n in raw_names] for row in response_json[1:]]
115116
return astropy.table.Table(names=names, rows=rows)
116117

117-
def service_metadata(self, hdu=False, cache=True):
118+
def _service_metadata(self, hdu=False, cache=True):
118119
"""A SIA metadata query: no images are requested; only metadata
119120
should be returned.
120121
@@ -137,7 +138,7 @@ def service_metadata(self, hdu=False, cache=True):
137138
response = self._request('GET', url, timeout=self.TIMEOUT, cache=cache)
138139
return response.json()
139140

140-
def query_region(self, coordinate, *, radius=0.1, hdu=False, cache=True):
141+
def query_region(self, coordinate, *, radius=0.1, hdu=False, cache=True, async_=False):
141142
"""Query for NOIRLab observations by region of the sky.
142143
143144
Given a sky coordinate and radius, returns a `~astropy.table.Table`
@@ -154,126 +155,76 @@ def query_region(self, coordinate, *, radius=0.1, hdu=False, cache=True):
154155
appropriate `~astropy.units.Quantity` object from
155156
`~astropy.units` may also be used.
156157
hdu : :class:`bool`, optional
157-
If ``True`` return the URL for HDU-based queries.
158+
If ``True``, perform the query on HDUs.
158159
cache : :class:`bool`, optional
159-
If ``True`` cache the result locally.
160+
If ``True``, cache the result locally.
161+
async : :class:`bool`, optional
162+
If ``True``, return the raw query response instead of a Table.
160163
161164
Returns
162165
-------
163166
:class:`~astropy.table.Table`
164167
A table containing the results.
165168
"""
166-
response = self.query_region_async(coordinate, radius=radius, hdu=hdu, cache=cache)
167-
response.raise_for_status()
168-
rectype = 'hdu' if hdu else 'file'
169-
return self._response_to_table(response.json())
170-
171-
def query_region_async(self, coordinate, *, radius=0.1, hdu=False, cache=True):
172-
"""Query for NOIRLab observations by region of the sky.
173-
174-
Given a sky coordinate and radius, returns a `~astropy.table.Table`
175-
of NOIRLab observations.
176-
177-
Parameters
178-
----------
179-
coordinate : :class:`str` or `~astropy.coordinates` object
180-
The target region which to search. It may be specified as a
181-
string or as the appropriate `~astropy.coordinates` object.
182-
radius : :class:`str` or `~astropy.units.Quantity` object, optional
183-
Default 0.1 degrees.
184-
The string must be parsable by `~astropy.coordinates.Angle`. The
185-
appropriate `~astropy.units.Quantity` object from
186-
`~astropy.units` may also be used.
187-
hdu : :class:`bool`, optional
188-
If ``True`` return the URL for HDU-based queries.
189-
cache : :class:`bool`, optional
190-
If ``True`` cache the result locally.
191-
192-
Returns
193-
-------
194-
:class:`~requests.Response`
195-
Response object.
196-
"""
197169
self._validate_version()
198170
ra, dec = coordinate.to_string('decimal').split()
199171
url = f'{self._sia_url(hdu=hdu)}?POS={ra},{dec}&SIZE={radius}&VERB=3&format=json'
200172
response = self._request('GET', url, timeout=self.TIMEOUT, cache=cache)
201-
# response.raise_for_status()
202-
return response
203-
204-
def core_fields(self, hdu=False, cache=True):
205-
"""List the available CORE fields for file or HDU searches.
206-
207-
CORE fields are faster to search than AUX fields.
208-
209-
Parameters
210-
----------
211-
hdu : :class:`bool`, optional
212-
If ``True`` return the fields for HDU-based queries.
213-
cache : :class:`bool`, optional
214-
If ``True`` cache the result locally.
215-
216-
Returns
217-
-------
218-
:class:`list`
219-
A list of field descriptions, each a :class:`dict`.
220-
"""
221-
url = self._fields_url(hdu=hdu, aux=False)
222-
response = self._request('GET', url, timeout=self.TIMEOUT, cache=cache)
173+
if async_:
174+
return response
223175
response.raise_for_status()
224-
return response.json()
176+
return self._response_to_table(response.json(), sia=True)
225177

226-
def aux_fields(self, instrument, proctype, hdu=False, cache=True):
227-
"""List the available AUX fields.
178+
def list_fields(self, *, aux=False, instrument=None, proctype=None, hdu=False,
179+
categorical=False, cache=True):
180+
"""List the available fields for searches using
181+
:meth:`~astroquery.noirlab.NOIRLabClass.query_metadata`.
228182
229-
AUX fields are any fields in the Archive FITS files that are not
230-
CORE DB fields. These are generally common to a single instrument,
231-
proctype combination. AUX fields are slower to search than CORE fields.
232-
Acceptable values for ``instrument`` and ``proctype`` are listed in the
233-
results of the :meth:`astroquery.noirlab.core.NOIRLabClass.categoricals`
234-
method.
183+
The default is to return core fields for file-based queries.
235184
236185
Parameters
237186
----------
238-
instrument : :class:`str`
187+
aux : :class:`bool`, optional
188+
If ``True``, return aux fields. `instrument` and `proctype` must also be specified.
189+
instrument : :class:`str`, optional
239190
The specific instrument, *e.g.* '90prime' or 'decam'.
240-
proctype : :class:`str`
191+
proctype : :class:`str`, optional
241192
A description of the type of image, *e.g.* 'raw' or 'instcal'.
242193
hdu : :class:`bool`, optional
243194
If ``True`` return the fields for HDU-based queries.
195+
categorical : :class:`bool`, optional
196+
If ``True`` return the categorical fields and their allowed values.
244197
cache : :class:`bool`, optional
245198
If ``True`` cache the result locally.
246199
247200
Returns
248201
-------
249-
:class:`list`
202+
:class:`list` or :class:`dict`
250203
A list of field descriptions, each a :class:`dict`.
251-
"""
252-
url = f'{self._fields_url(hdu=hdu, aux=True)}/{instrument}/{proctype}/'
253-
response = self._request('GET', url, timeout=self.TIMEOUT, cache=cache)
254-
response.raise_for_status()
255-
return response.json()
256-
257-
def categoricals(self, cache=True):
258-
"""List the currently acceptable values for each 'categorical field'
259-
associated with Archive files.
260-
261-
A 'categorical field' is one in which the values are restricted to a
262-
specific set. The specific set may grow over time, but not often.
263-
The categorical fields are: ``instrument``, ``obsmode``, ``obstype``,
264-
``proctype``, ``prodtype``, ``site``, ``survey``, ``telescope``.
204+
If ``categorical=True`` return a :class:`dict` describing the
205+
allowed values of each categorical field.
265206
266-
Parameters
267-
----------
268-
cache : :class:`bool`, optional
269-
If ``True`` cache the result locally.
207+
Raises
208+
------
209+
ValueError
210+
If ``aux=True`` and `instrument` or `proctype` are not specified.
270211
271-
Returns
272-
-------
273-
:class:`dict`
274-
A dictionary containing the category metadata.
212+
Notes
213+
-----
214+
* Core fields are faster to search than Aux fields.
215+
* The available fields depend on whether a File or a HDU query is requested.
216+
* Categorical fields can only take on one of a set of values.
275217
"""
276-
url = f'{self.NAT_URL}/api/adv_search/cat_lists/?format=json'
218+
if categorical:
219+
url = f'{self.NAT_URL}/api/adv_search/cat_lists/?format=json'
220+
else:
221+
url = self._fields_url(hdu=hdu, aux=aux)
222+
if aux:
223+
if instrument is None:
224+
raise ValueError("instrument must be specified if aux=True.")
225+
if proctype is None:
226+
raise ValueError("instrument must be specified if aux=True.")
227+
url = f'{url}/{instrument}/{proctype}/'
277228
response = self._request('GET', url, timeout=self.TIMEOUT, cache=cache)
278229
response.raise_for_status()
279230
return response.json()
@@ -319,7 +270,7 @@ def query_metadata(self, qspec=None, sort=None, limit=1000, hdu=False, cache=Tru
319270
response = self._request('POST', url, json=jdata,
320271
timeout=self.TIMEOUT, cache=cache)
321272
response.raise_for_status()
322-
return self._response_to_table(response.json(), rectype=rectype)
273+
return self._response_to_table(response.json())
323274

324275
def get_file(self, fileid):
325276
"""Simply fetch a file by MD5 ID.

astroquery/noirlab/tests/expected.py

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -121,28 +121,61 @@
121121
{'Field': 'CCDNUM', 'Type': 'str', 'Desc': ''},
122122
{'Field': 'CD1_1', 'Type': 'str', 'Desc': 'Coordinate matrix'}]
123123

124-
query_hdu_metadata = ['EXPTIME md5sum caldat archive_filename EQUINOX instrument proc_type AIRMASS',
125-
'------- -------------------------------- ---------- ----------------------------------------------------------------------- ------- ---------- --------- -------',
126-
' 90.0 004a631d6f5493e8adeb7123255380cb 2017-08-15 /net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz 2000.0 decam raw 1.04',
127-
' 90.0 004a631d6f5493e8adeb7123255380cb 2017-08-15 /net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz 2000.0 decam raw 1.04',
128-
' 90.0 004a631d6f5493e8adeb7123255380cb 2017-08-15 /net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz 2000.0 decam raw 1.04']
124+
query_hdu_metadata = [' CD1_2 CD1_1 proc_type md5sum caldat archive_filename instrument EXPTIME AIRMASS',
125+
'----------------- ----------------- --------- -------------------------------- ---------- ----------------------------------------------------------------------- ---------- ------- -------',
126+
'7.28535892432e-05 -1.8249413473e-07 raw 004a631d6f5493e8adeb7123255380cb 2017-08-15 /net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz decam 90 1.04',
127+
'7.28535892432e-05 -1.8249413473e-07 raw 004a631d6f5493e8adeb7123255380cb 2017-08-15 /net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz decam 90 1.04',
128+
'7.28535892432e-05 -1.8249413473e-07 raw 004a631d6f5493e8adeb7123255380cb 2017-08-15 /net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz decam 90 1.04']
129129

130-
query_hdu_metadata_raw = [{'META': {'endpoint': 'adv_search/find'},
131-
'PARAMETERS': {'rectype': 'hdu',
132-
'limit': 3,
133-
'sort': 'md5sum',
134-
'default_limit': 1000,
135-
'default_offset': 0,
136-
'default_sort': 'fitsfile__md5sum,hdu_idx',
137-
'oldest': None,
138-
'previd': None,
139-
'last': 3,
140-
'json_payload': {'outfields': ['md5sum', 'archive_filename', 'caldat', 'instrument', 'proc_type', 'AIRMASS', 'EXPTIME', 'EQUINOX'],
141-
'search': [['instrument', 'decam'], ['proc_type', 'raw'], ['caldat', '2017-08-14', '2017-08-16']]}},
142-
'HEADER': {'hdu:EXPTIME': 'str', 'hdu:md5sum': 'str', 'hdu:caldat': 'datetime64', 'hdu:archive_filename': 'str', 'hdu:EQUINOX': 'str', 'hdu:instrument': 'category', 'hdu:proc_type': 'category', 'hdu:AIRMASS': 'np.float64'}},
143-
{'hdu:EQUINOX': 2000.0, 'hdu:EXPTIME': 90.0, 'hdu:md5sum': '004a631d6f5493e8adeb7123255380cb', 'hdu:caldat': '2017-08-15', 'hdu:archive_filename': '/net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz', 'hdu:instrument': 'decam', 'hdu:proc_type': 'raw', 'hdu:AIRMASS': 1.04},
144-
{'hdu:EQUINOX': 2000.0, 'hdu:EXPTIME': 90.0, 'hdu:md5sum': '004a631d6f5493e8adeb7123255380cb', 'hdu:caldat': '2017-08-15', 'hdu:archive_filename': '/net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz', 'hdu:instrument': 'decam', 'hdu:proc_type': 'raw', 'hdu:AIRMASS': 1.04},
145-
{'hdu:EQUINOX': 2000.0, 'hdu:EXPTIME': 90.0, 'hdu:md5sum': '004a631d6f5493e8adeb7123255380cb', 'hdu:caldat': '2017-08-15', 'hdu:archive_filename': '/net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz', 'hdu:instrument': 'decam', 'hdu:proc_type': 'raw', 'hdu:AIRMASS': 1.04}]
130+
query_hdu_metadata_raw = [{"META": {"endpoint": "adv_search/find"},
131+
"PARAMETERS": {"rectype": "hdu",
132+
"format": "json",
133+
"limit": 3,
134+
"sort": "md5sum",
135+
"count": "n",
136+
"json_payload": {"outfields": ["md5sum",
137+
"archive_filename",
138+
"caldat",
139+
"instrument",
140+
"proc_type",
141+
"EXPTIME",
142+
"AIRMASS",
143+
"hdu:CD1_1",
144+
"hdu:CD1_2"],
145+
"search": [["caldat", "2017-08-14", "2017-08-16"],
146+
["instrument", "decam"],
147+
["proc_type", "raw"]]}},
148+
"HEADER": {"hdu:CD1_2": "str", "hdu:CD1_1": "str",
149+
"file:proc_type": "category", "file:md5sum": "str",
150+
"file:caldat": "datetime64", "file:archive_filename": "str",
151+
"file:instrument": "category", "file:EXPTIME": "str", "file:AIRMASS": "np.float64"}},
152+
{"hdu:CD1_2": 0.0000728535892432,
153+
"hdu:CD1_1": -1.8249413473e-7,
154+
"file:proc_type": "raw",
155+
"file:md5sum": "004a631d6f5493e8adeb7123255380cb",
156+
"file:caldat": "2017-08-15",
157+
"file:archive_filename": "/net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz",
158+
"file:instrument": "decam",
159+
"file:EXPTIME": 90,
160+
"file:AIRMASS": 1.04},
161+
{"hdu:CD1_2": 0.0000728535892432,
162+
"hdu:CD1_1": -1.8249413473e-7,
163+
"file:proc_type": "raw",
164+
"file:md5sum": "004a631d6f5493e8adeb7123255380cb",
165+
"file:caldat": "2017-08-15",
166+
"file:archive_filename": "/net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz",
167+
"file:instrument": "decam",
168+
"file:EXPTIME": 90,
169+
"file:AIRMASS": 1.04},
170+
{"hdu:CD1_2": 0.0000728535892432,
171+
"hdu:CD1_1": -1.8249413473e-7,
172+
"file:proc_type": "raw",
173+
"file:md5sum": "004a631d6f5493e8adeb7123255380cb",
174+
"file:caldat": "2017-08-15",
175+
"file:archive_filename": "/net/archive/mtn/20170815/ct4m/2017B-0110/c4d_170816_095757_ori.fits.fz",
176+
"file:instrument": "decam",
177+
"file:EXPTIME": 90,
178+
"file:AIRMASS": 1.04}]
146179

147180
categoricals = {'instruments': ['(p)odi',
148181
'90prime',

astroquery/noirlab/tests/test_noirlab.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def patch_request(monkeypatch):
5656
def test_service_metadata(patch_request, hdu):
5757
"""Test compliance with 6.1 of SIA spec v1.0.
5858
"""
59-
actual = NOIRLab.service_metadata(hdu=hdu)
59+
actual = NOIRLab._service_metadata(hdu=hdu)
6060
assert actual[0] == exp.service_metadata[0]
6161

6262

@@ -81,7 +81,7 @@ def test_query_region(patch_request, hdu, radius):
8181
def test_core_fields(patch_request, hdu):
8282
"""List the available CORE fields.
8383
"""
84-
actual = NOIRLab.core_fields(hdu=hdu)
84+
actual = NOIRLab.list_fields(hdu=hdu)
8585
if hdu:
8686
assert actual == exp.core_hdu_fields
8787
else:
@@ -92,7 +92,8 @@ def test_core_fields(patch_request, hdu):
9292
def test_aux_fields(patch_request, hdu):
9393
"""List the available AUX fields.
9494
"""
95-
actual = NOIRLab.aux_fields('decam', 'instcal', hdu=hdu)
95+
actual = NOIRLab.list_fields(aux=True, instrument='decam',
96+
proctype='instcal', hdu=hdu)
9697
if hdu:
9798
assert actual == exp.aux_hdu_fields
9899
else:
@@ -129,7 +130,8 @@ def test_query_hdu_metadata(patch_request):
129130
"proc_type",
130131
"EXPTIME",
131132
"AIRMASS",
132-
"EQUINOX"],
133+
"hdu:CD1_1",
134+
"hdu:CD1_2"],
133135
"search": [["caldat", "2017-08-14", "2017-08-16"],
134136
["instrument", "decam"],
135137
["proc_type", "raw"]]}
@@ -140,7 +142,7 @@ def test_query_hdu_metadata(patch_request):
140142
def test_categoricals(patch_request):
141143
"""List categories.
142144
"""
143-
actual = NOIRLab.categoricals()
145+
actual = NOIRLab.list_fields(categorical=True)
144146
assert actual == exp.categoricals
145147

146148

0 commit comments

Comments
 (0)