Example #1
0
    def getSpecificProductInformation(self, keyValue):

        print("In getSpecificProductInformation() method !")

        try:

            table = self.dynamodb.Table('Product')
            resp = table.get_item(Key=keyValue)

            # resp returns following value.
            print(resp)
            # {'Item': {'Id': Decimal('1'), 'ProductCategoryId': Decimal('1'), 'Name': 'IPhone 8\n'}, 'ResponseMetadata': {'RequestId': 'NMDA30M1HHF514MJVVUIBCELEFVV4KQNSO5AEMVJF66Q9ASUAAJG', 'HTTPStatusCode': 200, 'HTTPHeaders': {'server': 'Server', 'date': 'Mon, 05 Aug 2019 17:12:19 GMT', 'content-type': 'application/x-amz-json-1.0', 'content-length': '81', 'connection': 'keep-alive', 'x-amzn-requestid': 'NMDA30M1HHF514MJVVUIBCELEFVV4KQNSO5AEMVJF66Q9ASUAAJG', 'x-amz-crc32': '3394591035'}, 'RetryAttempts': 0}}

            if resp and resp["ResponseMetadata"]["HTTPStatusCode"] == 200:

                deserializer = TypeDeserializer()
                serializer = TypeSerializer()

                if resp["Item"]:
                    print(resp["Item"])
                    # {'Id': Decimal('1'), 'ProductCategoryId': Decimal('1'), 'Name': 'IPhone 8\n'}
                    data = {k: serializer.serialize(v) for k, v in resp["Item"].items()}

                else:
                    data = {}

                return data
            else:
                raise Exception

        except Exception as error:
            print("Not able to fetch item !")
            raise error
def convert_json_to_dynamo_json(input_json: list) -> list:
    """
    Re-Serializes the data into DynamoDB compatible JSON that can be used to put items into the dynamo table
    """
    # HACK: When serializing the JSON without dynamodb attribute types included, it wants to convert
    # The DynamoDB 'String Set' objects to DynamoDB List objects because python loads the data as lists and not sets.
    # I am choosing to go with DynamoDB attribute string sets, because I do not want duplicate entries for periods,
    # and it is easier to parse visually. The only drawback I have seen so far is that sets are unordered,
    # but since we are not evaluating the period string set responses in any particular order that should not matter.
    # Can we change this to use cls instead of for loops?

    serializer = TypeSerializer()
    py_data, json_data = [], []

    logger.info(f"Converting JSON config to DynamoDB compatible JSON.")

    # Loop through JSON file data looking for Python object type list
    # Convert the list object into a set of strings
    # Store new data types as python object
    for data in input_json:
        for k, v in data.items():
            if isinstance(v, list):
                data[k] = set(v)
        py_data.append(data)

    # Serialize previously modified python object data into DynamoDB JSON
    for data in py_data:
        dynamo_data = {k: serializer.serialize(v) for k, v in data.items()}
        json_data.append(dynamo_data)

    return json_data
Example #3
0
    def updateData(self, numRows, start_key, field_key, field_value):
        client = self.dynamodb_client()
        deserializer = TypeDeserializer()
        serializer = TypeSerializer()

        table_configs = self.expected_table_config()

        for table in table_configs:
            LOGGER.info('Updating %s Items by setting field with key %s to the value %s, with start_key %s, for table %s', numRows, field_key, field_value, start_key, table['TableName'])
            for item in table['generator'](numRows, start_key):
                record = deserializer.deserialize(item)
                hashKey = table['HashKey']
                key = {
                    hashKey: serializer.serialize(record[hashKey])
                }
                serializedFieldValue = serializer.serialize(field_value)
                # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.update_item
                client.update_item(
                    TableName=table['TableName'],
                    Key=key,
                    UpdateExpression='set {}=:v'.format(field_key),
                    ExpressionAttributeValues={
                        ':v': serializedFieldValue,
                    },
                )
