Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/client/wadl.py: 98%
229 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-06 15:01 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-06 15:01 +0000
1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6'''
7WADL data model.
8'''
10import re
12from pyrocko import guts
13from pyrocko.guts import make_typed_list_class, String, StringChoice, List, \
14 Int, Object, StringUnion, Bool, Defer
16from pyrocko.io.io_common import FileLoadError
18ResourceTypeList = make_typed_list_class(String)
21guts_prefix = 'wadl'
22guts_xmlns = 'http://wadl.dev.java.net/2009/02'
24re_rmsite = re.compile(r'https?://[^/]+')
25re_multisl = re.compile(r'/+')
28def clean_path(p):
29 p = re_rmsite.sub('', p)
30 p = re_multisl.sub('/', p)
31 if not p.startswith('/'):
32 p = '/' + p
34 return p
37class HTTPMethods(StringChoice):
38 choices = [
39 'GET',
40 'POST',
41 'PUT',
42 'HEAD',
43 'DELETE']
46UriList = make_typed_list_class(String)
48StatusCodeList = make_typed_list_class(Int)
51class ParamStyle(StringChoice):
52 choices = [
53 'plain',
54 'query',
55 'matrix',
56 'header',
57 'template']
60class Doc(Object):
61 xmltagname = 'doc'
62 title = String.T(optional=True, xmlstyle='attribute')
65class Method2(StringUnion):
66 members = [HTTPMethods, String]
69class Include(Object):
70 xmltagname = 'include'
71 href = String.T(optional=True, xmlstyle='attribute')
72 doc_list = List.T(Doc.T())
75class Option(Object):
76 xmltagname = 'option'
77 value = String.T(xmlstyle='attribute')
78 media_type = String.T(optional=True, xmlstyle='attribute')
79 doc_list = List.T(Doc.T())
82class Link(Object):
83 xmltagname = 'link'
84 resource_type = String.T(
85 optional=True, xmlstyle='attribute', xmltagname='resource_type')
86 rel = String.T(optional=True, xmlstyle='attribute')
87 rev = String.T(optional=True, xmlstyle='attribute')
88 doc_list = List.T(Doc.T())
91class Grammars(Object):
92 xmltagname = 'grammars'
93 doc_list = List.T(Doc.T())
94 include_list = List.T(Include.T())
97class DerefError(Exception):
98 pass
101class Element(Object):
103 def __init__(self, *args, **kwargs):
104 Object.__init__(self, *args, **kwargs)
105 self._hyper = None
107 def _update(self, hyper):
108 self._hyper = hyper
110 id_ = getattr(self, 'id', None)
112 if id_:
113 hyper[self.xmltagname][id_] = self
115 for child in self.get_children():
116 child._update(hyper)
118 def get_children(self):
119 raise NotImplementedError()
121 def deref(self):
122 if not self._hyper:
123 raise Exception('Must call _update() before calling deref()')
125 obj = self
126 seen = set()
127 while True:
128 seen.add(obj)
129 href = getattr(obj, 'href', None)
130 if href:
131 try:
132 obj = obj._hyper[obj.xmltagname][href.lstrip('#')]
133 if obj in seen:
134 raise DerefError('cyclic reference')
136 except KeyError:
137 raise DerefError(href)
139 else:
140 return obj
143class Param(Element):
144 xmltagname = 'param'
145 href = String.T(optional=True, xmlstyle='attribute')
146 name = String.T(optional=True, xmlstyle='attribute')
147 style = ParamStyle.T(optional=True, xmlstyle='attribute')
148 id = String.T(optional=True, xmlstyle='attribute')
149 type = String.T(default='xs:string', optional=True, xmlstyle='attribute')
150 default = String.T(optional=True, xmlstyle='attribute')
151 required = Bool.T(default='false', optional=True, xmlstyle='attribute')
152 repeating = Bool.T(default='false', optional=True, xmlstyle='attribute')
153 fixed = String.T(optional=True, xmlstyle='attribute')
154 path = String.T(optional=True, xmlstyle='attribute')
155 doc_list = List.T(Doc.T())
156 option_list = List.T(Option.T())
157 link = Link.T(optional=True)
159 def describe(self, indent):
160 return indent + self.name
162 def get_children(self):
163 return []
166class Representation(Element):
167 xmltagname = 'representation'
168 id = String.T(optional=True, xmlstyle='attribute')
169 element = String.T(optional=True, xmlstyle='attribute')
170 media_type = String.T(optional=True, xmlstyle='attribute')
171 href = String.T(optional=True, xmlstyle='attribute')
172 profile = UriList.T(optional=True, xmlstyle='attribute')
173 doc_list = List.T(Doc.T())
174 param_list = List.T(Param.T())
176 def get_children(self):
177 return self.param_list
180class Request(Element):
181 xmltagname = 'request'
182 doc_list = List.T(Doc.T())
183 param_list = List.T(Param.T())
184 representation_list = List.T(Representation.T())
186 def iter_params(self):
187 for param in self.param_list:
188 param = param.deref()
189 yield param
191 def describe(self, indent):
192 lines = []
193 for param in self.iter_params():
194 lines.append(param.describe(indent))
196 return lines
198 def get_children(self):
199 return self.param_list + self.representation_list
202class Response(Element):
203 xmltagname = 'response'
204 status = StatusCodeList.T(optional=True, xmlstyle='attribute')
205 doc_list = List.T(Doc.T())
206 param_list = List.T(Param.T())
207 representation_list = List.T(Representation.T())
209 def get_children(self):
210 return self.param_list + self.representation_list
213class Method(Element):
214 xmltagname = 'method'
215 id = String.T(optional=True, xmlstyle='attribute')
216 name = String.T(optional=True, xmlstyle='attribute')
217 href = String.T(optional=True, xmlstyle='attribute')
218 doc_list = List.T(Doc.T())
219 request = Request.T(optional=True)
220 response_list = List.T(Response.T())
222 def describe(self, indent):
223 lines = [indent + self.name]
224 if self.request:
225 lines.extend(self.request.describe(' ' + indent))
227 return lines
229 def get_children(self):
230 return ([self.request] if self.request else []) + self.response_list
233class Resource(Element):
234 xmltagname = 'resource'
235 id = String.T(optional=True, xmlstyle='attribute')
236 type = String.T(optional=True, xmlstyle='attribute')
237 query_type = String.T(
238 default='application/x-www-form-urlencoded',
239 optional=True,
240 xmlstyle='attribute')
241 path = String.T(optional=True, xmlstyle='attribute')
242 doc_list = List.T(Doc.T())
243 param_list = List.T(Param.T())
244 method_list = List.T(Method.T())
245 resource_list = List.T(Defer('Resource.T'))
247 def iter_resources(self):
248 yield self.path, self
249 for res in self.resource_list:
250 yield self.path + '/' + res.path, res
252 def iter_methods(self):
253 for method in self.method_list:
254 method = method.deref()
255 yield method
257 def describe(self, indent):
258 lines = []
259 for met in self.iter_methods():
260 lines.extend(met.describe(' ' + indent))
262 return lines
264 def get_children(self):
265 return self.param_list + self.method_list + self.resource_list
268class Resources(Element):
269 xmltagname = 'resources'
270 base = String.T(optional=True, xmlstyle='attribute')
271 doc_list = List.T(Doc.T())
272 resource_list = List.T(Resource.T())
274 def iter_resources(self):
275 for res in self.resource_list:
276 for p, sr in res.iter_resources():
277 yield self.base + '/' + p, sr
279 def get_children(self):
280 return self.resource_list
283class ResourceType(Element):
284 xmltagname = 'resource_type'
285 id = String.T(optional=True, xmlstyle='attribute')
286 doc_list = List.T(Doc.T())
287 param_list = List.T(Param.T())
288 method_list = List.T(Method.T())
289 resource_list = List.T(Resource.T())
291 def get_children(self):
292 return self.param_list + self.method_list + self.resource_list
295class Application(Element):
296 xmltagname = 'application'
297 guessable_xmlns = [guts_xmlns]
299 doc_list = List.T(Doc.T())
300 grammars = Grammars.T(optional=True)
301 resources_list = List.T(Resources.T())
302 resource_type_list = List.T(ResourceType.T(xmltagname='resource_type'))
303 method_list = List.T(Method.T())
304 representation_list = List.T(Representation.T())
305 param_list = List.T(Param.T())
307 def get_children(self):
308 return self.resources_list + self.resource_type_list \
309 + self.method_list + self.representation_list \
310 + self.param_list
312 def update(self, force=False):
313 if self._hyper is None or force:
314 hyper = dict(
315 resource_type={},
316 resource={},
317 method={},
318 representation={},
319 param={})
321 self._update(hyper)
323 def iter_resources(self):
324 self.update()
325 for rs in self.resources_list:
326 for p, res in rs.iter_resources():
327 yield clean_path(p), res
329 def iter_requests(self):
330 for res_path, res in self.iter_resources():
331 for method in res.iter_methods():
332 if method.request:
333 yield res_path, method.name, method.request
335 def supported_param_names(self, path, method='GET'):
336 path = clean_path(path)
337 for res_path, method_name, request in self.iter_requests():
338 if res_path == path and method_name == method:
339 return [param.name for param in request.param_list]
341 def describe(self, indent=''):
342 lines = []
343 for res_path, res in self.iter_resources():
344 lines.append(indent + res_path)
345 lines.extend(res.describe(indent))
347 return lines
349 def __str__(self):
350 return '\n'.join(self.describe())
353def load_xml(*args, **kwargs):
354 wadl = guts.load_xml(*args, **kwargs)
355 if not isinstance(wadl, Application):
356 FileLoadError('Not a WADL file.')
358 return wadl
361if __name__ == '__main__':
362 import os
363 import sys
364 import urllib.request
366 if os.path.exists(sys.argv[1]):
367 wadl = load_xml(filename=sys.argv[1])
368 else:
369 f = urllib.request.urlopen(sys.argv[1])
370 wadl = load_xml(stream=f)
372 print(wadl)