Неверно сформированный узел или строка с Dynamodb Возвращаемый предмет - PullRequest
1 голос
/ 19 февраля 2020

Я экспериментировал с DynamoDB в AWS и решил, что это не тот инструмент для меня. Работая в AWS, я загрузил в систему большое количество записей, которые сейчас пытаюсь получить, используя Python. Признаюсь, я совершенно новичок в Python, и то, что я собрал вместе, это из примеров, найденных вокруг inte rnet. Я работаю с журналами аудита Office 365, которые имеют много полей, и когда я извлекаю их из Dynamo, я обнаружил, что десятичные поля возвращаются как decimal('1').

{
  'ItemType': 'File',
  'SourceFileName': 'xxx',
  'UserKey': 'xxx',
  'RecordType': Decimal('6'),
  'UserId': 'xxx',
  'ClientIP': 'xxx',
  'CorrelationId': 'xxx',
  'ObjectId': 'xxx',
  'Version': Decimal('1'),
  'Site': 'xxx',
  'WebId': 'xxx',
  'SourceFileExtension': 'js',
  'SiteUrl': 'xxx',
  'Workload': 'SharePoint',
  'SourceRelativeUrl': 'xxx',
  'EventSource': 'SharePoint',
  'ListId': 'xxx',
  'OrganizationId': 'xxx',
  'Operation': 'FileAccessed',
  'UserAgent': 'xxx',
  'ListItemUniqueId': 'xxx',
  'CreationTime': '2019-07-26T21:54:45',
  'UserType': Decimal('0'),
  'Id': 'xxx',
  'CustomUniqueId': False
}

При устранении неполадок я нашел это удобным функция, которая преобразует десятичное число ('0') в фактическое десятичное число

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):

        if isinstance(o, decimal.Decimal):
            if o % 1 > 0:
                return float(o)
            else:
                return int(o)
        return super(DecimalEncoder, self).default(o)

, и эта функция называется

response = table.scan(Limit=10)
for i in response['Items']:
    d = ast.literal_eval((json.dumps(i, cls=DecimalEncoder)))

По большей части это работает нормально, если у меня нет логического поля (как в примере выше). Затем я получаю эту ошибку

malformed node or string: <_ast.Name object at 0x04B3F778>

Насколько я понимаю с Python, логические значения True и False пишутся с заглавной буквы правильно. Я рассмотрел добавление метода по умолчанию DecimalEncoder, но это не будет хотя он буквально возвращает одно и то же значение

elif isinstance(o,bool):
    return True if o else False

Я обнаружил, что, удалив ключ, я не получил ошибку

if 'CustomUniqueId' in i:
    del i['CustomUniqueId']

Однако я не хочу терять это поле. Я не знаю, как решить эту проблему.

1 Ответ

1 голос
/ 19 февраля 2020

Проблема заключается в том, что вы преобразуете свой объект Python в строку JSON (т.е. команду json.dumps), а затем пытаетесь интерпретировать эту строку как словарь Python (ast.literal_eval принимает строку и пытается запустить его как Python код). Словарь

python очень похож на объект JSON, но он не на 100% совместим. В JSON логическое значение представлено как true и false, а в Python оно представлено как True и False.

Я могу решить эту проблему, используя json.loads, который читает строку JSON и преобразует ее в Python эквивалент:

d = json.loads((json.dumps(i, cls=DecimalEncoder)))

Как говорится, это кажется например, много циклов / обработок для преобразования класса Decimal в нативные числа с плавающей запятой и рекомендовал бы просто использовать Decimal напрямую или преобразовать в число с плавающей точкой (например, float(d['RecordType'])), если вам нужно передать их чему-то, что ожидает число с плавающей запятой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...