Example #4
0
    def __init__(self, config):
        assert isinstance(config, dict), "Config must be provided during DynamoDbClient initialization"

        # If this is a test, make sure the table is a test table
        if os.environ.get('STAGE') == 'test' and 'table_name' in config:
            assert config['table_name'].startswith('autotest_') or config['table_name'] == 'config', \
                f"Bad table name {config['table_name']} in autotest"

        self.config = config

        if not str(config.get('table_name')).startswith('autotest_mock_'):
            self.dynamo_client = boto3.client('dynamodb')
        else:
            logger.info(f"Initialized DynamoClient without boto3 client for table {config.get('table_name')}")

        # storage for table description(s)
        self._table_descriptions: Optional[Dict[str, Dict]] = {}

        # initialize table store
        self._table_capacity = {}
        self.identify_dynamo_capacity(table_name=self.config['table_name'])

        self.stats = defaultdict(int)
        if not hasattr(self, 'row_mapper'):
            self.row_mapper = self.config.get('row_mapper')

        self.type_serializer = TypeSerializer()
        self.type_deserializer = TypeDeserializer()
Example #5
0
    def as_dynamo_flat_dict(self):
        """
        Flattens out User.as_dict() output into a simple structure without any signature or metadata.
        Effectively, this outputs something like this:
        ```{'uuid': '11c8a5c8-0305-4524-8b41-95970baba84c', 'user_id': 'email|c3cbf9f5830f1358e28d6b68a3e4bf15', ...```
        `flatten()` is recursive.
        Note that this form cannot be verified or validated back since it's missing all attributes!

        Return: dynamodb serialized low level dict of user in a "flattened" form for dynamodb consumption in particular
        """
        user = self._clean_dict()

        def flatten(attrs, field=None):
            flat = {}
            for f in attrs:
                # Skip "schema"
                if isinstance(attrs[f], str):
                    continue
                if not set(["value", "values"]).isdisjoint(set(attrs[f])):
                    res = attrs[f].get("value", attrs[f].get("values"))
                    if res is not None and res != "":
                        flat[f] = res
                else:
                    flat[f] = flatten(attrs[f])

            return flat

        serializer = TypeSerializer()
        return {k: serializer.serialize(v) for k, v in flatten(user).items()}
Example #6
0
def construct_dynamo_type_dict(d: dict):
    """
    DynamoDB transactions need a different way of specifying transaction.
    The structure has to be recursively implemented as:
                    'string': {
                        'S': 'string',
                        'N': 'string',
                        'B': b'bytes',
                        'SS': [
                            'string',
                        ],
                        'NS': [
                            'string',
                        ],
                        'BS': [
                            b'bytes',
                        ],
                        'M': {
                            'string': {'... recursive ...'}
                        },
                        'L': [
                            {'... recursive ...'},
                        ],
                        'NULL': True|False,
                        'BOOL': True|False
                    }
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.transact_write_items
    TypeSerializer and TypeDeserializer needs to be used to convert to appropriate representations for DynamoDB.
    serialize(d)['M'] has been used in line with the documentation.
    """
    serializer = TypeSerializer()
    return serializer.serialize(d)['M']
Example #7
0
def boto3_serializer(python_dict):
    serializer = TypeSerializer()
    return {
        k: serializer.serialize(
            v if not isinstance(v, float) else Decimal(str(v)))
        for k, v in python_dict.items()
    }
 def generate_items(self, num_items):
     serializer = TypeSerializer()
     for i in range(num_items):
         record = {
             'int_id':
             int(i / 10.0),
             'decimal_field':
             decimal.Decimal(str(i) + '.00000000001'),
             'string_field':
             str(i),
             'byte_field':
             b'some_bytes',
             'int_list_field': [i, i + 1, i + 2],
             'int_set_field':
             set([i, i + 1, i + 2]),
             'map_field': {
                 'map_entry_1': 'map_value_1',
                 'map_entry_2': 'map_value_2'
             },
             'string_list': [
                 self.random_string_generator(),
                 self.random_string_generator(),
                 self.random_string_generator()
             ],
             'boolean_field':
             True,
             'other_boolean_field':
             False,
             'null_field':
             None
         }
         yield serializer.serialize(record)
