Skip to content

Commit

Permalink
test: complete coverage of simbad utils
Browse files Browse the repository at this point in the history
  • Loading branch information
ManonMarchand committed Mar 25, 2024
1 parent cba2a6e commit 4c2c436
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 33 deletions.
49 changes: 44 additions & 5 deletions astroquery/simbad/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@

import pytest

from astroquery.simbad.setup_package import get_package_data

from astroquery.simbad.utils import (CriteriaTranslator, _parse_coordinate_and_convert_to_icrs,
_region_to_contains)
_region_to_contains, list_wildcards, _wildcard_to_regexp)

from astropy.coordinates.builtin_frames.icrs import ICRS
from astropy.coordinates import SkyCoord


def test_setup_package():
data = get_package_data()
assert data["astroquery.simbad.tests"] == ["data/simbad_output_options.xml"]
assert data["astroquery.simbad"] == ["data/query_criteria_fields.json"]


@pytest.mark.parametrize("coord_string, frame, epoch, equinox", [
("12 34 56.78 +12 34 56.78", None, None, None),
("10 +20", "galactic", None, None),
("10 20", "fk4", "J2000", "B1950")
("10 20", "fk4", "J2000", "1950")
])
def test_parse_coordinates_and_convert_to_icrs(coord_string, frame, epoch, equinox):
coord = _parse_coordinate_and_convert_to_icrs(coord_string, frame=frame, equinox=equinox, epoch=epoch)
assert isinstance(coord.frame, ICRS)


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


def test_wildcard_to_regexp():
# should add beginning and end operators, and translate * into .*
assert _wildcard_to_regexp("test*") == "^test.*$"
# should not replace escaped characters
assert _wildcard_to_regexp(r"test\*") == "^test\\*$"
# wildcard ? is regexp .
assert _wildcard_to_regexp("test?") == "^test.$"


@pytest.mark.remote_data()
def test_parse_coordinates_and_convert_to_icrs_sesame():
coord = _parse_coordinate_and_convert_to_icrs("m1")
assert isinstance(coord.frame, ICRS)


def test_region_to_contains():
def test_region_to_contains(monkeypatch):
# default shape is a circle, default frame is ICRS
assert "CIRCLE" in _region_to_contains("0 0, 1d")
assert "ICRS" in _region_to_contains("0 0,1d")
Expand All @@ -32,10 +56,17 @@ def test_region_to_contains():
_region_to_contains("rotatedbox, 0 0, 1d")
# shapes should not be case-sensitive
box = "CONTAINS(POINT('ICRS', ra, dec), BOX('ICRS', 0.0, 0.0, 2.0, 0.025)) = 1"
assert _region_to_contains("BoX, 0 0, 2d 1.5m") == box
assert _region_to_contains("BoX, J2000, 2024, 0 0, 2d 1.5m") == box
# polygons can have a lot of points
polygon = "CONTAINS(POINT('ICRS', ra, dec), POLYGON('ICRS', 0.0, 0.0, 1.0, 2.0, 65.0, 25.0, 10.0, -9.0)) = 1"
assert _region_to_contains("PolyGon, 0 0, 01 +02, 65 25, 10 -9") == polygon
# here we mock a case where the coordinates are given through a name

def mockreturn(name):
return SkyCoord(0, 0, unit="deg")
monkeypatch.setattr(SkyCoord, "from_name", mockreturn)
assert _region_to_contains("zero_zero, 2d") == ("CONTAINS(POINT('ICRS', ra, dec), "
"CIRCLE('ICRS', 0.0, 0.0, 2.0)) = 1")


def test_tokenizer():
Expand Down Expand Up @@ -70,9 +101,17 @@ def test_tokenizer():
" AND otype = 'G' AND (nbref >= 10 OR bibyear >= 2000)")),
("otype != 'Galaxy..'", "otype != 'Galaxy..'"),
("author ∼ 'egret*'", "regexp(author, '^egret.*$') = 1"),
("cat in ('hd','hip','ppm')", "cat IN ('hd','hip','ppm')")
("cat in ('hd','hip','ppm')", "cat IN ('hd','hip','ppm')"),
("author !~ 'test'", "regexp(author, '^test$') = 0")
]) # these are the examples from http://simbad.cds.unistra.fr/guide/sim-fsam.htx
def test_transpiler(test, result):
# to regenerate transpiler after a change in utils.py, delete `criteria_parsetab.py` and run this test file again.
translated = CriteriaTranslator.parse(test)
assert translated == result


