Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/boto/sdb/db/property.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 # Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/ | |
2 # | |
3 # Permission is hereby granted, free of charge, to any person obtaining a | |
4 # copy of this software and associated documentation files (the | |
5 # "Software"), to deal in the Software without restriction, including | |
6 # without limitation the rights to use, copy, modify, merge, publish, dis- | |
7 # tribute, sublicense, and/or sell copies of the Software, and to permit | |
8 # persons to whom the Software is furnished to do so, subject to the fol- | |
9 # lowing conditions: | |
10 # | |
11 # The above copyright notice and this permission notice shall be included | |
12 # in all copies or substantial portions of the Software. | |
13 # | |
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- | |
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | |
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
20 # IN THE SOFTWARE. | |
21 | |
22 import datetime | |
23 from boto.sdb.db.key import Key | |
24 from boto.utils import Password | |
25 from boto.sdb.db.query import Query | |
26 import re | |
27 import boto | |
28 import boto.s3.key | |
29 from boto.sdb.db.blob import Blob | |
30 from boto.compat import six, long_type | |
31 | |
32 | |
33 class Property(object): | |
34 | |
35 data_type = str | |
36 type_name = '' | |
37 name = '' | |
38 verbose_name = '' | |
39 | |
40 def __init__(self, verbose_name=None, name=None, default=None, | |
41 required=False, validator=None, choices=None, unique=False): | |
42 self.verbose_name = verbose_name | |
43 self.name = name | |
44 self.default = default | |
45 self.required = required | |
46 self.validator = validator | |
47 self.choices = choices | |
48 if self.name: | |
49 self.slot_name = '_' + self.name | |
50 else: | |
51 self.slot_name = '_' | |
52 self.unique = unique | |
53 | |
54 def __get__(self, obj, objtype): | |
55 if obj: | |
56 obj.load() | |
57 return getattr(obj, self.slot_name) | |
58 else: | |
59 return None | |
60 | |
61 def __set__(self, obj, value): | |
62 self.validate(value) | |
63 | |
64 # Fire off any on_set functions | |
65 try: | |
66 if obj._loaded and hasattr(obj, "on_set_%s" % self.name): | |
67 fnc = getattr(obj, "on_set_%s" % self.name) | |
68 value = fnc(value) | |
69 except Exception: | |
70 boto.log.exception("Exception running on_set_%s" % self.name) | |
71 | |
72 setattr(obj, self.slot_name, value) | |
73 | |
74 def __property_config__(self, model_class, property_name): | |
75 self.model_class = model_class | |
76 self.name = property_name | |
77 self.slot_name = '_' + self.name | |
78 | |
79 def default_validator(self, value): | |
80 if isinstance(value, six.string_types) or value == self.default_value(): | |
81 return | |
82 if not isinstance(value, self.data_type): | |
83 raise TypeError('Validation Error, %s.%s expecting %s, got %s' % (self.model_class.__name__, self.name, self.data_type, type(value))) | |
84 | |
85 def default_value(self): | |
86 return self.default | |
87 | |
88 def validate(self, value): | |
89 if self.required and value is None: | |
90 raise ValueError('%s is a required property' % self.name) | |
91 if self.choices and value and value not in self.choices: | |
92 raise ValueError('%s not a valid choice for %s.%s' % (value, self.model_class.__name__, self.name)) | |
93 if self.validator: | |
94 self.validator(value) | |
95 else: | |
96 self.default_validator(value) | |
97 return value | |
98 | |
99 def empty(self, value): | |
100 return not value | |
101 | |
102 def get_value_for_datastore(self, model_instance): | |
103 return getattr(model_instance, self.name) | |
104 | |
105 def make_value_from_datastore(self, value): | |
106 return value | |
107 | |
108 def get_choices(self): | |
109 if callable(self.choices): | |
110 return self.choices() | |
111 return self.choices | |
112 | |
113 | |
114 def validate_string(value): | |
115 if value is None: | |
116 return | |
117 elif isinstance(value, six.string_types): | |
118 if len(value) > 1024: | |
119 raise ValueError('Length of value greater than maxlength') | |
120 else: | |
121 raise TypeError('Expecting String, got %s' % type(value)) | |
122 | |
123 | |
124 class StringProperty(Property): | |
125 | |
126 type_name = 'String' | |
127 | |
128 def __init__(self, verbose_name=None, name=None, default='', | |
129 required=False, validator=validate_string, | |
130 choices=None, unique=False): | |
131 super(StringProperty, self).__init__(verbose_name, name, default, required, | |
132 validator, choices, unique) | |
133 | |
134 | |
135 class TextProperty(Property): | |
136 | |
137 type_name = 'Text' | |
138 | |
139 def __init__(self, verbose_name=None, name=None, default='', | |
140 required=False, validator=None, choices=None, | |
141 unique=False, max_length=None): | |
142 super(TextProperty, self).__init__(verbose_name, name, default, required, | |
143 validator, choices, unique) | |
144 self.max_length = max_length | |
145 | |
146 def validate(self, value): | |
147 value = super(TextProperty, self).validate(value) | |
148 if not isinstance(value, six.string_types): | |
149 raise TypeError('Expecting Text, got %s' % type(value)) | |
150 if self.max_length and len(value) > self.max_length: | |
151 raise ValueError('Length of value greater than maxlength %s' % self.max_length) | |
152 | |
153 | |
154 class PasswordProperty(StringProperty): | |
155 """ | |
156 | |
157 Hashed property whose original value can not be | |
158 retrieved, but still can be compared. | |
159 | |
160 Works by storing a hash of the original value instead | |
161 of the original value. Once that's done all that | |
162 can be retrieved is the hash. | |
163 | |
164 The comparison | |
165 | |
166 obj.password == 'foo' | |
167 | |
168 generates a hash of 'foo' and compares it to the | |
169 stored hash. | |
170 | |
171 Underlying data type for hashing, storing, and comparing | |
172 is boto.utils.Password. The default hash function is | |
173 defined there ( currently sha512 in most cases, md5 | |
174 where sha512 is not available ) | |
175 | |
176 It's unlikely you'll ever need to use a different hash | |
177 function, but if you do, you can control the behavior | |
178 in one of two ways: | |
179 | |
180 1) Specifying hashfunc in PasswordProperty constructor | |
181 | |
182 import hashlib | |
183 | |
184 class MyModel(model): | |
185 password = PasswordProperty(hashfunc=hashlib.sha224) | |
186 | |
187 2) Subclassing Password and PasswordProperty | |
188 | |
189 class SHA224Password(Password): | |
190 hashfunc=hashlib.sha224 | |
191 | |
192 class SHA224PasswordProperty(PasswordProperty): | |
193 data_type=MyPassword | |
194 type_name="MyPassword" | |
195 | |
196 class MyModel(Model): | |
197 password = SHA224PasswordProperty() | |
198 | |
199 """ | |
200 data_type = Password | |
201 type_name = 'Password' | |
202 | |
203 def __init__(self, verbose_name=None, name=None, default='', required=False, | |
204 validator=None, choices=None, unique=False, hashfunc=None): | |
205 | |
206 """ | |
207 The hashfunc parameter overrides the default hashfunc in boto.utils.Password. | |
208 | |
209 The remaining parameters are passed through to StringProperty.__init__""" | |
210 | |
211 super(PasswordProperty, self).__init__(verbose_name, name, default, required, | |
212 validator, choices, unique) | |
213 self.hashfunc = hashfunc | |
214 | |
215 def make_value_from_datastore(self, value): | |
216 p = self.data_type(value, hashfunc=self.hashfunc) | |
217 return p | |
218 | |
219 def get_value_for_datastore(self, model_instance): | |
220 value = super(PasswordProperty, self).get_value_for_datastore(model_instance) | |
221 if value and len(value): | |
222 return str(value) | |
223 else: | |
224 return None | |
225 | |
226 def __set__(self, obj, value): | |
227 if not isinstance(value, self.data_type): | |
228 p = self.data_type(hashfunc=self.hashfunc) | |
229 p.set(value) | |
230 value = p | |
231 super(PasswordProperty, self).__set__(obj, value) | |
232 | |
233 def __get__(self, obj, objtype): | |
234 return self.data_type(super(PasswordProperty, self).__get__(obj, objtype), hashfunc=self.hashfunc) | |
235 | |
236 def validate(self, value): | |
237 value = super(PasswordProperty, self).validate(value) | |
238 if isinstance(value, self.data_type): | |
239 if len(value) > 1024: | |
240 raise ValueError('Length of value greater than maxlength') | |
241 else: | |
242 raise TypeError('Expecting %s, got %s' % (type(self.data_type), type(value))) | |
243 | |
244 | |
245 class BlobProperty(Property): | |
246 data_type = Blob | |
247 type_name = "blob" | |
248 | |
249 def __set__(self, obj, value): | |
250 if value != self.default_value(): | |
251 if not isinstance(value, Blob): | |
252 oldb = self.__get__(obj, type(obj)) | |
253 id = None | |
254 if oldb: | |
255 id = oldb.id | |
256 b = Blob(value=value, id=id) | |
257 value = b | |
258 super(BlobProperty, self).__set__(obj, value) | |
259 | |
260 | |
261 class S3KeyProperty(Property): | |
262 | |
263 data_type = boto.s3.key.Key | |
264 type_name = 'S3Key' | |
265 validate_regex = "^s3:\/\/([^\/]*)\/(.*)$" | |
266 | |
267 def __init__(self, verbose_name=None, name=None, default=None, | |
268 required=False, validator=None, choices=None, unique=False): | |
269 super(S3KeyProperty, self).__init__(verbose_name, name, default, required, | |
270 validator, choices, unique) | |
271 | |
272 def validate(self, value): | |
273 value = super(S3KeyProperty, self).validate(value) | |
274 if value == self.default_value() or value == str(self.default_value()): | |
275 return self.default_value() | |
276 if isinstance(value, self.data_type): | |
277 return | |
278 match = re.match(self.validate_regex, value) | |
279 if match: | |
280 return | |
281 raise TypeError('Validation Error, expecting %s, got %s' % (self.data_type, type(value))) | |
282 | |
283 def __get__(self, obj, objtype): | |
284 value = super(S3KeyProperty, self).__get__(obj, objtype) | |
285 if value: | |
286 if isinstance(value, self.data_type): | |
287 return value | |
288 match = re.match(self.validate_regex, value) | |
289 if match: | |
290 s3 = obj._manager.get_s3_connection() | |
291 bucket = s3.get_bucket(match.group(1), validate=False) | |
292 k = bucket.get_key(match.group(2)) | |
293 if not k: | |
294 k = bucket.new_key(match.group(2)) | |
295 k.set_contents_from_string("") | |
296 return k | |
297 else: | |
298 return value | |
299 | |
300 def get_value_for_datastore(self, model_instance): | |
301 value = super(S3KeyProperty, self).get_value_for_datastore(model_instance) | |
302 if value: | |
303 return "s3://%s/%s" % (value.bucket.name, value.name) | |
304 else: | |
305 return None | |
306 | |
307 | |
308 class IntegerProperty(Property): | |
309 | |
310 data_type = int | |
311 type_name = 'Integer' | |
312 | |
313 def __init__(self, verbose_name=None, name=None, default=0, required=False, | |
314 validator=None, choices=None, unique=False, max=2147483647, min=-2147483648): | |
315 super(IntegerProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
316 self.max = max | |
317 self.min = min | |
318 | |
319 def validate(self, value): | |
320 value = int(value) | |
321 value = super(IntegerProperty, self).validate(value) | |
322 if value > self.max: | |
323 raise ValueError('Maximum value is %d' % self.max) | |
324 if value < self.min: | |
325 raise ValueError('Minimum value is %d' % self.min) | |
326 return value | |
327 | |
328 def empty(self, value): | |
329 return value is None | |
330 | |
331 def __set__(self, obj, value): | |
332 if value == "" or value is None: | |
333 value = 0 | |
334 return super(IntegerProperty, self).__set__(obj, value) | |
335 | |
336 | |
337 class LongProperty(Property): | |
338 | |
339 data_type = long_type | |
340 type_name = 'Long' | |
341 | |
342 def __init__(self, verbose_name=None, name=None, default=0, required=False, | |
343 validator=None, choices=None, unique=False): | |
344 super(LongProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
345 | |
346 def validate(self, value): | |
347 value = long_type(value) | |
348 value = super(LongProperty, self).validate(value) | |
349 min = -9223372036854775808 | |
350 max = 9223372036854775807 | |
351 if value > max: | |
352 raise ValueError('Maximum value is %d' % max) | |
353 if value < min: | |
354 raise ValueError('Minimum value is %d' % min) | |
355 return value | |
356 | |
357 def empty(self, value): | |
358 return value is None | |
359 | |
360 | |
361 class BooleanProperty(Property): | |
362 | |
363 data_type = bool | |
364 type_name = 'Boolean' | |
365 | |
366 def __init__(self, verbose_name=None, name=None, default=False, required=False, | |
367 validator=None, choices=None, unique=False): | |
368 super(BooleanProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
369 | |
370 def empty(self, value): | |
371 return value is None | |
372 | |
373 | |
374 class FloatProperty(Property): | |
375 | |
376 data_type = float | |
377 type_name = 'Float' | |
378 | |
379 def __init__(self, verbose_name=None, name=None, default=0.0, required=False, | |
380 validator=None, choices=None, unique=False): | |
381 super(FloatProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
382 | |
383 def validate(self, value): | |
384 value = float(value) | |
385 value = super(FloatProperty, self).validate(value) | |
386 return value | |
387 | |
388 def empty(self, value): | |
389 return value is None | |
390 | |
391 | |
392 class DateTimeProperty(Property): | |
393 """This class handles both the datetime.datetime object | |
394 And the datetime.date objects. It can return either one, | |
395 depending on the value stored in the database""" | |
396 | |
397 data_type = datetime.datetime | |
398 type_name = 'DateTime' | |
399 | |
400 def __init__(self, verbose_name=None, auto_now=False, auto_now_add=False, name=None, | |
401 default=None, required=False, validator=None, choices=None, unique=False): | |
402 super(DateTimeProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
403 self.auto_now = auto_now | |
404 self.auto_now_add = auto_now_add | |
405 | |
406 def default_value(self): | |
407 if self.auto_now or self.auto_now_add: | |
408 return self.now() | |
409 return super(DateTimeProperty, self).default_value() | |
410 | |
411 def validate(self, value): | |
412 if value is None: | |
413 return | |
414 if isinstance(value, datetime.date): | |
415 return value | |
416 return super(DateTimeProperty, self).validate(value) | |
417 | |
418 def get_value_for_datastore(self, model_instance): | |
419 if self.auto_now: | |
420 setattr(model_instance, self.name, self.now()) | |
421 return super(DateTimeProperty, self).get_value_for_datastore(model_instance) | |
422 | |
423 def now(self): | |
424 return datetime.datetime.utcnow() | |
425 | |
426 | |
427 class DateProperty(Property): | |
428 | |
429 data_type = datetime.date | |
430 type_name = 'Date' | |
431 | |
432 def __init__(self, verbose_name=None, auto_now=False, auto_now_add=False, name=None, | |
433 default=None, required=False, validator=None, choices=None, unique=False): | |
434 super(DateProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
435 self.auto_now = auto_now | |
436 self.auto_now_add = auto_now_add | |
437 | |
438 def default_value(self): | |
439 if self.auto_now or self.auto_now_add: | |
440 return self.now() | |
441 return super(DateProperty, self).default_value() | |
442 | |
443 def validate(self, value): | |
444 value = super(DateProperty, self).validate(value) | |
445 if value is None: | |
446 return | |
447 if not isinstance(value, self.data_type): | |
448 raise TypeError('Validation Error, expecting %s, got %s' % (self.data_type, type(value))) | |
449 | |
450 def get_value_for_datastore(self, model_instance): | |
451 if self.auto_now: | |
452 setattr(model_instance, self.name, self.now()) | |
453 val = super(DateProperty, self).get_value_for_datastore(model_instance) | |
454 if isinstance(val, datetime.datetime): | |
455 val = val.date() | |
456 return val | |
457 | |
458 def now(self): | |
459 return datetime.date.today() | |
460 | |
461 | |
462 class TimeProperty(Property): | |
463 data_type = datetime.time | |
464 type_name = 'Time' | |
465 | |
466 def __init__(self, verbose_name=None, name=None, | |
467 default=None, required=False, validator=None, choices=None, unique=False): | |
468 super(TimeProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
469 | |
470 def validate(self, value): | |
471 value = super(TimeProperty, self).validate(value) | |
472 if value is None: | |
473 return | |
474 if not isinstance(value, self.data_type): | |
475 raise TypeError('Validation Error, expecting %s, got %s' % (self.data_type, type(value))) | |
476 | |
477 | |
478 class ReferenceProperty(Property): | |
479 | |
480 data_type = Key | |
481 type_name = 'Reference' | |
482 | |
483 def __init__(self, reference_class=None, collection_name=None, | |
484 verbose_name=None, name=None, default=None, required=False, validator=None, choices=None, unique=False): | |
485 super(ReferenceProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique) | |
486 self.reference_class = reference_class | |
487 self.collection_name = collection_name | |
488 | |
489 def __get__(self, obj, objtype): | |
490 if obj: | |
491 value = getattr(obj, self.slot_name) | |
492 if value == self.default_value(): | |
493 return value | |
494 # If the value is still the UUID for the referenced object, we need to create | |
495 # the object now that is the attribute has actually been accessed. This lazy | |
496 # instantiation saves unnecessary roundtrips to SimpleDB | |
497 if isinstance(value, six.string_types): | |
498 value = self.reference_class(value) | |
499 setattr(obj, self.name, value) | |
500 return value | |
501 | |
502 def __set__(self, obj, value): | |
503 """Don't allow this object to be associated to itself | |
504 This causes bad things to happen""" | |
505 if value is not None and (obj.id == value or (hasattr(value, "id") and obj.id == value.id)): | |
506 raise ValueError("Can not associate an object with itself!") | |
507 return super(ReferenceProperty, self).__set__(obj, value) | |
508 | |
509 def __property_config__(self, model_class, property_name): | |
510 super(ReferenceProperty, self).__property_config__(model_class, property_name) | |
511 if self.collection_name is None: | |
512 self.collection_name = '%s_%s_set' % (model_class.__name__.lower(), self.name) | |
513 if hasattr(self.reference_class, self.collection_name): | |
514 raise ValueError('duplicate property: %s' % self.collection_name) | |
515 setattr(self.reference_class, self.collection_name, | |
516 _ReverseReferenceProperty(model_class, property_name, self.collection_name)) | |
517 | |
518 def check_uuid(self, value): | |
519 # This does a bit of hand waving to "type check" the string | |
520 t = value.split('-') | |
521 if len(t) != 5: | |
522 raise ValueError | |
523 | |
524 def check_instance(self, value): | |
525 try: | |
526 obj_lineage = value.get_lineage() | |
527 cls_lineage = self.reference_class.get_lineage() | |
528 if obj_lineage.startswith(cls_lineage): | |
529 return | |
530 raise TypeError('%s not instance of %s' % (obj_lineage, cls_lineage)) | |
531 except: | |
532 raise ValueError('%s is not a Model' % value) | |
533 | |
534 def validate(self, value): | |
535 if self.validator: | |
536 self.validator(value) | |
537 if self.required and value is None: | |
538 raise ValueError('%s is a required property' % self.name) | |
539 if value == self.default_value(): | |
540 return | |
541 if not isinstance(value, six.string_types): | |
542 self.check_instance(value) | |
543 | |
544 | |
545 class _ReverseReferenceProperty(Property): | |
546 data_type = Query | |
547 type_name = 'query' | |
548 | |
549 def __init__(self, model, prop, name): | |
550 self.__model = model | |
551 self.__property = prop | |
552 self.collection_name = prop | |
553 self.name = name | |
554 self.item_type = model | |
555 | |
556 def __get__(self, model_instance, model_class): | |
557 """Fetches collection of model instances of this collection property.""" | |
558 if model_instance is not None: | |
559 query = Query(self.__model) | |
560 if isinstance(self.__property, list): | |
561 props = [] | |
562 for prop in self.__property: | |
563 props.append("%s =" % prop) | |
564 return query.filter(props, model_instance) | |
565 else: | |
566 return query.filter(self.__property + ' =', model_instance) | |
567 else: | |
568 return self | |
569 | |
570 def __set__(self, model_instance, value): | |
571 """Not possible to set a new collection.""" | |
572 raise ValueError('Virtual property is read-only') | |
573 | |
574 | |
575 class CalculatedProperty(Property): | |
576 | |
577 def __init__(self, verbose_name=None, name=None, default=None, | |
578 required=False, validator=None, choices=None, | |
579 calculated_type=int, unique=False, use_method=False): | |
580 super(CalculatedProperty, self).__init__(verbose_name, name, default, required, | |
581 validator, choices, unique) | |
582 self.calculated_type = calculated_type | |
583 self.use_method = use_method | |
584 | |
585 def __get__(self, obj, objtype): | |
586 value = self.default_value() | |
587 if obj: | |
588 try: | |
589 value = getattr(obj, self.slot_name) | |
590 if self.use_method: | |
591 value = value() | |
592 except AttributeError: | |
593 pass | |
594 return value | |
595 | |
596 def __set__(self, obj, value): | |
597 """Not possible to set a new AutoID.""" | |
598 pass | |
599 | |
600 def _set_direct(self, obj, value): | |
601 if not self.use_method: | |
602 setattr(obj, self.slot_name, value) | |
603 | |
604 def get_value_for_datastore(self, model_instance): | |
605 if self.calculated_type in [str, int, bool]: | |
606 value = self.__get__(model_instance, model_instance.__class__) | |
607 return value | |
608 else: | |
609 return None | |
610 | |
611 | |
612 class ListProperty(Property): | |
613 | |
614 data_type = list | |
615 type_name = 'List' | |
616 | |
617 def __init__(self, item_type, verbose_name=None, name=None, default=None, **kwds): | |
618 if default is None: | |
619 default = [] | |
620 self.item_type = item_type | |
621 super(ListProperty, self).__init__(verbose_name, name, default=default, required=True, **kwds) | |
622 | |
623 def validate(self, value): | |
624 if self.validator: | |
625 self.validator(value) | |
626 if value is not None: | |
627 if not isinstance(value, list): | |
628 value = [value] | |
629 | |
630 if self.item_type in six.integer_types: | |
631 item_type = six.integer_types | |
632 elif self.item_type in six.string_types: | |
633 item_type = six.string_types | |
634 else: | |
635 item_type = self.item_type | |
636 | |
637 for item in value: | |
638 if not isinstance(item, item_type): | |
639 if item_type == six.integer_types: | |
640 raise ValueError('Items in the %s list must all be integers.' % self.name) | |
641 else: | |
642 raise ValueError('Items in the %s list must all be %s instances' % | |
643 (self.name, self.item_type.__name__)) | |
644 return value | |
645 | |
646 def empty(self, value): | |
647 return value is None | |
648 | |
649 def default_value(self): | |
650 return list(super(ListProperty, self).default_value()) | |
651 | |
652 def __set__(self, obj, value): | |
653 """Override the set method to allow them to set the property to an instance of the item_type instead of requiring a list to be passed in""" | |
654 if self.item_type in six.integer_types: | |
655 item_type = six.integer_types | |
656 elif self.item_type in six.string_types: | |
657 item_type = six.string_types | |
658 else: | |
659 item_type = self.item_type | |
660 if isinstance(value, item_type): | |
661 value = [value] | |
662 elif value is None: # Override to allow them to set this to "None" to remove everything | |
663 value = [] | |
664 return super(ListProperty, self).__set__(obj, value) | |
665 | |
666 | |
667 class MapProperty(Property): | |
668 | |
669 data_type = dict | |
670 type_name = 'Map' | |
671 | |
672 def __init__(self, item_type=str, verbose_name=None, name=None, default=None, **kwds): | |
673 if default is None: | |
674 default = {} | |
675 self.item_type = item_type | |
676 super(MapProperty, self).__init__(verbose_name, name, default=default, required=True, **kwds) | |
677 | |
678 def validate(self, value): | |
679 value = super(MapProperty, self).validate(value) | |
680 if value is not None: | |
681 if not isinstance(value, dict): | |
682 raise ValueError('Value must of type dict') | |
683 | |
684 if self.item_type in six.integer_types: | |
685 item_type = six.integer_types | |
686 elif self.item_type in six.string_types: | |
687 item_type = six.string_types | |
688 else: | |
689 item_type = self.item_type | |
690 | |
691 for key in value: | |
692 if not isinstance(value[key], item_type): | |
693 if item_type == six.integer_types: | |
694 raise ValueError('Values in the %s Map must all be integers.' % self.name) | |
695 else: | |
696 raise ValueError('Values in the %s Map must all be %s instances' % | |
697 (self.name, self.item_type.__name__)) | |
698 return value | |
699 | |
700 def empty(self, value): | |
701 return value is None | |
702 | |
703 def default_value(self): | |
704 return {} |