Example #9
0
 def serialize_output(value):
     try:
         td = TypeSerializer()
         for k, v in dict(value).items():
             value[k] = td.serialize(v)
     except BaseException:
         pass
     return value
def dynamodb_put_item(ddb_client, table_name: str, item: dict):
    serializer = TypeSerializer()
    serialized_item = serializer.serialize(item)['M']
    try:
        ddb_client.put_item(TableName=table_name, Item=serialized_item)
    except ddb_client.exceptions.ResourceNotFoundException:
        raise TyphoonResourceNotFoundError(
            f'Table {table_name} does not exist in DynamoDB')
Example #11
0
 def generate_items(self, num_items, start_key=0):
     serializer = TypeSerializer()
     for i in range(start_key, start_key + num_items):
         record = {
             'int_id': i,
             'string_field': self.random_string_generator(),
             'boolean_field': True,
         }
         yield serializer.serialize(record)
Example #12
0
def dict_to_ddb(item):
    # type: (Dict[str, Any]) -> Dict[str, Any]
    # TODO: narrow these types down
    """Converts a native Python dictionary to a raw DynamoDB item.

    :param dict item: Native item
    :returns: DynamoDB item
    :rtype: dict
    """
    serializer = TypeSerializer()
    return {key: serializer.serialize(value) for key, value in item.items()}
Example #13
0
    def _save_dice_pools(self):
        if self.pools is None:
            raise Exception("Tried to save dice pools before loading them.")

        ser = TypeSerializer()
        item = {
            'game': ser.serialize('Shadowrun'),
            'timestamp': ser.serialize(Decimal(time.time())),
            'pools': ser.serialize(self.pools)
        }
        logger.debug("Item before put_item()ing: {}".format(item))
        self._client.put_item(TableName='DicePools', Item=item)
def test_validate_products_multiple(lambda_module, product):
    """
    Test validate_products() with multiple DynamoDB calls
    """

    products = []
    for i in range(0, 105):
        product_temp = copy.deepcopy(product)
        product_temp["productId"] += str(i)
        products.append(product_temp)

    # Stub boto3
    dynamodb = stub.Stubber(lambda_module.dynamodb)
    response = {
        "Responses": {
            lambda_module.TABLE_NAME: [{k: TypeSerializer().serialize(v) for k, v in p.items()} for p in products[0:100]]
        }
    }
    expected_params = {
        "RequestItems": {
            lambda_module.TABLE_NAME: {
                "Keys": [{"productId": {"S": p["productId"]}} for p in products[0:100]],
                "ProjectionExpression": stub.ANY,
                "ExpressionAttributeNames": stub.ANY
            }
        }
    }
    dynamodb.add_response("batch_get_item", response, expected_params)
    response = {
        "Responses": {
            lambda_module.TABLE_NAME: [{k: TypeSerializer().serialize(v) for k, v in p.items()} for p in products[100:]]
        }
    }
    expected_params = {
        "RequestItems": {
            lambda_module.TABLE_NAME: {
                "Keys": [{"productId": {"S": p["productId"]}} for p in products[100:]],
                "ProjectionExpression": stub.ANY,
                "ExpressionAttributeNames": stub.ANY
            }
        }
    }
    dynamodb.add_response("batch_get_item", response, expected_params)
    dynamodb.activate()

    # Run command
    retval = lambda_module.validate_products(products)
    print(retval)
    assert len(retval) == 2
    assert len(retval[0]) == 0
    assert isinstance(retval[1], str)

    dynamodb.deactivate()
