Ошибка типа: индексы списка должны быть целыми числами или фрагментами, а не str Pytest с Moto DynamoDB

#python #pytest #moto

Вопрос:

Я новичок в Python, и эта ошибка, похоже, относится к общей, и я не могу понять ее в контексте моего случая. Я пытаюсь выполнить модульное тестирование класса, который используется для подключения к DynamoDB с помощью Pytest. и Moto mocks. Test:

 @mock_dynamodb
def test_save_alarm_configs_in_db(apigw_event):
    repo = DynamoDBRepository()
    client = boto3.resource('dynamodb', region_name='us-east-1')
    create_table_response = client.create_table(
        AttributeDefinitions=[
            {
                'AttributeName': 'frequency',
                'AttributeType': 'N'
            },
            {
                'AttributeName': 'time_period',
                'AttributeType': 'S'
            },
            {
                'AttributeName': 'destinations',
                'AttributeType': 'M'
            }
        ],
        TableName='alarm_configs',
        KeySchema=[
            {
                'AttributeName': "id",
                'KeyType': "HASH"
            }
        ]
    )

    alarm_configs = {
        "id": "123",
        "frequency": 2,
        "time_period": "hour",
        "destinations": [
            {"type": "SNS",
             "properties":
                 [{"topics": ["email_topic"]}]
             }
        ]
    }

    if create_table_response:
        put_response = client.put_item(TableName='alarm_configs', Item=alarm_configs)
        print("Put response:")
        print(put_response)
        expected_item = repo.get_alarm_configs_by_id("123")
        print(expected_item)
 

Ошибка:
https://gist.github.com/AdelinGhanaem/047d4bb32724432350b73f5917daccc7

Комментарии:

1. Ваш KeySchema список содержит один словарь, но, вероятно, должен быть просто словарем, без окружающего списка. Также, похоже, отсутствует ключ ‘HashKeyElement’. И мне не нужно говорить об этом пользователю с репутацией 16 тыс., но, пожалуйста, проведите некоторое исследование, прежде чем задавать вопрос; сообщение об ошибке в заголовке очень четкое и должно привести к бесчисленным обращениям Google, в которых будет точно указано, почему возникает такая ошибка.

2. Ошибка вводит в заблуждение @l4mpi — его ключевая схема верна. Смотрите мой ответ ниже.

3. @BertBlommers я бы предположил, что это из-за изменения в mock_dynamodb2 из вашего ответа, который, похоже, использует другой формат конфигурации. Мое предлагаемое исправление было основано на фрагменте кода, который можно увидеть в сообщении об ошибке, это спорный вопрос, если этот декоратор больше не должен использоваться в любом случае. Это подтверждает мое впечатление, что OP провел недостаточное исследование.

4. Boto3 определяет формат KeySchema, поэтому конфигурация не меняется. Moto просто анализирует все, что поступает из Boto3. Во всяком случае, это может быть классифицировано как ошибка в Moto, поскольку она не обнаруживает, что используется boto3.

5. Моя первоначальная реакция была такой же, FWIW, но думаю, что дополнительные исследования не указали бы OP нигде в правильном направлении. Документация Moto здесь вообще не помогла бы (и это исходит от меня, сопровождающего Moto ..)

Ответ №1:

В вашем коде есть несколько проблем — некоторые связаны с Moto, некоторые с boto3.

  • При использовании boto3 вы должны использовать @mock_dynamodb2 . mock_dynamodb считается устаревшим.

(Редактировать: см http://docs.getmoto.org/en/latest/docs/services/dynamodb.html и https://github.com/spulec/moto/issues/4526)

Исправление этого должно, по крайней мере, дать вам больше полезных ошибок.

Далее: AttributeDefinitions следует указать типы ключей — являются ли ключи строками, числами и т. Д. Это означает, что параметр AttributeDefinitions -всегда должен отражать KeySchema атрибут — .
Поскольку у вас есть только id ключ в KeySchema , он должен выглядеть так:

 AttributeDefinitions=[{
    'AttributeName': 'id',
    'AttributeType': 'S'
}],
 

Третье:
Существует два способа использования put_item -метода.
Первый: использование boto3.client("dynamodb").put_item -метода.
Два: использование Table.put_item -метода, где Table ссылается на экземпляр Table -class, который возвращается boto3.resource("..").create_table

Поскольку вы уже создали таблицу с помощью boto3.resource("..") -call , ввод элемента может быть выполнен следующим образом:

 put_response = create_table_response.put_item(Item=alarm_configs)