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

Side by Side Diff: boto/sdb/db/manager/sdbmanager.py

Issue 8386013: Merging in latest boto. (Closed) Base URL: svn://svn.chromium.org/boto
Patch Set: Redoing vendor drop by deleting and then merging. Created 9 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « boto/sdb/db/manager/pgmanager.py ('k') | boto/sdb/db/manager/xmlmanager.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/ 1 # Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/
2 # Copyright (c) 2010 Chris Moyer http://coredumped.org/ 2 # Copyright (c) 2010 Chris Moyer http://coredumped.org/
3 # 3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a 4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the 5 # copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including 6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish, dis- 7 # without limitation the rights to use, copy, modify, merge, publish, dis-
8 # tribute, sublicense, and/or sell copies of the Software, and to permit 8 # tribute, sublicense, and/or sell copies of the Software, and to permit
9 # persons to whom the Software is furnished to do so, subject to the fol- 9 # persons to whom the Software is furnished to do so, subject to the fol-
10 # lowing conditions: 10 # lowing conditions:
11 # 11 #
12 # The above copyright notice and this permission notice shall be included 12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software. 13 # in all copies or substantial portions of the Software.
14 # 14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 # IN THE SOFTWARE. 21 # IN THE SOFTWARE.
22 import boto 22 import boto
23 import re 23 import re
24 from boto.utils import find_class 24 from boto.utils import find_class
25 import uuid 25 import uuid
26 from boto.sdb.db.key import Key 26 from boto.sdb.db.key import Key
27 from boto.sdb.db.model import Model 27 from boto.sdb.db.model import Model
28 from boto.sdb.db.blob import Blob 28 from boto.sdb.db.blob import Blob
29 from boto.sdb.db.property import ListProperty, MapProperty 29 from boto.sdb.db.property import ListProperty, MapProperty
30 from datetime import datetime, date 30 from datetime import datetime, date, time
31 from boto.exception import SDBPersistenceError 31 from boto.exception import SDBPersistenceError, S3ResponseError
32 32
33 ISO8601 = '%Y-%m-%dT%H:%M:%SZ' 33 ISO8601 = '%Y-%m-%dT%H:%M:%SZ'
34 34
35 class TimeDecodeError(Exception):
36 pass
35 37
36 class SDBConverter: 38 class SDBConverter(object):
37 """ 39 """
38 Responsible for converting base Python types to format compatible with under lying 40 Responsible for converting base Python types to format compatible with under lying
39 database. For SimpleDB, that means everything needs to be converted to a st ring 41 database. For SimpleDB, that means everything needs to be converted to a st ring
40 when stored in SimpleDB and from a string when retrieved. 42 when stored in SimpleDB and from a string when retrieved.
41 43
42 To convert a value, pass it to the encode or decode method. The encode meth od 44 To convert a value, pass it to the encode or decode method. The encode meth od
43 will take a Python native value and convert to DB format. The decode method will 45 will take a Python native value and convert to DB format. The decode method will
44 take a DB format value and convert it to Python native format. To find the appropriate 46 take a DB format value and convert it to Python native format. To find the appropriate
45 method to call, the generic encode/decode methods will look for the type-spe cific 47 method to call, the generic encode/decode methods will look for the type-spe cific
46 method by searching for a method called "encode_<type name>" or "decode_<typ e name>". 48 method by searching for a method called "encode_<type name>" or "decode_<typ e name>".
47 """ 49 """
48 def __init__(self, manager): 50 def __init__(self, manager):
49 self.manager = manager 51 self.manager = manager
50 self.type_map = { bool : (self.encode_bool, self.decode_bool), 52 self.type_map = { bool : (self.encode_bool, self.decode_bool),
51 int : (self.encode_int, self.decode_int), 53 int : (self.encode_int, self.decode_int),
52 long : (self.encode_long, self.decode_long), 54 long : (self.encode_long, self.decode_long),
53 float : (self.encode_float, self.decode_float), 55 float : (self.encode_float, self.decode_float),
54 Model : (self.encode_reference, self.decode_reference) , 56 Model : (self.encode_reference, self.decode_reference) ,
55 Key : (self.encode_reference, self.decode_reference), 57 Key : (self.encode_reference, self.decode_reference),
56 datetime : (self.encode_datetime, self.decode_datetime ), 58 datetime : (self.encode_datetime, self.decode_datetime ),
57 date : (self.encode_date, self.decode_date), 59 date : (self.encode_date, self.decode_date),
60 time : (self.encode_time, self.decode_time),
58 Blob: (self.encode_blob, self.decode_blob), 61 Blob: (self.encode_blob, self.decode_blob),
62 str: (self.encode_string, self.decode_string),
59 } 63 }
60 64
61 def encode(self, item_type, value): 65 def encode(self, item_type, value):
62 try: 66 try:
63 if Model in item_type.mro(): 67 if Model in item_type.mro():
64 item_type = Model 68 item_type = Model
65 except: 69 except:
66 pass 70 pass
67 if item_type in self.type_map: 71 if item_type in self.type_map:
68 encode = self.type_map[item_type][0] 72 encode = self.type_map[item_type][0]
(...skipping 17 matching lines...) Expand all
86 # Just enumerate(value) won't work here because 90 # Just enumerate(value) won't work here because
87 # we need to add in some zero padding 91 # we need to add in some zero padding
88 # We support lists up to 1,000 attributes, since 92 # We support lists up to 1,000 attributes, since
89 # SDB technically only supports 1024 attributes anyway 93 # SDB technically only supports 1024 attributes anyway
90 values = {} 94 values = {}
91 for k,v in enumerate(value): 95 for k,v in enumerate(value):
92 values["%03d" % k] = v 96 values["%03d" % k] = v
93 return self.encode_map(prop, values) 97 return self.encode_map(prop, values)
94 98
95 def encode_map(self, prop, value): 99 def encode_map(self, prop, value):
100 import urllib
96 if value == None: 101 if value == None:
97 return None 102 return None
98 if not isinstance(value, dict): 103 if not isinstance(value, dict):
99 raise ValueError, 'Expected a dict value, got %s' % type(value) 104 raise ValueError, 'Expected a dict value, got %s' % type(value)
100 new_value = [] 105 new_value = []
101 for key in value: 106 for key in value:
102 item_type = getattr(prop, "item_type") 107 item_type = getattr(prop, "item_type")
103 if Model in item_type.mro(): 108 if Model in item_type.mro():
104 item_type = Model 109 item_type = Model
105 encoded_value = self.encode(item_type, value[key]) 110 encoded_value = self.encode(item_type, value[key])
106 if encoded_value != None: 111 if encoded_value != None:
107 new_value.append('%s:%s' % (key, encoded_value)) 112 new_value.append('%s:%s' % (urllib.quote(key), encoded_value))
108 return new_value 113 return new_value
109 114
110 def encode_prop(self, prop, value): 115 def encode_prop(self, prop, value):
111 if isinstance(prop, ListProperty): 116 if isinstance(prop, ListProperty):
112 return self.encode_list(prop, value) 117 return self.encode_list(prop, value)
113 elif isinstance(prop, MapProperty): 118 elif isinstance(prop, MapProperty):
114 return self.encode_map(prop, value) 119 return self.encode_map(prop, value)
115 else: 120 else:
116 return self.encode(prop.data_type, value) 121 return self.encode(prop.data_type, value)
117 122
(...skipping 19 matching lines...) Expand all
137 value = [value] 142 value = [value]
138 ret_value = {} 143 ret_value = {}
139 item_type = getattr(prop, "item_type") 144 item_type = getattr(prop, "item_type")
140 for val in value: 145 for val in value:
141 k,v = self.decode_map_element(item_type, val) 146 k,v = self.decode_map_element(item_type, val)
142 ret_value[k] = v 147 ret_value[k] = v
143 return ret_value 148 return ret_value
144 149
145 def decode_map_element(self, item_type, value): 150 def decode_map_element(self, item_type, value):
146 """Decode a single element for a map""" 151 """Decode a single element for a map"""
152 import urllib
147 key = value 153 key = value
148 if ":" in value: 154 if ":" in value:
149 key, value = value.split(':',1) 155 key, value = value.split(':',1)
156 key = urllib.unquote(key)
150 if Model in item_type.mro(): 157 if Model in item_type.mro():
151 value = item_type(id=value) 158 value = item_type(id=value)
152 else: 159 else:
153 value = self.decode(item_type, value) 160 value = self.decode(item_type, value)
154 return (key, value) 161 return (key, value)
155 162
156 def decode_prop(self, prop, value): 163 def decode_prop(self, prop, value):
157 if isinstance(prop, ListProperty): 164 if isinstance(prop, ListProperty):
158 return self.decode_list(prop, value) 165 return self.decode_list(prop, value)
159 elif isinstance(prop, MapProperty): 166 elif isinstance(prop, MapProperty):
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 return value 270 return value
264 return value.isoformat() 271 return value.isoformat()
265 272
266 def decode_date(self, value): 273 def decode_date(self, value):
267 try: 274 try:
268 value = value.split("-") 275 value = value.split("-")
269 return date(int(value[0]), int(value[1]), int(value[2])) 276 return date(int(value[0]), int(value[1]), int(value[2]))
270 except: 277 except:
271 return None 278 return None
272 279
280 encode_time = encode_date
281
282 def decode_time(self, value):
283 """ converts strings in the form of HH:MM:SS.mmmmmm
284 (created by datetime.time.isoformat()) to
285 datetime.time objects.
286
287 Timzone-aware strings ("HH:MM:SS.mmmmmm+HH:MM") won't
288 be handled right now and will raise TimeDecodeError.
289 """
290 if '-' in value or '+' in value:
291 # TODO: Handle tzinfo
292 raise TimeDecodeError("Can't handle timezone aware objects: %r" % va lue)
293 tmp = value.split('.')
294 arg = map(int, tmp[0].split(':'))
295 if len(tmp) == 2:
296 arg.append(int(tmp[1]))
297 return time(*arg)
298
273 def encode_reference(self, value): 299 def encode_reference(self, value):
274 if value in (None, 'None', '', ' '): 300 if value in (None, 'None', '', ' '):
275 return None 301 return None
276 if isinstance(value, str) or isinstance(value, unicode): 302 if isinstance(value, str) or isinstance(value, unicode):
277 return value 303 return value
278 else: 304 else:
279 return value.id 305 return value.id
280 306
281 def decode_reference(self, value): 307 def decode_reference(self, value):
282 if not value or value == "None": 308 if not value or value == "None":
(...skipping 24 matching lines...) Expand all
307 return value.id 333 return value.id
308 334
309 335
310 def decode_blob(self, value): 336 def decode_blob(self, value):
311 if not value: 337 if not value:
312 return None 338 return None
313 match = re.match("^s3:\/\/([^\/]*)\/(.*)$", value) 339 match = re.match("^s3:\/\/([^\/]*)\/(.*)$", value)
314 if match: 340 if match:
315 s3 = self.manager.get_s3_connection() 341 s3 = self.manager.get_s3_connection()
316 bucket = s3.get_bucket(match.group(1), validate=False) 342 bucket = s3.get_bucket(match.group(1), validate=False)
317 key = bucket.get_key(match.group(2)) 343 try:
344 key = bucket.get_key(match.group(2))
345 except S3ResponseError, e:
346 if e.reason != "Forbidden":
347 raise
348 return None
318 else: 349 else:
319 return None 350 return None
320 if key: 351 if key:
321 return Blob(file=key, id="s3://%s/%s" % (key.bucket.name, key.name)) 352 return Blob(file=key, id="s3://%s/%s" % (key.bucket.name, key.name))
322 else: 353 else:
323 return None 354 return None
324 355
356 def encode_string(self, value):
357 """Convert ASCII, Latin-1 or UTF-8 to pure Unicode"""
358 if not isinstance(value, str): return value
359 try:
360 return unicode(value, 'utf-8')
361 except: # really, this should throw an exception.
362 # in the interest of not breaking current
363 # systems, however:
364 arr = []
365 for ch in value:
366 arr.append(unichr(ord(ch)))
367 return u"".join(arr)
368
369 def decode_string(self, value):
370 """Decoding a string is really nothing, just
371 return the value as-is"""
372 return value
373
325 class SDBManager(object): 374 class SDBManager(object):
326 375
327 def __init__(self, cls, db_name, db_user, db_passwd, 376 def __init__(self, cls, db_name, db_user, db_passwd,
328 db_host, db_port, db_table, ddl_dir, enable_ssl, consistent=Non e): 377 db_host, db_port, db_table, ddl_dir, enable_ssl, consistent=Non e):
329 self.cls = cls 378 self.cls = cls
330 self.db_name = db_name 379 self.db_name = db_name
331 self.db_user = db_user 380 self.db_user = db_user
332 self.db_passwd = db_passwd 381 self.db_passwd = db_passwd
333 self.db_host = db_host 382 self.db_host = db_host
334 self.db_port = db_port 383 self.db_port = db_port
(...skipping 15 matching lines...) Expand all
350 self._connect() 399 self._connect()
351 return self._sdb 400 return self._sdb
352 401
353 @property 402 @property
354 def domain(self): 403 def domain(self):
355 if self._domain is None: 404 if self._domain is None:
356 self._connect() 405 self._connect()
357 return self._domain 406 return self._domain
358 407
359 def _connect(self): 408 def _connect(self):
360 self._sdb = boto.connect_sdb(aws_access_key_id=self.db_user, 409 args = dict(aws_access_key_id=self.db_user,
361 aws_secret_access_key=self.db_passwd, 410 aws_secret_access_key=self.db_passwd,
362 is_secure=self.enable_ssl) 411 is_secure=self.enable_ssl)
412 try:
413 region = [x for x in boto.sdb.regions() if x.endpoint == self.db_hos t][0]
414 args['region'] = region
415 except IndexError:
416 pass
417 self._sdb = boto.connect_sdb(**args)
363 # This assumes that the domain has already been created 418 # This assumes that the domain has already been created
364 # It's much more efficient to do it this way rather than 419 # It's much more efficient to do it this way rather than
365 # having this make a roundtrip each time to validate. 420 # having this make a roundtrip each time to validate.
366 # The downside is that if the domain doesn't exist, it breaks 421 # The downside is that if the domain doesn't exist, it breaks
367 self._domain = self._sdb.lookup(self.db_name, validate=False) 422 self._domain = self._sdb.lookup(self.db_name, validate=False)
368 if not self._domain: 423 if not self._domain:
369 self._domain = self._sdb.create_domain(self.db_name) 424 self._domain = self._sdb.create_domain(self.db_name)
370 425
371 def _object_lister(self, cls, query_lister): 426 def _object_lister(self, cls, query_lister):
372 for item in query_lister: 427 for item in query_lister:
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 if not(op in ["like", "not like"] and val.startswith("%")): 534 if not(op in ["like", "not like"] and val.startswith("%")):
480 val = "%%:%s" % val 535 val = "%%:%s" % val
481 return "%s %s '%s'" % (name, op, val.replace("'", "''")) 536 return "%s %s '%s'" % (name, op, val.replace("'", "''"))
482 537
483 def _build_filter_part(self, cls, filters, order_by=None, select=None): 538 def _build_filter_part(self, cls, filters, order_by=None, select=None):
484 """ 539 """
485 Build the filter part 540 Build the filter part
486 """ 541 """
487 import types 542 import types
488 query_parts = [] 543 query_parts = []
544
489 order_by_filtered = False 545 order_by_filtered = False
546
490 if order_by: 547 if order_by:
491 if order_by[0] == "-": 548 if order_by[0] == "-":
492 order_by_method = "DESC"; 549 order_by_method = "DESC";
493 order_by = order_by[1:] 550 order_by = order_by[1:]
494 else: 551 else:
495 order_by_method = "ASC"; 552 order_by_method = "ASC";
553
554 if select:
555 if order_by and order_by in select:
556 order_by_filtered = True
557 query_parts.append("(%s)" % select)
558
496 if isinstance(filters, str) or isinstance(filters, unicode): 559 if isinstance(filters, str) or isinstance(filters, unicode):
497 query = "WHERE `__type__` = '%s' AND %s" % (cls.__name__, filters) 560 query = "WHERE %s AND `__type__` = '%s'" % (filters, cls.__name__)
498 if order_by != None: 561 if order_by in ["__id__", "itemName()"]:
562 query += " ORDER BY itemName() %s" % order_by_method
563 elif order_by != None:
499 query += " ORDER BY `%s` %s" % (order_by, order_by_method) 564 query += " ORDER BY `%s` %s" % (order_by, order_by_method)
500 return query 565 return query
501 566
502 for filter in filters: 567 for filter in filters:
503 filter_parts = [] 568 filter_parts = []
504 filter_props = filter[0] 569 filter_props = filter[0]
505 if type(filter_props) != list: 570 if type(filter_props) != list:
506 filter_props = [filter_props] 571 filter_props = [filter_props]
507 for filter_prop in filter_props: 572 for filter_prop in filter_props:
508 (name, op) = filter_prop.strip().split(" ", 1) 573 (name, op) = filter_prop.strip().split(" ", 1)
(...skipping 21 matching lines...) Expand all
530 query_parts.append("(%s)" % (" or ".join(filter_parts))) 595 query_parts.append("(%s)" % (" or ".join(filter_parts)))
531 596
532 597
533 type_query = "(`__type__` = '%s'" % cls.__name__ 598 type_query = "(`__type__` = '%s'" % cls.__name__
534 for subclass in self._get_all_decendents(cls).keys(): 599 for subclass in self._get_all_decendents(cls).keys():
535 type_query += " or `__type__` = '%s'" % subclass 600 type_query += " or `__type__` = '%s'" % subclass
536 type_query +=")" 601 type_query +=")"
537 query_parts.append(type_query) 602 query_parts.append(type_query)
538 603
539 order_by_query = "" 604 order_by_query = ""
605
540 if order_by: 606 if order_by:
541 if not order_by_filtered: 607 if not order_by_filtered:
542 query_parts.append("`%s` LIKE '%%'" % order_by) 608 query_parts.append("`%s` LIKE '%%'" % order_by)
543 order_by_query = " ORDER BY `%s` %s" % (order_by, order_by_method) 609 if order_by in ["__id__", "itemName()"]:
544 610 order_by_query = " ORDER BY itemName() %s" % order_by_method
545 if select: 611 else:
546 query_parts.append("(%s)" % select) 612 order_by_query = " ORDER BY `%s` %s" % (order_by, order_by_metho d)
547 613
548 if len(query_parts) > 0: 614 if len(query_parts) > 0:
549 return "WHERE %s %s" % (" AND ".join(query_parts), order_by_query) 615 return "WHERE %s %s" % (" AND ".join(query_parts), order_by_query)
550 else: 616 else:
551 return "" 617 return ""
552 618
553 619
554 def _get_all_decendents(self, cls): 620 def _get_all_decendents(self, cls):
555 """Get all decendents for a given class""" 621 """Get all decendents for a given class"""
556 decendents = {} 622 decendents = {}
557 for sc in cls.__sub_classes__: 623 for sc in cls.__sub_classes__:
558 decendents[sc.__name__] = sc 624 decendents[sc.__name__] = sc
559 decendents.update(self._get_all_decendents(sc)) 625 decendents.update(self._get_all_decendents(sc))
560 return decendents 626 return decendents
561 627
562 def query_gql(self, query_string, *args, **kwds): 628 def query_gql(self, query_string, *args, **kwds):
563 raise NotImplementedError, "GQL queries not supported in SimpleDB" 629 raise NotImplementedError, "GQL queries not supported in SimpleDB"
564 630
565 def save_object(self, obj): 631 def save_object(self, obj, expected_value=None):
566 if not obj.id: 632 if not obj.id:
567 obj.id = str(uuid.uuid4()) 633 obj.id = str(uuid.uuid4())
568 634
569 attrs = {'__type__' : obj.__class__.__name__, 635 attrs = {'__type__' : obj.__class__.__name__,
570 '__module__' : obj.__class__.__module__, 636 '__module__' : obj.__class__.__module__,
571 '__lineage__' : obj.get_lineage()} 637 '__lineage__' : obj.get_lineage()}
572 del_attrs = [] 638 del_attrs = []
573 for property in obj.properties(hidden=False): 639 for property in obj.properties(hidden=False):
574 value = property.get_value_for_datastore(obj) 640 value = property.get_value_for_datastore(obj)
575 if value is not None: 641 if value is not None:
576 value = self.encode_value(property, value) 642 value = self.encode_value(property, value)
577 if value == []: 643 if value == []:
578 value = None 644 value = None
579 if value == None: 645 if value == None:
580 del_attrs.append(property.name) 646 del_attrs.append(property.name)
581 continue 647 continue
582 attrs[property.name] = value 648 attrs[property.name] = value
583 if property.unique: 649 if property.unique:
584 try: 650 try:
585 args = {property.name: value} 651 args = {property.name: value}
586 obj2 = obj.find(**args).next() 652 obj2 = obj.find(**args).next()
587 if obj2.id != obj.id: 653 if obj2.id != obj.id:
588 raise SDBPersistenceError("Error: %s must be unique!" % property.name) 654 raise SDBPersistenceError("Error: %s must be unique!" % property.name)
589 except(StopIteration): 655 except(StopIteration):
590 pass 656 pass
591 self.domain.put_attributes(obj.id, attrs, replace=True) 657 # Convert the Expected value to SDB format
658 if expected_value:
659 prop = obj.find_property(expected_value[0])
660 v = expected_value[1]
661 if v is not None and not type(v) == bool:
662 v = self.encode_value(prop, v)
663 expected_value[1] = v
664 self.domain.put_attributes(obj.id, attrs, replace=True, expected_value=e xpected_value)
592 if len(del_attrs) > 0: 665 if len(del_attrs) > 0:
593 self.domain.delete_attributes(obj.id, del_attrs) 666 self.domain.delete_attributes(obj.id, del_attrs)
594 return obj 667 return obj
595 668
596 def delete_object(self, obj): 669 def delete_object(self, obj):
597 self.domain.delete_attributes(obj.id) 670 self.domain.delete_attributes(obj.id)
598 671
599 def set_property(self, prop, obj, name, value): 672 def set_property(self, prop, obj, name, value):
673 setattr(obj, name, value)
600 value = prop.get_value_for_datastore(obj) 674 value = prop.get_value_for_datastore(obj)
601 value = self.encode_value(prop, value) 675 value = self.encode_value(prop, value)
602 if prop.unique: 676 if prop.unique:
603 try: 677 try:
604 args = {prop.name: value} 678 args = {prop.name: value}
605 obj2 = obj.find(**args).next() 679 obj2 = obj.find(**args).next()
606 if obj2.id != obj.id: 680 if obj2.id != obj.id:
607 raise SDBPersistenceError("Error: %s must be unique!" % prop .name) 681 raise SDBPersistenceError("Error: %s must be unique!" % prop .name)
608 except(StopIteration): 682 except(StopIteration):
609 pass 683 pass
(...skipping 19 matching lines...) Expand all
629 def get_key_value(self, obj, name): 703 def get_key_value(self, obj, name):
630 a = self.domain.get_attributes(obj.id, name,consistent_read=self.consist ent) 704 a = self.domain.get_attributes(obj.id, name,consistent_read=self.consist ent)
631 if a.has_key(name): 705 if a.has_key(name):
632 return a[name] 706 return a[name]
633 else: 707 else:
634 return None 708 return None
635 709
636 def get_raw_item(self, obj): 710 def get_raw_item(self, obj):
637 return self.domain.get_item(obj.id) 711 return self.domain.get_item(obj.id)
638 712
OLDNEW
« no previous file with comments | « boto/sdb/db/manager/pgmanager.py ('k') | boto/sdb/db/manager/xmlmanager.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698