Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(537)

Side by Side Diff: third_party/gsutil/boto/sdb/db/property.py

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

Powered by Google App Engine
This is Rietveld 408576698