def lambda_handler(event, context):
    accountId = str(event['accountId'])
    accountName = str(event['description'])
    accountRole = "customer"
    confidentialKMSKey = 'alias/TSI_Base_ConfidentialS3Key'
    internalKMSKey = 'alias/TSI_Base_InternalS3Key'
    if 'customermasteraccountid' in event:
        masteraccountId = event['customermasteraccountid']
    else:
        masteraccountId = os.environ['accountid']
    readonlyRole = 'TSI_Base_ReadOnlySwitchRole'
    securityEmail = str(event['email'])
    accountemail = str(event['accountemail'])
    enabledregions = event['enabledregions'].split(',')
    supportenabled = 'false'
    awsconfigenabled = 'false'
    if 'config' in event:
        config = event['config']
    else:
        config = "disabled"
    if 'support' in event:
        support = event['support']
    else:
        config = "disabled"
    ouname = event['ouname']
    terraformVersion = '1.0'
    writeRole = 'TSI_Base_FullAccess'
    featureLevel = 'full'
    dynamoentry = {
        'accountId': accountId,
        'accountName': accountName,
        'config': config,
        'support': support,
        'ouname': ouname,
        'accountRole': accountRole,
        'confidentialKMSKey': confidentialKMSKey,
        'internalKMSKey': internalKMSKey,
        'masteraccountId': masteraccountId,
        'readonlyRole': readonlyRole,
        'securityEmail': securityEmail,
        'accountemail': accountemail,
        'enabledregions': enabledregions,
        'supportenabled': supportenabled,
        'awsconfigenabled': awsconfigenabled,
        'terraformVersion': terraformVersion,
        'writeRole': writeRole,
        'featureLevel': featureLevel
    }
    serializer = TypeSerializer()
    print(json.dumps(serializer.serialize(dynamoentry)['M']))
    dynamoclient = boto3.client('dynamodb')
    return (dynamoclient.put_item(TableName='accounts',
                                  Item=serializer.serialize(dynamoentry)['M']))
Example #16
0
def dict_to_ddb(item):
    # type: (Dict[str, Any]) -> Dict[str, Any]
    # narrow these types down
    # https://github.com/aws/aws-dynamodb-encryption-python/issues/66
    """Converts a native Python dictionary to a raw DynamoDB item.

    :param dict item: Native item
    :returns: DynamoDB item
    :rtype: dict
    """
    serializer = TypeSerializer()
    return {key: serializer.serialize(value) for key, value in item.items()}
Example #17
0
    def as_dynamo_flat_dict(self):
        """
        Flattens out User.as_dict() output into a simple structure without any signature or metadata.
        Effectively, this outputs something like this:
        ```{'uuid': '11c8a5c8-0305-4524-8b41-95970baba84c', 'user_id': 'email|c3cbf9f5830f1358e28d6b68a3e4bf15', ...```
        `flatten()` is recursive.
        Note that this form cannot be verified or validated back since it's missing all attributes!

        Return: dynamodb serialized low level dict of user in a "flattened" form for dynamodb consumption in particular
        """
        user = self._clean_dict()

        def sanitize(attrs):
            # Types whose values need no sanitization to serialize.
            supported_base_types = [type(None), bool, int, float]

            # Empty strings cannot be sanitized.
            def is_nonempty_str(s):
                return isinstance(s, str) and len(s) > 0

            def not_empty_str(v):
                return not isinstance(v, str) or is_nonempty_str(v)

            if type(attrs) in supported_base_types or is_nonempty_str(attrs):
                return attrs

            # We want to remove empty strings from lists and sanitize everything else.
            if isinstance(attrs, list):
                cleaned = filter(not_empty_str, attrs)

                return list(map(sanitize, cleaned))

            # We are dealing with a dictionary.
            cleaned = {
                key: sanitize(value)
                for key, value in attrs.items()
                if not_empty_str(key) and not_empty_str(value)
            }

            # If we have a dictionary, we want to ensure it only has one of either
            # the "value" key or "values" key.
            has_value = "value" in cleaned
            has_values = "values" in cleaned

            if (has_value and not has_values) or (has_values
                                                  and not has_value):
                return cleaned.get("value", cleaned.get("values"))

            return cleaned

        serializer = TypeSerializer()
        return {k: serializer.serialize(v) for k, v in sanitize(user).items()}