def test_transpiler_errors(capsys):
with pytest.raises(ValueError, match="Syntax error for sim-script criteria"):
CriteriaTranslator.parse("otype % 'G'")
printed = capsys.readouterr().out
assert printed == "Unrecognized character '%' at position 6 for a sim-script criteria."
48 changes: 24 additions & 24 deletions astroquery/simbad/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,6 @@
from astropy.utils import classproperty


def list_wildcards():
"""
Displays the available wildcards that may be used in SIMBAD queries and
their usage.
Examples
--------
>>> from astroquery.simbad.utils import list_wildcards
>>> list_wildcards()
* : Any string of characters (including an empty one)
? : Any character (exactly one character)
[abc] : Exactly one character taken in the list. Can also be defined by a range of characters: [A-Z]
[^0-9] : Any (one) character not in the list.
"""
WILDCARDS = {'*': 'Any string of characters (including an empty one)',
'?': 'Any character (exactly one character)',
'[abc]': ('Exactly one character taken in the list. '
'Can also be defined by a range of characters: [A-Z]'),
'[^0-9]': 'Any (one) character not in the list.'}
print("\n".join(f"{k} : {v}" for k, v in WILDCARDS.items()))


def _catch_deprecated_fields_with_arguments(votable_field):
"""Raise informative errors for deprecated votable fields.
Expand Down Expand Up @@ -67,6 +45,28 @@ def _catch_deprecated_fields_with_arguments(votable_field):
# ----------------------------


def list_wildcards():
"""
Displays the available wildcards that may be used in SIMBAD queries and
their usage.
Examples
--------
>>> from astroquery.simbad.utils import list_wildcards
>>> list_wildcards()
*: Any string of characters (including an empty one)
?: Any character (exactly one character)
[abc]: Exactly one character taken in the list. Can also be defined by a range of characters: [A-Z]
[^0-9]: Any (one) character not in the list.
"""
WILDCARDS = {'*': 'Any string of characters (including an empty one)',
'?': 'Any character (exactly one character)',
'[abc]': ('Exactly one character taken in the list. '
'Can also be defined by a range of characters: [A-Z]'),
'[^0-9]': 'Any (one) character not in the list.'}
print("\n".join(f"{k}: {v}" for k, v in WILDCARDS.items()))


def _wildcard_to_regexp(wildcard_string):
r"""Translate a wildcard string into a regexp.
Expand Down Expand Up @@ -186,15 +186,15 @@ def _region_to_contains(region_string):
contains += f", {coordinates.ra.value}, {coordinates.dec.value}"
contains += ")) = 1"

else:
raise ValueError("Simbad TAP supports regions of types 'circle', 'box', or 'polygon'.")
return contains


def _parse_coordinate_and_convert_to_icrs(string_coordinate, *,
frame="icrs", epoch=None, equinox=None):
"""Convert a string into a SkyCoord object in the ICRS frame."""
if re.search(r"\d+ *[\+\- ]\d+", string_coordinate):
if equinox:
equinox = f"J{equinox}"
center = SkyCoord(string_coordinate, unit="deg", frame=frame, obstime=epoch, equinox=equinox)
else:
center = SkyCoord.from_name(string_coordinate)
Expand Down
8 changes: 4 additions & 4 deletions docs/simbad/simbad.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ To see the available wildcards and their functions:
>>> from astroquery.simbad.utils import list_wildcards
>>> list_wildcards()
* : Any string of characters (including an empty one)
? : Any character (exactly one character)
[abc] : Exactly one character taken in the list. Can also be defined by a range of characters: [A-Z]
[^0-9] : Any (one) character not in the list.
*: Any string of characters (including an empty one)
?: Any character (exactly one character)
[abc]: Exactly one character taken in the list. Can also be defined by a range of characters: [A-Z]
[^0-9]: Any (one) character not in the list.
Query to get all names (identifiers) of an object
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down

0 comments on commit 4c2c436

Please sign in to comment.