Skip to content

Commit 95c9216

Browse files
authored
Merge pull request #3017 from weaverba137/sdss-dr18-urls
Update download URLs for SDSS DR18
2 parents 5d42c1f + b014ad0 commit 95c9216

File tree

5 files changed

+192
-45
lines changed

5 files changed

+192
-45
lines changed

CHANGES.rst

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ vizier
4444
- Change the type of raised error when the catalog is not found in ``Vizier.get_catalog_metadata``
4545
from ``IndexError`` to ``EmptyResponseError`` [#2980]
4646

47+
sdss
48+
^^^^
49+
50+
- Support new SDSS-V DR18 access URLs. [#3017]
51+
4752
simbad
4853
^^^^^^
4954

astroquery/sdss/core.py

+46-18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""
33
Access Sloan Digital Sky Survey database online.
44
"""
5+
import re
56
import warnings
67
import numpy as np
78
import sys
@@ -11,12 +12,12 @@
1112
from astropy.table import Table, Column
1213
from astropy.utils.exceptions import AstropyWarning
1314

14-
from ..query import BaseQuery
15-
from . import conf
16-
from ..utils import commons, async_to_sync, prepend_docstr_nosections
17-
from ..exceptions import RemoteServiceError, NoResultsWarning
18-
from .field_names import (photoobj_defs, specobj_defs,
19-
crossid_defs, get_field_info)
15+
from astroquery.query import BaseQuery
16+
from astroquery.sdss import conf
17+
from astroquery.utils import commons, async_to_sync, prepend_docstr_nosections
18+
from astroquery.exceptions import RemoteServiceError, NoResultsWarning
19+
from astroquery.sdss.field_names import (photoobj_defs, specobj_defs,
20+
crossid_defs, get_field_info)
2021

2122
__all__ = ['SDSS', 'SDSSClass']
2223
__doctest_skip__ = ['SDSSClass.*']
@@ -28,6 +29,7 @@
2829
@async_to_sync
2930
class SDSSClass(BaseQuery):
3031
TIMEOUT = conf.timeout
32+
PARSE_BOSS_RUN2D = re.compile(r'v(?P<major>[0-9]+)_(?P<minor>[0-9]+)_(?P<bugfix>[0-9]+)')
3133
MAX_CROSSID_RADIUS = 3.0 * u.arcmin
3234
QUERY_URL_SUFFIX_DR_OLD = '/dr{dr}/en/tools/search/x_sql.asp'
3335
QUERY_URL_SUFFIX_DR_10 = '/dr{dr}/en/tools/search/x_sql.aspx'
@@ -39,8 +41,9 @@ class SDSSClass(BaseQuery):
3941
'{rerun}/{run}/{camcol}/'
4042
'frame-{band}-{run:06d}-{camcol}-'
4143
'{field:04d}.fits.bz2')
42-
SPECTRA_URL_SUFFIX = ('{base}/dr{dr}/sdss/spectro/redux/'
43-
'{run2d}/spectra/{plate:0>4d}/'
44+
# Note: {plate:0>4d} does allow 5-digit plates, while still zero-padding 3-digit plates.
45+
SPECTRA_URL_SUFFIX = ('{base}/dr{dr}/{redux_path}/'
46+
'{run2d}/{spectra_path}/{plate:0>4d}/'
4447
'spec-{plate:0>4d}-{mjd}-{fiber:04d}.fits')
4548

4649
TEMPLATES_URL = 'http://classic.sdss.org/dr7/algorithms/spectemplates/spDR2'
@@ -737,12 +740,39 @@ def get_spectra_async(self, *, coordinates=None, radius=2. * u.arcsec,
737740
run2d = str(row['run2d'])
738741
else:
739742
run2d = row['run2d']
743+
format_args = dict()
744+
format_args['base'] = conf.sas_baseurl
745+
format_args['dr'] = data_release
746+
format_args['redux_path'] = 'sdss/spectro/redux'
747+
format_args['run2d'] = run2d
748+
format_args['spectra_path'] = 'spectra'
749+
format_args['mjd'] = row['mjd']
750+
try:
751+
format_args['plate'] = row['plate']
752+
format_args['fiber'] = row['fiberID']
753+
except KeyError:
754+
format_args['fieldid'] = row['fieldID']
755+
format_args['catalogid'] = row['catalogID']
740756
if data_release > 15 and run2d not in ('26', '103', '104'):
741-
linkstr = linkstr.replace('/spectra/', '/spectra/full/')
742-
link = linkstr.format(
743-
base=conf.sas_baseurl, dr=data_release,
744-
run2d=run2d, plate=row['plate'],
745-
fiber=row['fiberID'], mjd=row['mjd'])
757+
#
758+
# Still want this applied to data_release > 17.
759+
#
760+
format_args['spectra_path'] = 'spectra/full'
761+
if data_release > 17:
762+
#
763+
# This change will fix everything except run2d==v6_0_4 in DR18,
764+
# which is handled by the if major > 5 block below.
765+
#
766+
format_args['redux_path'] = 'spectro/sdss/redux'
767+
match_run2d = self.PARSE_BOSS_RUN2D.match(run2d)
768+
if match_run2d is not None:
769+
major = int(match_run2d.group('major'))
770+
if major > 5:
771+
linkstr = linkstr.replace('/{plate:0>4d}/', '/{fieldid:0>4d}p/{mjd:5d}/')
772+
linkstr = linkstr.replace('spec-{plate:0>4d}-{mjd}-{fiber:04d}.fits',
773+
'spec-{fieldid:0>4d}-{mjd:5d}-{catalogid:0>11d}.fits')
774+
775+
link = linkstr.format(**format_args)
746776
results.append(commons.FileContainer(link,
747777
encoding='binary',
748778
remote_timeout=timeout,
@@ -903,6 +933,8 @@ def get_images_async(self, coordinates=None, radius=2. * u.arcsec,
903933
instrument = 'boss'
904934
if data_release > 12:
905935
instrument = 'eboss'
936+
if data_release > 17:
937+
instrument = 'prior-surveys/sdss4-dr17-eboss'
906938
link = linkstr.format(base=conf.sas_baseurl, run=row['run'],
907939
dr=data_release, instrument=instrument,
908940
rerun=row['rerun'], camcol=row['camcol'],
@@ -1267,7 +1299,7 @@ def _get_crossid_url(self, data_release):
12671299
self._last_url = url
12681300
return url
12691301

1270-
def _rectangle_sql(self, ra, dec, width, height=None, cosdec=False):
1302+
def _rectangle_sql(self, ra, dec, width, height=None):
12711303
"""
12721304
Generate SQL for a rectangular query centered on ``ra``, ``dec``.
12731305
@@ -1284,10 +1316,6 @@ def _rectangle_sql(self, ra, dec, width, height=None, cosdec=False):
12841316
Width of rectangle in degrees.
12851317
height : float, optional
12861318
Height of rectangle in degrees. If not specified, ``width`` is used.
1287-
cosdec : bool, optional
1288-
If ``True`` apply ``cos(dec)`` correction to the rectangle.
1289-
Otherwise, rectangles become increasingly triangle-like
1290-
near the poles.
12911319
12921320
Returns
12931321
-------

astroquery/sdss/field_names.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from astropy.utils.data import get_pkg_data_contents
77
from astropy.utils.exceptions import AstropyUserWarning
88

9-
from . import conf
10-
from ..utils.mocks import MockResponse
9+
from astroquery.sdss import conf
10+
from astroquery.utils.mocks import MockResponse
1111

1212
__all__ = ['get_field_info', 'photoobj_defs', 'specobj_defs', 'crossid_defs']
1313

astroquery/sdss/tests/test_sdss.py

+96-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
from astropy.utils.exceptions import AstropyWarning
1616
import pytest
1717

18-
from ... import sdss
18+
from astroquery.sdss import conf
19+
from astroquery import sdss
20+
from astroquery.exceptions import TimeoutError
21+
from astroquery.utils import commons
1922
from astroquery.utils.mocks import MockResponse
20-
from ...exceptions import TimeoutError
21-
from ...utils import commons
2223

2324
# actual spectra/data are a bit heavy to include in astroquery, so we don't try
2425
# to deal with them. Would be nice to find a few very small examples
@@ -114,7 +115,7 @@ def data_path(filename):
114115
coords_column = Column(coords_list, name='coordinates')
115116

116117
# List of all data releases.
117-
dr_list = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)
118+
dr_list = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
118119

119120

120121
# We are not testing queries for DR11 because it is not easily available to
@@ -145,6 +146,47 @@ def url_tester_crossid(data_release):
145146
assert sdss.SDSS._last_url == baseurl
146147

147148

149+
def url_tester_images(data_release, rerun, run, camcol, band, field):
150+
instrument = 'boss'
151+
if data_release > 12:
152+
instrument = 'eboss'
153+
if data_release > 17:
154+
instrument = 'prior-surveys/sdss4-dr17-eboss'
155+
url = sdss.SDSS.IMAGING_URL_SUFFIX.format(base=conf.sas_baseurl, run=run,
156+
dr=data_release, instrument=instrument,
157+
rerun=rerun, camcol=camcol,
158+
field=field, band=band)
159+
return url
160+
161+
162+
def url_tester_spectra(data_release, run2d, plate, mjd, fiber):
163+
linkstr = sdss.SDSS.SPECTRA_URL_SUFFIX
164+
eFEDS = False
165+
redux_path = 'sdss/spectro/redux'
166+
spectra_path = 'spectra'
167+
if data_release > 15 and run2d not in ('26', '103', '104'):
168+
spectra_path = 'spectra/full'
169+
if data_release > 17:
170+
redux_path = 'spectro/sdss/redux'
171+
match_run2d = sdss.SDSS.PARSE_BOSS_RUN2D.match(run2d)
172+
if match_run2d is not None:
173+
major = int(match_run2d.group('major'))
174+
if major > 5:
175+
eFEDS = True
176+
linkstr = linkstr.replace('/{plate:0>4d}/', '/{fieldid:0>4d}p/{mjd:5d}/')
177+
linkstr = linkstr.replace('spec-{plate:0>4d}-{mjd}-{fiber:04d}.fits',
178+
'spec-{fieldid:0>4d}-{mjd:5d}-{catalogid:0>11d}.fits')
179+
if eFEDS:
180+
url = linkstr.format(base=conf.sas_baseurl, dr=data_release,
181+
redux_path=redux_path, run2d=run2d, spectra_path=spectra_path,
182+
fieldid=plate, catalogid=fiber, mjd=mjd)
183+
else:
184+
url = linkstr.format(base=conf.sas_baseurl, dr=data_release,
185+
redux_path=redux_path, run2d=run2d, spectra_path=spectra_path,
186+
plate=plate, fiber=fiber, mjd=mjd)
187+
return url
188+
189+
148190
def compare_xid_data(xid, data):
149191
for col in xid.colnames:
150192
if xid[col].dtype.type is np.str_:
@@ -660,6 +702,56 @@ def test_get_images_coordinates_payload(patch_request, dr):
660702
assert query_payload['photoScope'] == 'nearPrim'
661703

662704

705+
@pytest.mark.parametrize("dr", dr_list)
706+
def test_get_images_async_url(patch_request, patch_get_readable_fileobj, dr):
707+
matches = Table()
708+
matches['run'] = [1, 12, 123, 1234]
709+
matches['camcol'] = [1, 2, 4, 6]
710+
matches['field'] = [10, 100, 1000, 10000]
711+
matches['rerun'] = [301, 301, 301, 301]
712+
download_urls = sdss.SDSS.get_images_async(matches=matches, band='ugriz',
713+
data_release=dr)
714+
for i, row in enumerate(matches):
715+
for j, band in enumerate('ugriz'):
716+
k = 5*i + j
717+
assert download_urls[k]._target == url_tester_images(dr,
718+
row['rerun'],
719+
row['run'],
720+
row['camcol'],
721+
band,
722+
row['field'])
723+
724+
725+
@pytest.mark.parametrize("dr", dr_list)
726+
def test_get_spectra_async_url(patch_request, patch_get_readable_fileobj, dr):
727+
matches = Table()
728+
matches['plate'] = [12, 123, 1234, 1234, 5432, 12345]
729+
matches['fiberID'] = [10, 100, 621, 123, 456, 986]
730+
matches['mjd'] = [54321, 54321, 54321, 65432, 76543, 87654]
731+
matches['run2d'] = ['26', '26', '26', 'v5_12_2', 'v5_12_2', 'v5_12_2']
732+
download_urls = sdss.SDSS.get_spectra_async(matches=matches,
733+
data_release=dr)
734+
for i, row in enumerate(matches):
735+
assert matches[i]['plate'] == row['plate']
736+
assert download_urls[i]._target == url_tester_spectra(dr, row['run2d'],
737+
row['plate'],
738+
row['mjd'],
739+
row['fiberID'])
740+
if dr > 17:
741+
matches = Table()
742+
matches['fieldID'] = [15170, 15265]
743+
matches['mjd'] = [59292, 59316]
744+
matches['catalogID'] = [4570401475, 4592713531]
745+
matches['run2d'] = ['v6_0_4', 'v6_0_4']
746+
download_urls = sdss.SDSS.get_spectra_async(matches=matches,
747+
data_release=dr)
748+
for i, row in enumerate(matches):
749+
assert download_urls[i]._target == url_tester_spectra(dr, row['run2d'],
750+
row['fieldID'],
751+
row['mjd'],
752+
row['catalogID'])
753+
754+
663755
@pytest.mark.parametrize("dr", dr_list)
664756
def test_spectra_plate_mjd_payload(patch_request, dr):
665757
expect = ("SELECT DISTINCT "

astroquery/sdss/tests/test_sdss_remote.py

+43-21
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010

1111
from urllib.error import URLError
1212

13-
from ... import sdss
14-
from ...exceptions import TimeoutError
13+
# Timeout is the superclass of both ReadTimeout and ConnectTimeout
14+
from requests.exceptions import Timeout
15+
16+
from astroquery import sdss
17+
from astroquery.exceptions import TimeoutError
1518

1619
# DR11 is a quasi-internal data release that does not have SkyServer support.
17-
dr_list = (8, 9, 10, 12, 13, 14, 15, 16, 17)
20+
dr_list = (8, 9, 10, 12, 13, 14, 15, 16, 17, 18)
1821
dr_warn_list = (8, 9)
1922

2023

@@ -57,19 +60,38 @@ def test_sdss_spectrum(self, dr):
5760
xid = sdss.SDSS.query_region(self.coords, width=2.0 * u.arcsec, spectro=True, data_release=dr)
5861

5962
assert isinstance(xid, Table)
60-
sdss.SDSS.get_spectra(matches=xid, data_release=dr)
63+
downloaded_files = sdss.SDSS.get_spectra(matches=xid, data_release=dr)
64+
assert len(downloaded_files) == len(xid)
6165

6266
def test_sdss_spectrum_plate_mjd_fiber(self):
63-
"""These plates are only available in recent data releases.
67+
"""These plates are only available in relatively recent data releases.
68+
"""
69+
downloaded_files = sdss.SDSS.get_spectra(plate=9403, mjd=58018, fiberID=485, data_release=16)
70+
assert len(downloaded_files) == 1
71+
downloaded_files = sdss.SDSS.get_spectra(plate=10909, mjd=58280, fiberID=485, data_release=16)
72+
assert len(downloaded_files) == 1
73+
74+
def test_sdss_spectrum_field_mjd_catalog(self):
75+
"""These eFEDS spectra are only available in data releases >= 18.
76+
77+
https://data.sdss.org/sas/dr18/spectro/sdss/redux/v6_0_4/spectra/full/15170p/59292/spec-15170-59292-04570401475.fits
78+
https://data.sdss.org/sas/dr18/spectro/sdss/redux/v6_0_4/spectra/full/15265p/59316/spec-15265-59316-04592713531.fits
6479
"""
65-
sdss.SDSS.get_spectra(plate=9403, mjd=58018, fiberID=485, data_release=16)
66-
sdss.SDSS.get_spectra(plate=10909, mjd=58280, fiberID=485, data_release=16)
80+
matches = Table()
81+
matches['fieldID'] = [15170, 15265]
82+
matches['mjd'] = [59292, 59316]
83+
matches['catalogID'] = [4570401475, 4592713531]
84+
matches['run2d'] = ['v6_0_4', 'v6_0_4']
85+
downloaded_files = sdss.SDSS.get_spectra(matches=matches, data_release=18, cache=False)
86+
assert len(downloaded_files) == 2
6787

6888
def test_sdss_spectrum_mjd(self):
69-
sdss.SDSS.get_spectra(plate=2345, fiberID=572)
89+
downloaded_files = sdss.SDSS.get_spectra(plate=2345, fiberID=572)
90+
assert len(downloaded_files) == 1
7091

7192
def test_sdss_spectrum_coords(self):
72-
sdss.SDSS.get_spectra(coordinates=self.coords)
93+
downloaded_files = sdss.SDSS.get_spectra(coordinates=self.coords)
94+
assert len(downloaded_files) == 1
7395

7496
def test_sdss_sql(self):
7597
query = """
@@ -88,16 +110,20 @@ class = 'galaxy'
88110
def test_sdss_image(self):
89111
xid = sdss.SDSS.query_region(self.coords, width=2.0 * u.arcsec)
90112
assert isinstance(xid, Table)
91-
sdss.SDSS.get_images(matches=xid)
113+
downloaded_files = sdss.SDSS.get_images(matches=xid)
114+
assert len(downloaded_files) == len(xid)
92115

93116
def test_sdss_template(self):
94-
sdss.SDSS.get_spectral_template('qso')
117+
downloaded_files = sdss.SDSS.get_spectral_template('qso')
118+
assert len(downloaded_files) == 1
95119

96120
def test_sdss_image_run(self):
97-
sdss.SDSS.get_images(run=1904, camcol=3, field=164)
121+
downloaded_files = sdss.SDSS.get_images(run=1904, camcol=3, field=164)
122+
assert len(downloaded_files) == 1
98123

99124
def test_sdss_image_coord(self):
100-
sdss.SDSS.get_images(coordinates=self.coords)
125+
downloaded_files = sdss.SDSS.get_images(coordinates=self.coords)
126+
assert len(downloaded_files) == 1
101127

102128
def test_sdss_specobj(self):
103129
colnames = ['ra', 'dec', 'objid', 'run', 'rerun', 'camcol', 'field',
@@ -157,17 +183,13 @@ def test_sdss_photoobj(self):
157183
else:
158184
assert xid[i][c] == row[c]
159185

160-
@pytest.mark.xfail(reason=("Timeout isn't raised since switching to "
161-
"self._request, fix it before merging #586"))
162186
def test_query_timeout(self):
163-
with pytest.raises(TimeoutError):
164-
sdss.SDSS.query_region(self.coords, timeout=self.mintimeout)
187+
with pytest.raises(Timeout):
188+
sdss.SDSS.query_region(self.coords, width=2.0 * u.arcsec, cache=False, timeout=self.mintimeout)
165189

166-
@pytest.mark.xfail(reason=("Timeout isn't raised since switching to "
167-
"self._request, fix it before merging #586"))
168190
def test_spectra_timeout(self):
169-
with pytest.raises(TimeoutError):
170-
sdss.SDSS.get_spectra(coordinates=self.coords, timeout=self.mintimeout)
191+
with pytest.raises(Timeout):
192+
sdss.SDSS.get_spectra(coordinates=self.coords, cache=False, timeout=self.mintimeout)
171193

172194
def test_query_non_default_field(self):
173195
# A regression test for #469

0 commit comments

Comments
 (0)