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