def test_unicode_deserialize(self): """ UnicodeAttribute.deserialize """ attr = UnicodeAttribute() assert attr.deserialize('foo') == six.u('foo') assert attr.deserialize(u'foo') == six.u('foo')
def test_unicode_deserialize(self): """ UnicodeAttribute.deserialize """ attr = UnicodeAttribute() self.assertEqual(attr.deserialize('foo'), six.u('foo')) self.assertEqual(attr.deserialize(u'foo'), six.u('foo'))
def test_unicode_serialize(self): """ UnicodeAttribute.serialize """ attr = UnicodeAttribute() assert attr.serialize('foo') == six.u('foo') assert attr.serialize(u'foo') == six.u('foo') assert attr.serialize(u'') is None assert attr.serialize(None) is None
def test_unicode_serialize(self): """ UnicodeAttribute.serialize """ attr = UnicodeAttribute() self.assertEqual(attr.serialize("foo"), six.u("foo")) self.assertEqual(attr.serialize(u"foo"), six.u("foo")) self.assertEqual(attr.serialize(u""), None) self.assertEqual(attr.serialize(None), None)
def test_unicode_serialize(self): """ UnicodeAttribute.serialize """ attr = UnicodeAttribute() self.assertEqual(attr.serialize('foo'), six.u('foo')) self.assertEqual(attr.serialize(u'foo'), six.u('foo')) self.assertEqual(attr.serialize(u''), None) self.assertEqual(attr.serialize(None), None)
class Photo(Model): """ Photo table for DynamoDB """ class Meta: table_name = 'Photo' region = AWS_REGION user_id = UnicodeAttribute(hash_key=True) id = UnicodeAttribute(range_key=True) tags = UnicodeAttribute(null=True) desc = UnicodeAttribute(null=True) filename_orig = UnicodeAttribute(null=True) filename = UnicodeAttribute(null=True) filesize = NumberAttribute(null=True) geotag_lat = UnicodeAttribute(null=True) geotag_lng = UnicodeAttribute(null=True) upload_date = UTCDateTimeAttribute(default=datetime.now(get_localzone())) taken_date = UTCDateTimeAttribute(null=True) make = UnicodeAttribute(null=True) model = UnicodeAttribute(null=True) width = UnicodeAttribute(null=True) height = UnicodeAttribute(null=True) city = UnicodeAttribute(null=True) nation = UnicodeAttribute(null=True) address = UnicodeAttribute(null=True)
class UserModel(Model): """ DYnamoDB UserModel """ class Meta(): table_name = os.environ['usersTable'] if 'IS_LOCAL' in os.environ: host = 'http://localhost:8000' else: region = os.environ['AWS_REGION'] host = 'https://dynamodb.{}.amazonaws.com'.format(region) id = UnicodeAttribute(hash_key = True) email = UnicodeAttribute() users_gsi_email = EmailIndex() userToken = UnicodeAttribute(null = True) users_gsi_userToken = UserTokonIndex() name = UnicodeAttribute() phoneNumber = UnicodeAttribute() expiry = UTCDateTimeAttribute(null = True) password = UnicodeAttribute() createdAt = UTCDateTimeAttribute(default = datetime.now()) updatedAt = UTCDateTimeAttribute(default = datetime.now()) lastLogin = UTCDateTimeAttribute(default = datetime.now()) deleteFlag = BooleanAttribute(default = False) def __iter__(self): for name, attr in self.get_attributes().items(): if name not in ['deleteFlag', 'password', 'userToken', 'expiry']: yield name, attr.serialize(getattr(self, name)) @classmethod def get(cls, hash_key, range_key=None, consistent_read=False, attributes_to_get=None): """ override: get() """ user = super().get(hash_key, range_key, consistent_read, attributes_to_get) if not user.deleteFlag: return user else: raise cls.DoesNotExist() def update(self, actions = [], condition = None): actions.append(UserModel.updatedAt.set(datetime.now())) super().update(actions, condition) def save(self, condition = None): self.before_save() self.updatedAt = datetime.now() super().save(condition) def before_save(self): # validation for name if not self.name: raise InvalidNameError('The name attribute has not to be empty') if not isinstance(self.name, str): raise InvalidNameError('The name attribute has to be string') # validation for phoneNumber if not self.phoneNumber: raise InvalidPhoneNumberError('The phoneNumber attribute has not to be empty') if not isinstance(self.phoneNumber, str): raise InvalidPhoneNumberError('The phoneNumber attribute has to be string') if not re.match(r'^0\d{9,10}$', self.phoneNumber): raise InvalidPhoneNumberError('Invalid phoneNumber') # validation for email if not self.email: raise InvalidEmailError('The email attribute has to be string') if not isinstance(self.email, str): raise InvalidEmailError('The email attribute has not to be empty') if not re.match(r'[A-Za-z0-9\._+]+@[A-Za-z]+\.[A-Za-z]', self.email): raise InvalidEmailError('Invalid email') if self.email_uniqueness(): raise InvalidEmailError('This email has been registered') def logic_delete(self): """ change deleteFlag to True """ actions = [ UserModel.deleteFlag.set(True), UserModel.userToken.remove(), UserModel.expiry.remove() ] self.update(actions) def email_uniqueness(self): check = UserModel.users_gsi_email.query( self.email, UserModel.deleteFlag == False ) check = [ele for ele in check] if len(check) == 0: return False else: if self.id == check[0].id: return False else: return True def get_tasks(self): tasks = models.task_model.TaskModel.scan( (models.task_model.TaskModel.userIds.contains(self.id)) & (models.task_model.TaskModel.deleteFlag == False) ) return tasks def hash_password(self): if not self.password: raise InvalidPasswordError('no password') if not isinstance(self.password, str): raise InvalidPasswordError('password must be string') if len(self.password) < 8: raise InvalidPasswordError('password is longer than 8') hash = hashlib.sha256() hash.update(self.password.encode() + self.email.encode()) self.password = hash.hexdigest() def create_token(self): self.userToken = secrets.token_hex() self.expiry = datetime.now() + timedelta(weeks = 2) def get_expiry(self): return self.get_attributes()['expiry'].serialize(self.expiry)
class MessageAttribute(MapAttribute): MessageContent = UnicodeAttribute(null=False) ImagePath = UnicodeAttribute(null=True) Timestamp = UTCDateTimeAttribute(null=True)
class CustomAttrMap(MapAttribute): overridden_number_attr = NumberAttribute(attr_name="number_attr") overridden_unicode_attr = UnicodeAttribute(attr_name="unicode_attr")
class UpdateExpressionTestCase(TestCase): def setUp(self): self.attribute = UnicodeAttribute(attr_name='foo') self.list_attribute = ListAttribute(attr_name='foo_list', default=[]) def test_set_action(self): action = self.attribute.set('bar') placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_set_action_attribute_container(self): # Simulate initialization from inside an AttributeContainer my_map_attribute = MapAttribute(attr_name='foo') my_map_attribute._make_attribute() my_map_attribute._update_attribute_paths(my_map_attribute.attr_name) action = my_map_attribute.set(MapAttribute(bar='baz')) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'M': {'bar': {'S': 'baz'}}}} def test_increment_action(self): action = self.attribute.set(Path('bar') + 0) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = #1 + :0" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {':0': {'N': '0'}} def test_increment_action_value(self): action = self.attribute.set(Value(0) + Path('bar')) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0 + #1" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {':0': {'N': '0'}} def test_decrement_action(self): action = self.attribute.set(Path('bar') - 0) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = #1 - :0" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {':0': {'N': '0'}} def test_decrement_action_value(self): action = self.attribute.set(Value(0) - Path('bar')) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0 - #1" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {':0': {'N': '0'}} def test_append_action(self): action = self.attribute.set(Path('bar').append(['baz'])) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = list_append (#1, :0)" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {':0': {'L': [{'S': 'baz'}]}} def test_prepend_action(self): action = self.attribute.set(Path('bar').prepend(['baz'])) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = list_append (:0, #1)" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {':0': {'L': [{'S': 'baz'}]}} def test_conditional_set_action(self): action = self.attribute.set(Path('bar') | 'baz') placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = if_not_exists (#1, :0)" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {':0': {'S': 'baz'}} def test_remove_action(self): action = self.attribute.remove() placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {} def test_add_action(self): action = Path('foo').add(0) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'N': '0'}} def test_add_action_set(self): action = NumberSetAttribute(attr_name='foo').add(0, 1) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'NS': ['0', '1']}} def test_add_action_serialized(self): action = NumberSetAttribute(attr_name='foo').add({'NS': ['0']}) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'NS': ['0']}} def test_add_action_list(self): with self.assertRaises(ValueError): Path('foo').add({'L': [{'N': '0'}]}) def test_delete_action(self): action = NumberSetAttribute(attr_name='foo').delete(0, 1) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'NS': ['0', '1']}} def test_delete_action_set(self): action = NumberSetAttribute(attr_name='foo').delete({0, 1}) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'NS': ['0', '1']}} def test_delete_action_serialized(self): action = NumberSetAttribute(attr_name='foo').delete({'NS': ['0']}) placeholder_names, expression_attribute_values = {}, {} expression = action.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'NS': ['0']}} def test_delete_action_non_set(self): with self.assertRaises(ValueError): Path('foo').delete({'N': '0'}) def test_update(self): update = Update( self.attribute.set({'S': 'bar'}), self.attribute.remove(), self.attribute.add({'N': '0'}), self.attribute.delete({'NS': ['0']}) ) placeholder_names, expression_attribute_values = {}, {} expression = update.serialize(placeholder_names, expression_attribute_values) assert expression == "SET #0 = :0 REMOVE #0 ADD #0 :1 DELETE #0 :2" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == { ':0': {'S': 'bar'}, ':1': {'N': '0'}, ':2': {'NS': ['0']} } def test_list_update_remove_by_index(self): update = Update( self.list_attribute.remove_indexes(0), ) placeholder_names, expression_attribute_values = {}, {} expression = update.serialize(placeholder_names, expression_attribute_values) assert expression == "REMOVE #0[0]" assert placeholder_names == {'foo_list': '#0'} assert expression_attribute_values == {} update = Update( self.list_attribute.remove_indexes(0, 10), ) placeholder_names, expression_attribute_values = {}, {} expression = update.serialize(placeholder_names, expression_attribute_values) assert expression == "REMOVE #0[0], #0[10]" assert placeholder_names == {'foo_list': '#0'} assert expression_attribute_values == {} with self.assertRaises(ValueError) as e: Update(self.list_attribute.remove_indexes(0, "a")) assert str(e.exception) == "Method 'remove_indexes' arguments must be 'int'"
class ConditionExpressionTestCase(TestCase): def setUp(self): self.attribute = UnicodeAttribute(attr_name='foo') def test_equal(self): condition = self.attribute == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_not_equal(self): condition = self.attribute != 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 <> :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_less_than(self): condition = self.attribute < 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 < :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_less_than_or_equal(self): condition = self.attribute <= 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 <= :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_greater_than(self): condition = self.attribute > 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 > :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_greater_than_or_equal(self): condition = self.attribute >= 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 >= :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_between(self): condition = self.attribute.between('bar', 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 BETWEEN :0 AND :1" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_in(self): condition = self.attribute.is_in('bar', 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 IN (:0, :1)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_exists(self): condition = self.attribute.exists() placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "attribute_exists (#0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {} def test_does_not_exist(self): condition = self.attribute.does_not_exist() placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "attribute_not_exists (#0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {} def test_is_type(self): condition = self.attribute.is_type() placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "attribute_type (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'S'}} def test_begins_with(self): condition = self.attribute.startswith('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "begins_with (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains(self): condition = self.attribute.contains('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains_string_set(self): condition = UnicodeSetAttribute(attr_name='foo').contains('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains_number_set(self): condition = NumberSetAttribute(attr_name='foo').contains(1) placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'N' : '1'}} def test_contains_list(self): condition = ListAttribute(attr_name='foo').contains('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains_attribute(self): condition = ListAttribute(attr_name='foo').contains(Path('bar')) placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, #1)" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {} def test_size(self): condition = size(self.attribute) == 3 placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "size (#0) = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'N' : '3'}} def test_sizes(self): condition = size(self.attribute) == size(Path('bar')) placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "size (#0) = size (#1)" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {} def test_and(self): condition = (self.attribute < 'bar') & (self.attribute > 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(#0 < :0 AND #0 > :1)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_invalid_and(self): condition = self.attribute < 'bar' with self.assertRaises(TypeError): condition &= None def test_rand(self): condition = None condition &= self.attribute < 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 < :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_invalid_rand(self): condition = 42 with self.assertRaises(TypeError): condition &= self.attribute < 'bar' def test_or(self): condition = (self.attribute < 'bar') | (self.attribute > 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(#0 < :0 OR #0 > :1)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_invalid_or(self): condition = self.attribute < 'bar' with self.assertRaises(TypeError): condition |= None def test_not(self): condition = ~(self.attribute < 'bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(NOT #0 < :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_compound_logic(self): condition = (~(self.attribute < 'bar') & (self.attribute > 'baz')) | (self.attribute == 'foo') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(((NOT #0 < :0) AND #0 > :1) OR #0 = :2)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}, ':2': {'S': 'foo'}} def test_indexing(self): condition = ListAttribute(attr_name='foo')[0] == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0[0] = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_invalid_indexing(self): with self.assertRaises(TypeError): self.attribute[0] def test_double_indexing(self): condition = ListAttribute(attr_name='foo')[0][1] == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0[0][1] = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_map_comparison(self): # Simulate initialization from inside an AttributeContainer my_map_attribute = MapAttribute(attr_name='foo') my_map_attribute._make_attribute() my_map_attribute._update_attribute_paths(my_map_attribute.attr_name) condition = my_map_attribute == MapAttribute(bar='baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'M': {'bar': {'S': 'baz'}}}} def test_list_comparison(self): condition = ListAttribute(attr_name='foo') == ['bar', 'baz'] placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'L': [{'S' : 'bar'}, {'S': 'baz'}]}} def test_dotted_attribute_name(self): self.attribute.attr_name = 'foo.bar' condition = self.attribute == 'baz' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo.bar': '#0'} assert expression_attribute_values == {':0': {'S': 'baz'}} def test_map_attribute_indexing(self): # Simulate initialization from inside an AttributeContainer my_map_attribute = MapAttribute(attr_name='foo.bar') my_map_attribute._make_attribute() my_map_attribute._update_attribute_paths(my_map_attribute.attr_name) condition = my_map_attribute['foo'] == 'baz' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0.#1 = :0" assert placeholder_names == {'foo.bar': '#0', 'foo': '#1'} assert expression_attribute_values == {':0': {'S': 'baz'}} def test_map_attribute_dereference(self): class MyMapAttribute(MapAttribute): nested_string = self.attribute # Simulate initialization from inside an AttributeContainer my_map_attribute = MyMapAttribute(attr_name='foo.bar') my_map_attribute._make_attribute() my_map_attribute._update_attribute_paths(my_map_attribute.attr_name) condition = my_map_attribute.nested_string == 'baz' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0.#1 = :0" assert placeholder_names == {'foo.bar': '#0', 'foo': '#1'} assert expression_attribute_values == {':0': {'S': 'baz'}} def test_map_attribute_dereference_via_indexing(self): class MyMapAttribute(MapAttribute): nested_string = self.attribute # Simulate initialization from inside an AttributeContainer my_map_attribute = MyMapAttribute(attr_name='foo.bar') my_map_attribute._make_attribute() my_map_attribute._update_attribute_paths(my_map_attribute.attr_name) condition = my_map_attribute['nested_string'] == 'baz' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0.#1 = :0" assert placeholder_names == {'foo.bar': '#0', 'foo': '#1'} assert expression_attribute_values == {':0': {'S': 'baz'}} def test_map_attribute_dereference_via_indexing_missing_attribute(self): class MyMapAttribute(MapAttribute): nested_string = self.attribute # Simulate initialization from inside an AttributeContainer my_map_attribute = MyMapAttribute(attr_name='foo.bar') my_map_attribute._make_attribute() my_map_attribute._update_attribute_paths(my_map_attribute.attr_name) with self.assertRaises(AttributeError): my_map_attribute['missing_attribute'] == 'baz'
class StringValue(TypedValue, discriminator=class_name): value = UnicodeAttribute()
from datetime import datetime from pynamodb.models import Model from pynamodb.attributes import UnicodeAttribute, NumberAttribute, UTCDateTImeAttribute class Entry(Model); class Meta: table_name = "serverless_blog_entries" region = 'ap-northeast-1' aws_access_key_id = 'AWS_ACCESS_KEY_ID' aws_secret_access_key = 'AWS_SECRET_ACCESS_KEY' host = "http://localhost:8000" id = NumberAttribute(hash_key=True, null=False) title = UnicodeAttribute(null=True) text = UnicodeAttribute(null=True) created_at = UTCDateTimeAttribute(default=datetime.now)
class Person(MapAttribute): firstName = UnicodeAttribute() lastName = UnicodeAttribute() age = NumberAttribute()
class Location(MapAttribute): latitude = NumberAttribute() longitude = NumberAttribute() name = UnicodeAttribute()
class ChildModel(DiscriminatorTestModel, discriminator='Child'): value = UnicodeAttribute()
class Scrap(Base): """ スクラップモデル スクレイピングデータを扱う """ class Meta: table_name = 'scrap' # スクレイピング対象のURL scrap_url = UnicodeAttribute(hash_key=True, null=False) # スクレイピング対象毎の連番 unit_id = NumberAttribute(range_key=True, null=False) # 取得したテキスト text = UnicodeAttribute(null=False) # リンク先のURL redirect_url = UnicodeAttribute() # 公開日時 released_at = UnicodeAttribute(null=False) def save( self, condition=None, conditional_operator=None, **expected_values ): """ 保存処理 unit_idをインクリメント設定させるので、 オーバーライド """ # idをインクリメント self.unit_id = Sequence.next_sequence('Scrap_'+self.scrap_url) super().save( condition=condition, conditional_operator=conditional_operator, **expected_values ) @classmethod def get_latest(cls, scrap_url): """ 最新データ取得 """ latest_unit_id = cls.__get_latest_unit_id(scrap_url) if latest_unit_id is None: return None try: return cls.get(scrap_url, latest_unit_id) except cls.DoesNotExist: return None @classmethod def __get_latest_unit_id(cls, scrap_url): try: return Sequence.get( cls.__target_sequence_name(scrap_url) ).current_id except Sequence.DoesNotExist: return None @classmethod def __target_sequence_name(cls, scrap_url): """ unit_idのシーケンス管理用の名前 """ return "{}_{}".format(__class__.__name__, scrap_url)
class CurrentHistoricalModel(BaseHistoricalModel): """The base Historical Current Table model base class.""" eventTime = EventTimeAttribute(default=default_event_time) ttl = NumberAttribute(default=default_ttl()) eventSource = UnicodeAttribute()
class MyModel(Model): Meta = dynamodb_table_meta(__name__) key = UnicodeAttribute(hash_key=True) value = IntegerAttribute(null=True)
class ShoppingQuery(MapAttribute): # ref: https://developers.naver.com/docs/search/shopping/ query = UnicodeAttribute() display = NumberAttribute(default=50) sort = UnicodeAttribute(default='sim')
class ConditionExpressionTestCase(TestCase): def setUp(self): self.attribute = UnicodeAttribute(attr_name='foo') def test_equals(self): condition = self.attribute == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_less_than(self): condition = self.attribute < 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 < :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_less_than_or_equal(self): condition = self.attribute <= 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 <= :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_greater_than(self): condition = self.attribute > 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 > :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_greater_than_or_equal(self): condition = self.attribute >= 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 >= :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_between(self): condition = self.attribute.between('bar', 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 BETWEEN :0 AND :1" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == { ':0': { 'S': 'bar' }, ':1': { 'S': 'baz' } } def test_begins_with(self): condition = self.attribute.startswith('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "begins_with (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_indexing(self): condition = ListAttribute(attr_name='foo')[0] == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0[0] = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_invalid_indexing(self): with self.assertRaises(TypeError): self.attribute[0] def test_double_indexing(self): condition = ListAttribute(attr_name='foo')[0][1] == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0[0][1] = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_list_comparison(self): condition = ListAttribute(attr_name='foo') == ['bar', 'baz'] placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == { ':0': { 'L': [{ 'S': 'bar' }, { 'S': 'baz' }] } } def test_dotted_attribute_name(self): self.attribute.attr_name = 'foo.bar' condition = self.attribute == 'baz' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo.bar': '#0'} assert expression_attribute_values == {':0': {'S': 'baz'}}
class RenamedValue(TypedValue, discriminator='custom_name'): value = UnicodeAttribute()
class JiraBug(pynamodb.models.Model): id = UnicodeAttribute(hash_key=True) key = UnicodeAttribute() project = UnicodeAttribute() summary = UnicodeAttribute() description = UnicodeAttribute(null=True) issuetype = UnicodeAttribute() universal_id = UnicodeAttribute(null=True) table_parameter_name = "/tables/bugdex/jira_bugs" class Meta: table_name = "bugdex_jira_bugs_v1" region = "us-west-2" @classmethod def from_issue_dict(cls, issue_key, issue_dict): return cls( key=issue_key, project=issue_dict['project']['id'], summary=issue_dict['summary'], description=issue_dict['description'], issuetype=issue_dict['issuetype']['name'], ) @classmethod def from_raw_issue(cls, issue: Issue): for existing_bug in cls.query(issue.id): if existing_bug.universal_id: universal_id = existing_bug.universal_id break else: universal_id = str(uuid4()).lower() return cls( id=issue.id, key=issue.key, project=issue.fields.project.key, summary=issue.fields.summary, description=issue.fields.description, issuetype=issue.fields.issuetype.name, universal_id=universal_id, ) def to_raw_issue(self, jira_server: JIRA): return jira_server.issue(self.key) @classmethod def ingest(cls, jira_server: JIRA, issues: Iterable[Issue] = ()) -> Iterable[JiraBug]: from .core import UniversalBug jql_str = """ (labels = AppSec) AND (resolution is EMPTY OR status in (Reopened)) AND status not in (Closed, Resolved) ORDER BY summary ASC, created ASC """.strip() if not issues: issues = chain( search_issues_with_scrolling(jira_server, jql_str), ) visited = set() for issue in issues: if issue.key in visited: continue bug = cls.from_raw_issue(issue) bug.save() UniversalBug.propose( universal_id=bug.universal_id, source='jira', source_specific_id=bug.id, ) yield bug visited.add(bug.key) @classmethod def ingest_one(cls, jira_server: JIRA, issue: Issue, canonical_bug=None): from .core import UniversalBug bug = cls.from_raw_issue( issue if isinstance(issue, Issue) else jira_server.issue(issue['id']) ) bug.save() UniversalBug.propose( universal_id=bug.universal_id, source='jira', source_specific_id=bug.id, canonical_bug=canonical_bug, ) return bug
def setUp(self): self.attribute = UnicodeAttribute(attr_name='foo')
class DefaultsMap(MapAttribute): map_field = MapAttribute(default={}) string_field = UnicodeAttribute(null=True)
def setUp(self): self.attribute = UnicodeAttribute(attr_name='foo') self.list_attribute = ListAttribute(attr_name='foo_list', default=[])
class SubMapAttribute(MapAttribute): foo = UnicodeAttribute(attr_name='dyn_foo')
class RumorModel(Model): class Meta: region = setting.region if setting.region else 'ap-northeast-1' table_name = setting.rumor_ddb_table if setting.rumor_ddb_table else 'stg-rumor_source' if setting.role: credentials = gen_sts_credentials(setting) aws_access_key_id = credentials["AccessKeyId"] aws_secret_access_key = credentials["SecretAccessKey"] aws_session_token = credentials["SessionToken"] id = UnicodeAttribute(hash_key=True) clarification = UnicodeAttribute(null=True) preface = UnicodeAttribute(null=True) create_date = UnicodeAttribute(null=True) link = UnicodeAttribute(null=True) rumors = ListAttribute(null=True) source = UnicodeAttribute(null=True) title = UnicodeAttribute(null=True) original_title = UnicodeAttribute(null=True) image_link = UnicodeAttribute(null=True) tags = UnicodeAttribute(null=True) sensitive_categories = UnicodeAttribute(null=True) rating = UnicodeAttribute(null=True) source_create_date_index = SourceCreateDateIndex()
class SubSubMapAttribute(SubMapAttribute): bar = UnicodeAttribute(attr_name='dyn_bar')
class CourseAttribute(MapAttribute): CourseId = NumberAttribute(null=False) CourseName = UnicodeAttribute(null=False)
class ConditionExpressionTestCase(TestCase): def setUp(self): self.attribute = UnicodeAttribute(attr_name='foo') def test_equal(self): condition = self.attribute == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_not_equal(self): condition = self.attribute != 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 <> :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_less_than(self): condition = self.attribute < 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 < :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_less_than_or_equal(self): condition = self.attribute <= 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 <= :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_greater_than(self): condition = self.attribute > 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 > :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_greater_than_or_equal(self): condition = self.attribute >= 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 >= :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_between(self): condition = self.attribute.between('bar', 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 BETWEEN :0 AND :1" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_in(self): condition = self.attribute.is_in('bar', 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 IN (:0, :1)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_exists(self): condition = self.attribute.exists() placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "attribute_exists (#0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {} def test_does_not_exist(self): condition = self.attribute.does_not_exist() placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "attribute_not_exists (#0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {} def test_is_type(self): condition = self.attribute.is_type() placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "attribute_type (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'S'}} def test_begins_with(self): condition = self.attribute.startswith('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "begins_with (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains(self): condition = self.attribute.contains('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains_string_set(self): condition = UnicodeSetAttribute(attr_name='foo').contains('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains_number_set(self): condition = NumberSetAttribute(attr_name='foo').contains(1) placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'N' : '1'}} def test_contains_list(self): condition = ListAttribute(attr_name='foo').contains('bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_contains_attribute(self): condition = ListAttribute(attr_name='foo').contains(Path('bar')) placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "contains (#0, #1)" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {} def test_size(self): condition = size(self.attribute) == 3 placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "size (#0) = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'N' : '3'}} def test_sizes(self): condition = size(self.attribute) == size(Path('bar')) placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "size (#0) = size (#1)" assert placeholder_names == {'foo': '#0', 'bar': '#1'} assert expression_attribute_values == {} def test_and(self): condition = (self.attribute < 'bar') & (self.attribute > 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(#0 < :0 AND #0 > :1)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_or(self): condition = (self.attribute < 'bar') | (self.attribute > 'baz') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(#0 < :0 OR #0 > :1)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}} def test_not(self): condition = ~(self.attribute < 'bar') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(NOT #0 < :0)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}} def test_compound_logic(self): condition = (~(self.attribute < 'bar') & (self.attribute > 'baz')) | (self.attribute == 'foo') placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "(((NOT #0 < :0) AND #0 > :1) OR #0 = :2)" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S': 'bar'}, ':1': {'S': 'baz'}, ':2': {'S': 'foo'}} def test_indexing(self): condition = ListAttribute(attr_name='foo')[0] == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0[0] = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_invalid_indexing(self): with self.assertRaises(TypeError): self.attribute[0] def test_double_indexing(self): condition = ListAttribute(attr_name='foo')[0][1] == 'bar' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0[0][1] = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'S' : 'bar'}} def test_list_comparison(self): condition = ListAttribute(attr_name='foo') == ['bar', 'baz'] placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo': '#0'} assert expression_attribute_values == {':0': {'L': [{'S' : 'bar'}, {'S': 'baz'}]}} def test_dotted_attribute_name(self): self.attribute.attr_name = 'foo.bar' condition = self.attribute == 'baz' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0 = :0" assert placeholder_names == {'foo.bar': '#0'} assert expression_attribute_values == {':0': {'S': 'baz'}} def test_map_attribute_dereference(self): class MyMapAttribute(MapAttribute): nested_string = self.attribute # Simulate initialization from inside an AttributeContainer my_map_attribute = MyMapAttribute(attr_name='foo.bar') my_map_attribute._make_attribute() my_map_attribute._update_attribute_paths(my_map_attribute.attr_name) condition = my_map_attribute.nested_string == 'baz' placeholder_names, expression_attribute_values = {}, {} expression = condition.serialize(placeholder_names, expression_attribute_values) assert expression == "#0.#1 = :0" assert placeholder_names == {'foo.bar': '#0', 'foo': '#1'} assert expression_attribute_values == {':0': {'S': 'baz'}}
class AssetModel(Model): class Meta: table_name = os.environ['DYNAMODB_TABLE'] if 'ENV' in os.environ: host = 'http://localhost:8000' else: region = os.environ['REGION'] host = os.environ['DYNAMODB_HOST'] # 'https://dynamodb.us-east-1.amazonaws.com' asset_id = UnicodeAttribute(hash_key=True) state = UnicodeAttribute(null=False, default=State.CREATED.name) createdAt = UTCDateTimeAttribute(null=False, default=datetime.now().astimezone()) updatedAt = UTCDateTimeAttribute(null=False, default=datetime.now().astimezone()) def __str__(self): return 'asset_id:{}, state:{}'.format(self.asset_id, self.state) def get_key(self): return u'{}/{}'.format(KEY_BASE, self.asset_id) def save(self, conditional_operator=None, **expected_values): try: self.updatedAt = datetime.now().astimezone() logger.debug('saving: {}'.format(self)) super(AssetModel, self).save() except Exception as e: logger.error('save {} failed: {}'.format(self.asset_id, e), exc_info=True) raise e def __iter__(self): for name, attr in self._get_attributes().items(): yield name, attr.serialize(getattr(self, name)) def get_upload_url(self, ttl=60): """ :param ttl: url duration in seconds :return: a temporary presigned PUT url """ s3 = boto3.client('s3') put_url = s3.generate_presigned_url('put_object', Params={ 'Bucket': BUCKET, 'Key': self.get_key() }, ExpiresIn=ttl, HttpMethod='PUT') logger.debug('upload URL: {}'.format(put_url)) return put_url def get_download_url(self, ttl=60): """ :param ttl: url duration in seconds :return: a temporary presigned download url """ s3 = boto3.client('s3') if self.state != State.UPLOADED.name: raise AssertionError( 'Asset {} is marked as {}, must be marked {} to retrieve.'. format(self.asset_id, self.state, State.UPLOADED.name)) get_url = s3.generate_presigned_url('get_object', Params={ 'Bucket': BUCKET, 'Key': self.get_key(), }, ExpiresIn=ttl, HttpMethod='GET') logger.debug('download URL: {}'.format(get_url)) return get_url def mark_received(self): """ Mark asset as having been received via the s3 objectCreated:Put event """ self.state = State.RECEIVED.name logger.debug('mark asset received: {}'.format(self.asset_id)) self.save() def mark_uploaded(self): """ Mark asset as having been uploaded via a PUT to the asset's REST path """ uploaded_states = [State.RECEIVED.name, State.UPLOADED.name] if self.state not in uploaded_states: raise AssertionError('State: \"{}\" must be one of {}'.format( self.state, uploaded_states)) self.state = State.UPLOADED.name logger.debug('mark asset uploaded: {}'.format(self.asset_id)) self.save() def mark_deleted(self): """ Mark asset as deleted (soft delete) """ self.state = State.DELETED.name logger.debug('mark asset deleted: {}'.format(self.asset_id)) self.save()
class TypedValue(MapAttribute): _cls = DiscriminatorAttribute(attr_name='cls') name = UnicodeAttribute()
class S3Model: """S3 specific fields for DynamoDB.""" BucketName = UnicodeAttribute() Region = UnicodeAttribute()
class DiscriminatedModel(Model): hash_key = UnicodeAttribute(hash_key=True) _cls = DiscriminatorAttribute()
def test_should_string_convert_string(): assert_attribute_conversion(UnicodeAttribute(), graphene.String)