web-dev-qa-db-fra.com

Comment convertir un élément boto3 Dynamo DB en un dictionnaire ordinaire en Python?

En Python, lorsqu'un élément est récupéré de Dynamo DB à l'aide de boto3, un schéma comme le suivant est obtenu.

{
  "ACTIVE": {
    "BOOL": true
  },
  "CRC": {
    "N": "-1600155180"
  },
  "ID": {
    "S": "bewfv43843b"
  },
  "params": {
    "M": {
      "customer": {
        "S": "TEST"
      },
      "index": {
        "N": "1"
      }
    }
  },
  "THIS_STATUS": {
    "N": "10"
  },
  "TYPE": {
    "N": "22"
  }
}

De plus, lors de l'insertion ou de la numérisation, les dictionnaires doivent être convertis de cette manière. Je n'ai pas été en mesure de trouver un wrapper qui prend en charge une telle conversion. Puisqu'apparemment boto3 ne le supporte pas, y a-t-il de meilleures alternatives que d'implémenter du code pour cela?

25
manelmc

Afin de comprendre comment résoudre ce problème, il est important de reconnaître que boto3 a deux modes de fonctionnement de base: l'un qui utilise l'API Client de bas niveau, et l'autre qui utilise des abstractions de niveau supérieur comme Tablea . La structure de données présentée dans la question est un exemple de ce qui est consommé/produit par l'API de bas niveau, qui est également utilisée par l'AWS CLI et les services Web dynamodb.

Pour répondre à votre question - si vous pouvez travailler exclusivement avec les abstractions de haut niveau comme Table lors de l'utilisation de boto3, alors les choses seront beaucoup plus faciles pour vous, comme le suggèrent les commentaires. Ensuite, vous pouvez contourner tout le problème - python sont marshalés vers et depuis le format de données de bas niveau pour vous.

Cependant, il y a des moments où il n'est pas possible d'utiliser exclusivement ces constructions de haut niveau. J'ai rencontré spécifiquement ce problème lorsque j'ai traité des flux DynamoDB attachés à Lambdas. Les entrées du lambda sont toujours au format bas niveau, et ce format est plus difficile à travailler avec IMO.

Après quelques recherches, j'ai trouvé que boto3 lui-même avait quelques fonctionnalités astucieuses cachées pour faire des conversions. Ces fonctionnalités sont utilisées implicitement dans toutes les conversions internes mentionnées précédemment. Pour les utiliser directement, importez les classes TypeDeserializer/TypeSerializer et combinez-les avec des compréhensions dict comme ceci:

import boto3

low_level_data = {
  "ACTIVE": {
    "BOOL": True
  },
  "CRC": {
    "N": "-1600155180"
  },
  "ID": {
    "S": "bewfv43843b"
  },
  "params": {
    "M": {
      "customer": {
        "S": "TEST"
      },
      "index": {
        "N": "1"
      }
    }
  },
  "THIS_STATUS": {
    "N": "10"
  },
  "TYPE": {
    "N": "22"
  }
}

# Lazy-eval the dynamodb attribute (boto3 is dynamic!)
boto3.resource('dynamodb')

# To go from low-level format to python
deserializer = boto3.dynamodb.types.TypeDeserializer()
python_data = {k: deserializer.deserialize(v) for k,v in low_level_data.items()}

# To go from python to low-level format
serializer = boto3.dynamodb.types.TypeSerializer()
low_level_copy = {k: serializer.serialize(v) for k,v in python_data.items()}

assert low_level_data == low_level_copy
51
killthrush