Example #18
0
def dumps(dct, as_dict=False, **kwargs):
    """ Dump the dict to json in DynamoDB Format
        You can use any other simplejson or json options
        :param dct - the dict to dump
        :param as_dict - returns the result as python dict (useful for DynamoDB boto3 library) or as json sting
        :returns: DynamoDB json format.
        """

    result_ = TypeSerializer().serialize(
        json.loads(json.dumps(dct, default=json_serial), use_decimal=True))
    if as_dict:
        return result_.iteritems().next()[1]
    else:
        return json.dumps(result_.iteritems().next()[1], **kwargs)
 def log_finish_to_dynamodb(self, event, context):
     dynamodb.update_item(
         TableName=self.dynamodb_table,
         Key={
             'request_id':
             TypeSerializer().serialize(str(context.aws_request_id)),
         },
         UpdateExpression='set lambda_status = :s, finish_time = :t',
         ExpressionAttributeValues={
             ':s':
             TypeSerializer().serialize('done'),
             ':t':
             TypeSerializer().serialize(
                 int(datetime.datetime.now().timestamp())),
         })
Example #20
0
 def build_shopify_url(self):
     #Get page number:
     ts = TypeSerializer()
     pageNumber = int(ts.serialize(self.params['pages'])['N'])
     query_params = [{
         "url":
         "{}products.json?page={}".format(self.params['url'], p),
         "country":
         self.params['country'],
         "current_datetime":
         self.current_datetime,
         "id_shop":
         self.idTable
     } for p in range(1, pageNumber + 1)]
     return query_params
Example #21
0
def insert_data(order):
    record = {
        "awsRegion": "us-east-1",
        "dynamodb": {
            "Keys": {
                "orderId": {
                    "S": order["orderId"]
                }
            },
            "NewImage":
            {k: TypeSerializer().serialize(v)
             for k, v in order.items()},
            "SequenceNumber": "1234567890123456789012345",
            "SizeBytes": 123,
            "StreamViewType": "NEW_AND_OLD_IMAGES"
        },
        "eventID": str(uuid.uuid4()),
        "eventName": "INSERT",
        "eventSource": "aws:dynamodb",
        "eventVersion": "1.0"
    }
    event = {
        "Source": "ecommerce.orders",
        "Resources": [order["orderId"]],
        "DetailType": "OrderCreated",
        "Detail": json.dumps(order),
        "EventBusName": "EVENT_BUS_NAME"
    }

    return {"record": record, "event": event}
Example #22
0
def test_validate_products(lambda_module, product):
    """
    Test validate_products() against an incorrect product
    """

    product_incorrect = copy.deepcopy(product)
    product_incorrect["price"] += 200

    # Stub boto3
    table = stub.Stubber(lambda_module.table.meta.client)
    response = {
        "Item": {k: TypeSerializer().serialize(v) for k, v in product.items()}
    }
    expected_params = {
        "Key": {"productId": product["productId"]},
        "ProjectionExpression": stub.ANY,
        "ExpressionAttributeNames": stub.ANY,
        "TableName": lambda_module.TABLE_NAME
    }
    table.add_response("get_item", response, expected_params)
    table.activate()

    # Run command
    retval = lambda_module.validate_products([product_incorrect])
    assert len(retval) == 2
    assert len(retval[0]) == 1
    assert isinstance(retval[1], str)

    table.deactivate()
def convert_to_dyn_objects(user_msg_list, tnow):
    tnow_dec = quantize_tstamp(decimal.Decimal(tnow))
    ts = TypeSerializer()
    msg_d = {}

    def build_item(user_id, msg):
        # hash of message and timestamp
        item = msg.copy()
        item['userId'] = user_id
        item['created'] = tnow_dec
        item = common.floats_to_decimals(item)
        # filter out item values
        item_dyn = dict([(k, ts.serialize(v)) for k, v in item.iteritems()])
        item_dyn = dict(trim_empty_leafs(item_dyn))
        return ((item['userId'], item['messageId']), {
            'PutRequest': {
                'Item': item_dyn
            }
        })

    # adding to dict will ensure only latest message kept for each user_id/message_id
    for user_id, m in user_msg_list:
        key, dyn_item = build_item(user_id, m)
        msg_d[key] = dyn_item
    return msg_d.values()
