| OLD | NEW |
| 1 # Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/ | 1 # Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/ |
| 2 # | 2 # |
| 3 # Permission is hereby granted, free of charge, to any person obtaining a | 3 # Permission is hereby granted, free of charge, to any person obtaining a |
| 4 # copy of this software and associated documentation files (the | 4 # copy of this software and associated documentation files (the |
| 5 # "Software"), to deal in the Software without restriction, including | 5 # "Software"), to deal in the Software without restriction, including |
| 6 # without limitation the rights to use, copy, modify, merge, publish, dis- | 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 | 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- | 8 # persons to whom the Software is furnished to do so, subject to the fol- |
| 9 # lowing conditions: | 9 # lowing conditions: |
| 10 # | 10 # |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 boto.log.exception("Exception running on_set_%s" % self.name) | 68 boto.log.exception("Exception running on_set_%s" % self.name) |
| 69 | 69 |
| 70 setattr(obj, self.slot_name, value) | 70 setattr(obj, self.slot_name, value) |
| 71 | 71 |
| 72 def __property_config__(self, model_class, property_name): | 72 def __property_config__(self, model_class, property_name): |
| 73 self.model_class = model_class | 73 self.model_class = model_class |
| 74 self.name = property_name | 74 self.name = property_name |
| 75 self.slot_name = '_' + self.name | 75 self.slot_name = '_' + self.name |
| 76 | 76 |
| 77 def default_validator(self, value): | 77 def default_validator(self, value): |
| 78 if value == self.default_value(): | 78 if isinstance(value, basestring) or value == self.default_value(): |
| 79 return | 79 return |
| 80 if not isinstance(value, self.data_type): | 80 if not isinstance(value, self.data_type): |
| 81 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.da
ta_type, type(value)) | 81 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.da
ta_type, type(value)) |
| 82 | 82 |
| 83 def default_value(self): | 83 def default_value(self): |
| 84 return self.default | 84 return self.default |
| 85 | 85 |
| 86 def validate(self, value): | 86 def validate(self, value): |
| 87 if self.required and value==None: | 87 if self.required and value==None: |
| 88 raise ValueError, '%s is a required property' % self.name | 88 raise ValueError, '%s is a required property' % self.name |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 class TextProperty(Property): | 128 class TextProperty(Property): |
| 129 | 129 |
| 130 type_name = 'Text' | 130 type_name = 'Text' |
| 131 | 131 |
| 132 def __init__(self, verbose_name=None, name=None, default='', required=False, | 132 def __init__(self, verbose_name=None, name=None, default='', required=False, |
| 133 validator=None, choices=None, unique=False, max_length=None): | 133 validator=None, choices=None, unique=False, max_length=None): |
| 134 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) | 134 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) |
| 135 self.max_length = max_length | 135 self.max_length = max_length |
| 136 | 136 |
| 137 def validate(self, value): | 137 def validate(self, value): |
| 138 value = super(TextProperty, self).validate(value) |
| 138 if not isinstance(value, str) and not isinstance(value, unicode): | 139 if not isinstance(value, str) and not isinstance(value, unicode): |
| 139 raise TypeError, 'Expecting Text, got %s' % type(value) | 140 raise TypeError, 'Expecting Text, got %s' % type(value) |
| 140 if self.max_length and len(value) > self.max_length: | 141 if self.max_length and len(value) > self.max_length: |
| 141 raise ValueError, 'Length of value greater than maxlength %s' % self
.max_length | 142 raise ValueError, 'Length of value greater than maxlength %s' % self
.max_length |
| 142 | 143 |
| 143 class PasswordProperty(StringProperty): | 144 class PasswordProperty(StringProperty): |
| 144 """ | 145 """ |
| 145 Hashed property who's original value can not be | 146 |
| 146 retrieved, but still can be compaired. | 147 Hashed property whose original value can not be |
| 148 retrieved, but still can be compared. |
| 149 |
| 150 Works by storing a hash of the original value instead |
| 151 of the original value. Once that's done all that |
| 152 can be retrieved is the hash. |
| 153 |
| 154 The comparison |
| 155 |
| 156 obj.password == 'foo' |
| 157 |
| 158 generates a hash of 'foo' and compares it to the |
| 159 stored hash. |
| 160 |
| 161 Underlying data type for hashing, storing, and comparing |
| 162 is boto.utils.Password. The default hash function is |
| 163 defined there ( currently sha512 in most cases, md5 |
| 164 where sha512 is not available ) |
| 165 |
| 166 It's unlikely you'll ever need to use a different hash |
| 167 function, but if you do, you can control the behavior |
| 168 in one of two ways: |
| 169 |
| 170 1) Specifying hashfunc in PasswordProperty constructor |
| 171 |
| 172 import hashlib |
| 173 |
| 174 class MyModel(model): |
| 175 password = PasswordProperty(hashfunc=hashlib.sha224) |
| 176 |
| 177 2) Subclassing Password and PasswordProperty |
| 178 |
| 179 class SHA224Password(Password): |
| 180 hashfunc=hashlib.sha224 |
| 181 |
| 182 class SHA224PasswordProperty(PasswordProperty): |
| 183 data_type=MyPassword |
| 184 type_name="MyPassword" |
| 185 |
| 186 class MyModel(Model): |
| 187 password = SHA224PasswordProperty() |
| 188 |
| 147 """ | 189 """ |
| 148 data_type = Password | 190 data_type = Password |
| 149 type_name = 'Password' | 191 type_name = 'Password' |
| 150 | 192 |
| 151 def __init__(self, verbose_name=None, name=None, default='', required=False, | 193 def __init__(self, verbose_name=None, name=None, default='', required=False, |
| 152 validator=None, choices=None, unique=False): | 194 validator=None, choices=None, unique=False, hashfunc=None): |
| 195 |
| 196 """ |
| 197 The hashfunc parameter overrides the default hashfunc in boto.utils.P
assword. |
| 198 |
| 199 The remaining parameters are passed through to StringProperty.__init_
_""" |
| 200 |
| 201 |
| 153 StringProperty.__init__(self, verbose_name, name, default, required, val
idator, choices, unique) | 202 StringProperty.__init__(self, verbose_name, name, default, required, val
idator, choices, unique) |
| 203 self.hashfunc=hashfunc |
| 154 | 204 |
| 155 def make_value_from_datastore(self, value): | 205 def make_value_from_datastore(self, value): |
| 156 p = Password(value) | 206 p = self.data_type(value, hashfunc=self.hashfunc) |
| 157 return p | 207 return p |
| 158 | 208 |
| 159 def get_value_for_datastore(self, model_instance): | 209 def get_value_for_datastore(self, model_instance): |
| 160 value = StringProperty.get_value_for_datastore(self, model_instance) | 210 value = StringProperty.get_value_for_datastore(self, model_instance) |
| 161 if value and len(value): | 211 if value and len(value): |
| 162 return str(value) | 212 return str(value) |
| 163 else: | 213 else: |
| 164 return None | 214 return None |
| 165 | 215 |
| 166 def __set__(self, obj, value): | 216 def __set__(self, obj, value): |
| 167 if not isinstance(value, Password): | 217 if not isinstance(value, self.data_type): |
| 168 p = Password() | 218 p = self.data_type(hashfunc=self.hashfunc) |
| 169 p.set(value) | 219 p.set(value) |
| 170 value = p | 220 value = p |
| 171 Property.__set__(self, obj, value) | 221 Property.__set__(self, obj, value) |
| 172 | 222 |
| 173 def __get__(self, obj, objtype): | 223 def __get__(self, obj, objtype): |
| 174 return Password(StringProperty.__get__(self, obj, objtype)) | 224 return self.data_type(StringProperty.__get__(self, obj, objtype), hashfu
nc=self.hashfunc) |
| 175 | 225 |
| 176 def validate(self, value): | 226 def validate(self, value): |
| 177 value = Property.validate(self, value) | 227 value = Property.validate(self, value) |
| 178 if isinstance(value, Password): | 228 if isinstance(value, self.data_type): |
| 179 if len(value) > 1024: | 229 if len(value) > 1024: |
| 180 raise ValueError, 'Length of value greater than maxlength' | 230 raise ValueError, 'Length of value greater than maxlength' |
| 181 else: | 231 else: |
| 182 raise TypeError, 'Expecting Password, got %s' % type(value) | 232 raise TypeError, 'Expecting %s, got %s' % (type(self.data_type), typ
e(value)) |
| 183 | 233 |
| 184 class BlobProperty(Property): | 234 class BlobProperty(Property): |
| 185 data_type = Blob | 235 data_type = Blob |
| 186 type_name = "blob" | 236 type_name = "blob" |
| 187 | 237 |
| 188 def __set__(self, obj, value): | 238 def __set__(self, obj, value): |
| 189 if value != self.default_value(): | 239 if value != self.default_value(): |
| 190 if not isinstance(value, Blob): | 240 if not isinstance(value, Blob): |
| 191 oldb = self.__get__(obj, type(obj)) | 241 oldb = self.__get__(obj, type(obj)) |
| 192 id = None | 242 id = None |
| 193 if oldb: | 243 if oldb: |
| 194 id = oldb.id | 244 id = oldb.id |
| 195 b = Blob(value=value, id=id) | 245 b = Blob(value=value, id=id) |
| 196 value = b | 246 value = b |
| 197 Property.__set__(self, obj, value) | 247 Property.__set__(self, obj, value) |
| 198 | 248 |
| 199 class S3KeyProperty(Property): | 249 class S3KeyProperty(Property): |
| 200 | 250 |
| 201 data_type = boto.s3.key.Key | 251 data_type = boto.s3.key.Key |
| 202 type_name = 'S3Key' | 252 type_name = 'S3Key' |
| 203 validate_regex = "^s3:\/\/([^\/]*)\/(.*)$" | 253 validate_regex = "^s3:\/\/([^\/]*)\/(.*)$" |
| 204 | 254 |
| 205 def __init__(self, verbose_name=None, name=None, default=None, | 255 def __init__(self, verbose_name=None, name=None, default=None, |
| 206 required=False, validator=None, choices=None, unique=False): | 256 required=False, validator=None, choices=None, unique=False): |
| 207 Property.__init__(self, verbose_name, name, default, required, | 257 Property.__init__(self, verbose_name, name, default, required, |
| 208 validator, choices, unique) | 258 validator, choices, unique) |
| 209 | 259 |
| 210 def validate(self, value): | 260 def validate(self, value): |
| 261 value = super(S3KeyProperty, self).validate(value) |
| 211 if value == self.default_value() or value == str(self.default_value()): | 262 if value == self.default_value() or value == str(self.default_value()): |
| 212 return self.default_value() | 263 return self.default_value() |
| 213 if isinstance(value, self.data_type): | 264 if isinstance(value, self.data_type): |
| 214 return | 265 return |
| 215 match = re.match(self.validate_regex, value) | 266 match = re.match(self.validate_regex, value) |
| 216 if match: | 267 if match: |
| 217 return | 268 return |
| 218 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.data_t
ype, type(value)) | 269 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.data_t
ype, type(value)) |
| 219 | 270 |
| 220 def __get__(self, obj, objtype): | 271 def __get__(self, obj, objtype): |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) | 384 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) |
| 334 self.auto_now = auto_now | 385 self.auto_now = auto_now |
| 335 self.auto_now_add = auto_now_add | 386 self.auto_now_add = auto_now_add |
| 336 | 387 |
| 337 def default_value(self): | 388 def default_value(self): |
| 338 if self.auto_now or self.auto_now_add: | 389 if self.auto_now or self.auto_now_add: |
| 339 return self.now() | 390 return self.now() |
| 340 return Property.default_value(self) | 391 return Property.default_value(self) |
| 341 | 392 |
| 342 def validate(self, value): | 393 def validate(self, value): |
| 394 value = super(DateTimeProperty, self).validate(value) |
| 343 if value == None: | 395 if value == None: |
| 344 return | 396 return |
| 345 if not isinstance(value, self.data_type): | 397 if not isinstance(value, self.data_type): |
| 346 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.da
ta_type, type(value)) | 398 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.da
ta_type, type(value)) |
| 347 | 399 |
| 348 def get_value_for_datastore(self, model_instance): | 400 def get_value_for_datastore(self, model_instance): |
| 349 if self.auto_now: | 401 if self.auto_now: |
| 350 setattr(model_instance, self.name, self.now()) | 402 setattr(model_instance, self.name, self.now()) |
| 351 return Property.get_value_for_datastore(self, model_instance) | 403 return Property.get_value_for_datastore(self, model_instance) |
| 352 | 404 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 363 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) | 415 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) |
| 364 self.auto_now = auto_now | 416 self.auto_now = auto_now |
| 365 self.auto_now_add = auto_now_add | 417 self.auto_now_add = auto_now_add |
| 366 | 418 |
| 367 def default_value(self): | 419 def default_value(self): |
| 368 if self.auto_now or self.auto_now_add: | 420 if self.auto_now or self.auto_now_add: |
| 369 return self.now() | 421 return self.now() |
| 370 return Property.default_value(self) | 422 return Property.default_value(self) |
| 371 | 423 |
| 372 def validate(self, value): | 424 def validate(self, value): |
| 425 value = super(DateProperty, self).validate(value) |
| 373 if value == None: | 426 if value == None: |
| 374 return | 427 return |
| 375 if not isinstance(value, self.data_type): | 428 if not isinstance(value, self.data_type): |
| 376 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.da
ta_type, type(value)) | 429 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.da
ta_type, type(value)) |
| 377 | 430 |
| 378 def get_value_for_datastore(self, model_instance): | 431 def get_value_for_datastore(self, model_instance): |
| 379 if self.auto_now: | 432 if self.auto_now: |
| 380 setattr(model_instance, self.name, self.now()) | 433 setattr(model_instance, self.name, self.now()) |
| 381 val = Property.get_value_for_datastore(self, model_instance) | 434 val = Property.get_value_for_datastore(self, model_instance) |
| 382 if isinstance(val, datetime.datetime): | 435 if isinstance(val, datetime.datetime): |
| 383 val = val.date() | 436 val = val.date() |
| 384 return val | 437 return val |
| 385 | 438 |
| 386 def now(self): | 439 def now(self): |
| 387 return datetime.date.today() | 440 return datetime.date.today() |
| 388 | 441 |
| 442 |
| 443 class TimeProperty(Property): |
| 444 data_type = datetime.time |
| 445 type_name = 'Time' |
| 446 |
| 447 def __init__(self, verbose_name=None, name=None, |
| 448 default=None, required=False, validator=None, choices=None, uni
que=False): |
| 449 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) |
| 450 |
| 451 def validate(self, value): |
| 452 value = super(TimeProperty, self).validate(value) |
| 453 if value is None: |
| 454 return |
| 455 if not isinstance(value, self.data_type): |
| 456 raise TypeError, 'Validation Error, expecting %s, got %s' % (self.da
ta_type, type(value)) |
| 457 |
| 458 |
| 389 class ReferenceProperty(Property): | 459 class ReferenceProperty(Property): |
| 390 | 460 |
| 391 data_type = Key | 461 data_type = Key |
| 392 type_name = 'Reference' | 462 type_name = 'Reference' |
| 393 | 463 |
| 394 def __init__(self, reference_class=None, collection_name=None, | 464 def __init__(self, reference_class=None, collection_name=None, |
| 395 verbose_name=None, name=None, default=None, required=False, val
idator=None, choices=None, unique=False): | 465 verbose_name=None, name=None, default=None, required=False, val
idator=None, choices=None, unique=False): |
| 396 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) | 466 Property.__init__(self, verbose_name, name, default, required, validator
, choices, unique) |
| 397 self.reference_class = reference_class | 467 self.reference_class = reference_class |
| 398 self.collection_name = collection_name | 468 self.collection_name = collection_name |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 try: | 506 try: |
| 437 obj_lineage = value.get_lineage() | 507 obj_lineage = value.get_lineage() |
| 438 cls_lineage = self.reference_class.get_lineage() | 508 cls_lineage = self.reference_class.get_lineage() |
| 439 if obj_lineage.startswith(cls_lineage): | 509 if obj_lineage.startswith(cls_lineage): |
| 440 return | 510 return |
| 441 raise TypeError, '%s not instance of %s' % (obj_lineage, cls_lineage
) | 511 raise TypeError, '%s not instance of %s' % (obj_lineage, cls_lineage
) |
| 442 except: | 512 except: |
| 443 raise ValueError, '%s is not a Model' % value | 513 raise ValueError, '%s is not a Model' % value |
| 444 | 514 |
| 445 def validate(self, value): | 515 def validate(self, value): |
| 516 if self.validator: |
| 517 self.validator(value) |
| 446 if self.required and value==None: | 518 if self.required and value==None: |
| 447 raise ValueError, '%s is a required property' % self.name | 519 raise ValueError, '%s is a required property' % self.name |
| 448 if value == self.default_value(): | 520 if value == self.default_value(): |
| 449 return | 521 return |
| 450 if not isinstance(value, str) and not isinstance(value, unicode): | 522 if not isinstance(value, str) and not isinstance(value, unicode): |
| 451 self.check_instance(value) | 523 self.check_instance(value) |
| 452 | 524 |
| 453 class _ReverseReferenceProperty(Property): | 525 class _ReverseReferenceProperty(Property): |
| 454 data_type = Query | 526 data_type = Query |
| 455 type_name = 'query' | 527 type_name = 'query' |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 data_type = list | 593 data_type = list |
| 522 type_name = 'List' | 594 type_name = 'List' |
| 523 | 595 |
| 524 def __init__(self, item_type, verbose_name=None, name=None, default=None, **
kwds): | 596 def __init__(self, item_type, verbose_name=None, name=None, default=None, **
kwds): |
| 525 if default is None: | 597 if default is None: |
| 526 default = [] | 598 default = [] |
| 527 self.item_type = item_type | 599 self.item_type = item_type |
| 528 Property.__init__(self, verbose_name, name, default=default, required=Tr
ue, **kwds) | 600 Property.__init__(self, verbose_name, name, default=default, required=Tr
ue, **kwds) |
| 529 | 601 |
| 530 def validate(self, value): | 602 def validate(self, value): |
| 603 if self.validator: |
| 604 self.validator(value) |
| 531 if value is not None: | 605 if value is not None: |
| 532 if not isinstance(value, list): | 606 if not isinstance(value, list): |
| 533 value = [value] | 607 value = [value] |
| 534 | 608 |
| 535 if self.item_type in (int, long): | 609 if self.item_type in (int, long): |
| 536 item_type = (int, long) | 610 item_type = (int, long) |
| 537 elif self.item_type in (str, unicode): | 611 elif self.item_type in (str, unicode): |
| 538 item_type = (str, unicode) | 612 item_type = (str, unicode) |
| 539 else: | 613 else: |
| 540 item_type = self.item_type | 614 item_type = self.item_type |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 data_type = dict | 648 data_type = dict |
| 575 type_name = 'Map' | 649 type_name = 'Map' |
| 576 | 650 |
| 577 def __init__(self, item_type=str, verbose_name=None, name=None, default=None
, **kwds): | 651 def __init__(self, item_type=str, verbose_name=None, name=None, default=None
, **kwds): |
| 578 if default is None: | 652 if default is None: |
| 579 default = {} | 653 default = {} |
| 580 self.item_type = item_type | 654 self.item_type = item_type |
| 581 Property.__init__(self, verbose_name, name, default=default, required=Tr
ue, **kwds) | 655 Property.__init__(self, verbose_name, name, default=default, required=Tr
ue, **kwds) |
| 582 | 656 |
| 583 def validate(self, value): | 657 def validate(self, value): |
| 658 value = super(MapProperty, self).validate(value) |
| 584 if value is not None: | 659 if value is not None: |
| 585 if not isinstance(value, dict): | 660 if not isinstance(value, dict): |
| 586 raise ValueError, 'Value must of type dict' | 661 raise ValueError, 'Value must of type dict' |
| 587 | 662 |
| 588 if self.item_type in (int, long): | 663 if self.item_type in (int, long): |
| 589 item_type = (int, long) | 664 item_type = (int, long) |
| 590 elif self.item_type in (str, unicode): | 665 elif self.item_type in (str, unicode): |
| 591 item_type = (str, unicode) | 666 item_type = (str, unicode) |
| 592 else: | 667 else: |
| 593 item_type = self.item_type | 668 item_type = self.item_type |
| 594 | 669 |
| 595 for key in value: | 670 for key in value: |
| 596 if not isinstance(value[key], item_type): | 671 if not isinstance(value[key], item_type): |
| 597 if item_type == (int, long): | 672 if item_type == (int, long): |
| 598 raise ValueError, 'Values in the %s Map must all be integers
.' % self.name | 673 raise ValueError, 'Values in the %s Map must all be integers
.' % self.name |
| 599 else: | 674 else: |
| 600 raise ValueError('Values in the %s Map must all be %s instan
ces' % | 675 raise ValueError('Values in the %s Map must all be %s instan
ces' % |
| 601 (self.name, self.item_type.__name__)) | 676 (self.name, self.item_type.__name__)) |
| 602 return value | 677 return value |
| 603 | 678 |
| 604 def empty(self, value): | 679 def empty(self, value): |
| 605 return value is None | 680 return value is None |
| 606 | 681 |
| 607 def default_value(self): | 682 def default_value(self): |
| 608 return {} | 683 return {} |
| OLD | NEW |