From 2a5da5aaec7f9e04169f877330eec6908f025562 Mon Sep 17 00:00:00 2001 From: Henrik Norman Date: Mon, 2 Mar 2026 10:21:43 +0100 Subject: [PATCH 01/10] Migrated ESASky module to use pyVO instead of TAPPlus --- astroquery/esasky/__init__.py | 31 ++-- astroquery/esasky/core.py | 167 ++++++------------ astroquery/esasky/tests/test_esasky_remote.py | 77 ++++---- 3 files changed, 108 insertions(+), 167 deletions(-) diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index af4dcc29f1..208e36332d 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -1,23 +1,32 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst from astropy import config as _config +from astropy.config import paths + +import os + +ESASKY_COMMON_SERVER = "https://sky.esa.int/esasky-tap/" + +ESASKY_TAP_COMMON = "tap" + class Conf(_config.ConfigNamespace): """ Configuration parameters for `astroquery.esasky`. """ - urlBase = _config.ConfigItem( - 'https://sky.esa.int/esasky-tap', - 'ESASky base URL') - - timeout = _config.ConfigItem( - 1000, - 'Time limit for connecting to template_module server.') - - row_limit = _config.ConfigItem( - 10000, - 'Maximum number of rows returned (set to -1 for unlimited).') + ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server") + ESASKY_TAP_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON, "ESASky TAP Server") + ESASKY_DATA_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'data?', "ESASky Data Server") + ESASKY_TABLES_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON + "/tables", "ESASky TAP Tables Server") + ESASKY_TARGET_ACTION = _config.ConfigItem("servlet/target-resolver?", "ESASky Target Resolver") + ESASKY_MESSAGES = _config.ConfigItem("notification?action=GetNotifications", "ESASky Messages") + ESASKY_LOGIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'login', "ESASky Login Server") + ESASKY_LOGOUT_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'logout', "ESASky Logout Server") + ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.') + ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).') + + cache_location = os.path.join(paths.get_cache_dir(), 'astroquery/esasky', ) conf = Conf() diff --git a/astroquery/esasky/core.py b/astroquery/esasky/core.py index 34755789b3..9f34e49584 100644 --- a/astroquery/esasky/core.py +++ b/astroquery/esasky/core.py @@ -1,8 +1,12 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst +from numpy.testing import verbose + +import astroquery.esa.utils.utils as esautils import json import os import tarfile as esatar +import pyvo import sys import re import warnings @@ -18,8 +22,7 @@ from requests import HTTPError from requests import ConnectionError -from ..query import BaseQuery -from ..utils.tap.core import TapPlus +from astroquery.esa.utils import EsaTap from ..utils import commons from ..utils import async_to_sync from . import conf @@ -33,12 +36,15 @@ esatar.TarFile.extraction_filter = staticmethod(esatar.fully_trusted_filter) -@async_to_sync -class ESASkyClass(BaseQuery): +class ESASkyClass(EsaTap): - URLbase = conf.urlBase - TIMEOUT = conf.timeout - DEFAULT_ROW_LIMIT = conf.row_limit + URLbase = conf.ESASKY_DOMAIN_SERVER + ESA_ARCHIVE_NAME = "ESASky" + TAP_URL = conf.ESASKY_TAP_SERVER + LOGIN_URL = conf.ESASKY_LOGIN_SERVER + LOGOUT_URL = conf.ESASKY_LOGOUT_SERVER + CONNECTION_TIMEOUT = conf.ESASKY_CONNECTION_TIMEOUT + DEFAULT_ROW_LIMIT = conf.ESASKY_ROW_LIMIT __FITS_STRING = ".fits" __FTZ_STRING = ".FTZ" @@ -79,21 +85,23 @@ class ESASkyClass(BaseQuery): SSO_TYPES = ['ALL', 'ASTEROID', 'COMET', 'SATELLITE', 'PLANET', 'DWARF_PLANET', 'SPACECRAFT', 'SPACEJUNK', 'EXOPLANET', 'STAR'] - def __init__(self, tap_handler=None): - super().__init__() + def __init__(self, *, show_messages=False, auth_session=None, tap_url=None): + super().__init__(auth_session=auth_session, tap_url=tap_url) + + if show_messages: + self.get_status_messages() - if tap_handler is None: - self._tap = TapPlus(url=self.URLbase + "/tap") - else: - self._tap = tap_handler - def query(self, query, *, output_file=None, output_format="votable", verbose=False): - """Launches a synchronous job to query the ESASky TAP + def query(self, query, *, async_job=False, output_file=None, output_format="votable", verbose=False): + """Launches a synchronous or asynchronous job to query the ESASky TAP Parameters ---------- query : str, mandatory query (adql) to be executed + async_job : bool, optional, default 'False' + executes the query (job) in asynchronous/synchronous mode (default + synchronous) output_file : str, optional, default None file name where the results are saved if dumpToFile is True. If this parameter is not provided, the jobid is used instead @@ -107,91 +115,7 @@ def query(self, query, *, output_file=None, output_format="votable", verbose=Fal ------- A table object """ - if not verbose: - with warnings.catch_warnings(): - commons.suppress_vo_warnings() - warnings.filterwarnings("ignore", category=u.UnitsWarning) - job = self._tap.launch_job(query=query, output_file=output_file, output_format=output_format, - verbose=False, dump_to_file=output_file is not None) - else: - job = self._tap.launch_job(query=query, output_file=output_file, output_format=output_format, - verbose=True, dump_to_file=output_file is not None) - return job.get_results() - - def get_tables(self, *, only_names=True, verbose=False, cache=True): - """ - Get the available table in ESASky TAP service - - Parameters - ---------- - only_names : bool, optional, default 'True' - True to load table names only - verbose : bool, optional, default 'False' - flag to display information about the process - - Returns - ------- - A list of tables - """ - - if cache and self._cached_tables is not None: - tables = self._cached_tables - else: - tables = self._tap.load_tables(only_names=only_names, include_shared_tables=False, verbose=verbose) - self._cached_tables = tables - if only_names: - return [t.name for t in tables] - else: - return tables - - def get_columns(self, table_name, *, only_names=True, verbose=False): - """ - Get the available columns for a table in ESASky TAP service - - Parameters - ---------- - table_name : str, mandatory, default None - table name of which, columns will be returned - only_names : bool, optional, default 'True' - True to load table names only - verbose : bool, optional, default 'False' - flag to display information about the process - - Returns - ------- - A list of columns - """ - - tables = self.get_tables(only_names=False, verbose=verbose) - columns = None - for table in tables: - if str(table.name) == str(table_name): - columns = table.columns - break - - if columns is None: - raise ValueError("table name specified is not found in " - "ESASky TAP service") - - if only_names: - return [c.name for c in columns] - else: - return columns - - def get_tap(self): - """ - Get a TAP+ instance for the ESASky servers, which supports - all common TAP+ operations (synchronous & asynchronous queries, - uploading of tables, table sharing and more) - Full documentation and examples available here: - https://astroquery.readthedocs.io/en/latest/utils/tap.html - - Returns - ------- - tap : `~astroquery.utils.tap.core.TapPlus` - """ - - return self._tap + return self.query_tap(query=query, async_job=async_job, output_file=output_file, output_format=output_format, verbose=verbose) def list_maps(self): """ @@ -944,9 +868,9 @@ def query_ids_catalogs(self, source_ids, *, catalogs=__ALL_STRING, row_limit=DEF Examples -------- - query_ids_catalogs(source_ids=['2CXO J090341.1-322609', '2CXO J090353.8-322642'], catalogs="CHANDRA-SC2") - query_ids_catalogs(source_ids='2CXO J090341.1-322609') - query_ids_catalogs(source_ids=['2CXO J090341.1-322609', '45057'], catalogs=["CHANDRA-SC2", "Hipparcos-2"]) + query_ids_catalogs(source_ids=['2CXO J031306.2-852820', '2CXO J031339.7-852543'], catalogs="CHANDRA-SC21") + query_ids_catalogs(source_ids='2CXO J031306.2-852820') + query_ids_catalogs(source_ids=['2CXO J031306.2-852820', '45057'], catalogs=["CHANDRA-SC21", "Hipparcos-2"]) """ sanitized_catalogs = self._sanitize_input_catalogs(catalogs) sanitized_row_limit = self._sanitize_input_row_limit(row_limit) @@ -1349,6 +1273,27 @@ def get_spectra_from_table(self, query_table_list, missions=__ALL_STRING, log.info("No spectra found.") return spectra + def get_status_messages(self): + """Retrieve the messages to inform users about the status of the ESASky TAP""" + + try: + esautils.execute_servlet_request( + url=conf.ESASKY_TAP_SERVER + "/" + conf.ESASKY_MESSAGES, + tap=self.tap, + query_params={}, + parser_method=self.parse_messages_response + ) + except OSError: + print("Status messages could not be retrieved") + + def parse_messages_response(self, response): + string_messages = [] + for line in response.iter_lines(): + string_message = line.decode("utf-8") + string_messages.append(string_message[string_message.index('=') + 1:]) + print(string_messages[len(string_messages)-1]) + return string_messages + def _sanitize_input_radius(self, radius): if isinstance(radius, (str, u.Quantity)): return radius @@ -1709,9 +1654,9 @@ def _query(self, name, descriptors, verbose=False, **kwargs): if not query: # Could not create query. The most common reason for this is a type mismatch between user specified ID and # data type of database column. - # For example query_ids_catalogs(source_ids=["2CXO J090341.1-322609"], mission=["CHANDRA", "HSC"]) + # For example query_ids_catalogs(source_ids=["2CXO J031306.2-852820"], mission=["CHANDRA", "HSC"]) # would be able to create a query for Chandra, but not for Hubble because the hubble source id column type - # is a number and "2CXO J090341.1-322609" cannot be converted to a number. + # is a number and "2CXO J031306.2-852820" cannot be converted to a number. return query return self.query(query, output_format="votable", verbose=verbose) @@ -1773,13 +1718,13 @@ def _build_id_query(self, ids, row_limit, descriptor): if id_column == "designation": id_column = "obsid" - data_type = None - for column in self.get_columns(table_name=descriptor['table_name'], only_names=False): + datatype = None + for column in self.get_table(table=descriptor['table_name']).columns: if column.name == id_column: - data_type = column.data_type + datatype = column.datatype valid_ids = ids - if data_type in self._NUMBER_DATA_TYPES: + if datatype in self._NUMBER_DATA_TYPES: valid_ids = [int(obs_id) for obs_id in ids if obs_id.isdigit()] if not valid_ids: raise ValueError(f"Could not construct query for mission {descriptor['mission']}. Database column " @@ -1850,7 +1795,7 @@ def _send_get_request(self, url_extension, request_payload, cache): return self._request('GET', url, params=request_payload, - timeout=self.TIMEOUT, + timeout=self.CONNECTION_TIMEOUT, cache=cache, headers=self._get_header()) @@ -1861,4 +1806,4 @@ def _get_header(self): return {'User-Agent': user_agent} -ESASky = ESASkyClass() +ESASky = ESASkyClass(show_messages=False) diff --git a/astroquery/esasky/tests/test_esasky_remote.py b/astroquery/esasky/tests/test_esasky_remote.py index 9f43ed294e..47a8863a69 100755 --- a/astroquery/esasky/tests/test_esasky_remote.py +++ b/astroquery/esasky/tests/test_esasky_remote.py @@ -6,9 +6,8 @@ import pytest from astropy.io.fits.hdu.hdulist import HDUList +from astroquery.exceptions import InputWarning from astroquery.utils.commons import TableList -from astroquery.utils.tap.model.tapcolumn import TapColumn -from astroquery.utils.tap.model.taptable import TapTableMeta from astroquery.esasky import ESASky @@ -34,18 +33,18 @@ def test_esasky_query_ids_maps(self): assert "1342221848" in result["HERSCHEL"].columns["observation_id"] def test_esasky_query_ids_catalogs(self): - result = ESASky.query_ids_catalogs(source_ids=["2CXO J090341.1-322609", "2CXO J090353.8-322642"], - catalogs="CHANDRA-SC2") + result = ESASky.query_ids_catalogs(source_ids=["2CXO J031306.2-852820", "2CXO J031339.7-852543"], + catalogs="CHANDRA-SC21") assert isinstance(result, TableList) - assert "2CXO J090341.1-322609" in result["CHANDRA-SC2"].columns["name"] - assert "2CXO J090353.8-322642" in result["CHANDRA-SC2"].columns["name"] + assert "2CXO J031306.2-852820" in result["CHANDRA-SC21"].columns["name"] + assert "2CXO J031339.7-852543" in result["CHANDRA-SC21"].columns["name"] - result = ESASky.query_ids_catalogs(source_ids=["2CXO J090341.1-322609", - "2CXO J090353.8-322642", "44899", "45057"], - catalogs=["CHANDRA-SC2", "Hipparcos-2"]) + result = ESASky.query_ids_catalogs(source_ids=["2CXO J031306.2-852820", + "2CXO J031339.7-852543", "44899", "45057"], + catalogs=["CHANDRA-SC21", "Hipparcos-2"]) assert isinstance(result, TableList) - assert "2CXO J090341.1-322609" in result["CHANDRA-SC2"].columns["name"] - assert "2CXO J090353.8-322642" in result["CHANDRA-SC2"].columns["name"] + assert "2CXO J031306.2-852820" in result["CHANDRA-SC21"].columns["name"] + assert "2CXO J031339.7-852543" in result["CHANDRA-SC21"].columns["name"] assert "44899" in result["HIPPARCOS-2"].columns["name"] assert "45057" in result["HIPPARCOS-2"].columns["name"] @@ -85,8 +84,7 @@ def test_esasky_get_images_obs_id(self, tmp_path, mission, obsid): assert isinstance(result[mission.upper()][0]["500"], HDUList) else: assert isinstance(result[mission.upper()][0], HDUList) - for hdu_list in result[mission.upper()]: - hdu_list.close() + self._close_hdu_lists(result, mission) @pytest.mark.parametrize("mission, observation_id", zip(["ISO-IR", "Chandra", "IUE", "XMM-NEWTON", @@ -118,30 +116,28 @@ def test_esasky_query_object_maps(self): 'ISO-IR', 'Herschel', 'Spitzer']) def test_esasky_get_images(self, tmp_path, mission): result = ESASky.get_images(position="M51", missions=mission, download_dir=tmp_path) - assert tmp_path.stat().st_size + assert any(p.is_file() for p in tmp_path.rglob("*")) if mission != "Herschel" and result: - for hdu_list in result[mission.upper()]: - hdu_list.close() + self._close_hdu_lists(result, mission) @pytest.mark.bigdata def test_esasky_get_images_for_erosita(self, tmp_path): mission = 'eROSITA' - result = ESASky.get_images(position="67.84 -61.44", missions=mission, download_dir=tmp_path) - assert tmp_path.stat().st_size - - for hdu_list in result[mission.upper()]: - hdu_list.close() + with pytest.warns(InputWarning): + result = ESASky.get_images(position="67.84 -61.44", missions=mission, download_dir=tmp_path) + assert any(p.is_file() for p in tmp_path.rglob("*")) + self._close_hdu_lists(result, mission) @pytest.mark.bigdata @pytest.mark.parametrize('mission, position', zip(['JWST-MID-IR', 'JWST-NEAR-IR'], ['340.50123388127435 -69.17904779241904', '225.6864099965157 -3.0315781490149467'])) def test_esasky_get_images_jwst(self, tmp_path, mission, position): - result = ESASky.get_images(position=position, missions=mission, download_dir=tmp_path) - assert tmp_path.stat().st_size - for hdu_list in result[mission.upper()]: - hdu_list.close() + with pytest.warns(InputWarning): + result = ESASky.get_images(position=position, missions=mission, download_dir=tmp_path) + assert any(p.is_file() for p in tmp_path.rglob("*")) + self._close_hdu_lists(result, mission) @pytest.mark.bigdata def test_esasky_get_images_hst(self, tmp_path): @@ -167,14 +163,12 @@ def test_esasky_get_maps(self, tmp_path): iso_maps[mission].remove_rows([0, 1]) result = ESASky.get_maps(iso_maps, download_dir=tmp_path) assert len(os.listdir(file_path)) == len(all_maps[mission]) - 2 - for hdu_list in result[mission]: - hdu_list.close() + self._close_hdu_lists(result, mission) iso_maps2 = dict({mission: all_maps[mission][:2]}) result = ESASky.get_maps(iso_maps2, download_dir=tmp_path) assert len(os.listdir(file_path)) == len(all_maps[mission]) - for hdu_list in result[mission]: - hdu_list.close() + self._close_hdu_lists(result, mission) def test_esasky_query_region_spectra(self): result = ESASky.query_region_spectra(position="M51", radius="5 arcmin") @@ -196,8 +190,7 @@ def test_esasky_get_spectra(self, tmp_path, mission): assert Path(tmp_path, mission.upper()).exists() if mission != "Herschel": - for hdu_list in result[mission.upper()]: - hdu_list.close() + self._close_hdu_lists(result, mission) def test_esasky_get_spectra_small(self, tmp_path): missions = ['HST-IR'] @@ -217,35 +210,24 @@ def test_esasky_get_spectra_from_table(self, tmp_path): # Remove a few maps, so the other list will have downloadable ones, too iso_spectra[mission].remove_rows([0, 1]) result = ESASky.get_spectra_from_table(query_table_list=iso_spectra, download_dir=tmp_path) - for hdu_list in result[mission]: - hdu_list.close() + self._close_hdu_lists(result, mission) assert len(os.listdir(file_path)) == len(all_spectra[mission]) - 2 iso_spectra2 = dict({mission: all_spectra[mission][:2]}) result = ESASky.get_spectra_from_table(query_table_list=iso_spectra2, download_dir=tmp_path) - for hdu_list in result[mission]: - hdu_list.close() + self._close_hdu_lists(result, mission) assert len(os.listdir(file_path)) == len(all_spectra[mission]) def test_query(self): result = ESASky.query(query="SELECT * from observations.mv_v_esasky_xmm_om_uv_fdw") - assert len(result) == 2000 # Default row limit is 2000 + assert len(result) > 0 def test_get_tables(self): table_names = ESASky.get_tables(only_names=True) assert len(table_names) > 70 tables = ESASky.get_tables(only_names=False) - assert isinstance(tables[0], TapTableMeta) assert len(table_names) == len(tables) - def test_get_columns(self): - column_names = ESASky.get_columns(table_name='observations.mv_v_esasky_xmm_om_uv_fdw', only_names=True) - assert len(column_names) == 17 - - columns = ESASky.get_columns(table_name='observations.mv_v_esasky_xmm_om_uv_fdw', only_names=False) - assert isinstance(columns[0], TapColumn) - assert len(column_names) == len(columns) - def test_esasky_query_sso(self): result = ESASky.query_sso(sso_name="ceres") assert isinstance(result, TableList) @@ -303,3 +285,8 @@ def test_esasky_get_images_sso(self, tmp_path): assert isinstance(fits_files["XMM"][0], HDUList) assert Path(tmp_path, "XMM").exists() + + def _close_hdu_lists(self, result, mission): + for hdu_list in result[mission.upper()]: + if hdu_list is not None: + hdu_list.close() From cb98f6be484fb867880e5f12a0f1381ab768d358 Mon Sep 17 00:00:00 2001 From: Henrik Norman Date: Tue, 31 Mar 2026 12:54:18 +0200 Subject: [PATCH 02/10] Fixed codestyle issues --- astroquery/esasky/__init__.py | 4 +++- astroquery/esasky/core.py | 8 ++------ astroquery/esasky/tests/test_esasky_remote.py | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index 208e36332d..9f6db5f4eb 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -18,7 +18,8 @@ class Conf(_config.ConfigNamespace): ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server") ESASKY_TAP_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON, "ESASky TAP Server") ESASKY_DATA_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'data?', "ESASky Data Server") - ESASKY_TABLES_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON + "/tables", "ESASky TAP Tables Server") + ESASKY_TABLES_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON + "/tables", + "ESASky TAP Tables Server") ESASKY_TARGET_ACTION = _config.ConfigItem("servlet/target-resolver?", "ESASky Target Resolver") ESASKY_MESSAGES = _config.ConfigItem("notification?action=GetNotifications", "ESASky Messages") ESASKY_LOGIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'login', "ESASky Login Server") @@ -28,6 +29,7 @@ class Conf(_config.ConfigNamespace): cache_location = os.path.join(paths.get_cache_dir(), 'astroquery/esasky', ) + conf = Conf() from .core import ESASky, ESASkyClass diff --git a/astroquery/esasky/core.py b/astroquery/esasky/core.py index 9f34e49584..de670cc177 100644 --- a/astroquery/esasky/core.py +++ b/astroquery/esasky/core.py @@ -1,12 +1,9 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -from numpy.testing import verbose - import astroquery.esa.utils.utils as esautils import json import os import tarfile as esatar -import pyvo import sys import re import warnings @@ -24,7 +21,6 @@ from astroquery.esa.utils import EsaTap from ..utils import commons -from ..utils import async_to_sync from . import conf from .. import version from astropy.coordinates.name_resolve import sesame_database @@ -91,7 +87,6 @@ def __init__(self, *, show_messages=False, auth_session=None, tap_url=None): if show_messages: self.get_status_messages() - def query(self, query, *, async_job=False, output_file=None, output_format="votable", verbose=False): """Launches a synchronous or asynchronous job to query the ESASky TAP @@ -115,7 +110,8 @@ def query(self, query, *, async_job=False, output_file=None, output_format="vota ------- A table object """ - return self.query_tap(query=query, async_job=async_job, output_file=output_file, output_format=output_format, verbose=verbose) + return self.query_tap(query=query, async_job=async_job, output_file=output_file, output_format=output_format, + verbose=verbose) def list_maps(self): """ diff --git a/astroquery/esasky/tests/test_esasky_remote.py b/astroquery/esasky/tests/test_esasky_remote.py index 47a8863a69..5fd8b6a504 100755 --- a/astroquery/esasky/tests/test_esasky_remote.py +++ b/astroquery/esasky/tests/test_esasky_remote.py @@ -288,5 +288,5 @@ def test_esasky_get_images_sso(self, tmp_path): def _close_hdu_lists(self, result, mission): for hdu_list in result[mission.upper()]: - if hdu_list is not None: - hdu_list.close() + if hdu_list is not None: + hdu_list.close() From 30e05fd278b05fd80fcc9b41cb13d2cdb8a34a1e Mon Sep 17 00:00:00 2001 From: Henrik Norman Date: Mon, 6 Apr 2026 13:06:38 +0200 Subject: [PATCH 03/10] Improved backwards compatibility of ESASky module --- astroquery/esasky/__init__.py | 52 ++++++++++++++++++++++++++++++++--- astroquery/esasky/core.py | 50 ++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index 9f6db5f4eb..d65b20ffd5 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -1,7 +1,9 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -from astropy import config as _config +import warnings +from astropy import config as _config from astropy.config import paths +from astropy.utils.exceptions import AstropyDeprecationWarning import os @@ -15,7 +17,7 @@ class Conf(_config.ConfigNamespace): Configuration parameters for `astroquery.esasky`. """ - ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server") + ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server", alias='urlBase') ESASKY_TAP_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON, "ESASky TAP Server") ESASKY_DATA_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'data?', "ESASky Data Server") ESASKY_TABLES_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON + "/tables", @@ -24,8 +26,50 @@ class Conf(_config.ConfigNamespace): ESASKY_MESSAGES = _config.ConfigItem("notification?action=GetNotifications", "ESASky Messages") ESASKY_LOGIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'login', "ESASky Login Server") ESASKY_LOGOUT_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'logout', "ESASky Logout Server") - ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.') - ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).') + ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.', alias='timeout') + ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', alias='row_limit') + + @property + def urlBase(self): + return self.ESASKY_DOMAIN_SERVER + + @urlBase.setter + def urlBase(self, value): + warnings.warn( + "'urlBase' is deprecated and will be removed in a future version. " + "Use 'ESASKY_DOMAIN_SERVER' instead.", + AstropyDeprecationWarning, + stacklevel=2, + ) + self.ESASKY_DOMAIN_SERVER = value + + @property + def timeout(self): + return self.ESASKY_CONNECTION_TIMEOUT + + @timeout.setter + def timeout(self, value): + warnings.warn( + "'timeout' is deprecated and will be removed in a future version. " + "Use 'ESASKY_CONNECTION_TIMEOUT' instead.", + AstropyDeprecationWarning, + stacklevel=2, + ) + self.ESASKY_CONNECTION_TIMEOUT = value + + @property + def row_limit(self): + return self.ESASKY_ROW_LIMIT + + @row_limit.setter + def row_limit(self, value): + warnings.warn( + "'row_limit' is deprecated and will be removed in a future version. " + "Use 'ESASKY_ROW_LIMIT' instead.", + AstropyDeprecationWarning, + stacklevel=2, + ) + self.ESASKY_ROW_LIMIT = value cache_location = os.path.join(paths.get_cache_dir(), 'astroquery/esasky', ) diff --git a/astroquery/esasky/core.py b/astroquery/esasky/core.py index de670cc177..e3b865025d 100644 --- a/astroquery/esasky/core.py +++ b/astroquery/esasky/core.py @@ -1,5 +1,6 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst +from astropy_helpers.astropy_helpers.utils import AstropyDeprecationWarning import astroquery.esa.utils.utils as esautils import json import os @@ -15,6 +16,7 @@ from astropy.coordinates import Angle from astropy.io import fits from astropy.utils.console import ProgressBar +from astropy.utils import deprecated from astroquery import log from requests import HTTPError from requests import ConnectionError @@ -81,8 +83,15 @@ class ESASkyClass(EsaTap): SSO_TYPES = ['ALL', 'ASTEROID', 'COMET', 'SATELLITE', 'PLANET', 'DWARF_PLANET', 'SPACECRAFT', 'SPACEJUNK', 'EXOPLANET', 'STAR'] - def __init__(self, *, show_messages=False, auth_session=None, tap_url=None): + def __init__(self, *, tap_handler=None, show_messages=False, auth_session=None, tap_url=None): super().__init__(auth_session=auth_session, tap_url=tap_url) + if tap_handler is not None: + warnings.warn( + "The 'tap_handler' parameter is deprecated and will be removed in a future version. " + "Use the ESASky instance directly for TAP queries (Using esa.utils.EsaTap and PyVO).", + AstropyDeprecationWarning, + stacklevel=2, + ) if show_messages: self.get_status_messages() @@ -113,6 +122,45 @@ def query(self, query, *, async_job=False, output_file=None, output_format="vota return self.query_tap(query=query, async_job=async_job, output_file=output_file, output_format=output_format, verbose=verbose) + def get_columns(self, table_name, *, only_names=True): + """ + Get the available columns for a table in ESASky TAP service + + Parameters + ---------- + table_name : str, mandatory, default None + table name of which, columns will be returned + only_names : bool, optional, default 'True' + True to load table names only + + Returns + ------- + A list of columns + """ + columns = self.get_table(table=table_name).columns + + if only_names: + return [c.name for c in columns] + else: + return columns + + @deprecated(since="0.4.12", message="The ESASky module no longer uses the TapPlus module. Equivalent functionality" + "is available directly on the ESASky module (Using esa.utils.EsaTap and PyVO).") + def get_tap(self): + """ + Get a TAP+ instance for the ESASky servers, which supports + all common TAP+ operations (synchronous & asynchronous queries, + uploading of tables, table sharing and more) + Full documentation and examples available here: + https://astroquery.readthedocs.io/en/latest/utils/tap.html + + Returns + ------- + tap : `~astroquery.utils.tap.core.TapPlus` + """ + + return self + def list_maps(self): """ Get a list of the mission names of the available observations in ESASky From 7e0dee88c01871df14fddb9429b01af2b08af53b Mon Sep 17 00:00:00 2001 From: Henrik Norman Date: Mon, 6 Apr 2026 13:11:19 +0200 Subject: [PATCH 04/10] Fixed codestyle issues --- astroquery/esasky/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index d65b20ffd5..997b998b60 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -17,7 +17,7 @@ class Conf(_config.ConfigNamespace): Configuration parameters for `astroquery.esasky`. """ - ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server", alias='urlBase') + ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server", aliases='urlBase') ESASKY_TAP_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON, "ESASky TAP Server") ESASKY_DATA_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'data?', "ESASky Data Server") ESASKY_TABLES_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON + "/tables", @@ -26,8 +26,10 @@ class Conf(_config.ConfigNamespace): ESASKY_MESSAGES = _config.ConfigItem("notification?action=GetNotifications", "ESASky Messages") ESASKY_LOGIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'login', "ESASky Login Server") ESASKY_LOGOUT_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'logout', "ESASky Logout Server") - ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.', alias='timeout') - ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', alias='row_limit') + ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.', + aliases='timeout') + ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', + aliases='row_limit') @property def urlBase(self): From aeb358afe146464bc13750c01eb391e69015116d Mon Sep 17 00:00:00 2001 From: Henrik Norman Date: Mon, 6 Apr 2026 13:15:07 +0200 Subject: [PATCH 05/10] Fixed codestyle issues --- astroquery/esasky/__init__.py | 4 ++-- astroquery/esasky/core.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index 997b998b60..9fcb8a43ea 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -26,9 +26,9 @@ class Conf(_config.ConfigNamespace): ESASKY_MESSAGES = _config.ConfigItem("notification?action=GetNotifications", "ESASky Messages") ESASKY_LOGIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'login', "ESASky Login Server") ESASKY_LOGOUT_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'logout', "ESASky Logout Server") - ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.', + ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.', aliases='timeout') - ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', + ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', aliases='row_limit') @property diff --git a/astroquery/esasky/core.py b/astroquery/esasky/core.py index e3b865025d..0f47cab752 100644 --- a/astroquery/esasky/core.py +++ b/astroquery/esasky/core.py @@ -1,6 +1,5 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst - -from astropy_helpers.astropy_helpers.utils import AstropyDeprecationWarning +from astropy.utils.exceptions import AstropyDeprecationWarning import astroquery.esa.utils.utils as esautils import json import os From d0d5448c811574cd15f97a214ad34d6196f5167b Mon Sep 17 00:00:00 2001 From: Henrik Norman Date: Mon, 6 Apr 2026 13:36:12 +0200 Subject: [PATCH 06/10] Added namespaces to aliases --- astroquery/esasky/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index 9fcb8a43ea..398cff72fc 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -17,7 +17,8 @@ class Conf(_config.ConfigNamespace): Configuration parameters for `astroquery.esasky`. """ - ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server", aliases='urlBase') + ESASKY_DOMAIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER, "ESASky TAP Common Server", + aliases=['astroquery.esasky.urlBase']) ESASKY_TAP_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON, "ESASky TAP Server") ESASKY_DATA_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'data?', "ESASky Data Server") ESASKY_TABLES_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + ESASKY_TAP_COMMON + "/tables", @@ -27,9 +28,9 @@ class Conf(_config.ConfigNamespace): ESASKY_LOGIN_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'login', "ESASky Login Server") ESASKY_LOGOUT_SERVER = _config.ConfigItem(ESASKY_COMMON_SERVER + 'logout', "ESASky Logout Server") ESASKY_CONNECTION_TIMEOUT = _config.ConfigItem(1000, 'Time limit for connecting to a data product server.', - aliases='timeout') + aliases=['astroquery.esasky.timeout']) ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', - aliases='row_limit') + aliases=['astroquery.esasky.row_limit']) @property def urlBase(self): From a0cecbdcaf78004604282d164203ea3e1c0f74a3 Mon Sep 17 00:00:00 2001 From: Erik Mellegard Date: Wed, 8 Apr 2026 14:09:13 +0200 Subject: [PATCH 07/10] Fix broken tests in ESASky documentation --- docs/esasky/esasky.rst | 122 +++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/docs/esasky/esasky.rst b/docs/esasky/esasky.rst index 13d2cfa021..865758ed25 100644 --- a/docs/esasky/esasky.rst +++ b/docs/esasky/esasky.rst @@ -31,14 +31,15 @@ If you know the names of all the available catalogs you can use :meth:`~astroque >>> from astroquery.esasky import ESASky >>> catalog_list = ESASky.list_catalogs() - >>> print(catalog_list) - ['TYCHO-2', '2RXS', 'INTEGRAL', 'GAIA-DR3', 'XMM-EPIC', 'OU_BLAZARS', 'XMM-SLEW', 'HIPPARCOS-2', - 'HERSCHEL-SPSC-500', 'AKARI-IRC-SC', 'HERSCHEL-HPPSC-070', 'HERSCHEL-HPPSC-100', 'HERSCHEL-HPPSC-160', - 'HERSCHEL-SPSC-250', 'HERSCHEL-SPSC-350', 'PLANCK-PCCS2E-HFI', 'PLANCK-PGCC', 'PLANCK-PCCS2-HFI', - 'PLANCK-PCCS2-LFI', 'PLANCK-PSZ2', 'CHANDRA-SC2', 'ALLWISE', 'TWOMASS', 'EROSITA-EFEDS-MAIN', - 'EROSITA-EFEDS-HARD', 'XMM-OM', 'XMM-EPIC-STACK', 'FERMI_4FGL-DR2', 'FERMI_3FHL', 'EROSITA-ETACHA-MAIN', - 'SWIFT-2SXPS', 'ICECUBE', 'FERMI_4LAC-DR2', 'EROSITA-ETACHA-HARD', 'HSC', 'PLATO ASPIC1.1', '2WHSP', - 'GAIA-FPR', 'EROSITA-ERASS-MAIN', 'EROSITA-ERASS-HARD', 'GLADE+', 'LAMOST_MRS', 'LAMOST_LRS'] + >>> print(catalog_list) # doctest: +IGNORE_OUTPUT + ['TYCHO-2', '2RXS', 'HERSCHEL-HPPSC-070', 'XMM-SLEW', 'GAIA-DR3', 'HERSCHEL-SPSC-350', + 'OU_BLAZARS', 'HERSCHEL-SPSC-250', 'HERSCHEL-HPPSC-160', 'HIPPARCOS-2', 'INTEGRAL', + 'HERSCHEL-SPSC-500', 'AKARI-IRC-SC', 'HERSCHEL-HPPSC-100', 'TWOMASS', 'ALLWISE', + 'XMM-EPIC', 'PLANCK-PSZ2', 'PLANCK-PCCS2-LFI', 'PLANCK-PCCS2-HFI', 'PLANCK-PGCC', + 'PLANCK-PCCS2E-HFI', 'EROSITA-EFEDS-MAIN', 'EROSITA-EFEDS-HARD', 'EUCLID-MER', 'XMM-OM', + 'CHANDRA-SC21', 'XMM-EPIC-STACK', 'HCV', 'EROSITA-ETACHA-MAIN', 'FERMI_3FHL', 'FERMI_4FGL-DR2', + 'SWIFT-2SXPS', 'ICECUBE', 'HSC', 'FERMI_4LAC-DR2', 'EROSITA-ETACHA-HARD', 'PLATO ASPIC1.1', + 'GAIA-FPR', '2WHSP', 'EROSITA-ERASS-HARD', 'EROSITA-ERASS-MAIN', 'GLADE+', 'LAMOST_MRS', 'LAMOST_LRS'] Get the available maps mission names ------------------------------------ @@ -48,9 +49,10 @@ If you know the names of all the available maps missions you can use :meth:`~ast .. doctest-remote-data:: >>> maps_list = ESASky.list_maps() - >>> print(maps_list) - ['ALMA', 'ISO-IR', 'SPITZER', 'AKARI', 'HST-IR', 'HST-UV', 'HST-OPTICAL', 'EROSITA', 'INTEGRAL', - 'SUZAKU', 'HERSCHEL', 'JWST-MID-IR', 'JWST-NEAR-IR', 'XMM', 'XMM-OM-UV', 'XMM-OM-OPTICAL', 'CHANDRA'] + >>> print(maps_list) # doctest: +IGNORE_OUTPUT + ['EUCLID-NISP', 'EUCLID-VIS', 'ALMA', 'ISO-IR', 'SPITZER', 'HST-UV', 'HST-IR', 'AKARI', + 'HST-OPTICAL', 'EROSITA', 'INTEGRAL', 'SUZAKU', 'JWST-MID-IR', 'JWST-NEAR-IR', 'HERSCHEL', + 'XMM', 'XMM-OM-OPTICAL', 'XMM-OM-UV', 'CHANDRA'] Get the available spectra mission names --------------------------------------- @@ -60,9 +62,9 @@ If you know the names of all the available spectra you can use :meth:`~astroquer .. doctest-remote-data:: >>> spectra_list = ESASky.list_spectra() - >>> print(spectra_list) - ['HERSCHEL', 'CHANDRA', 'IUE', 'ISO-IR', 'CHEOPS', 'XMM-NEWTON', 'JWST-MID-IR', 'JWST-NEAR-IR', - 'HST-OPTICAL', 'HST-UV', 'HST-IR', 'LAMOST_MRS', 'LAMOST_LRS'] + >>> print(spectra_list) # doctest: +IGNORE_OUTPUT + ['COROT-EXO', 'COROT-ASTERO', 'CHANDRA', 'HERSCHEL', 'XMM-NEWTON', 'ISO-IR', 'IUE', + 'JWST-MID-IR', 'JWST-NEAR-IR', 'HST-UV', 'HST-OPTICAL', 'HST-IR', 'LAMOST_MRS', 'LAMOST_LRS'] Get the available SSO mission names ----------------------------------- @@ -73,7 +75,7 @@ If you know the names of all the available missions with SSO cross match data, y .. doctest-remote-data:: >>> sso_list = ESASky.list_sso() - >>> print(sso_list) + >>> print(sso_list) # doctest: +IGNORE_OUTPUT ['XMM-OM', 'HST', 'HERSCHEL', 'XMM'] @@ -115,19 +117,21 @@ To see the result: .. doctest-remote-data:: - >>> print(result) - TableList with 11 tables: - '0:XMM-EPIC' with 223 column(s) and 15 row(s) - '1:HERSCHEL-HPPSC-070' with 21 column(s) and 1 row(s) - '2:HERSCHEL-HPPSC-100' with 21 column(s) and 1 row(s) - '3:CHANDRA-SC2' with 41 column(s) and 9 row(s) - '4:ALLWISE' with 25 column(s) and 1 row(s) - '5:TWOMASS' with 14 column(s) and 3 row(s) - '6:XMM-OM' with 122 column(s) and 7 row(s) - '7:XMM-EPIC-STACK' with 161 column(s) and 15 row(s) - '8:SWIFT-2SXPS' with 232 column(s) and 1 row(s) - '9:HSC' with 27 column(s) and 230 row(s) - '10:GLADE+' with 40 column(s) and 1 row(s) + >>> print(result) # doctest: +IGNORE_OUTPUT + TableList with 12 tables: + '0:HERSCHEL-HPPSC-070' with 21 column(s) and 1 row(s) + '1:XMM-SLEW' with 106 column(s) and 3 row(s) + '2:HERSCHEL-HPPSC-100' with 21 column(s) and 1 row(s) + '3:TWOMASS' with 14 column(s) and 3 row(s) + '4:ALLWISE' with 25 column(s) and 1 row(s) + '5:XMM-EPIC' with 223 column(s) and 15 row(s) + '6:XMM-OM' with 125 column(s) and 21 row(s) + '7:CHANDRA-SC21' with 517 column(s) and 9 row(s) + '8:XMM-EPIC-STACK' with 161 column(s) and 15 row(s) + '9:SWIFT-2SXPS' with 232 column(s) and 1 row(s) + '10:HSC' with 27 column(s) and 230 row(s) + '11:GLADE+' with 40 column(s) and 1 row(s) + All the results are returned as a `~astroquery.utils.TableList` object. This is a container for `~astropy.table.Table` objects. It is basically an extension to `~collections.OrderedDict` for storing a `~astropy.table.Table` against its @@ -197,30 +201,31 @@ To see the result: .. doctest-remote-data:: - >>> print(result) + >>> print(result) # doctest: +IGNORE_OUTPUT TableList with 22 tables: - '0:2RXS' with 306 column(s) and 2 row(s) - '1:GAIA-DR3' with 153 column(s) and 932 row(s) - '2:XMM-EPIC' with 223 column(s) and 1467 row(s) - '3:XMM-SLEW' with 106 column(s) and 2 row(s) - '4:HERSCHEL-SPSC-500' with 36 column(s) and 7 row(s) - '5:AKARI-IRC-SC' with 29 column(s) and 1 row(s) - '6:HERSCHEL-HPPSC-070' with 21 column(s) and 93 row(s) - '7:HERSCHEL-HPPSC-100' with 21 column(s) and 122 row(s) - '8:HERSCHEL-HPPSC-160' with 21 column(s) and 93 row(s) - '9:HERSCHEL-SPSC-250' with 36 column(s) and 59 row(s) - '10:HERSCHEL-SPSC-350' with 36 column(s) and 24 row(s) - '11:PLANCK-PCCS2-HFI' with 9 column(s) and 8 row(s) - '12:CHANDRA-SC2' with 41 column(s) and 430 row(s) - '13:ALLWISE' with 25 column(s) and 1762 row(s) - '14:TWOMASS' with 14 column(s) and 188 row(s) - '15:XMM-OM' with 122 column(s) and 7026 row(s) - '16:XMM-EPIC-STACK' with 161 column(s) and 4185 row(s) - '17:SWIFT-2SXPS' with 232 column(s) and 120 row(s) - '18:HSC' with 27 column(s) and 10000 row(s) - '19:PLATO ASPIC1.1' with 70 column(s) and 3 row(s) - '20:GLADE+' with 40 column(s) and 51 row(s) - '21:LAMOST_LRS' with 40 column(s) and 47 row(s) + '0:2RXS' with 306 column(s) and 2 row(s) + '1:HERSCHEL-HPPSC-070' with 21 column(s) and 93 row(s) + '2:XMM-SLEW' with 106 column(s) and 11 row(s) + '3:GAIA-DR3' with 153 column(s) and 932 row(s) + '4:HERSCHEL-SPSC-350' with 36 column(s) and 24 row(s) + '5:HERSCHEL-SPSC-250' with 36 column(s) and 59 row(s) + '6:HERSCHEL-HPPSC-160' with 21 column(s) and 93 row(s) + '7:HERSCHEL-SPSC-500' with 36 column(s) and 7 row(s) + '8:AKARI-IRC-SC' with 29 column(s) and 1 row(s) + '9:HERSCHEL-HPPSC-100' with 21 column(s) and 122 row(s) + '10:TWOMASS' with 14 column(s) and 188 row(s) + '11:ALLWISE' with 25 column(s) and 1762 row(s) + '12:XMM-EPIC' with 223 column(s) and 1467 row(s) + '13:PLANCK-PCCS2-HFI' with 9 column(s) and 8 row(s) + '14:XMM-OM' with 125 column(s) and 10000 row(s) + '15:CHANDRA-SC21' with 517 column(s) and 450 row(s) + '16:XMM-EPIC-STACK' with 161 column(s) and 4185 row(s) + '17:SWIFT-2SXPS' with 232 column(s) and 120 row(s) + '18:HSC' with 27 column(s) and 10000 row(s) + '19:PLATO ASPIC1.1' with 70 column(s) and 3 row(s) + '20:GLADE+' with 40 column(s) and 51 row(s) + '21:LAMOST_LRS' with 40 column(s) and 47 row(s) + You can use, :meth:`~astroquery.esasky.ESASkyClass.query_region_maps` and :meth:`~astroquery.esasky.ESASkyClass.query_region_maps` with the same parameters. To execute the same command as above @@ -243,12 +248,9 @@ If you already know the observation ID's or source names of interest, you can ge .. doctest-remote-data:: - >>> maps = ESASky.query_ids_maps(observation_ids=["lbsk03vbq", "ieag90010"], missions="HST-UV") - INFO: Retrieving tables... [astroquery.utils.tap.core] - INFO: Parsing tables... [astroquery.utils.tap.core] - INFO: Done. [astroquery.utils.tap.core] + >>> maps = ESASky.query_ids_maps(observation_ids=["lbsk03vbq", "ieag90010"], missions="HST-UV") # doctest: +IGNORE_OUTPUT >>> catalogs = ESASky.query_ids_catalogs(source_ids=["2CXO J090341.1-322609", "2CXO J090353.8-322642", - ... "44899", "45057"], catalogs=["CHANDRA-SC2", "Hipparcos-2"]) + ... "44899", "45057"], catalogs=["CHANDRA-SC21", "Hipparcos-2"]) >>> spectra = ESASky.query_ids_spectra(observation_ids="0001730501") If you already know which missions you are interested in, it is recommended to explicitly mention them in the mission @@ -423,15 +425,15 @@ In this case, you can specify the sso_type >>> from astroquery.esasky import ESASky >>> ESASky.query_sso(sso_name="503", sso_type="SATELLITE") TableList with 2 tables: - '0:HST' with 45 column(s) and 618 row(s) - '1:XMM' with 45 column(s) and 33 row(s) + '0:XMM' with 45 column(s) and 33 row(s) + '1:HST' with 45 column(s) and 618 row(s) You can see the available missions with: .. doctest-remote-data:: >>> from astroquery.esasky import ESASky - >>> ESASky.list_sso() + >>> ESASky.list_sso() # doctest: +IGNORE_OUTPUT ['XMM-OM', 'HST', 'HERSCHEL', 'XMM'] Other parameters and the return value are structured in the same manner as the other query methods. @@ -456,9 +458,9 @@ Or download everything on an SSO by something like this: >>> from astroquery.esasky import ESASky >>> images=ESASky.get_images_sso(sso_name="2017 RN65") - INFO: Starting download of HST data. (1 files) [astroquery.esasky.core] INFO: Starting download of HERSCHEL data. (1 files) [astroquery.esasky.core] INFO: Starting download of XMM data. (1 files) [astroquery.esasky.core] + INFO: Starting download of HST data. (1 files) [astroquery.esasky.core] ... This module also offers access to IMCCE's SsODNet resolver, which allows you to find solar and extra solar system From 90851c35009775b12de830dcb422a308da8d2e6c Mon Sep 17 00:00:00 2001 From: Erik Mellegard Date: Thu, 14 May 2026 14:14:03 +0200 Subject: [PATCH 08/10] Deprecate arguments with deprecation decorators instead of warnings --- astroquery/esasky/__init__.py | 48 +++-------------------------------- astroquery/esasky/core.py | 12 +++------ 2 files changed, 8 insertions(+), 52 deletions(-) diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index 398cff72fc..4c1b3c9051 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -1,9 +1,7 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -import warnings - from astropy import config as _config from astropy.config import paths -from astropy.utils.exceptions import AstropyDeprecationWarning +from astropy.utils.decorators import deprecated_attribute import os @@ -32,47 +30,9 @@ class Conf(_config.ConfigNamespace): ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', aliases=['astroquery.esasky.row_limit']) - @property - def urlBase(self): - return self.ESASKY_DOMAIN_SERVER - - @urlBase.setter - def urlBase(self, value): - warnings.warn( - "'urlBase' is deprecated and will be removed in a future version. " - "Use 'ESASKY_DOMAIN_SERVER' instead.", - AstropyDeprecationWarning, - stacklevel=2, - ) - self.ESASKY_DOMAIN_SERVER = value - - @property - def timeout(self): - return self.ESASKY_CONNECTION_TIMEOUT - - @timeout.setter - def timeout(self, value): - warnings.warn( - "'timeout' is deprecated and will be removed in a future version. " - "Use 'ESASKY_CONNECTION_TIMEOUT' instead.", - AstropyDeprecationWarning, - stacklevel=2, - ) - self.ESASKY_CONNECTION_TIMEOUT = value - - @property - def row_limit(self): - return self.ESASKY_ROW_LIMIT - - @row_limit.setter - def row_limit(self, value): - warnings.warn( - "'row_limit' is deprecated and will be removed in a future version. " - "Use 'ESASKY_ROW_LIMIT' instead.", - AstropyDeprecationWarning, - stacklevel=2, - ) - self.ESASKY_ROW_LIMIT = value + urlBase = deprecated_attribute(name='urlBase', alternative='ESASKY_DOMAIN_SERVER', since='8.0') + timeout = deprecated_attribute(name='timeout', alternative='ESASKY_CONNECTION_TIMEOUT', since='8.0') + row_limit = deprecated_attribute(name='row_limit', alternative='ESASKY_ROW_LIMIT', since='8.0') cache_location = os.path.join(paths.get_cache_dir(), 'astroquery/esasky', ) diff --git a/astroquery/esasky/core.py b/astroquery/esasky/core.py index 0f47cab752..adcbb3b4c7 100644 --- a/astroquery/esasky/core.py +++ b/astroquery/esasky/core.py @@ -1,5 +1,4 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -from astropy.utils.exceptions import AstropyDeprecationWarning import astroquery.esa.utils.utils as esautils import json import os @@ -25,6 +24,7 @@ from . import conf from .. import version from astropy.coordinates.name_resolve import sesame_database +from astropy.utils import deprecated_renamed_argument # We do trust the ESA tar files, this is to avoid the new to Python 3.12 deprecation warning @@ -82,15 +82,11 @@ class ESASkyClass(EsaTap): SSO_TYPES = ['ALL', 'ASTEROID', 'COMET', 'SATELLITE', 'PLANET', 'DWARF_PLANET', 'SPACECRAFT', 'SPACEJUNK', 'EXOPLANET', 'STAR'] + @deprecated_renamed_argument('tap_handler', None, since='8.0', message="The 'tap_handler' parameter is deprecated" + "and will be removed in a future version. Use the ESASky instance directly for TAP" + "queries (Using esa.utils.EsaTap and PyVO).") def __init__(self, *, tap_handler=None, show_messages=False, auth_session=None, tap_url=None): super().__init__(auth_session=auth_session, tap_url=tap_url) - if tap_handler is not None: - warnings.warn( - "The 'tap_handler' parameter is deprecated and will be removed in a future version. " - "Use the ESASky instance directly for TAP queries (Using esa.utils.EsaTap and PyVO).", - AstropyDeprecationWarning, - stacklevel=2, - ) if show_messages: self.get_status_messages() From f4e3f45827debf79d0960ef103d767256b0d7694 Mon Sep 17 00:00:00 2001 From: Erik Mellegard Date: Thu, 21 May 2026 09:47:30 +0200 Subject: [PATCH 09/10] Update CHANGES.rst with ESASky changes --- CHANGES.rst | 7 +++++++ astroquery/esasky/__init__.py | 6 +++--- astroquery/esasky/core.py | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index c5094bfbea..21a8c94db2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -55,6 +55,13 @@ esa.euclid - The ``get_product_list`` method now also returns file_name_list column when the product type belongs to BASIC_DOWNLOAD_DATA_PRODUCTS. [#3562] +esa.esasky + +- The argument tap_handler on ESASky has been deprecated. Use the ESASky instance directly for TAP + queries (Using esa.utils.EsaTap and PyVO). +- Attribute urlBase has been deprecated on esasky.conf, use ESASKY_DOMAIN_SERVER instead. +- Attribute timeout has been deprecated on esasky.conf, use ESASKY_CONNECTION_TIMEOUT instead. +- Attribute row_limit has been deprecated on esasky.conf, use ESASKY_ROW_LIMIT instead. vizier ^^^^^^ diff --git a/astroquery/esasky/__init__.py b/astroquery/esasky/__init__.py index 4c1b3c9051..890f27e4d7 100644 --- a/astroquery/esasky/__init__.py +++ b/astroquery/esasky/__init__.py @@ -30,9 +30,9 @@ class Conf(_config.ConfigNamespace): ESASKY_ROW_LIMIT = _config.ConfigItem(10000, 'Maximum number of rows returned (set to -1 for unlimited).', aliases=['astroquery.esasky.row_limit']) - urlBase = deprecated_attribute(name='urlBase', alternative='ESASKY_DOMAIN_SERVER', since='8.0') - timeout = deprecated_attribute(name='timeout', alternative='ESASKY_CONNECTION_TIMEOUT', since='8.0') - row_limit = deprecated_attribute(name='row_limit', alternative='ESASKY_ROW_LIMIT', since='8.0') + urlBase = deprecated_attribute(name='urlBase', alternative='ESASKY_DOMAIN_SERVER', since='0.4.12') + timeout = deprecated_attribute(name='timeout', alternative='ESASKY_CONNECTION_TIMEOUT', since='0.4.12') + row_limit = deprecated_attribute(name='row_limit', alternative='ESASKY_ROW_LIMIT', since='0.4.12') cache_location = os.path.join(paths.get_cache_dir(), 'astroquery/esasky', ) diff --git a/astroquery/esasky/core.py b/astroquery/esasky/core.py index adcbb3b4c7..cdad2d38f1 100644 --- a/astroquery/esasky/core.py +++ b/astroquery/esasky/core.py @@ -82,9 +82,9 @@ class ESASkyClass(EsaTap): SSO_TYPES = ['ALL', 'ASTEROID', 'COMET', 'SATELLITE', 'PLANET', 'DWARF_PLANET', 'SPACECRAFT', 'SPACEJUNK', 'EXOPLANET', 'STAR'] - @deprecated_renamed_argument('tap_handler', None, since='8.0', message="The 'tap_handler' parameter is deprecated" - "and will be removed in a future version. Use the ESASky instance directly for TAP" - "queries (Using esa.utils.EsaTap and PyVO).") + @deprecated_renamed_argument('tap_handler', None, since='0.4.12', message="The 'tap_handler' parameter is" + "deprecated and will be removed in a future version. Use the ESASky instance" + "directly for TAP queries (Using esa.utils.EsaTap and PyVO).") def __init__(self, *, tap_handler=None, show_messages=False, auth_session=None, tap_url=None): super().__init__(auth_session=auth_session, tap_url=tap_url) From eef477ea3a4407af021ef44d694a7469d742c012 Mon Sep 17 00:00:00 2001 From: Erik Mellegard Date: Thu, 21 May 2026 15:36:08 +0200 Subject: [PATCH 10/10] Remove Integral from ESASky tests as it's no longer part of our tap --- astroquery/esasky/tests/test_esasky_remote.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astroquery/esasky/tests/test_esasky_remote.py b/astroquery/esasky/tests/test_esasky_remote.py index 5fd8b6a504..443c24b25f 100755 --- a/astroquery/esasky/tests/test_esasky_remote.py +++ b/astroquery/esasky/tests/test_esasky_remote.py @@ -69,10 +69,10 @@ def test_esasky_query_ids_spectra(self): @pytest.mark.parametrize("mission, obsid", zip(["SUZAKU", "ISO-IR", "Chandra", "XMM-OM-OPTICAL", "XMM", "XMM-OM-UV", "HST-IR", "Herschel", - "Spitzer", "HST-UV", "HST-OPTICAL", "INTEGRAL"], + "Spitzer", "HST-UV", "HST-OPTICAL"], ["100001010", "01500403", "21171", "0852000101", "0851180201", "0851180201", "n3tr01c3q", "1342247257", - "30002561-25100", "hst_07553_3h_wfpc2_f160bw_pc", "ocli05leq", "88600210001"])) + "30002561-25100", "hst_07553_3h_wfpc2_f160bw_pc", "ocli05leq"])) def test_esasky_get_images_obs_id(self, tmp_path, mission, obsid): result = ESASky.get_images(observation_ids=obsid, missions=mission, download_dir=tmp_path)