"Fossies" - the Fresh Open Source Software Archive 
Member "buildbot-2.5.1/buildbot/data/types.py" (24 Nov 2019, 11071 Bytes) of package /linux/misc/buildbot-2.5.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "types.py" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.5.0_vs_2.5.1.
1 # This file is part of Buildbot. Buildbot is free software: you can
2 # redistribute it and/or modify it under the terms of the GNU General Public
3 # License as published by the Free Software Foundation, version 2.
4 #
5 # This program is distributed in the hope that it will be useful, but WITHOUT
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
8 # details.
9 #
10 # You should have received a copy of the GNU General Public License along with
11 # this program; if not, write to the Free Software Foundation, Inc., 51
12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13 #
14 # Copyright Buildbot Team Members
15
16 # See "Type Validation" in master/docs/developer/tests.rst
17 import datetime
18 import json
19 import re
20
21 from buildbot import util
22 from buildbot.util import bytes2unicode
23
24
25 class Type:
26
27 name = None
28 doc = None
29
30 @property
31 def ramlname(self):
32 return self.name
33
34 def valueFromString(self, arg):
35 # convert a urldecoded bytestring as given in a URL to a value, or
36 # raise an exception trying. This parent method raises an exception,
37 # so if the method is missing in a subclass, it cannot be created from
38 # a string.
39 raise TypeError
40
41 def cmp(self, val, arg):
42 argVal = self.valueFromString(arg)
43 if val < argVal:
44 return -1
45 elif val == argVal:
46 return 0
47 return 1
48
49 def validate(self, name, object):
50 raise NotImplementedError
51
52 def getSpec(self):
53 r = dict(name=self.name)
54 if self.doc is not None:
55 r["doc"] = self.doc
56 return r
57
58
59 class NoneOk(Type):
60
61 def __init__(self, nestedType):
62 assert isinstance(nestedType, Type)
63 self.nestedType = nestedType
64 self.name = self.nestedType.name + " or None"
65
66 @property
67 def ramlname(self):
68 return self.nestedType.ramlname
69
70 def valueFromString(self, arg):
71 return self.nestedType.valueFromString(arg)
72
73 def cmp(self, val, arg):
74 return self.nestedType.cmp(val, arg)
75
76 def validate(self, name, object):
77 if object is None:
78 return
79 for msg in self.nestedType.validate(name, object):
80 yield msg
81
82 def getSpec(self):
83 r = self.nestedType.getSpec()
84 r["can_be_null"] = True
85 return r
86
87 def toRaml(self):
88 return self.nestedType.toRaml()
89
90
91 class Instance(Type):
92
93 types = ()
94 ramlType = "unknown"
95
96 @property
97 def ramlname(self):
98 return self.ramlType
99
100 def validate(self, name, object):
101 if not isinstance(object, self.types):
102 yield "%s (%r) is not a %s" % (
103 name, object, self.name or repr(self.types))
104
105 def toRaml(self):
106 return self.ramlType
107
108
109 class Integer(Instance):
110
111 name = "integer"
112 types = (int,)
113 ramlType = "integer"
114
115 def valueFromString(self, arg):
116 return int(arg)
117
118
119 class DateTime(Instance):
120 name = "datetime"
121 types = (datetime.datetime)
122 ramlType = "date"
123
124
125 class String(Instance):
126
127 name = "string"
128 types = (str,)
129 ramlType = "string"
130
131 def valueFromString(self, arg):
132 val = util.bytes2unicode(arg)
133 return val
134
135
136 class Binary(Instance):
137
138 name = "binary"
139 types = (bytes,)
140 ramlType = "string"
141
142 def valueFromString(self, arg):
143 return arg
144
145
146 class Boolean(Instance):
147
148 name = "boolean"
149 types = (bool,)
150 ramlType = "boolean"
151
152 def valueFromString(self, arg):
153 return util.string2boolean(arg)
154
155
156 class Identifier(Type):
157
158 name = "identifier"
159 identRe = re.compile('^[a-zA-Z_-][a-zA-Z0-9._-]*$')
160 ramlType = "string"
161
162 def __init__(self, len=None, **kwargs):
163 super().__init__(**kwargs)
164 self.len = len
165
166 def valueFromString(self, arg):
167 val = util.bytes2unicode(arg)
168 if not self.identRe.match(val) or len(val) > self.len or not val:
169 raise TypeError
170 return val
171
172 def validate(self, name, object):
173 if not isinstance(object, str):
174 yield "%s - %r - is not a unicode string" % (name, object)
175 elif not self.identRe.match(object):
176 yield "%s - %r - is not an identifier" % (name, object)
177 elif not object:
178 yield "%s - identifiers cannot be an empty string" % (name,)
179 elif len(object) > self.len:
180 yield "%s - %r - is longer than %d characters" % (name, object,
181 self.len)
182
183 def toRaml(self):
184 return {'type': self.ramlType,
185 'pattern': self.identRe.pattern}
186
187
188 class List(Type):
189
190 name = "list"
191 ramlType = "list"
192
193 @property
194 def ramlname(self):
195 return self.of.ramlname
196
197 def __init__(self, of=None, **kwargs):
198 super().__init__(**kwargs)
199 self.of = of
200
201 def validate(self, name, object):
202 if not isinstance(object, list): # we want a list, and NOT a subclass
203 yield "%s (%r) is not a %s" % (name, object, self.name)
204 return
205
206 for idx, elt in enumerate(object):
207 for msg in self.of.validate("%s[%d]" % (name, idx), elt):
208 yield msg
209
210 def valueFromString(self, arg):
211 # valueFromString is used to process URL args, which come one at
212 # a time, so we defer to the `of`
213 return self.of.valueFromString(arg)
214
215 def getSpec(self):
216 return dict(type=self.name,
217 of=self.of.getSpec())
218
219 def toRaml(self):
220 return {'type': 'array', 'items': self.of.name}
221
222
223 def maybeNoneOrList(k, v):
224 if isinstance(v, NoneOk):
225 return k + "?"
226 if isinstance(v, List):
227 return k + "[]"
228 return k
229
230
231 class SourcedProperties(Type):
232
233 name = "sourcedproperties"
234
235 def validate(self, name, object):
236 if not isinstance(object, dict): # we want a dict, and NOT a subclass
237 yield "%s is not sourced properties (not a dict)" % (name,)
238 return
239 for k, v in object.items():
240 if not isinstance(k, str):
241 yield "%s property name %r is not unicode" % (name, k)
242 if not isinstance(v, tuple) or len(v) != 2:
243 yield "%s property value for '%s' is not a 2-tuple" % (name, k)
244 return
245 propval, propsrc = v
246 if not isinstance(propsrc, str):
247 yield "%s[%s] source %r is not unicode" % (name, k, propsrc)
248 try:
249 json.loads(bytes2unicode(propval))
250 except ValueError:
251 yield "%s[%r] value is not JSON-able" % (name, k)
252
253 def toRaml(self):
254 return {'type': "object",
255 'properties':
256 {'[]': {'type': 'object',
257 'properties': {
258 1: 'string',
259 2: 'integer | string | object | array | boolean'
260 }
261 }}}
262
263
264 class Dict(Type):
265 name = "dict"
266
267 @property
268 def ramlname(self):
269 return self.toRaml()
270
271 def __init__(self, **contents):
272 self.contents = contents
273 self.keys = set(contents)
274
275 def validate(self, name, object):
276 if not isinstance(object, dict):
277 yield "%s (%r) is not a dictionary (got type %s)" \
278 % (name, object, type(object))
279 return
280
281 gotNames = set(object.keys())
282
283 unexpected = gotNames - self.keys
284 if unexpected:
285 yield "%s has unexpected keys %s" % (name,
286 ", ".join([repr(n) for n in unexpected]))
287
288 missing = self.keys - gotNames
289 if missing:
290 yield "%s is missing keys %s" % (name,
291 ", ".join([repr(n) for n in missing]))
292
293 for k in gotNames & self.keys:
294 f = self.contents[k]
295 for msg in f.validate("%s[%r]" % (name, k), object[k]):
296 yield msg
297
298 def getSpec(self):
299 return dict(type=self.name,
300 fields=[dict(name=k,
301 type=v.name,
302 type_spec=v.getSpec())
303 for k, v in self.contents.items()
304 ])
305
306 def toRaml(self):
307 return {'type': "object",
308 'properties': {maybeNoneOrList(k, v): v.ramlname for k, v in self.contents.items()}}
309
310
311 class JsonObject(Type):
312 name = "jsonobject"
313 ramlname = 'object'
314
315 def validate(self, name, object):
316 if not isinstance(object, dict):
317 yield "%s (%r) is not a dictionary (got type %s)" \
318 % (name, object, type(object))
319 return
320
321 # make sure JSON can represent it
322 try:
323 json.dumps(object)
324 except Exception as e:
325 yield "%s is not JSON-able: %s" % (name, e)
326 return
327
328 def toRaml(self):
329 return "object"
330
331
332 class Entity(Type):
333
334 # NOTE: this type is defined by subclassing it in each resource type class.
335 # Instances are generally accessed at e.g.,
336 # * buildsets.Buildset.entityType or
337 # * self.master.data.rtypes.buildsets.entityType
338
339 name = None # set in constructor
340 fields = {}
341 fieldNames = set([])
342
343 def __init__(self, name):
344 fields = {}
345 for k, v in self.__class__.__dict__.items():
346 if isinstance(v, Type):
347 fields[k] = v
348 self.fields = fields
349 self.fieldNames = set(fields)
350 self.name = name
351
352 def validate(self, name, object):
353 # this uses isinstance, allowing dict subclasses as used by the DB API
354 if not isinstance(object, dict):
355 yield "%s (%r) is not a dictionary (got type %s)" \
356 % (name, object, type(object))
357 return
358
359 gotNames = set(object.keys())
360
361 unexpected = gotNames - self.fieldNames
362 if unexpected:
363 yield "%s has unexpected keys %s" % (name,
364 ", ".join([repr(n) for n in unexpected]))
365
366 missing = self.fieldNames - gotNames
367 if missing:
368 yield "%s is missing keys %s" % (name,
369 ", ".join([repr(n) for n in missing]))
370
371 for k in gotNames & self.fieldNames:
372 f = self.fields[k]
373 for msg in f.validate("%s[%r]" % (name, k), object[k]):
374 yield msg
375
376 def getSpec(self):
377 return dict(type=self.name,
378 fields=[dict(name=k,
379 type=v.name,
380 type_spec=v.getSpec())
381 for k, v in self.fields.items()
382 ])
383
384 def toRaml(self):
385 return {'type': "object",
386 'properties': {
387 maybeNoneOrList(k, v): {'type': v.ramlname, 'description': ''}
388 for k, v in self.fields.items()}}