1
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2 1
"""
3
Module to search the SAO/NASA Astrophysics Data System
4

5
:author: Magnus Persson <magnusp@vilhelm.nu>
6

7
"""
8 1
import os
9

10 1
from astropy.table import Table
11 1
from six.moves.urllib.parse import quote as urlencode
12

13 1
from ..query import BaseQuery
14 1
from ..utils import async_to_sync
15 1
from ..utils.class_or_instance import class_or_instance
16

17 1
from .utils import _get_data_from_xml
18 1
from . import conf
19

20

21 1
from xml.dom import minidom
22

23 1
__all__ = ['ADS', 'ADSClass']
24

25

26 1
@async_to_sync
27 1
class ADSClass(BaseQuery):
28

29 1
    SERVER = conf.server
30 1
    QUERY_SIMPLE_PATH = conf.simple_path
31 1
    TIMEOUT = conf.timeout
32 1
    ADS_FIELDS = conf.adsfields
33 1
    SORT = conf.sort
34 1
    NROWS = conf.nrows
35 1
    NSTART = conf.nstart
36 1
    TOKEN = conf.token
37

38 1
    QUERY_SIMPLE_URL = SERVER + QUERY_SIMPLE_PATH
39

40 1
    def __init__(self, *args):
41
        """ set some parameters """
42 1
        super(ADSClass, self).__init__()
43

44 1
    @class_or_instance
45 1
    def query_simple(self, query_string, get_query_payload=False,
46
                     get_raw_response=False, cache=True):
47
        """
48
        Basic query.  Uses a string and the ADS generic query.
49
        """
50 1
        request_string = self._args_to_url(query_string)
51 1
        request_fields = self._fields_to_url()
52 1
        request_sort = self._sort_to_url()
53 1
        request_rows = self._rows_to_url(self.NROWS, self.NSTART)
54 1
        request_url = self.QUERY_SIMPLE_URL + request_string + request_fields + request_sort + request_rows
55

56
        # primarily for debug purposes, but also useful if you want to send
57
        # someone a URL linking directly to the data
58 1
        if get_query_payload:
59 1
            return request_url
60

61 1
        response = self._request(method='GET', url=request_url,
62
                                 headers={'Authorization': 'Bearer ' + self._get_token()},
63
                                 timeout=self.TIMEOUT, cache=cache)
64

65 1
        response.raise_for_status()
66

67 1
        if get_raw_response:
68 0
            return response
69
        # parse the XML response into AstroPy Table
70 1
        resulttable = self._parse_response(response.json())
71

72 1
        return resulttable
73

74 1
    def _parse_response(self, response):
75

76 1
        try:
77 1
            response['response']['docs'][0]['bibcode']
78 0
        except IndexError:
79 0
            raise RuntimeError('No results returned!')
80

81
        # get the list of hits
82 1
        hitlist = response['response']['docs']
83

84 1
        t = Table()
85
        # Grab the various fields and put into AstroPy table
86 1
        for field in self.ADS_FIELDS:
87 1
            tmp = _get_data_from_xml(hitlist, field)
88 1
            t[field] = tmp
89

90 1
        return t
91

92 1
    def _args_to_url(self, query_string):
93
        # convert arguments to a valid requests payload
94
        # i.e. a dictionary
95 1
        request_string = 'q=' + urlencode(query_string)
96 1
        return request_string
97

98 1
    def _fields_to_url(self):
99 1
        request_fields = '&fl=' + ','.join(self.ADS_FIELDS)
100 1
        return request_fields
101

102 1
    def _sort_to_url(self):
103 1
        request_sort = '&sort=' + urlencode(self.SORT)
104 1
        return request_sort
105

106 1
    def _rows_to_url(self, nrows=10, nstart=0):
107 1
        request_rows = '&rows=' + str(nrows) + '&start=' + str(nstart)
108 1
        return request_rows
109

110 1
    def _get_token(self):
111
        """
112
        Try to get token from the places Andy Casey's python ADS client expects it, otherwise return an error
113
        """
114 1
        if self.TOKEN is not None:
115 1
            return self.TOKEN
116

117 0
        self.TOKEN = os.environ.get('ADS_DEV_KEY', None)
118 0
        if self.TOKEN is not None:
119 0
            return self.TOKEN
120

121 0
        token_file = os.path.expanduser(os.path.join('~', '.ads', 'dev_key'))
122 0
        try:
123 0
            with open(token_file) as f:
124 0
                self.TOKEN = f.read().strip()
125 0
            return self.TOKEN
126 0
        except IOError:
127 0
            raise RuntimeError('No API token found! Get yours from: '
128
                               'https://ui.adsabs.harvard.edu/#user/settings/token '
129
                               'and store it in the API_DEV_KEY environment variable.')
130

131

132 1
ADS = ADSClass()

Read our documentation on viewing source code .

Loading