def test_get_order(lambda_module, order):
    """
    Test get_order()
    """

    # Stub boto3
    table = stub.Stubber(lambda_module.table.meta.client)
    response = {
        "Item": {k: TypeSerializer().serialize(v)
                 for k, v in order.items()},
        # We do not use ConsumedCapacity
        "ConsumedCapacity": {}
    }
    expected_params = {
        "TableName": lambda_module.TABLE_NAME,
        "Key": {
            "orderId": order["orderId"]
        }
    }
    table.add_response("get_item", response, expected_params)
    table.activate()

    # Gather orders
    ddb_order = lambda_module.get_order(order["orderId"])

    # Remove stub
    table.assert_no_pending_responses()
    table.deactivate()

    # Check response
    compare_dict(order, ddb_order)
class UserRepository:
    serializer = TypeSerializer()
    deserializer = TypeDeserializer()
    usersTable: any

    def __init__(self):
        dynamodb = boto3.resource('dynamodb')
        self.usersTable = dynamodb.Table('Users')

    def getAll(self):
        users = []
        response = self.usersTable.scan()
        for item in response['Items']:
            dictionary = {
                k: self.deserializer.deserialize(v)
                for k, v in item.items() if k != 'userId'
            }
            dictionary["userId"] = int(item["userId"])
            if not 'customReason' in dictionary:
                dictionary['customReason'] = ''
            user = User.Schema().load(dictionary)
            users.append(user)
        return users

    def save(self, user: User):
        json = {
            k: self.serializer.serialize(v)
            for k, v in User.Schema().dump(user).items() if v != ""
        }
        json['userId'] = user.userId
        self.usersTable.put_item(Item=json)
        return

    def delete(self, user: User):
        self.usersTable.delete_item(Key={'userId': user.userId})
def test_handler(lambda_module, apigateway_event, order, context):
    """
    Test handler()
    """

    # Stub boto3
    table = stub.Stubber(lambda_module.table.meta.client)
    response = {
        "Item": {k: TypeSerializer().serialize(v)
                 for k, v in order.items()},
        # We do not use ConsumedCapacity
        "ConsumedCapacity": {}
    }
    expected_params = {
        "TableName": lambda_module.TABLE_NAME,
        "Key": {
            "orderId": order["orderId"]
        }
    }
    table.add_response("get_item", response, expected_params)
    table.activate()

    # Send request
    response = lambda_module.handler(apigateway_event, context)

    # Remove stub
    table.assert_no_pending_responses()
    table.deactivate()

    assert response["statusCode"] == 200
    assert "body" in response
    body = json.loads(response["body"])
    compare_dict(order, body)
def test_validate_products(lambda_module, product):
    """
    Test validate_products() against a correct product
    """


    # Stub boto3
    dynamodb = stub.Stubber(lambda_module.dynamodb)
    response = {
        "Responses": {
            lambda_module.TABLE_NAME: [{k: TypeSerializer().serialize(v) for k, v in product.items()}]
        }
    }
    expected_params = {
        "RequestItems": {
            lambda_module.TABLE_NAME: {
                "Keys": [{"productId": {"S": product["productId"]}}],
                "ProjectionExpression": stub.ANY,
                "ExpressionAttributeNames": stub.ANY
            }
        }
    }
    dynamodb.add_response("batch_get_item", response, expected_params)
    dynamodb.activate()

    # Run command
    retval = lambda_module.validate_products([product])
    print(retval)
    assert len(retval) == 2
    assert len(retval[0]) == 0
    assert isinstance(retval[1], str)

    dynamodb.deactivate()
Example #28
0
def _api_to_doc(event):
    '''Serialize a DDB Document to a DDB API Item'''
    if event.get('Item') is not None:
        ddb_items = event.get('Item')
        event['Item'] = {
            k: TypeSerializer().serialize(v)
            for k, v in ddb_items.items()
        }
    if event.get('Key') is not None:
        ddb_key = event.get('Key')
        event['Key'] = {
            k: TypeSerializer().serialize(v)
            for k, v in ddb_key.items()
        }

    return event
