Skip to content

Commit

Permalink
feat: reduce API changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ManonMarchand committed Jun 3, 2024
1 parent 4c5cd0e commit aaf9c5b
Show file tree
Hide file tree
Showing 9 changed files with 436 additions and 169 deletions.
276 changes: 226 additions & 50 deletions astroquery/simbad/core.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion astroquery/simbad/criteria_lextab.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
_lexreflags = 34
_lexliterals = '&\\|\\(\\)'
_lexstateinfo = {'INITIAL': 'inclusive'}
_lexstatere = {'INITIAL': [("(?P<t_IN>in\\b)|(?P<t_LIST>\\( *'[^\\)]*\\))|(?P<t_BINARY_OPERATOR>>=|<=|!=|>|<|=)|(?P<t_LIKE>~|∼)|(?P<t_NOTLIKE>!~|!∼)|(?P<t_STRING>'[^']*')|(?P<t_REGION>region\\([^\\)]*\\))|(?P<t_COLUMN>[a-zA-Z_][a-zA-Z_0-9]*)|(?P<t_NUMBER>\\d*\\.?\\d+)", [None, ('t_IN', 'IN'), ('t_LIST', 'LIST'), ('t_BINARY_OPERATOR', 'BINARY_OPERATOR'), ('t_LIKE', 'LIKE'), ('t_NOTLIKE', 'NOTLIKE'), ('t_STRING', 'STRING'), ('t_REGION', 'REGION'), ('t_COLUMN', 'COLUMN'), (None, 'NUMBER')])]}
_lexstatere = {'INITIAL': [("(?P<t_IN>in\\b)|(?P<t_LIST>\\( *'[^\\)]*\\))|(?P<t_BINARY_OPERATOR>>=|<=|!=|>|<|=)|(?P<t_LIKE>~|∼)|(?P<t_NOTLIKE>!~|!∼)|(?P<t_STRING>'[^']*')|(?P<t_REGION>region\\([^\\)]*\\))|(?P<t_COLUMN>[a-zA-Z_*][a-zA-Z_0-9*]*)|(?P<t_NUMBER>\\d*\\.?\\d+)", [None, ('t_IN', 'IN'), ('t_LIST', 'LIST'), ('t_BINARY_OPERATOR', 'BINARY_OPERATOR'), ('t_LIKE', 'LIKE'), ('t_NOTLIKE', 'NOTLIKE'), ('t_STRING', 'STRING'), ('t_REGION', 'REGION'), ('t_COLUMN', 'COLUMN'), (None, 'NUMBER')])]}
_lexstateignore = {'INITIAL': ', \t\n'}
_lexstateerrorf = {'INITIAL': 't_error'}
_lexstateeoff = {}
23 changes: 12 additions & 11 deletions astroquery/simbad/criteria_parsetab.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

_lr_method = 'LALR'

_lr_signature = "BINARY_OPERATOR COLUMN IN LIKE LIST NOTLIKE NUMBER REGION STRINGcriteria : criteria '|' criteriacriteria : criteria '&' criteriacriteria : '(' criteria ')'criteria : COLUMN BINARY_OPERATOR STRING\n | COLUMN BINARY_OPERATOR NUMBER\n criteria : COLUMN LIKE STRINGcriteria : COLUMN NOTLIKE STRINGcriteria : COLUMN IN LISTcriteria : REGION"
_lr_signature = "BINARY_OPERATOR COLUMN IN LIKE LIST NOTLIKE NUMBER REGION STRINGcriteria : criteria '|' criteriacriteria : criteria '&' criteriacriteria : '(' criteria ')'criteria : COLUMN BINARY_OPERATOR STRING\n | COLUMN BINARY_OPERATOR NUMBER\n | COLUMN IN LIST\n criteria : COLUMN BINARY_OPERATOR COLUMN\n criteria : COLUMN LIKE STRINGcriteria : COLUMN NOTLIKE STRINGcriteria : REGION"

