-
-
Notifications
You must be signed in to change notification settings - Fork 437
Migrated ESASky module to use EsaTap/PyVO instead of TAPPlus #3572
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
Open
imbasimba
wants to merge
8
commits into
astropy:main
Choose a base branch
from
imbasimba:esasky-pyvo
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+228
−193
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
2a5da5a
Migrated ESASky module to use pyVO instead of TAPPlus
imbasimba cb98f6b
Fixed codestyle issues
imbasimba 30e05fd
Improved backwards compatibility of ESASky module
imbasimba 7e0dee8
Fixed codestyle issues
imbasimba aeb358a
Fixed codestyle issues
imbasimba d0d5448
Added namespaces to aliases
imbasimba a0cecbd
Fix broken tests in ESASky documentation
emellega fca11cc
Merge pull request #2 from emellega/esasky-pyvo
imbasimba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| # 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 | ||
| import tarfile as esatar | ||
|
|
@@ -14,14 +15,13 @@ | |
| 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 | ||
|
|
||
| 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 | ||
| from .. import version | ||
| from astropy.coordinates.name_resolve import sesame_database | ||
|
|
@@ -33,12 +33,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 +82,29 @@ 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, *, tap_handler=None, show_messages=False, auth_session=None, tap_url=None): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please use the @deprecated_renamed_argument decorator from astropy.utils instead; plenty of examples for it in the other modules here |
||
| 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 tap_handler is None: | ||
| self._tap = TapPlus(url=self.URLbase + "/tap") | ||
| else: | ||
| self._tap = tap_handler | ||
| if show_messages: | ||
| self.get_status_messages() | ||
|
|
||
| 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,44 +118,10 @@ 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() | ||
| return self.query_tap(query=query, async_job=async_job, output_file=output_file, output_format=output_format, | ||
| verbose=verbose) | ||
|
|
||
| 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): | ||
| def get_columns(self, table_name, *, only_names=True): | ||
| """ | ||
| Get the available columns for a table in ESASky TAP service | ||
|
|
||
|
|
@@ -154,30 +131,20 @@ def get_columns(self, table_name, *, only_names=True, verbose=False): | |
| 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") | ||
| 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 | ||
|
|
@@ -191,7 +158,7 @@ def get_tap(self): | |
| tap : `~astroquery.utils.tap.core.TapPlus` | ||
| """ | ||
|
|
||
| return self._tap | ||
| return self | ||
|
|
||
| def list_maps(self): | ||
| """ | ||
|
|
@@ -944,9 +911,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 +1316,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 +1697,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 +1761,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 +1838,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 +1849,4 @@ def _get_header(self): | |
| return {'User-Agent': user_agent} | ||
|
|
||
|
|
||
| ESASky = ESASkyClass() | ||
| ESASky = ESASkyClass(show_messages=False) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry not picking up on this in the first round, but I wonder if we could/should use the deprecated_attribute functionality from astropy.utils instead?
usage is shown e.g. here: astropy/astropy#19593 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
although in these cases the alternative is not another property, so you may want to use the
messagerather than thealternativeargument, and may need to instead follow the example in its documentation