Skip to content

Commit abeabdc

Browse files
authored
Merge pull request #2836 from bsipocz/ENH_basevoquery
ENH: adding minimalist BaseVOQuery baseclass
2 parents 6eefe6d + 46d9ed5 commit abeabdc

File tree

7 files changed

+86
-16
lines changed

7 files changed

+86
-16
lines changed

CHANGES.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,9 @@ Infrastructure, Utility and Other Changes and Additions
301301
- New function, ``utils.cleanup_downloads.cleanup_saved_downloads``, is
302302
added to help the testcleanup narrative in narrative documentations. [#2384]
303303

304-
- Adding more system information to User-Agent. [#2762]
304+
- Adding new ``BaseVOQuery`` baseclass for modules using VO tools. [#2836]
305+
306+
- Adding more system and package information to User-Agent. [#2762, #2836]
305307

306308
- Removal of the non-functional ``nrao`` module as it was completely
307309
incompatible with the refactored upstream API. [#2546]

astroquery/alma/core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from ..exceptions import LoginError
3131
from ..utils import commons
3232
from ..utils.process_asyncs import async_to_sync
33-
from ..query import BaseQuery, QueryWithLogin
33+
from ..query import BaseQuery, QueryWithLogin, BaseVOQuery
3434
from .tapsql import (_gen_pos_sql, _gen_str_sql, _gen_numeric_sql,
3535
_gen_band_list_sql, _gen_datetime_sql, _gen_pol_sql, _gen_pub_sql,
3636
_gen_science_sql, _gen_spec_res_sql, ALMA_DATE_FORMAT)
@@ -212,7 +212,7 @@ def _gen_sql(payload):
212212
return sql + where
213213

214214

215-
class AlmaAuth(BaseQuery):
215+
class AlmaAuth(BaseVOQuery, BaseQuery):
216216
"""Authentication session information for passing credentials to an OIDC instance
217217
218218
Assumes an OIDC system like Keycloak with a preconfigured client app called "oidc" to validate against.
@@ -366,7 +366,7 @@ def sia_url(self):
366366
@property
367367
def tap(self):
368368
if not self._tap:
369-
self._tap = pyvo.dal.tap.TAPService(baseurl=self.tap_url)
369+
self._tap = pyvo.dal.tap.TAPService(baseurl=self.tap_url, session=self._session)
370370
return self._tap
371371

372372
@property

astroquery/cadc/core.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from ..utils.class_or_instance import class_or_instance
1919
from ..utils import async_to_sync, commons
20-
from ..query import BaseQuery
20+
from ..query import BaseQuery, BaseVOQuery
2121
from bs4 import BeautifulSoup
2222
from astropy import units as u
2323
from astropy.coordinates import Angle
@@ -37,7 +37,7 @@
3737

3838

3939
@async_to_sync
40-
class CadcClass(BaseQuery):
40+
class CadcClass(BaseVOQuery, BaseQuery):
4141
"""
4242
Class for accessing CADC data. Typical usage:
4343

astroquery/ipac/irsa/core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from astropy.utils.decorators import deprecated_renamed_argument
1414
from pyvo.dal import TAPService
1515
from astroquery import log
16-
from astroquery.query import BaseQuery
16+
from astroquery.query import BaseVOQuery
1717
from astroquery.utils.commons import parse_coordinates
1818
from astroquery.ipac.irsa import conf
1919
from astroquery.exceptions import InvalidQueryError
@@ -22,7 +22,7 @@
2222
__all__ = ['Irsa', 'IrsaClass']
2323

2424

25-
class IrsaClass(BaseQuery):
25+
class IrsaClass(BaseVOQuery):
2626

2727
def __init__(self):
2828
super().__init__()
@@ -32,7 +32,7 @@ def __init__(self):
3232
@property
3333
def tap(self):
3434
if not self._tap:
35-
self._tap = TAPService(baseurl=self.tap_url)
35+
self._tap = TAPService(baseurl=self.tap_url, session=self._session)
3636
return self._tap
3737

3838
def query_tap(self, query, *, maxrec=None):

astroquery/ipac/nexsci/nasa_exoplanet_archive/core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
# Import astroquery utilities
2323
from astroquery.exceptions import InputWarning, InvalidQueryError, NoResultsWarning, RemoteServiceError
24-
from astroquery.query import BaseQuery
24+
from astroquery.query import BaseQuery, BaseVOQuery
2525
from astroquery.utils import async_to_sync, commons
2626
from astroquery.utils.class_or_instance import class_or_instance
2727
from astroquery.ipac.nexsci.nasa_exoplanet_archive import conf
@@ -129,7 +129,7 @@ class InvalidTableError(InvalidQueryError):
129129
# Class decorator, async_to_sync, modifies NasaExoplanetArchiveClass to convert
130130
# all query_x_async methods to query_x methods
131131
@async_to_sync
132-
class NasaExoplanetArchiveClass(BaseQuery):
132+
class NasaExoplanetArchiveClass(BaseVOQuery, BaseQuery):
133133
"""
134134
The interface for querying the NASA Exoplanet Archive TAP and API services
135135
@@ -230,7 +230,7 @@ def query_criteria_async(self, table, get_query_payload=False, cache=None, **cri
230230
cache = self.CACHE
231231

232232
if table in self.TAP_TABLES:
233-
tap = pyvo.dal.tap.TAPService(baseurl=self.URL_TAP)
233+
tap = pyvo.dal.tap.TAPService(baseurl=self.URL_TAP, session=self._session)
234234
# construct query from table and request_payload (including format)
235235
tap_query = self._request_to_sql(request_payload)
236236

astroquery/query.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
import astropy.utils.data
2222
from astropy.utils import deprecated
2323

24+
import pyvo
25+
2426
from astroquery import version, log, cache_conf
2527
from astroquery.utils import system_tools
2628

2729

28-
__all__ = ['BaseQuery', 'QueryWithLogin']
30+
__all__ = ['BaseVOQuery', 'BaseQuery', 'QueryWithLogin']
2931

3032

3133
def to_cache(response, cache_file):
@@ -175,18 +177,45 @@ def login(*args, **kwargs):
175177
return newcls
176178

177179

180+
class BaseVOQuery:
181+
"""
182+
Bare minimum base query that sets the Session header to include both astroquery and pyvo.
183+
Use in modules that rely on PyVO, either on its own or in combination with ``BaseQuery`` (be mindful
184+
about resolution order of base classes!).
185+
"""
186+
def __init__(self):
187+
super().__init__()
188+
if not hasattr(self, '_session'):
189+
# We don't want to override another, e.g. already authenticated session from another baseclass
190+
self._session = requests.Session()
191+
192+
user_agents = self._session.headers['User-Agent'].split()
193+
if 'astroquery' in user_agents[0]:
194+
if 'pyVO' not in user_agents[1]:
195+
user_agents[0] = f"astroquery/{version.version} pyVO/{pyvo.__version__}"
196+
elif 'pyVO' in user_agents[0]:
197+
user_agents[0] = f"astroquery/{version.version} pyVO/{pyvo.__version__}"
198+
else:
199+
user_agents = [f"astroquery/{version.version} pyVO/{pyvo.__version__} "
200+
f"Python/{platform.python_version()} ({platform.system()})"] + user_agents
201+
202+
self._session.headers['User-Agent'] = " ".join(user_agents)
203+
204+
self.name = self.__class__.__name__.split("Class")[0]
205+
206+
178207
class BaseQuery(metaclass=LoginABCMeta):
179208
"""
180209
This is the base class for all the query classes in astroquery. It
181210
is implemented as an abstract class and must not be directly instantiated.
182211
"""
183212

184213
def __init__(self):
185-
S = self._session = requests.Session()
214+
self._session = requests.Session()
186215
self._session.hooks['response'].append(self._response_hook)
187-
S.headers['User-Agent'] = (
216+
self._session.headers['User-Agent'] = (
188217
f"astroquery/{version.version} Python/{platform.python_version()} ({platform.system()}) "
189-
f"{S.headers['User-Agent']}")
218+
f"{self._session.headers['User-Agent']}")
190219

191220
self.name = self.__class__.__name__.split("Class")[0]
192221
self._cache_location = None

astroquery/tests/test_query.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2+
from astroquery.query import BaseQuery, BaseVOQuery
3+
4+
5+
class with_VO(BaseVOQuery, BaseQuery):
6+
pass
7+
8+
9+
class without_VO(BaseQuery):
10+
pass
11+
12+
13+
class only_VO(BaseVOQuery):
14+
pass
15+
16+
17+
def test_session_VO_header():
18+
test_instance = with_VO()
19+
user_agent = test_instance._session.headers['User-Agent']
20+
assert 'astroquery' in user_agent
21+
assert 'pyVO' in user_agent
22+
assert user_agent.count('astroquery') == 1
23+
24+
25+
def test_session_nonVO_header():
26+
test_instance = without_VO()
27+
user_agent = test_instance._session.headers['User-Agent']
28+
assert 'astroquery' in user_agent
29+
assert 'pyVO' not in user_agent
30+
assert user_agent.count('astroquery') == 1
31+
32+
33+
def test_session_hooks():
34+
# Test that we don't override the session in the BaseVOQuery
35+
test_instance = with_VO()
36+
assert len(test_instance._session.hooks['response']) > 0
37+
38+
test_VO_instance = only_VO()
39+
assert len(test_VO_instance._session.hooks['response']) == 0

0 commit comments

Comments
 (0)