_lr_action_items = {'(':([0,2,5,6,],[2,2,2,2,]),'COLUMN':([0,2,5,6,],[3,3,3,3,]),'REGION':([0,2,5,6,],[4,4,4,4,]),'$end':([1,4,12,13,14,15,16,17,18,19,],[0,-9,-1,-2,-3,-4,-5,-6,-7,-8,]),'|':([1,4,7,12,13,14,15,16,17,18,19,],[5,-9,5,5,5,-3,-4,-5,-6,-7,-8,]),'&':([1,4,7,12,13,14,15,16,17,18,19,],[6,-9,6,6,6,-3,-4,-5,-6,-7,-8,]),'BINARY_OPERATOR':([3,],[8,]),'LIKE':([3,],[9,]),'NOTLIKE':([3,],[10,]),'IN':([3,],[11,]),')':([4,7,12,13,14,15,16,17,18,19,],[-9,14,-1,-2,-3,-4,-5,-6,-7,-8,]),'STRING':([8,9,10,],[15,17,18,]),'NUMBER':([8,],[16,]),'LIST':([11,],[19,]),}
_lr_action_items = {'(':([0,2,5,6,],[2,2,2,2,]),'COLUMN':([0,2,5,6,8,],[3,3,3,3,15,]),'REGION':([0,2,5,6,],[4,4,4,4,]),'$end':([1,4,12,13,14,15,16,17,18,19,20,],[0,-10,-1,-2,-3,-7,-4,-5,-6,-8,-9,]),'|':([1,4,7,12,13,14,15,16,17,18,19,20,],[5,-10,5,5,5,-3,-7,-4,-5,-6,-8,-9,]),'&':([1,4,7,12,13,14,15,16,17,18,19,20,],[6,-10,6,6,6,-3,-7,-4,-5,-6,-8,-9,]),'BINARY_OPERATOR':([3,],[8,]),'IN':([3,],[9,]),'LIKE':([3,],[10,]),'NOTLIKE':([3,],[11,]),')':([4,7,12,13,14,15,16,17,18,19,20,],[-10,14,-1,-2,-3,-7,-4,-5,-6,-8,-9,]),'STRING':([8,10,11,],[16,19,20,]),'NUMBER':([8,],[17,]),'LIST':([9,],[18,]),}

_lr_action = {}
for _k, _v in _lr_action_items.items():
Expand All @@ -38,13 +38,14 @@
del _lr_goto_items
_lr_productions = [
("S' -> criteria","S'",1,None,None,None),
('criteria -> criteria | criteria','criteria',3,'p_criteria_OR','utils.py',374),
('criteria -> criteria & criteria','criteria',3,'p_criteria_AND','utils.py',378),
('criteria -> ( criteria )','criteria',3,'p_criteria_parenthesis','utils.py',382),
('criteria -> COLUMN BINARY_OPERATOR STRING','criteria',3,'p_criteria_string','utils.py',386),
('criteria -> COLUMN BINARY_OPERATOR NUMBER','criteria',3,'p_criteria_string','utils.py',387),
('criteria -> COLUMN LIKE STRING','criteria',3,'p_criteria_like','utils.py',392),
('criteria -> COLUMN NOTLIKE STRING','criteria',3,'p_criteria_notlike','utils.py',396),
('criteria -> COLUMN IN LIST','criteria',3,'p_criteria_in','utils.py',400),
('criteria -> REGION','criteria',1,'p_criteria_region','utils.py',404),
('criteria -> criteria | criteria','criteria',3,'p_criteria_OR','utils.py',298),
('criteria -> criteria & criteria','criteria',3,'p_criteria_AND','utils.py',302),
('criteria -> ( criteria )','criteria',3,'p_criteria_parenthesis','utils.py',306),
('criteria -> COLUMN BINARY_OPERATOR STRING','criteria',3,'p_criteria_string','utils.py',310),
('criteria -> COLUMN BINARY_OPERATOR NUMBER','criteria',3,'p_criteria_string','utils.py',311),
('criteria -> COLUMN IN LIST','criteria',3,'p_criteria_string','utils.py',312),
('criteria -> COLUMN BINARY_OPERATOR COLUMN','criteria',3,'p_criteria_string_no_ticks','utils.py',317),
('criteria -> COLUMN LIKE STRING','criteria',3,'p_criteria_like','utils.py',323),
('criteria -> COLUMN NOTLIKE STRING','criteria',3,'p_criteria_notlike','utils.py',327),
('criteria -> REGION','criteria',1,'p_criteria_region','utils.py',331),
]
119 changes: 90 additions & 29 deletions astroquery/simbad/tests/test_simbad.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ def _mock_simbad_class(monkeypatch):
table = parse_single_table(f).to_table()
# This should not change too often, to regenerate this file, do:
# >>> from astroquery.simbad import Simbad
# >>> options = Simbad.list_output_options()
# >>> options = Simbad.list_votable_fields()
# >>> options.write("simbad_output_options.xml", format="votable")
monkeypatch.setattr(simbad.SimbadClass, "hardlimit", 2000000)
monkeypatch.setattr(simbad.SimbadClass, "list_output_options", lambda self: table)
monkeypatch.setattr(simbad.SimbadClass, "list_votable_fields", lambda self: table)