def dynamo_extend_items_with_schedule(items_list, full=False, df_format=False):
    df = pd.DataFrame(items_list)
    # Extract items primary keys and format it for getitem
    extract = df[["day_train_num", "station_id"]]
    extract.station_id = extract.station_id.apply(str)

    # Serialize in dynamo types
    seres = TypeSerializer()
    extract_ser = extract.applymap(seres.serialize)
    items_keys = extract_ser.to_dict(orient="records")

    # Submit requests
    responses = dynamo_submit_batch_getitem_request(items_keys,
                                                    dynamo_sched_dep)

    # Deserialize into clean dataframe
    resp_df = pd.DataFrame(responses)
    deser = TypeDeserializer()
    resp_df = resp_df.applymap(deser.deserialize)

    # Select columns to keep:
    all_columns = [
        'arrival_time', 'block_id', 'day_train_num', 'direction_id',
        'drop_off_type', 'pickup_type', 'route_id', 'route_short_name',
        'scheduled_departure_day', 'scheduled_departure_time', 'service_id',
        'station_id', 'stop_headsign', 'stop_id', 'stop_sequence', 'train_num',
        'trip_headsign', 'trip_id'
    ]
    columns_to_keep = [
        'day_train_num', 'station_id', 'scheduled_departure_time', 'trip_id',
        'service_id', 'route_short_name', 'trip_headsign', 'stop_sequence'
    ]
    if full:
        resp_df = resp_df[all_columns]
    else:
        resp_df = resp_df[columns_to_keep]

    # Merge to add response dataframe to initial dataframe
    # We use left jointure to keep items even if we couldn't find schedule
    index_cols = ["day_train_num", "station_id"]
    df_updated = df.merge(resp_df, on=index_cols, how="left")

    # Compute delay
    df_updated.loc[:, "delay"] = df_updated.apply(lambda x: compute_delay(
        x["scheduled_departure_time"], x["expected_passage_time"]),
                                                  axis=1)

    # Inform
    logger.info(
        "Asked to find schedule and trip_id for %d items, we found %d of them."
        % (len(df), len(resp_df)))
    if df_format:
        return df_updated

    # Safe json serializable python dict
    df_updated = df_updated.applymap(str)
    items_updated = json.loads(df_updated.to_json(orient='records'))
    return items_updated
Example #30
0
def update_item_from_dict(table_name, key, dictionary, client):
    """
    Update the item identified by `key` in the DynamoDB `table` by adding
    all of the attributes in the `dictionary`.
    Args:
        table_name (str):
        key (dict):
        dictionary (dict):
        client:

    Returns:
        dict
    """
    serializer = TypeSerializer()
    deserializer = TypeDeserializer()

    # Prepare data by generating an alphanumeric version of the key
    working_data = {k: [pattern.sub("", k), v] for k, v in dictionary.items()}

    updates_string = ', '.join(
        [f'#{v[0]} = :{v[0]}' for v in working_data.values()])
    update_expression = f'SET {updates_string}'
    attribute_names = {f'#{v[0]}': k for k, v in working_data.items()}
    attribute_values = {
        f':{v[0]}': serializer.serialize(v[1])
        for k, v in working_data.items()
    }
    item = client.update_item(
        TableName=table_name,
        Key={k: serializer.serialize(v)
             for k, v in key.items()},
        UpdateExpression=update_expression,
        ExpressionAttributeNames=attribute_names,
        ExpressionAttributeValues=attribute_values,
        ReturnValues='ALL_NEW',
    )
    if item:
        result_data = item.get('Attributes', {})
        output_data = {}
        for k, v in result_data.items():
            output_data[k] = deserializer.deserialize(v)
        return output_data
    else:
        return None
