comparison env/lib/python3.7/site-packages/boto/dynamodb/table.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 # Copyright (c) 2012 Mitch Garnaat http://garnaat.org/
2 # Copyright (c) 2012 Amazon.com, Inc. or its affiliates. All Rights Reserved
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
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
9 # persons to whom the Software is furnished to do so, subject to the fol-
10 # lowing conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
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-
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,
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
21 # IN THE SOFTWARE.
22 #
23
24 from boto.dynamodb.batch import BatchList
25 from boto.dynamodb.schema import Schema
26 from boto.dynamodb.item import Item
27 from boto.dynamodb import exceptions as dynamodb_exceptions
28 import time
29
30
31 class TableBatchGenerator(object):
32 """
33 A low-level generator used to page through results from
34 batch_get_item operations.
35
36 :ivar consumed_units: An integer that holds the number of
37 ConsumedCapacityUnits accumulated thus far for this
38 generator.
39 """
40
41 def __init__(self, table, keys, attributes_to_get=None,
42 consistent_read=False):
43 self.table = table
44 self.keys = keys
45 self.consumed_units = 0
46 self.attributes_to_get = attributes_to_get
47 self.consistent_read = consistent_read
48
49 def _queue_unprocessed(self, res):
50 if u'UnprocessedKeys' not in res:
51 return
52 if self.table.name not in res[u'UnprocessedKeys']:
53 return
54
55 keys = res[u'UnprocessedKeys'][self.table.name][u'Keys']
56
57 for key in keys:
58 h = key[u'HashKeyElement']
59 r = key[u'RangeKeyElement'] if u'RangeKeyElement' in key else None
60 self.keys.append((h, r))
61
62 def __iter__(self):
63 while self.keys:
64 # Build the next batch
65 batch = BatchList(self.table.layer2)
66 batch.add_batch(self.table, self.keys[:100],
67 self.attributes_to_get)
68 res = batch.submit()
69
70 # parse the results
71 if self.table.name not in res[u'Responses']:
72 continue
73 self.consumed_units += res[u'Responses'][self.table.name][u'ConsumedCapacityUnits']
74 for elem in res[u'Responses'][self.table.name][u'Items']:
75 yield elem
76
77 # re-queue un processed keys
78 self.keys = self.keys[100:]
79 self._queue_unprocessed(res)
80
81
82 class Table(object):
83 """
84 An Amazon DynamoDB table.
85
86 :ivar name: The name of the table.
87 :ivar create_time: The date and time that the table was created.
88 :ivar status: The current status of the table. One of:
89 'ACTIVE', 'UPDATING', 'DELETING'.
90 :ivar schema: A :class:`boto.dynamodb.schema.Schema` object representing
91 the schema defined for the table.
92 :ivar item_count: The number of items in the table. This value is
93 set only when the Table object is created or refreshed and
94 may not reflect the actual count.
95 :ivar size_bytes: Total size of the specified table, in bytes.
96 Amazon DynamoDB updates this value approximately every six hours.
97 Recent changes might not be reflected in this value.
98 :ivar read_units: The ReadCapacityUnits of the tables
99 Provisioned Throughput.
100 :ivar write_units: The WriteCapacityUnits of the tables
101 Provisioned Throughput.
102 :ivar schema: The Schema object associated with the table.
103 """
104
105 def __init__(self, layer2, response):
106 """
107
108 :type layer2: :class:`boto.dynamodb.layer2.Layer2`
109 :param layer2: A `Layer2` api object.
110
111 :type response: dict
112 :param response: The output of
113 `boto.dynamodb.layer1.Layer1.describe_table`.
114
115 """
116 self.layer2 = layer2
117 self._dict = {}
118 self.update_from_response(response)
119
120 @classmethod
121 def create_from_schema(cls, layer2, name, schema):
122 """Create a Table object.
123
124 If you know the name and schema of your table, you can
125 create a ``Table`` object without having to make any
126 API calls (normally an API call is made to retrieve
127 the schema of a table).
128
129 Example usage::
130
131 table = Table.create_from_schema(
132 boto.connect_dynamodb(),
133 'tablename',
134 Schema.create(hash_key=('keyname', 'N')))
135
136 :type layer2: :class:`boto.dynamodb.layer2.Layer2`
137 :param layer2: A ``Layer2`` api object.
138
139 :type name: str
140 :param name: The name of the table.
141
142 :type schema: :class:`boto.dynamodb.schema.Schema`
143 :param schema: The schema associated with the table.
144
145 :rtype: :class:`boto.dynamodb.table.Table`
146 :return: A Table object representing the table.
147
148 """
149 table = cls(layer2, {'Table': {'TableName': name}})
150 table._schema = schema
151 return table
152
153 def __repr__(self):
154 return 'Table(%s)' % self.name
155
156 @property
157 def name(self):
158 return self._dict['TableName']
159
160 @property
161 def create_time(self):
162 return self._dict.get('CreationDateTime', None)
163
164 @property
165 def status(self):
166 return self._dict.get('TableStatus', None)
167
168 @property
169 def item_count(self):
170 return self._dict.get('ItemCount', 0)
171
172 @property
173 def size_bytes(self):
174 return self._dict.get('TableSizeBytes', 0)
175
176 @property
177 def schema(self):
178 return self._schema
179
180 @property
181 def read_units(self):
182 try:
183 return self._dict['ProvisionedThroughput']['ReadCapacityUnits']
184 except KeyError:
185 return None
186
187 @property
188 def write_units(self):
189 try:
190 return self._dict['ProvisionedThroughput']['WriteCapacityUnits']
191 except KeyError:
192 return None
193
194 def update_from_response(self, response):
195 """
196 Update the state of the Table object based on the response
197 data received from Amazon DynamoDB.
198 """
199 # 'Table' is from a describe_table call.
200 if 'Table' in response:
201 self._dict.update(response['Table'])
202 # 'TableDescription' is from a create_table call.
203 elif 'TableDescription' in response:
204 self._dict.update(response['TableDescription'])
205 if 'KeySchema' in self._dict:
206 self._schema = Schema(self._dict['KeySchema'])
207
208 def refresh(self, wait_for_active=False, retry_seconds=5):
209 """
210 Refresh all of the fields of the Table object by calling
211 the underlying DescribeTable request.
212
213 :type wait_for_active: bool
214 :param wait_for_active: If True, this command will not return
215 until the table status, as returned from Amazon DynamoDB, is
216 'ACTIVE'.
217
218 :type retry_seconds: int
219 :param retry_seconds: If wait_for_active is True, this
220 parameter controls the number of seconds of delay between
221 calls to update_table in Amazon DynamoDB. Default is 5 seconds.
222 """
223 done = False
224 while not done:
225 response = self.layer2.describe_table(self.name)
226 self.update_from_response(response)
227 if wait_for_active:
228 if self.status == 'ACTIVE':
229 done = True
230 else:
231 time.sleep(retry_seconds)
232 else:
233 done = True
234
235 def update_throughput(self, read_units, write_units):
236 """
237 Update the ProvisionedThroughput for the Amazon DynamoDB Table.
238
239 :type read_units: int
240 :param read_units: The new value for ReadCapacityUnits.
241
242 :type write_units: int
243 :param write_units: The new value for WriteCapacityUnits.
244 """
245 self.layer2.update_throughput(self, read_units, write_units)
246
247 def delete(self):
248 """
249 Delete this table and all items in it. After calling this
250 the Table objects status attribute will be set to 'DELETING'.
251 """
252 self.layer2.delete_table(self)
253
254 def get_item(self, hash_key, range_key=None,
255 attributes_to_get=None, consistent_read=False,
256 item_class=Item):
257 """
258 Retrieve an existing item from the table.
259
260 :type hash_key: int|long|float|str|unicode|Binary
261 :param hash_key: The HashKey of the requested item. The
262 type of the value must match the type defined in the
263 schema for the table.
264
265 :type range_key: int|long|float|str|unicode|Binary
266 :param range_key: The optional RangeKey of the requested item.
267 The type of the value must match the type defined in the
268 schema for the table.
269
270 :type attributes_to_get: list
271 :param attributes_to_get: A list of attribute names.
272 If supplied, only the specified attribute names will
273 be returned. Otherwise, all attributes will be returned.
274
275 :type consistent_read: bool
276 :param consistent_read: If True, a consistent read
277 request is issued. Otherwise, an eventually consistent
278 request is issued.
279
280 :type item_class: Class
281 :param item_class: Allows you to override the class used
282 to generate the items. This should be a subclass of
283 :class:`boto.dynamodb.item.Item`
284 """
285 return self.layer2.get_item(self, hash_key, range_key,
286 attributes_to_get, consistent_read,
287 item_class)
288 lookup = get_item
289
290 def has_item(self, hash_key, range_key=None, consistent_read=False):
291 """
292 Checks the table to see if the Item with the specified ``hash_key``
293 exists. This may save a tiny bit of time/bandwidth over a
294 straight :py:meth:`get_item` if you have no intention to touch
295 the data that is returned, since this method specifically tells
296 Amazon not to return anything but the Item's key.
297
298 :type hash_key: int|long|float|str|unicode|Binary
299 :param hash_key: The HashKey of the requested item. The
300 type of the value must match the type defined in the
301 schema for the table.
302
303 :type range_key: int|long|float|str|unicode|Binary
304 :param range_key: The optional RangeKey of the requested item.
305 The type of the value must match the type defined in the
306 schema for the table.
307
308 :type consistent_read: bool
309 :param consistent_read: If True, a consistent read
310 request is issued. Otherwise, an eventually consistent
311 request is issued.
312
313 :rtype: bool
314 :returns: ``True`` if the Item exists, ``False`` if not.
315 """
316 try:
317 # Attempt to get the key. If it can't be found, it'll raise
318 # an exception.
319 self.get_item(hash_key, range_key=range_key,
320 # This minimizes the size of the response body.
321 attributes_to_get=[hash_key],
322 consistent_read=consistent_read)
323 except dynamodb_exceptions.DynamoDBKeyNotFoundError:
324 # Key doesn't exist.
325 return False
326 return True
327
328 def new_item(self, hash_key=None, range_key=None, attrs=None,
329 item_class=Item):
330 """
331 Return an new, unsaved Item which can later be PUT to
332 Amazon DynamoDB.
333
334 This method has explicit (but optional) parameters for
335 the hash_key and range_key values of the item. You can use
336 these explicit parameters when calling the method, such as::
337
338 >>> my_item = my_table.new_item(hash_key='a', range_key=1,
339 attrs={'key1': 'val1', 'key2': 'val2'})
340 >>> my_item
341 {u'bar': 1, u'foo': 'a', 'key1': 'val1', 'key2': 'val2'}
342
343 Or, if you prefer, you can simply put the hash_key and range_key
344 in the attrs dictionary itself, like this::
345
346 >>> attrs = {'foo': 'a', 'bar': 1, 'key1': 'val1', 'key2': 'val2'}
347 >>> my_item = my_table.new_item(attrs=attrs)
348 >>> my_item
349 {u'bar': 1, u'foo': 'a', 'key1': 'val1', 'key2': 'val2'}
350
351 The effect is the same.
352
353 .. note:
354 The explicit parameters take priority over the values in
355 the attrs dict. So, if you have a hash_key or range_key
356 in the attrs dict and you also supply either or both using
357 the explicit parameters, the values in the attrs will be
358 ignored.
359
360 :type hash_key: int|long|float|str|unicode|Binary
361 :param hash_key: The HashKey of the new item. The
362 type of the value must match the type defined in the
363 schema for the table.
364
365 :type range_key: int|long|float|str|unicode|Binary
366 :param range_key: The optional RangeKey of the new item.
367 The type of the value must match the type defined in the
368 schema for the table.
369
370 :type attrs: dict
371 :param attrs: A dictionary of key value pairs used to
372 populate the new item.
373
374 :type item_class: Class
375 :param item_class: Allows you to override the class used
376 to generate the items. This should be a subclass of
377 :class:`boto.dynamodb.item.Item`
378 """
379 return item_class(self, hash_key, range_key, attrs)
380
381 def query(self, hash_key, *args, **kw):
382 """
383 Perform a query on the table.
384
385 :type hash_key: int|long|float|str|unicode|Binary
386 :param hash_key: The HashKey of the requested item. The
387 type of the value must match the type defined in the
388 schema for the table.
389
390 :type range_key_condition: :class:`boto.dynamodb.condition.Condition`
391 :param range_key_condition: A Condition object.
392 Condition object can be one of the following types:
393
394 EQ|LE|LT|GE|GT|BEGINS_WITH|BETWEEN
395
396 The only condition which expects or will accept two
397 values is 'BETWEEN', otherwise a single value should
398 be passed to the Condition constructor.
399
400 :type attributes_to_get: list
401 :param attributes_to_get: A list of attribute names.
402 If supplied, only the specified attribute names will
403 be returned. Otherwise, all attributes will be returned.
404
405 :type request_limit: int
406 :param request_limit: The maximum number of items to retrieve
407 from Amazon DynamoDB on each request. You may want to set
408 a specific request_limit based on the provisioned throughput
409 of your table. The default behavior is to retrieve as many
410 results as possible per request.
411
412 :type max_results: int
413 :param max_results: The maximum number of results that will
414 be retrieved from Amazon DynamoDB in total. For example,
415 if you only wanted to see the first 100 results from the
416 query, regardless of how many were actually available, you
417 could set max_results to 100 and the generator returned
418 from the query method will only yeild 100 results max.
419
420 :type consistent_read: bool
421 :param consistent_read: If True, a consistent read
422 request is issued. Otherwise, an eventually consistent
423 request is issued.
424
425 :type scan_index_forward: bool
426 :param scan_index_forward: Specified forward or backward
427 traversal of the index. Default is forward (True).
428
429 :type exclusive_start_key: list or tuple
430 :param exclusive_start_key: Primary key of the item from
431 which to continue an earlier query. This would be
432 provided as the LastEvaluatedKey in that query.
433
434 :type count: bool
435 :param count: If True, Amazon DynamoDB returns a total
436 number of items for the Query operation, even if the
437 operation has no matching items for the assigned filter.
438 If count is True, the actual items are not returned and
439 the count is accessible as the ``count`` attribute of
440 the returned object.
441
442
443 :type item_class: Class
444 :param item_class: Allows you to override the class used
445 to generate the items. This should be a subclass of
446 :class:`boto.dynamodb.item.Item`
447 """
448 return self.layer2.query(self, hash_key, *args, **kw)
449
450 def scan(self, *args, **kw):
451 """
452 Scan through this table, this is a very long
453 and expensive operation, and should be avoided if
454 at all possible.
455
456 :type scan_filter: A dict
457 :param scan_filter: A dictionary where the key is the
458 attribute name and the value is a
459 :class:`boto.dynamodb.condition.Condition` object.
460 Valid Condition objects include:
461
462 * EQ - equal (1)
463 * NE - not equal (1)
464 * LE - less than or equal (1)
465 * LT - less than (1)
466 * GE - greater than or equal (1)
467 * GT - greater than (1)
468 * NOT_NULL - attribute exists (0, use None)
469 * NULL - attribute does not exist (0, use None)
470 * CONTAINS - substring or value in list (1)
471 * NOT_CONTAINS - absence of substring or value in list (1)
472 * BEGINS_WITH - substring prefix (1)
473 * IN - exact match in list (N)
474 * BETWEEN - >= first value, <= second value (2)
475
476 :type attributes_to_get: list
477 :param attributes_to_get: A list of attribute names.
478 If supplied, only the specified attribute names will
479 be returned. Otherwise, all attributes will be returned.
480
481 :type request_limit: int
482 :param request_limit: The maximum number of items to retrieve
483 from Amazon DynamoDB on each request. You may want to set
484 a specific request_limit based on the provisioned throughput
485 of your table. The default behavior is to retrieve as many
486 results as possible per request.
487
488 :type max_results: int
489 :param max_results: The maximum number of results that will
490 be retrieved from Amazon DynamoDB in total. For example,
491 if you only wanted to see the first 100 results from the
492 query, regardless of how many were actually available, you
493 could set max_results to 100 and the generator returned
494 from the query method will only yeild 100 results max.
495
496 :type count: bool
497 :param count: If True, Amazon DynamoDB returns a total
498 number of items for the Scan operation, even if the
499 operation has no matching items for the assigned filter.
500 If count is True, the actual items are not returned and
501 the count is accessible as the ``count`` attribute of
502 the returned object.
503
504 :type exclusive_start_key: list or tuple
505 :param exclusive_start_key: Primary key of the item from
506 which to continue an earlier query. This would be
507 provided as the LastEvaluatedKey in that query.
508
509 :type item_class: Class
510 :param item_class: Allows you to override the class used
511 to generate the items. This should be a subclass of
512 :class:`boto.dynamodb.item.Item`
513
514 :return: A TableGenerator (generator) object which will iterate
515 over all results
516 :rtype: :class:`boto.dynamodb.layer2.TableGenerator`
517 """
518 return self.layer2.scan(self, *args, **kw)
519
520 def batch_get_item(self, keys, attributes_to_get=None):
521 """
522 Return a set of attributes for a multiple items from a single table
523 using their primary keys. This abstraction removes the 100 Items per
524 batch limitations as well as the "UnprocessedKeys" logic.
525
526 :type keys: list
527 :param keys: A list of scalar or tuple values. Each element in the
528 list represents one Item to retrieve. If the schema for the
529 table has both a HashKey and a RangeKey, each element in the
530 list should be a tuple consisting of (hash_key, range_key). If
531 the schema for the table contains only a HashKey, each element
532 in the list should be a scalar value of the appropriate type
533 for the table schema. NOTE: The maximum number of items that
534 can be retrieved for a single operation is 100. Also, the
535 number of items retrieved is constrained by a 1 MB size limit.
536
537 :type attributes_to_get: list
538 :param attributes_to_get: A list of attribute names.
539 If supplied, only the specified attribute names will
540 be returned. Otherwise, all attributes will be returned.
541
542 :return: A TableBatchGenerator (generator) object which will
543 iterate over all results
544 :rtype: :class:`boto.dynamodb.table.TableBatchGenerator`
545 """
546 return TableBatchGenerator(self, keys, attributes_to_get)