Skip to content

ESA HST module PyVO migration #3367

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
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ New Tools and Services
API changes
-----------

esa.hubble
^^^^^^^^^^

- Migration to PyVO [#3367]

gaia
^^^^

Expand Down
9 changes: 8 additions & 1 deletion astroquery/esa/hubble/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@

"""


from astropy import config as _config
from astropy.config import paths
import os

EHST_COMMON_SERVER = "https://hst.esac.esa.int/tap-server/"
EHST_TAP_COMMON = "tap"


class Conf(_config.ConfigNamespace):
"""
Configuration parameters for `astroquery.esa.hubble`.
"""
EHST_TAP_SERVER = _config.ConfigItem("https://hst.esac.esa.int/tap-server/tap", "eHST TAP Server")
EHST_DOMAIN_SERVER = _config.ConfigItem(EHST_COMMON_SERVER, "eHST TAP Common Server")
EHST_TAP_SERVER = _config.ConfigItem(EHST_COMMON_SERVER + EHST_TAP_COMMON, "eHST TAP Server")
EHST_DATA_SERVER = _config.ConfigItem(EHST_COMMON_SERVER + 'data?', "eHST Data Server")
EHST_TABLES_SERVER = _config.ConfigItem(EHST_COMMON_SERVER + EHST_TAP_COMMON + "/tables", "eHST TAP Common Server")
EHST_TARGET_ACTION = _config.ConfigItem("servlet/target-resolver?", "eHST Target Resolver")
EHST_MESSAGES = _config.ConfigItem("notification?action=GetNotifications", "eHST Messages")
TIMEOUT = 60
Expand Down
154 changes: 90 additions & 64 deletions astroquery/esa/hubble/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
European Space Agency (ESA)

"""


import os
from urllib.parse import urlencode

import astroquery.esa.utils.utils as esautils

Expand All @@ -18,20 +19,20 @@
from astropy.coordinates import Angle
from numpy.ma import MaskedArray

from astroquery.utils.tap import TapPlus
from astroquery.query import BaseQuery
import json
from astroquery.query import BaseQuery, BaseVOQuery
import warnings
import pyvo
from astropy.utils.exceptions import AstropyDeprecationWarning
from astropy.utils.decorators import deprecated

from . import conf
import time
from astroquery import log

__all__ = ['ESAHubble', 'ESAHubbleClass']


class ESAHubbleClass(BaseQuery):
class ESAHubbleClass(BaseVOQuery, BaseQuery):
"""
Class to init ESA Hubble Module and communicate with eHST TAP
"""
Expand All @@ -41,15 +42,33 @@
product_types = ["SCIENCE", "PREVIEW", "THUMBNAIL", "AUXILIARY"]
copying_string = "Copying file to {0}..."

def __init__(self, *, tap_handler=None, show_messages=True):
if tap_handler is None:
self._tap = TapPlus(url=conf.EHST_TAP_SERVER,
data_context='data', client_id="ASTROQUERY")
def __init__(self, *, show_messages=True, auth_session=None):
super().__init__()

self._vo = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call this self._tap to be consistent with the other modules

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

# Checks if auth session has been defined. If not, create a new session
if auth_session:
self._auth_session = auth_session

Check warning on line 51 in astroquery/esa/hubble/core.py

View check run for this annotation

Codecov / codecov/patch

astroquery/esa/hubble/core.py#L51

Added line #L51 was not covered by tests
else:
self._tap = tap_handler
self._auth_session = esautils.ESAAuthSession()
self._auth_session.add_security_method_for_url(url=conf.EHST_TAP_SERVER, security_method="anonymous")
self._auth_session.add_security_method_for_url(
url=conf.EHST_TABLES_SERVER,
security_method="anonymous",
exact=True
)

if show_messages:
self.get_status_messages()

@property
def vo(self) -> pyvo.dal.TAPService:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call this tap to be consistent with the other modules

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if self._vo is None:
self._vo = pyvo.dal.TAPService(
conf.EHST_TAP_SERVER, session=self._auth_session)

return self._vo

def download_product(self, observation_id, *, calibration_level=None,
filename=None, folder=None, verbose=False, product_type=None):
"""
Expand Down Expand Up @@ -95,7 +114,6 @@
AstropyDeprecationWarning)

params = {"OBSERVATIONID": observation_id,
"TAPCLIENT": "ASTROQUERY",
"RETRIEVAL_TYPE": "OBSERVATION"}

if filename is None:
Expand All @@ -112,8 +130,13 @@

filename = self._get_product_filename(product_type, filename)
output_file = self.__get_download_path(folder, filename)
self._tap.load_data(params_dict=params, output_file=output_file, verbose=verbose)

esautils.download_file(
url=conf.EHST_DATA_SERVER,
session=self.vo._session,
params=params,
verbose=verbose,
filename=output_file
)
return esautils.check_rename_to_gz(filename=output_file)

def __get_download_path(self, folder, filename):
Expand Down Expand Up @@ -417,12 +440,17 @@
None. The file is associated
"""

params = {"RETRIEVAL_TYPE": "PRODUCT", "ARTIFACTID": file, "TAPCLIENT": "ASTROQUERY"}
params = {"RETRIEVAL_TYPE": "PRODUCT", "ARTIFACTID": file}
if filename is None:
filename = file
output_file = self.__get_download_path(folder, filename)
self._tap.load_data(params_dict=params, output_file=output_file, verbose=verbose)

esautils.download_file(
url=conf.EHST_DATA_SERVER,
session=self.vo._session,
params=params,
verbose=verbose,
filename=output_file
)
return esautils.check_rename_to_gz(filename=output_file)

def get_postcard(self, observation_id, *, calibration_level="RAW",
Expand Down Expand Up @@ -458,8 +486,7 @@

params = {"RETRIEVAL_TYPE": "OBSERVATION",
"OBSERVATIONID": observation_id,
"PRODUCTTYPE": "PREVIEW",
"TAPCLIENT": "ASTROQUERY"}
"PRODUCTTYPE": "PREVIEW"}
if calibration_level:
params["CALIBRATIONLEVEL"] = calibration_level

Expand All @@ -469,8 +496,8 @@
if filename is None:
filename = observation_id

self._tap.load_data(params_dict=params, output_file=filename, verbose=verbose)

esautils.download_file(url=conf.EHST_DATA_SERVER, session=self.vo._session, params=params, verbose=verbose,
filename=filename)
return filename

def __get_product_type_by_resolution(self, resolution):
Expand Down Expand Up @@ -670,18 +697,17 @@
try:
params = {"TARGET_NAME": target,
"RESOLVER_TYPE": "ALL",
"FORMAT": "json",
"TAPCLIENT": "ASTROQUERY"}

subContext = conf.EHST_TARGET_ACTION
connHandler = self._tap._TapPlus__getconnhandler()
data = urlencode(params)
target_response = connHandler.execute_secure(subContext, data, verbose=True)
for line in target_response:
target_result = json.loads(line.decode("utf-8"))
if target_result['objects']:
ra = target_result['objects'][0]['raDegrees']
dec = target_result['objects'][0]['decDegrees']
"FORMAT": "json"}