Example #31
0
    def _get_dict(self):
        '''
        Parses self.__dict__ and returns only those objects that should be stored in the database.

        :rtype: dict
        '''
        ts = TypeSerializer()
        d = {}
        for a in [k for k in dir(self) if k not in dir(type(self))]:
            # limited to only instance attributes, not class attributes
            try:
                if not inspect.ismethod(getattr(self,a)) and not inspect.isfunction(getattr(self,a)) and not a[0] == '_' and not (hasattr(type(self),a) and isinstance(getattr(type(self),a), property)):
                    if not isinstance(getattr(self,a), Object):
                        # if DDB will choke on the data type, this will throw an error and prevent it from getting added to the dict
                        # however, we convert Objects to foreign-key references before saving, so don't do this if it's one of ours.
                        ts.serialize(getattr(self,a))
                    d[a] = getattr(self,a)
            except Exception as e:
                pass
#                 logger.exception("Exception occured while parsing attr {} of object {}.  NOT STORING.".format(str(a), str(self)))
        return d
Example #32
0
class TestSerializer(unittest.TestCase):
    def setUp(self):
        self.serializer = TypeSerializer()

    def test_serialize_unsupported_type(self):
        with self.assertRaisesRegexp(TypeError, 'Unsupported type'):
            self.serializer.serialize(object())

    def test_serialize_null(self):
        self.assertEqual(self.serializer.serialize(None), {'NULL': True})

    def test_serialize_boolean(self):
        self.assertEqual(self.serializer.serialize(False), {'BOOL': False})

    def test_serialize_integer(self):
        self.assertEqual(self.serializer.serialize(1), {'N': '1'})

    def test_serialize_decimal(self):
        self.assertEqual(
            self.serializer.serialize(Decimal('1.25')), {'N': '1.25'})

    def test_serialize_float_error(self):
        with self.assertRaisesRegexp(
                TypeError,
                'Float types are not supported. Use Decimal types instead'):
            self.serializer.serialize(1.25)

    def test_serialize_NaN_error(self):
        with self.assertRaisesRegexp(
                TypeError,
                'Infinity and NaN not supported'):
            self.serializer.serialize(Decimal('NaN'))

    def test_serialize_string(self):
        self.assertEqual(self.serializer.serialize('foo'), {'S': 'foo'})

    def test_serialize_binary(self):
        self.assertEqual(self.serializer.serialize(
            Binary(b'\x01')), {'B': b'\x01'})

    def test_serialize_bytearray(self):
        self.assertEqual(self.serializer.serialize(bytearray([1])),
                         {'B': b'\x01'})

    @unittest.skipIf(six.PY2,
                     'This is a test when using python3 version of bytes')
    def test_serialize_bytes(self):
        self.assertEqual(self.serializer.serialize(b'\x01'), {'B': b'\x01'})

    def test_serialize_number_set(self):
        serialized_value = self.serializer.serialize(set([1, 2, 3]))
        self.assertEqual(len(serialized_value), 1)
        self.assertIn('NS', serialized_value)
        self.assertCountEqual(serialized_value['NS'], ['1', '2', '3'])

    def test_serialize_string_set(self):
        serialized_value = self.serializer.serialize(set(['foo', 'bar']))
        self.assertEqual(len(serialized_value), 1)
        self.assertIn('SS', serialized_value)
        self.assertCountEqual(serialized_value['SS'], ['foo', 'bar'])

    def test_serialize_binary_set(self):
        serialized_value = self.serializer.serialize(
            set([Binary(b'\x01'), Binary(b'\x02')]))
        self.assertEqual(len(serialized_value), 1)
        self.assertIn('BS', serialized_value)
        self.assertCountEqual(serialized_value['BS'], [b'\x01', b'\x02'])

    def test_serialize_list(self):
        serialized_value = self.serializer.serialize(['foo', 1, [1]])
        self.assertEqual(len(serialized_value), 1)
        self.assertIn('L', serialized_value)
        self.assertCountEqual(
            serialized_value['L'],
            [{'S': 'foo'}, {'N': '1'}, {'L': [{'N': '1'}]}]
        )

    def test_serialize_map(self):
        serialized_value = self.serializer.serialize(
            {'foo': 'bar', 'baz': {'biz': 1}})
        self.assertEqual(
            serialized_value,
            {'M': {'foo': {'S': 'bar'}, 'baz': {'M': {'biz': {'N': '1'}}}}})
Example #33
0
 def setUp(self):
     self.serializer = TypeSerializer()