Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ gaia

- New datalink DR4 retrieval type RESIDUAL_IMAGE. [#3489]
- The method ``load_data`` parses ecsv files [#3500].
- Fixed decimal precision for query_object and cone_search to use 14 decimal places [#3539].

esa.hubble
^^^^^^^^^^
Expand Down
49 changes: 36 additions & 13 deletions astroquery/gaia/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', verbose=False):
return self.__gaiadata.get_datalinks(ids=ids, linking_parameter=final_linking_parameter, verbose=verbose)

def __query_object(self, coordinate, *, radius=None, width=None, height=None,
async_job=False, verbose=False, columns=()):
async_job=False, verbose=False, columns=(), get_query_payload=False):
"""Launches a job
TAP & TAP+

Expand All @@ -491,6 +491,9 @@ def __query_object(self, coordinate, *, radius=None, width=None, height=None,
flag to display information about the process
columns: list, optional, default ()
if empty, all columns will be selected
get_query_payload : bool, optional
If True, return the SQL query string that would be sent to the server,
instead of executing the query. This is useful for debugging and testing.

Returns
-------
Expand Down Expand Up @@ -518,7 +521,7 @@ def __query_object(self, coordinate, *, radius=None, width=None, height=None,
{row_limit}
DISTANCE(
POINT('ICRS', {ra_column}, {dec_column}),
POINT('ICRS', {ra}, {dec})
POINT('ICRS', {ra:.14f}, {dec:.14f})
) as dist,
{columns}
FROM
Expand All @@ -528,10 +531,10 @@ def __query_object(self, coordinate, *, radius=None, width=None, height=None,
POINT('ICRS', {ra_column}, {dec_column}),
BOX(
'ICRS',
{ra},
{dec},
{width},
{height}
{ra:.14f},
{dec:.14f},
{width:.14f},
{height:.14f}
)
)
ORDER BY
Expand All @@ -541,13 +544,18 @@ def __query_object(self, coordinate, *, radius=None, width=None, height=None,
'columns': columns, 'table_name': self.MAIN_GAIA_TABLE or conf.MAIN_GAIA_TABLE,
'ra': ra, 'dec': dec,
'width': widthDeg.value, 'height': heightDeg.value})

if get_query_payload:
return query

if async_job:
job = self.launch_job_async(query, verbose=verbose)
else:
job = self.launch_job(query, verbose=verbose)
return job.get_results()

def query_object(self, coordinate, *, radius=None, width=None, height=None, verbose=False, columns=()):
def query_object(self, coordinate, *, radius=None, width=None, height=None, verbose=False, columns=(),
get_query_payload=False):
"""Launches a synchronous cone search for the input search radius or the box on the sky, sorted by angular
separation
TAP & TAP+
Expand All @@ -566,13 +574,16 @@ def query_object(self, coordinate, *, radius=None, width=None, height=None, verb
flag to display information about the process
columns: list, optional, default ()
if empty, all columns will be selected
get_query_payload : bool, optional
If True, return the SQL query string that would be sent to the server,
instead of executing the query. This is useful for debugging and testing.

Returns
-------
The job results (astropy.table).
"""
return self.__query_object(coordinate, radius=radius, width=width, height=height, async_job=False,
verbose=verbose, columns=columns)
verbose=verbose, columns=columns, get_query_payload=get_query_payload)

def query_object_async(self, coordinate, *, radius=None, width=None, height=None, verbose=False, columns=()):
"""Launches an asynchronous cone search for the input search radius or the box on the sky, sorted by angular
Expand Down Expand Up @@ -608,7 +619,8 @@ def __cone_search(self, coordinate, radius, *, table_name=None,
background=False,
output_file=None, output_format="votable_gzip", verbose=False,
dump_to_file=False,
columns=()):
columns=(),
get_query_payload=False):
"""Cone search sorted by distance
TAP & TAP+

Expand Down Expand Up @@ -641,6 +653,9 @@ def __cone_search(self, coordinate, radius, *, table_name=None,
if True, the results are saved in a file instead of using memory
columns: list, optional, default ()
if empty, all columns will be selected
get_query_payload : bool, optional
If True, return the SQL query string that would be sent to the server,
instead of executing it. This is useful for debugging and testing.

Returns
-------
Expand All @@ -664,14 +679,14 @@ def __cone_search(self, coordinate, radius, *, table_name=None,
{columns},
DISTANCE(
POINT('ICRS', {ra_column}, {dec_column}),
POINT('ICRS', {ra}, {dec})
POINT('ICRS', {ra:.14f}, {dec:.14f})
) AS dist
FROM
{table_name}
WHERE
1 = CONTAINS(
POINT('ICRS', {ra_column}, {dec_column}),
CIRCLE('ICRS', {ra}, {dec}, {radius})
CIRCLE('ICRS', {ra:.14f}, {dec:.14f}, {radius:.14f})
)
ORDER BY
dist ASC
Expand All @@ -681,6 +696,9 @@ def __cone_search(self, coordinate, radius, *, table_name=None,
'radius': radiusDeg,
'table_name': table_name or self.MAIN_GAIA_TABLE or conf.MAIN_GAIA_TABLE})

if get_query_payload:
return query

if async_job:
return self.launch_job_async(query=query, output_file=output_file, output_format=output_format,
verbose=verbose, dump_to_file=dump_to_file, background=background)
Expand All @@ -695,7 +713,8 @@ def cone_search(self, coordinate, *, radius=None,
output_file=None,
output_format="votable_gzip", verbose=False,
dump_to_file=False,
columns=()):
columns=(),
get_query_payload=False):
"""Cone search sorted by distance (sync.)
TAP & TAP+

Expand All @@ -722,6 +741,9 @@ def cone_search(self, coordinate, *, radius=None,
if True, the results are saved in a file instead of using memory
columns: list, optional, default ()
if empty, all columns will be selected
get_query_payload : bool, optional
If True, return the SQL query string that would be sent to the server,
instead of executing the query. This is useful for debugging and testing.

Returns
-------
Expand All @@ -737,7 +759,8 @@ def cone_search(self, coordinate, *, radius=None,
output_file=output_file,
output_format=output_format,
verbose=verbose,
dump_to_file=dump_to_file, columns=columns)
dump_to_file=dump_to_file, columns=columns,
get_query_payload=get_query_payload)

def cone_search_async(self, coordinate, *, radius=None,
table_name=None,
Expand Down
47 changes: 47 additions & 0 deletions astroquery/gaia/tests/test_gaiatap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import astropy.units as u
import numpy as np
import pytest
import re
from astropy.coordinates.sky_coordinate import SkyCoord
from astropy.table import Column, Table
from astropy.units import Quantity
Expand Down Expand Up @@ -517,6 +518,52 @@ def test_query_object_async(column_attrs, mock_querier_async, kwargs):
assert table[colname].attrs_equal(attrs)


def test_query_object_precision(mock_querier):
"""
Verifies that query_object() produces a query where RA, DEC, width and height
are formatted with exactly 14 decimal places when using get_query_payload=True.
"""
coord = SkyCoord(ra=19 * u.deg, dec=20 * u.deg)
width = 12 * u.deg
height = 10 * u.deg

query = mock_querier.query_object(
coord,
width=width,
height=height,
get_query_payload=True
)

float14 = r"[0-9]+\.[0-9]{14}"
matches = re.findall(float14, query)

assert len(matches) == 6, (
f"Expected 6 float values with 14 decimals, found {len(matches)}.\n{query}"
)


def test_cone_search_precision(mock_querier):
"""
Verifies that cone_search() produces a query where RA, DEC and radius
appear formatted with exactly 14 decimal places when using get_query_payload=True.
"""
coord = SkyCoord(ra=19*u.deg, dec=20*u.deg)
radius = 1*u.deg

query = mock_querier.cone_search(
coord,
radius=radius,
get_query_payload=True,
)

float14 = r"[0-9]+\.[0-9]{14}"
matches = re.findall(float14, query)

assert len(matches) == 5, (
f"Expected 5 float values with 14 decimals, found {len(matches)}.\n{query}"
)


def test_cone_search_sync(column_attrs, mock_querier):
assert mock_querier.USE_NAMES_OVER_IDS is True

Expand Down
Loading