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 {} |