target_response = esautils.execute_servlet_request(
tap=self.vo,
query_params=params,
url=conf.EHST_DOMAIN_SERVER + conf.EHST_TARGET_ACTION
)
if target_response:
if target_response['objects']:
ra = target_response['objects'][0]['raDegrees']
dec = target_response['objects'][0]['decDegrees']
return SkyCoord(ra=ra, dec=dec, unit="deg")
except (ValueError, KeyError):
raise ValueError("This target cannot be resolved")
Expand Down Expand Up @@ -747,18 +773,18 @@
A table object
"""
if async_job:
job = self._tap.launch_job_async(query=query,
output_file=output_file,
output_format=output_format,
verbose=verbose,
dump_to_file=output_file is not None)
job = self.vo.submit_job(query)
job.run()
while job.phase == 'EXECUTING':
time.sleep(3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to add a manual sleep in here. Also, why not just run it with run_async instead of doing the submission/run/fetch cycle? (genuine question, you may have good reasons to prefer this way)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed it to the method you proposed, and it works fine. Thank you!

result = job.fetch_result().to_table()

Check warning on line 780 in astroquery/esa/hubble/core.py

View check run for this annotation

Codecov / codecov/patch

astroquery/esa/hubble/core.py#L776-L780

Added lines #L776 - L780 were not covered by tests
else:
job = self._tap.launch_job(query=query, output_file=output_file,
output_format=output_format,
verbose=verbose,
dump_to_file=output_file is not None)
table = job.get_results()
return table
result = self.vo.search(query).to_table()

if output_file:
esautils.download_table(result, output_file, output_format)

return result

@deprecated(since="0.4.7", alternative="query_tap")
def query_hst_tap(self, query, *, async_job=False, output_file=None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated so can be done in a separate PR, but given this backend change, the deprecations could be also cleaned up (but we can also keep them in longer if you prefer that)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method was cleaned up!

Expand Down Expand Up @@ -923,34 +949,35 @@
-------
A list of tables
"""

tables = self._tap.load_tables(only_names=only_names,
include_shared_tables=False,
verbose=verbose)
if only_names is True:
table_names = []
for t in tables:
table_names.append(t.name)
return table_names
tables = self.vo.tables
if only_names:
return list(tables.keys())
else:
return tables
return list(tables.values())

Check warning on line 956 in astroquery/esa/hubble/core.py

View check run for this annotation

Codecov / codecov/patch

astroquery/esa/hubble/core.py#L956

Added line #L956 was not covered by tests

def get_status_messages(self):
"""Retrieve the messages to inform users about
the status of eHST TAP
"""

try:
subContext = conf.EHST_MESSAGES
connHandler = self._tap._TapPlus__getconnhandler()
response = connHandler.execute_tapget(subContext, verbose=False)
if response.status == 200:
for line in response:
string_message = line.decode("utf-8")
print(string_message[string_message.index('=') + 1:])
esautils.execute_servlet_request(
url=conf.EHST_TAP_SERVER + "/" + conf.EHST_MESSAGES,
tap=self.vo,
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 get_columns(self, table_name, *, only_names=True, verbose=False):
"""Get the available columns for a table in EHST TAP service

Expand All @@ -968,9 +995,7 @@
A list of columns
"""

tables = self._tap.load_tables(only_names=False,
include_shared_tables=False,
verbose=verbose)
tables = self.get_tables(only_names=False)
columns = None
for t in tables:
if str(t.name) == str(table_name):
Expand Down Expand Up @@ -1061,4 +1086,5 @@
return full_path


ESAHubble = ESAHubbleClass()
# Neet to be false in order to avoid errors in tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rephrase

Suggested change
# Neet to be false in order to avoid errors in tests
# Need to be False in order to avoid reaching out to the remote server at import time

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

ESAHubble = ESAHubbleClass(show_messages=False)
Loading
Loading