File indexing completed on 2024-11-27 03:17:45
0001 import urllib, re, json, socket
0002
0003 """
0004 Python object that enables connection to RR v3 API.
0005 Errors (not bugs!) and more welcome fixes/suggestions please
0006 post to https://savannah.cern.ch/projects/cmsrunregistry/
0007 """
0008
0009 class RRApiError(Exception):
0010 """
0011 API Exception class
0012 """
0013
0014 def __init__(self, resp):
0015 """
0016 Construct exception by providing response object.
0017 """
0018 if isinstance(resp, str):
0019 self.message = resp
0020 else:
0021 self.url = resp.geturl()
0022 self.code = resp.getcode()
0023 self.stack = None
0024 for line in resp.read().split("\n"):
0025 if self.stack == None:
0026 m = re.search("<pre>(.*)", line)
0027 if m != None:
0028 self.stack = m.group(1)
0029 m = re.search("^.+\\.([^\\.]+: .*)$", self.stack)
0030 if m != None:
0031 self.message = m.group(1)
0032 else:
0033 self.message = line
0034 else:
0035 m = re.search("(.*)</pre>", line)
0036 if m != None:
0037 self.stack = self.stack + "\n" + m.group(1)
0038 break
0039 else:
0040 self.stack = self.stack + "\n" + line
0041
0042 def __str__(self):
0043 """ Get message """
0044 return self.message
0045
0046 class RRApi:
0047 """
0048 RR API object
0049 """
0050
0051 def __init__(self, url, debug = False):
0052 """
0053 Construct API object.
0054 url: URL to RRv3 API, i.e. http://localhost:8080/rr_user
0055 debug: should debug messages be printed out? Verbose!
0056 """
0057 self.debug = debug
0058 self.url = re.sub("/*$", "/api/", url)
0059 self.app = self.get(["app"])
0060 self.dprint("app = ", self.app)
0061
0062 def dprint(self, *args):
0063 """
0064 Print debug information
0065 """
0066 if self.debug:
0067 print("RRAPI:", end=' ')
0068 for arg in args:
0069 print(arg, end=' ')
0070 print()
0071
0072 def get(self, parts, data = None):
0073 """
0074 General API call (do not use it directly!)
0075 """
0076
0077
0078
0079
0080
0081 callurl = self.url + "/".join(urllib.quote(p) for p in parts)
0082
0083
0084
0085
0086
0087 sdata = None
0088 if data != None:
0089 sdata = json.dumps(data)
0090
0091
0092
0093
0094
0095 self.dprint(callurl, "with payload", sdata)
0096
0097 resp = urllib.urlopen(callurl, sdata)
0098
0099 has_getcode = "getcode" in dir(resp)
0100 if self.debug:
0101 if has_getcode:
0102 self.dprint("Response", resp.getcode(), " ".join(str(resp.info()).split("\r\n")))
0103 else:
0104 self.dprint("Response", " ".join(str(resp.info()).split("\r\n")))
0105
0106 if not has_getcode or resp.getcode() == 200:
0107 rdata = resp.read()
0108 if re.search("json", resp.info().gettype()):
0109 try:
0110 return json.loads(rdata)
0111 except TypeError as e:
0112 self.dprint(e)
0113 return rdata
0114 else:
0115 return rdata
0116 else:
0117 raise RRApiError(resp)
0118
0119 def tags(self):
0120 """
0121 Get version tags (USER app only)
0122 """
0123 if self.app != "user":
0124 raise RRApiError("Tags call is possible only in user app")
0125 return self.get(["tags"])
0126
0127 def workspaces(self):
0128 """
0129 Get workspaces (all apps)
0130 """
0131 return self.get(["workspaces"])
0132
0133 def tables(self, workspace):
0134 """
0135 Get tables for workspace (all apps)
0136 """
0137 return self.get([workspace, "tables"])
0138
0139 def columns(self, workspace, table):
0140 """
0141 Get columns for table for workspace (all apps)
0142 """
0143 return self.get([workspace, table, "columns"])
0144
0145 def templates(self, workspace, table):
0146 """
0147 Get output templates for table for workspace (all apps)
0148 """
0149 return self.get([workspace, table, "templates"])
0150
0151 def count(self, workspace, table, filter = None, query = None, tag = None):
0152 """
0153 Get number of rows for table for workspace with filter, query (all apps) or tag (USER app only)
0154 """
0155
0156
0157
0158
0159
0160 req = [ workspace, table ]
0161 if tag != None:
0162 if self.app != "user":
0163 raise RRApiError("Tags are possible only in user app")
0164 else:
0165 req.append(tag)
0166 req.append("count")
0167
0168
0169
0170
0171
0172 filters = {}
0173 if filter != None:
0174 filters['filter'] = filter
0175 if query != None:
0176 filters['query'] = query
0177
0178 return int(self.get(req, filters))
0179
0180 def data(self, workspace, table, template, columns = None, filter = None, query = None, order = None, tag = None):
0181 """
0182 Get data for table for workspace with filter, query (all apps) or tag (USER app only)
0183 """
0184
0185
0186
0187
0188
0189 if not isinstance(workspace, str):
0190 raise RRApiError("workspace parameter must be str")
0191
0192
0193
0194
0195
0196 req = [ workspace, table, template ]
0197 if columns != None:
0198 req.append(",".join(columns))
0199 else:
0200 req.append("all")
0201 if order != None:
0202 req.append(",".join(order))
0203 else:
0204 req.append("none")
0205 if tag != None:
0206 if self.app != "user":
0207 raise RRApiError("Tags are possible only in user app")
0208 else:
0209 req.append(tag)
0210 req.append("data")
0211
0212
0213
0214
0215
0216 filters = {}
0217 if filter != None:
0218 filters['filter'] = filter
0219 if query != None:
0220 filters['query'] = query
0221
0222 return self.get(req, filters)
0223
0224 def reports(self, workspace):
0225 """
0226 Get available reports (USER app only)
0227 """
0228 if self.app != "user":
0229 raise RRApiError("Reports available only in user app")
0230 return self.get([workspace, "reports"])
0231
0232 def report(self, workspace, report):
0233 """
0234 Get report data (USER app only)
0235 """
0236 if self.app != "user":
0237 raise RRApiError("Reports available only in user app")
0238 return self.get([workspace, report, "data"])
0239
0240
0241 if __name__ == '__main__':
0242
0243 print("RR API library.")