Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simbad: refactor to use TAP #2954

Merged
merged 28 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6de7ce5
refactor: simbad query methods now call query_tap internally
ManonMarchand Feb 20, 2024
e133042
lint: add yacc and lex automatically generated files to flake8 ignore
ManonMarchand Feb 20, 2024
506fe36
fix: add a __call__ definition to make BaseVOQuery behave as BaseQuery
ManonMarchand Feb 20, 2024
879bcef
add query_criteria_fialds.json
ManonMarchand Feb 20, 2024
43a791d
docs: document simbad refactoring
ManonMarchand Feb 20, 2024
bfbbc77
fix: propagate simbad changes to jwst module
ManonMarchand Feb 21, 2024
afaddfc
docs: propagate simbad changes into the general documentation
ManonMarchand Feb 21, 2024
cf88d47
docs: simbad cache works differently now
ManonMarchand Feb 21, 2024
c961fd7
tests: add simbad_output_options to path_tests
ManonMarchand Feb 22, 2024
d892a45
refactor: remove utilities for the former sim script queries
ManonMarchand Mar 25, 2024
198cdeb
feat: add bibcodelist to possible outputs
ManonMarchand Mar 25, 2024
6088f25
test: complete coverage of simbad utils
ManonMarchand Mar 25, 2024
a7c07b4
tests: improve coverage for the tests without remote access
ManonMarchand Mar 27, 2024
650595f
docs: update simbad's doc
ManonMarchand Mar 28, 2024
2a5eff3
fix: typo in vizier link
ManonMarchand Mar 28, 2024
95232f2
feat: add ROW_LIMIT as a settable property
ManonMarchand Apr 8, 2024
91789f1
rename 'add_to_output' into 'add_output_columns'
ManonMarchand Apr 16, 2024
3f3d52b
docs: edit version of deprecation
ManonMarchand Apr 16, 2024
a795f82
feat: reduce API changes
ManonMarchand Jun 3, 2024
34000cf
docs: edits on votable fields utils
ManonMarchand Jun 3, 2024
aacd4ae
docs: add changelog
ManonMarchand Jun 3, 2024
e804139
fix: rename typed_id into user_specified_id
ManonMarchand Jun 4, 2024
82d6d2e
feat: add get_query_payload for the methods using TAP
ManonMarchand Jun 5, 2024
b87c23d
fix: wildcards in query_objects
ManonMarchand Jun 14, 2024
4534b22
docs: edit docstring and changelog from review
ManonMarchand Jun 17, 2024
7c51ec9
tests: new measurement for sirius rotation
ManonMarchand Jun 20, 2024
86ed0d7
refactor: remove Column and Join from SimbadClass
ManonMarchand Jun 20, 2024
6594ebb
DOC: minor changelog rephrase and reformat
bsipocz Jun 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,51 @@ vizier
- Change the type of raised error when the catalog is not found in ``Vizier.get_catalog_metadata``
from ``IndexError`` to ``EmptyResponseError`` [#2980]

simbad
^^^^^^

- The ``ROW_LIMIT`` value to have the maximum number of rows is now -1.
Use ``ROW_LIMIT = 0`` to retrieve the output's meta-data. [#2954]

- ``ROW_LIMIT`` can now be set at instantiation
(e.g.: ``simbad = Simbad(ROW_LIMIT=10))``). [#2954]

- ``list_votable_fields`` now return an astropy Table with added fields
information instead of a list of strings. [#2954]

- ``list_votable_fields`` is now queried directly from SIMBAD instead of reading
a file in astroquery. This prevents it from being outdated. [#2954]

- ``get_votable_fields`` now prints the table name and column name instead of
just the column name. [#2954]

- The ``verbose`` and ``cache`` kwargs have been deprecated from all methods
as they have no effect with with the new query interface. [#2954]

- ``get_adql`` is deprecated and replaced by ``get_query_payload`` in
``list_columns`` and ``list_table``.
The payload output contains the ADQL under the ``QUERY`` key. [#2954]

- all query methods except ``query_tap`` and ``query_criteria`` now accept a
``criteria`` argument to restrict the results with custom criteria. [#2954]

- ``query_objects`` outputs now have an additional column ``user_specified_id``
containing the objects' name as specified by the user.
The ``votable_field`` option ``typed_id`` is removed. [#2954]

- The ``equinox`` and ``epoch`` kwargs are deprecated in ``query_region``,
use astropy.coordinates.SkyCoord directly instead. [#2954]

- ``query_bibcode`` has a new option ``abstract`` that allows to also
retrieve the article's abstract. [#2954]

- ``query_bibcode`` output is now in an astropy Table with distinct columns
instead of a single one in which all the information was a string. [#2954]

- ``query_criteria`` is now deprecated and should be replaced by either custom
TAP queries or by the ``criteria`` argument added in the other query methods.
A helper method was added ``astroquery.simbad.utils.CriteriaTranslator`` to
translate between the sim-script syntax and the TAP/ADQL syntax. [#2954]

skyview
^^^^^^^
Expand Down
7 changes: 4 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ website <https://simbad.cds.unistra.fr/simbad/>`_, use the ``simbad`` sub-packag
>>> from astroquery.simbad import Simbad
>>> theta1c = Simbad.query_object('tet01 Ori C')
>>> theta1c.pprint()
MAIN_ID RA DEC ... COO_QUAL COO_WAVELENGTH COO_BIBCODE
------------- ------------- ------------- ... -------- -------------- -------------------
* tet01 Ori C 05 35 16.4637 -05 23 22.848 ... A O 2007A&A...474..653V
main_id ra dec ... coo_wavelength coo_bibcode matched_id
deg deg ...
------------- ------------- ------------- ... -------------- ------------------- -------------
* tet01 Ori C 83.8186095697 -5.3897005033 ... O 2020yCat.1350....0G * tet01 Ori C

Installation and Requirements
-----------------------------
Expand Down
9 changes: 6 additions & 3 deletions astroquery/esa/jwst/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,12 @@ def resolve_target_coordinates(self, target_name, target_resolver):
if target_resolver == "ALL" or target_resolver == "SIMBAD":
try:
result_table = Simbad.query_object(target_name)
return SkyCoord((f'{result_table["RA"][0]} '
f'{result_table["DEC"][0]}'),
unit=(units.hourangle,
# new simbad behavior does not return None but an empty table
if len(result_table) == 0:
result_table = None
return SkyCoord((f'{result_table["ra"][0]} '
f'{result_table["dec"][0]}'),
unit=(units.deg,
units.deg), frame="icrs")
except (KeyError, TypeError, ConnectionError):
log.info("SIMBAD could not resolve this target")
Expand Down
73 changes: 73 additions & 0 deletions astroquery/esa/jwst/tests/data/simbad_M1.vot
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Produced with astropy.io.votable version 6.0.0
http://www.astropy.org/ -->
<VOTABLE version="1.3" xmlns="http://www.ivoa.net/xml/VOTable/v1.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/VOTable-1.3.xsd">
<RESOURCE type="results">
<INFO ID="QUERY_STATUS" name="QUERY_STATUS" value="OK"/>
<INFO ID="PROVIDER" name="PROVIDER" value="CDS">SIMBAD TAP Service</INFO>
<INFO ID="QUERY" name="QUERY" value="SELECT basic.&quot;main_id&quot;, basic.&quot;ra&quot;, basic.&quot;dec&quot;, basic.&quot;coo_err_maj&quot;, basic.&quot;coo_err_min&quot;, basic.&quot;coo_err_angle&quot;, basic.&quot;coo_wavelength&quot;, basic.&quot;coo_bibcode&quot;, ident.&quot;id&quot; AS matched_id FROM basic JOIN ident ON basic.&quot;oid&quot; = ident.&quot;oidref&quot; WHERE id = &apos;M1&apos;"/>
<TABLE ID="result_S1708521282485" name="result_S1708521282485">
<FIELD ID="main_id" arraysize="*" datatype="char" name="main_id" ucd="meta.id;meta.main">
<DESCRIPTION>
Main identifier for an object
</DESCRIPTION>
</FIELD>
<FIELD ID="ra" datatype="double" name="ra" ucd="pos.eq.ra;meta.main" unit="deg">
<DESCRIPTION>
Right ascension
</DESCRIPTION>
</FIELD>
<FIELD ID="dec" datatype="double" name="dec" ucd="pos.eq.dec;meta.main" unit="deg">
<DESCRIPTION>
Declination
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_err_maj" datatype="float" name="coo_err_maj" ucd="phys.angSize.smajAxis;pos.errorEllipse;pos.eq" unit="mas">
<DESCRIPTION>
Coordinate error major axis
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_err_min" datatype="float" name="coo_err_min" ucd="phys.angSize.sminAxis;pos.errorEllipse;pos.eq" unit="mas">
<DESCRIPTION>
Coordinate error minor axis
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_err_angle" datatype="short" name="coo_err_angle" ucd="pos.posAng;pos.errorEllipse;pos.eq" unit="deg">
<DESCRIPTION>
Coordinate error angle
</DESCRIPTION>
<VALUES null="-32768"/>
</FIELD>
<FIELD ID="coo_wavelength" arraysize="1" datatype="char" name="coo_wavelength" ucd="instr.bandpass;pos.eq">
<DESCRIPTION>
Wavelength class for the origin of the coordinates (R,I,V,U,X,G)
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_bibcode" arraysize="*" datatype="char" name="coo_bibcode" ucd="meta.bib.bibcode;pos.eq">
<DESCRIPTION>
Coordinate reference
</DESCRIPTION>
</FIELD>
<FIELD ID="matched_id" arraysize="*" datatype="char" name="matched_id" ucd="meta.id">
<DESCRIPTION>
Identifier
</DESCRIPTION>
</FIELD>
<DATA>
<TABLEDATA>
<TR>
<TD>M 1</TD>
<TD>83.6287</TD>
<TD>22.0147</TD>
<TD>18500</TD>
<TD>18500</TD>
<TD>0</TD>
<TD>R</TD>
<TD>1995AuJPh..48..143S</TD>
<TD>M 1</TD>
</TR>
</TABLEDATA>
</DATA>
</TABLE>
</RESOURCE>
</VOTABLE>
58 changes: 58 additions & 0 deletions astroquery/esa/jwst/tests/data/simbad_TEST.vot
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Produced with astropy.io.votable version 6.0.0
http://www.astropy.org/ -->
<VOTABLE version="1.3" xmlns="http://www.ivoa.net/xml/VOTable/v1.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/VOTable-1.3.xsd">
<RESOURCE type="results">
<INFO ID="QUERY_STATUS" name="QUERY_STATUS" value="OK"/>
<INFO ID="PROVIDER" name="PROVIDER" value="CDS">SIMBAD TAP Service</INFO>
<INFO ID="QUERY" name="QUERY" value="SELECT basic.&quot;main_id&quot;, basic.&quot;ra&quot;, basic.&quot;dec&quot;, basic.&quot;coo_err_maj&quot;, basic.&quot;coo_err_min&quot;, basic.&quot;coo_err_angle&quot;, basic.&quot;coo_wavelength&quot;, basic.&quot;coo_bibcode&quot;, ident.&quot;id&quot; AS matched_id FROM basic JOIN ident ON basic.&quot;oid&quot; = ident.&quot;oidref&quot; WHERE id = &apos;TEST&apos;"/>
<TABLE ID="result_S1708521454265" name="result_S1708521454265">
<FIELD ID="main_id" arraysize="*" datatype="char" name="main_id" ucd="meta.id;meta.main">
<DESCRIPTION>
Main identifier for an object
</DESCRIPTION>
</FIELD>
<FIELD ID="ra" datatype="double" name="ra" ucd="pos.eq.ra;meta.main" unit="deg">
<DESCRIPTION>
Right ascension
</DESCRIPTION>
</FIELD>
<FIELD ID="dec" datatype="double" name="dec" ucd="pos.eq.dec;meta.main" unit="deg">
<DESCRIPTION>
Declination
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_err_maj" datatype="float" name="coo_err_maj" ucd="phys.angSize.smajAxis;pos.errorEllipse;pos.eq" unit="mas">
<DESCRIPTION>
Coordinate error major axis
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_err_min" datatype="float" name="coo_err_min" ucd="phys.angSize.sminAxis;pos.errorEllipse;pos.eq" unit="mas">
<DESCRIPTION>
Coordinate error minor axis
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_err_angle" datatype="short" name="coo_err_angle" ucd="pos.posAng;pos.errorEllipse;pos.eq" unit="deg">
<DESCRIPTION>
Coordinate error angle
</DESCRIPTION>
<VALUES null="-32768"/>
</FIELD>
<FIELD ID="coo_wavelength" arraysize="1" datatype="char" name="coo_wavelength" ucd="instr.bandpass;pos.eq">
<DESCRIPTION>
Wavelength class for the origin of the coordinates (R,I,V,U,X,G)
</DESCRIPTION>
</FIELD>
<FIELD ID="coo_bibcode" arraysize="*" datatype="char" name="coo_bibcode" ucd="meta.bib.bibcode;pos.eq">
<DESCRIPTION>
Coordinate reference
</DESCRIPTION>
</FIELD>
<FIELD ID="matched_id" arraysize="*" datatype="char" name="matched_id" ucd="meta.id">
<DESCRIPTION>
Identifier
</DESCRIPTION>
</FIELD>
</TABLE>
</RESOURCE>
</VOTABLE>
104 changes: 55 additions & 49 deletions astroquery/esa/jwst/tests/test_jwsttap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import os
import shutil
from pathlib import Path
from unittest.mock import MagicMock
from unittest.mock import MagicMock, patch
import sys
import io

Expand All @@ -21,14 +21,15 @@
from astropy import units
from astropy.coordinates.name_resolve import NameResolveError
from astropy.coordinates.sky_coordinate import SkyCoord
from astropy.io.votable import parse_single_table
from astropy.table import Table
from astropy.units import Quantity
from astroquery.exceptions import TableParseError

from astroquery.esa.jwst import JwstClass
from astroquery.esa.jwst.tests.DummyTapHandler import DummyTapHandler
from astroquery.ipac.ned import Ned
from astroquery.simbad import Simbad
from astroquery.simbad import SimbadClass
from astroquery.utils.tap.conn.tests.DummyConnHandler import DummyConnHandler
from astroquery.utils.tap.conn.tests.DummyResponse import DummyResponse
from astroquery.utils.tap.core import TapPlus
Expand Down Expand Up @@ -914,53 +915,58 @@ def __check_extracted_files(self, files_expected, files_returned):
raise ValueError(f"Not found expected file: {f}")

def test_query_target_error(self):
jwst = JwstClass(show_messages=False)
simbad = Simbad()
ned = Ned()
vizier = Vizier()
# Testing default parameters
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="M1", target_resolver="")
assert "This target resolver is not allowed" in err.value.args[0]
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target("TEST")
assert ('This target name cannot be determined with this '
'resolver: ALL' in err.value.args[0] or 'Failed to parse' in err.value.args[0])
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="M1", target_resolver="ALL")
assert err.value.args[0] in ["This target name cannot be determined "
"with this resolver: ALL", "Missing "
"required argument: 'width'"]

# Testing no valid coordinates from resolvers
simbad_file = data_path('test_query_by_target_name_simbad_ned_error.vot')
simbad_table = Table.read(simbad_file)
simbad.query_object = MagicMock(return_value=simbad_table)
ned_file = data_path('test_query_by_target_name_simbad_ned_error.vot')
ned_table = Table.read(ned_file)
ned.query_object = MagicMock(return_value=ned_table)
vizier_file = data_path('test_query_by_target_name_vizier_error.vot')
vizier_table = Table.read(vizier_file)
vizier.query_object = MagicMock(return_value=vizier_table)

# coordinate_error = 'coordinate must be either a string or astropy.coordinates'
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="test", target_resolver="SIMBAD",
radius=units.Quantity(5, units.deg))
assert ('This target name cannot be determined with this '
'resolver: SIMBAD' in err.value.args[0] or 'Failed to parse' in err.value.args[0])

with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="test", target_resolver="NED",
radius=units.Quantity(5, units.deg))
assert ('This target name cannot be determined with this '
'resolver: NED' in err.value.args[0] or 'Failed to parse' in err.value.args[0])

with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="test", target_resolver="VIZIER",
radius=units.Quantity(5, units.deg))
assert ('This target name cannot be determined with this resolver: '
'VIZIER' in err.value.args[0] or 'Failed to parse' in err.value.args[0])
# need to patch simbad query object here
with patch("astroquery.simbad.SimbadClass.query_object",
side_effect=lambda object_name: parse_single_table(
Path(__file__).parent / "data" / f"simbad_{object_name}.vot"
).to_table()):
jwst = JwstClass(show_messages=False)
simbad = SimbadClass()
ned = Ned()
vizier = Vizier()
# Testing default parameters
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="M1", target_resolver="")
assert "This target resolver is not allowed" in err.value.args[0]
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target("TEST")
assert ('This target name cannot be determined with this '
'resolver: ALL' in err.value.args[0] or 'Failed to parse' in err.value.args[0])
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="M1", target_resolver="ALL")
assert err.value.args[0] in ["This target name cannot be determined "
"with this resolver: ALL", "Missing "
"required argument: 'width'"]

# Testing no valid coordinates from resolvers
simbad_file = data_path('test_query_by_target_name_simbad_ned_error.vot')
simbad_table = Table.read(simbad_file)
simbad.query_object = MagicMock(return_value=simbad_table)
ned_file = data_path('test_query_by_target_name_simbad_ned_error.vot')
ned_table = Table.read(ned_file)
ned.query_object = MagicMock(return_value=ned_table)
vizier_file = data_path('test_query_by_target_name_vizier_error.vot')
vizier_table = Table.read(vizier_file)
vizier.query_object = MagicMock(return_value=vizier_table)

# coordinate_error = 'coordinate must be either a string or astropy.coordinates'
with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="TEST", target_resolver="SIMBAD",
radius=units.Quantity(5, units.deg))
assert ('This target name cannot be determined with this '
'resolver: SIMBAD' in err.value.args[0] or 'Failed to parse' in err.value.args[0])

with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="TEST", target_resolver="NED",
radius=units.Quantity(5, units.deg))
assert ('This target name cannot be determined with this '
'resolver: NED' in err.value.args[0] or 'Failed to parse' in err.value.args[0])

with pytest.raises((ValueError, TableParseError)) as err:
jwst.query_target(target_name="TEST", target_resolver="VIZIER",
radius=units.Quantity(5, units.deg))
assert ('This target name cannot be determined with this resolver: '
'VIZIER' in err.value.args[0] or 'Failed to parse' in err.value.args[0])

def test_remove_jobs(self):
dummyTapHandler = DummyTapHandler()
Expand Down
4 changes: 4 additions & 0 deletions astroquery/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ def __init__(self):

self.name = self.__class__.__name__.split("Class")[0]

def __call__(self, *args, **kwargs):
""" init a fresh copy of self """
return self.__class__(*args, **kwargs)


class BaseQuery(metaclass=LoginABCMeta):
"""
Expand Down
22 changes: 11 additions & 11 deletions astroquery/simbad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
SIMBAD Query Tool
=================

The SIMBAD query tool creates a `script query
<https://simbad.cds.unistra.fr/simbad/sim-fscript>`__ that returns VOtable XML
data that is then parsed into a SimbadResult object. This object then
parses the data and returns a table parsed with `astropy.io.votable.parse`.
The SIMBAD query tool creates `TAP ADQL queries
<https://cds.unistra.fr/help/documentation/simbad-more/adql-simbad/>`__ that return VOtable XML
data. This is then parsed into a `~astropy.table.Table` object.
"""
from astropy import config as _config

Expand All @@ -27,16 +26,17 @@ class Conf(_config.ConfigNamespace):
'Time limit for connecting to Simbad server.')

row_limit = _config.ConfigItem(
# O defaults to the maximum limit
0,
# defaults to the maximum limit
-1,
'Maximum number of rows that will be fetched from the result.')

# should be columns of 'basic'
default_columns = ["main_id", "ra", "dec", "coo_err_maj", "coo_err_min",
"coo_err_angle", "coo_wavelength", "coo_bibcode"]


conf = Conf()

from .core import Simbad, SimbadClass, SimbadBaseQuery
from .core import Simbad, SimbadClass

__all__ = ['Simbad', 'SimbadClass',
'SimbadBaseQuery',
'Conf', 'conf',
]
__all__ = ['Simbad', 'SimbadClass', 'Conf', 'conf']
Loading
Loading