@pytest.fixture()
Expand All @@ -50,7 +50,7 @@ def _mock_list_columns(self, table_name=None):
"""Patch a call with basic as an argument only."""
if table_name == "basic":
return table
# to test in add_output_columns
# to test in add_votable_fields
if table_name == "mesdistance":
return Table(
[["bibcode"]], names=["column_name"]
Expand Down Expand Up @@ -146,8 +146,8 @@ def test_init_columns_in_output():
@pytest.mark.usefixtures("_mock_simbad_class")
def test_mocked_simbad():
simbad_instance = simbad.Simbad()
# this mocks the list_output_options
options = simbad_instance.list_output_options()
# this mocks the list_votable_fields
options = simbad_instance.list_votable_fields()
assert len(options) > 90
# this mocks the hardlimit
assert simbad_instance.hardlimit == 2000000
Expand All @@ -158,16 +158,39 @@ def test_mocked_simbad():


@pytest.mark.usefixtures("_mock_basic_columns")
def test_list_output_options(monkeypatch):
def test_votable_fields_utils(monkeypatch):
monkeypatch.setattr(simbad.SimbadClass, "query_tap",
lambda self, _: Table([["biblio"], ["biblio description"]],
names=["name", "description"],
dtype=["object", "object"]))
options = simbad.SimbadClass().list_output_options()
options = simbad.SimbadClass().list_votable_fields()
assert set(options.group_by("type").groups.keys["type"]) == {"table",
"column of basic",
"bundle of basic columns"}

description = simbad.SimbadClass().get_field_description("velocity")
assert description == 'all fields related with radial velocity and redshift'
fields = simbad.SimbadClass().get_votable_fields()
expected_fields = [
'basic.main_id', 'basic.ra', 'basic.dec', 'basic.coo_err_maj',
'basic.coo_err_min', 'basic.coo_err_angle', 'basic.coo_wavelength',
'basic.coo_bibcode'
]
assert fields == expected_fields


@pytest.mark.usefixtures("_mock_simbad_class")
@pytest.mark.usefixtures("_mock_basic_columns")
@pytest.mark.usefixtures("_mock_linked_to_basic")
def test_reset_votable_fields():
simbad_instance = simbad.Simbad()
# add one
simbad_instance.add_votable_fields("otype")
assert simbad.Simbad.Column("basic", "otype") in simbad_instance.columns_in_output
# reset
simbad_instance.reset_votable_fields()
assert not simbad.Simbad.Column("basic", "otype") in simbad_instance.columns_in_output


@pytest.mark.usefixtures("_mock_basic_columns")
@pytest.mark.parametrize(("bundle_name", "column"),
Expand Down Expand Up @@ -204,52 +227,60 @@ def test_add_table_to_output(monkeypatch):
@pytest.mark.usefixtures("_mock_simbad_class")
@pytest.mark.usefixtures("_mock_basic_columns")
@pytest.mark.usefixtures("_mock_linked_to_basic")
def test_add_output_columns():
def test_add_votable_fields():
simbad_instance = simbad.Simbad()
# add columns from basic (one value)
simbad_instance.add_output_columns("pmra")
simbad_instance.add_votable_fields("pmra")
assert simbad.SimbadClass.Column("basic", "pmra") in simbad_instance.columns_in_output
# add two columns from basic
simbad_instance.add_output_columns("pmdec", "pm_bibcodE") # also test case insensitive
simbad_instance.add_votable_fields("pmdec", "pm_bibcodE") # also test case insensitive
expected = [simbad.SimbadClass.Column("basic", "pmdec"),
simbad.SimbadClass.Column("basic", "pm_bibcode")]
assert all(column in simbad_instance.columns_in_output for column in expected)
# add a table
simbad_instance.columns_in_output = []
simbad_instance.add_output_columns("basic")
simbad_instance.add_votable_fields("basic")
assert [simbad.SimbadClass.Column("basic", "*")] == simbad_instance.columns_in_output
# add a bundle
simbad_instance.add_output_columns("dimensions")
simbad_instance.add_votable_fields("dimensions")
assert simbad.SimbadClass.Column("basic", "galdim_majaxis") in simbad_instance.columns_in_output
# a column which name has changed should raise a warning but still
# be added under its new name
simbad_instance.columns_in_output = []
with pytest.warns(DeprecationWarning, match=r"'id\(1\)' has been renamed 'main_id'. You'll see it "
"appearing with its new name in the output table"):
simbad_instance.add_output_columns("id(1)")
simbad_instance.add_votable_fields("id(1)")
assert simbad.SimbadClass.Column("basic", "main_id") in simbad_instance.columns_in_output
# a table which name has changed should raise a warning too
with pytest.warns(DeprecationWarning, match="'distance' has been renamed 'mesdistance'*"):
simbad_instance.add_output_columns("distance")
simbad_instance.add_votable_fields("distance")
# errors are raised for the deprecated fields with options
with pytest.raises(ValueError, match="Criteria on filters are deprecated when defining Simbad's output.*"):
simbad_instance.add_to_output("fluxdata(V)")
with pytest.raises(ValueError, match="Coordinates conversion and formatting is no longer supported.*"):
simbad_instance.add_to_output("coo(s)", "dec(d)")
simbad_instance = simbad.SimbadClass()
with pytest.warns(DeprecationWarning, match=r"The notation \'flux\(X\)\' is deprecated since 0.4.8. *"):
simbad_instance.add_votable_fields("flux(u)")
assert "u_" in str(simbad_instance.columns_in_output)
with pytest.raises(ValueError, match="Coordinates conversion and formatting is no longer supported*"):
simbad_instance.add_votable_fields("coo(s)", "dec(d)")
with pytest.raises(ValueError, match="Catalog Ids are no longer supported as an output option.*"):
simbad_instance.add_output_columns("ID(Gaia)")
simbad_instance.add_votable_fields("ID(Gaia)")
with pytest.raises(ValueError, match="Selecting a range of years for bibcode is removed.*"):
simbad_instance.add_output_columns("bibcodelist(2042-2050)")
simbad_instance.add_votable_fields("bibcodelist(2042-2050)")
# historical measurements
with pytest.raises(ValueError, match="'einstein' is no longer a part of SIMBAD.*"):
simbad_instance.add_output_columns("einstein")
simbad_instance.add_votable_fields("einstein")
# typos should have suggestions
with pytest.raises(ValueError, match="'alltype' is not one of the accepted options which can be "
"listed with 'list_output_options'. Did you mean 'alltypes' or 'otype' or 'otypes'?"):
simbad_instance.add_output_columns("ALLTYPE")
"listed with 'list_votable_fields'. Did you mean 'alltypes' or 'otype' or 'otypes'?"):
simbad_instance.add_votable_fields("ALLTYPE")
# bundles and tables require a connection to the tap_schema and are thus tested in test_simbad_remote


def test_list_wildcards(capsys):
simbad.SimbadClass.list_wildcards()
wildcards = capsys.readouterr()
assert "*: Any string of characters (including an empty one)" in wildcards.out


# ------------------------------------------
# Test query_*** methods that call query_tap
# ------------------------------------------
Expand Down Expand Up @@ -277,12 +308,13 @@ def test_query_bibcode_class():

@pytest.mark.usefixtures("_mock_simbad_class")
def test_query_objectids():
adql = simbad.core.Simbad.query_objectids('Polaris',
criteria="ident.id LIKE 'HD%'",
get_adql=True)
expected = ("SELECT ident.id FROM ident AS id_typed JOIN ident USING(oidref)"
"WHERE id_typed.id = 'Polaris' AND ident.id LIKE 'HD%'")
assert adql == expected
with pytest.raises(AstropyDeprecationWarning, match='"get_query_payload"*'):
adql = simbad.core.Simbad.query_objectids('Polaris',
criteria="ident.id LIKE 'HD%'",
get_query_payload=True)
expected = ("SELECT ident.id FROM ident AS id_typed JOIN ident USING(oidref)"
"WHERE id_typed.id = 'Polaris' AND ident.id LIKE 'HD%'")
assert adql == expected


@pytest.mark.usefixtures("_mock_simbad_class")
Expand Down Expand Up @@ -392,6 +424,35 @@ def test_query_object():
end = "AND (otype = 'G..')"
assert adql.endswith(end)

# ------------------------
# Tests for query_criteria
# ------------------------


@pytest.mark.usefixtures("_mock_simbad_class")
def test_query_criteria():
with pytest.warns(AstropyDeprecationWarning, match="'query_criteria' is deprecated*"):
# with a region and otype criteria
adql = simbad.core.Simbad.query_criteria("region(box, GAL, 49.89 -0.3, 0.5d 0.5d)",
otype='HII', get_adql=True)
expected = ("SELECT basic.\"main_id\", basic.\"ra\", basic.\"dec\", "
"basic.\"coo_err_maj\", basic.\"coo_err_min\", "
"basic.\"coo_err_angle\", basic.\"coo_wavelength\", "
"basic.\"coo_bibcode\" FROM basic JOIN otypes ON basic.\"oid\" = "
"otypes.\"oidref\" WHERE (CONTAINS(POINT('ICRS', ra, dec), "
"BOX('ICRS', 291.04898804231215, 14.903593816641127, 0.5, 0.5)) = 1 "
"AND otypes.otype = 'HII')")
assert adql == expected
# with a flux criteria
adql = simbad.core.Simbad.query_criteria("Umag < 9", get_adql=True)
expected = (
'SELECT basic."main_id", basic."ra", basic."dec", basic."coo_err_maj", '
'basic."coo_err_min", basic."coo_err_angle", basic."coo_wavelength", '
'basic."coo_bibcode" FROM basic JOIN allfluxes ON basic."oid" = '
'allfluxes."oidref" WHERE (allfluxes.U < 9)'
)
assert adql == expected

# -------------------------
# Test query_tap exceptions
# -------------------------
Expand Down
21 changes: 15 additions & 6 deletions astroquery/simbad/tests/test_simbad_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from astropy.coordinates import SkyCoord
import astropy.units as u
from astropy.utils.exceptions import AstropyDeprecationWarning
from astropy.table import Table

from astroquery.simbad import Simbad
Expand Down Expand Up @@ -40,7 +41,7 @@ def test_non_ascii_bibcode(self):

def test_query_bibobj(self):
self.simbad.ROW_LIMIT = 5
self.simbad.add_output_columns("otype")
self.simbad.add_votable_fields("otype")
bibcode = '2005A&A...430..165F'
result = self.simbad.query_bibobj(bibcode, criteria="otype='*..'")
assert all((bibcode == code) for code in result["bibcode"].data.data)
Expand Down Expand Up @@ -82,7 +83,7 @@ def test_query_multi_object(self):
def test_simbad_flux_qual(self):
'''Regression test for issue 680'''
simbad_instance = Simbad()
simbad_instance.add_output_columns("flux")
simbad_instance.add_votable_fields("flux")
response = simbad_instance.query_object('algol', criteria="filter='V'")
# this is bugged, it should be "flux.qual", see https://github.com/gmantele/vollt/issues/154
# when the issue upstream in vollt (the TAP software used in SIMBAD) is fixed we can rewrite this test
Expand All @@ -95,6 +96,14 @@ def test_query_object(self):
result = self.simbad.query_object("NGC [0-9]*", wildcard=True)
assert all(matched_id.startswith("NGC") for matched_id in result["matched_id"].data.data)

def test_query_criteria(self):
simbad_instance = Simbad()
simbad_instance.add_votable_fields("otype")
with pytest.warns(AstropyDeprecationWarning, match="'query_criteria' is deprecated*"):
result = simbad_instance.query_criteria("region(Galactic Center, 10s)", maintype="X")
assert all(result["otype"].data.data == "X")
assert len(result) >= 16 # there could be more measurements, there are 16 sources in 2024

def test_query_tap(self):
# a robust query about something that should not change in Simbad
filtername = self.simbad.query_tap("select filtername from filter where filtername='B'")
Expand Down Expand Up @@ -148,7 +157,7 @@ def test_add_bundle_to_output(self):
# empty before the test
simbad_instance.columns_in_output = []
# add a bundle
simbad_instance.add_output_columns("dim")
simbad_instance.add_votable_fields("dim")
# check the length
assert len(simbad_instance.columns_in_output) == 8
assert Simbad.Column("basic", "galdim_majaxis") in simbad_instance.columns_in_output
Expand All @@ -157,17 +166,17 @@ def test_add_table_to_output(self):
simbad_instance = Simbad()
# empty before the test
simbad_instance.columns_in_output = []
simbad_instance.add_output_columns("otypes")
simbad_instance.add_votable_fields("otypes")
assert Simbad.Column("otypes", "otype", '"otypes.otype"') in simbad_instance.columns_in_output
# tables also require a join
assert Simbad.Join("otypes",
Simbad.Column("basic", "oid"),
Simbad.Column("otypes", "oidref")) == simbad_instance.joins[0]
# tables that have been renamed should warn
with pytest.warns(DeprecationWarning, match="'iue' has been renamed 'mesiue'.*"):
simbad_instance.add_output_columns("IUE")
simbad_instance.add_votable_fields("IUE")
# empty before the test
simbad_instance.columns_in_output = []
# mixed columns bundles and tables
simbad_instance.add_output_columns("flux", "velocity", "update_date")
simbad_instance.add_votable_fields("flux", "velocity", "update_date")
assert len(simbad_instance.columns_in_output) == 19
Loading

0 comments on commit aaf9c5b

Please sign in to comment.