1
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2 1
"""
3
=============
4
TAP plus
5
=============
6

7
@author: Juan Carlos Segovia
8
@contact: juan.carlos.segovia@sciops.esa.int
9

10
European Space Astronomy Centre (ESAC)
11
European Space Agency (ESA)
12

13
Created on 30 jun. 2016
14

15

16
"""
17

18 1
import re
19

20 1
TAP_UTILS_QUERY_TOP_PATTERN = re.compile(
21
    r"\s*SELECT\s+(ALL\s+|DISTINCT\s+)?TOP\s+\d+\s+", re.IGNORECASE)
22 1
TAP_UTILS_QUERY_ALL_DISTINCT_PATTERN = re.compile(
23
    r"\s*SELECT\s+(ALL\s+|DISTINCT\s+)", re.IGNORECASE)
24

25 1
TAP_UTILS_HTTP_ERROR_MSG_START = "<li><b>Message: </b>"
26 1
TAP_UTILS_HTTP_VOTABLE_ERROR = '<INFO name="QUERY_STATUS" value="ERROR">'
27 1
TAP_UTILS_VOTABLE_INFO = '</INFO>'
28

29

30 1
def taputil_find_header(headers, key):
31
    """Searches for the specified keyword
32

33
    Parameters
34
    ----------
35
    headers : HTTP(s) headers object, mandatory
36
        HTTP(s) response headers
37
    key : str, mandatory
38
        header key to be searched for
39

40
    Returns
41
    -------
42
    The requested header value or None if the header is not found
43
    """
44 1
    for entry in headers:
45 1
        if key.lower() == entry[0].lower():
46 1
            return entry[1]
47 0
    return None
48

49

50 1
def taputil_create_sorted_dict_key(dictionaryObject):
51
    """Searches for the specified keyword
52

53
    Parameters
54
    ----------
55
    dictionaryObject : dictionary object, mandatory
56
        Dictionary
57

58
    Returns
59
    -------
60
    A keyword based on a sorted dictionary key+value items
61
    """
62 1
    if dictionaryObject is None:
63 0
        return None
64 1
    listTmp = []
65 1
    for k in sorted(dictionaryObject):
66 1
        listTmp.append(str(k) + '=' + str(dictionaryObject[k]))
67 1
    return '&'.join(listTmp)
68

69

70 1
def set_top_in_query(query, top):
71
    """Adds TOP statement if the query does not have one.
72

73
    Parameters
74
    ----------
75
    query : ADQL query, mandatory
76
        ADQL query
77
    top : str, optional
78
        ADQL TOP value
79

80
    Returns
81
    -------
82
    The query with the provided TOP statement, if the query does not have one.
83
    """
84 1
    if query is None:
85 0
        return query
86 1
    if top is None:
87 0
        return query
88 1
    q = query.upper()
89 1
    if TAP_UTILS_QUERY_TOP_PATTERN.search(q):
90
        # top is present
91 1
        return query
92
    else:
93
        # top is not present
94
        # check all|distinct
95 0
        m = TAP_UTILS_QUERY_ALL_DISTINCT_PATTERN.search(q)
96 0
        if m:
97
            # all | distinct is present: add top after all|distinct
98 0
            endPos = m.end()
99 0
            nq = query[0:endPos] + " TOP " + str(top) + " " + query[endPos:]
100
        else:
101
            # no all nor distinct: add top after select
102 0
            p = q.replace("\n", " ").find("SELECT ")
103 0
            nq = query[0:p+7] + " TOP " + str(top) + " " + query[p+7:]
104 0
        return nq
105

106

107 1
def get_http_response_error(response):
108
    """Extracts an HTTP error message from an HTML response.
109

110
    Parameters
111
    ----------
112
    response : HTTP response, mandatory
113
        HTTP response
114

115
    Returns
116
    -------
117
    A string with the response error message.
118
    """
119 1
    responseBytes = response.read()
120 1
    responseStr = responseBytes.decode('utf-8')
121 1
    return parse_http_response_error(responseStr, response.status)
122

123

124 1
def parse_http_response_error(responseStr, status):
125
    """Extracts an HTTP error message from an HTML response.
126

127
    Parameters
128
    ----------
129
    responseStr : HTTP response, mandatory
130
        HTTP response
131

132
    Returns
133
    -------
134
    A string with the response error message.
135
    """
136 1
    pos1 = responseStr.find(TAP_UTILS_HTTP_ERROR_MSG_START)
137 1
    if pos1 == -1:
138 1
        return parse_http_votable_response_error(responseStr, status)
139 0
    pos2 = responseStr.find('</li>', pos1)
140 0
    if pos2 == -1:
141 0
        return parse_http_votable_response_error(responseStr, status)
142 0
    msg = responseStr[(pos1+len(TAP_UTILS_HTTP_ERROR_MSG_START)):pos2]
143 0
    return str("Error " + str(status) + ":\n" + msg)
144

145

146 1
def parse_http_votable_response_error(responseStr, status):
147
    """Extracts an HTTP error message from an VO response.
148

149
    Parameters
150
    ----------
151
    responseStr : HTTP VO response, mandatory
152
        HTTP VO response
153

154
    Returns
155
    -------
156
    A string with the response error message.
157
    """
158 1
    pos1 = responseStr.find(TAP_UTILS_HTTP_VOTABLE_ERROR)
159 1
    if pos1 == -1:
160 1
        return str("Error " + str(status) + ":\n" + responseStr)
161 0
    pos2 = responseStr.find(TAP_UTILS_VOTABLE_INFO, pos1)
162 0
    if pos2 == -1:
163 0
        return str("Error " + str(status) + ":\n" + responseStr)
164 0
    msg = responseStr[(pos1+len(TAP_UTILS_HTTP_VOTABLE_ERROR)):pos2]
165 0
    return str("Error " + str(status) + ": " + msg)
166

167

168 1
def get_jobid_from_location(location):
169
    """Extracts an HTTP error message from an VO response.
170

171
    Parameters
172
    ----------
173
    location : HTTP VO 303 response location header, mandatory
174
        HTTP VO redirection location
175

176
    Returns
177
    -------
178
    A jobid.
179
    """
180 1
    pos = location.rfind('/')+1
181 1
    jobid = location[pos:]
182 1
    return jobid
183

184

185 1
def get_schema_name(full_qualified_table_name):
186
    """Extracts the schema name from a full qualified table name.
187

188
    Parameters
189
    ----------
190
    full_qualified_table_name : str, mandatory
191
        A full qualified table name (i.e. schema name and table name)
192

193
    Returns
194
    -------
195
    The schema name or None.
196
    """
197 1
    pos = full_qualified_table_name.rfind('.')
198 1
    if pos == -1:
199 1
        return None
200 1
    name = full_qualified_table_name[0:pos]
201 1
    return name
202

203

204 1
def get_table_name(full_qualified_table_name):
205
    """Extracts the table name form a full qualified table name.
206

207
    Parameters
208
    ----------
209
    full_qualified_table_name : str, mandatory
210
        A full qualified table name (i.e. schema name and table name)
211

212
    Returns
213
    -------
214
    The table name or None.
215
    """
216 1
    pos = full_qualified_table_name.rfind('.')
217 1
    if pos == -1:
218 0
        return full_qualified_table_name
219 1
    name = full_qualified_table_name[pos+1:]
220 1
    return name

Read our documentation on viewing source code .

Loading