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 |