awscli dynamodb 不通过任务运行程序执行查询,但通过 shell 正确执行

awscli dynamodb not executing queries via task runner but executes properly via shell

我有一个关于字符串转义的奇怪问题:因为我试图查询的值是字节字符串,如果我 运行 通过 shell 的命令,例如:

aws --endpoint-url=http://localhost:4566 \
   dynamodb query \
  --table-name user_storage \
  --key-condition-expression "id = :v1" \
  --expression-attribute-values '{":v1": {"S": "b\'id-value-here\'"}}'

它正确执行并打印输出:

{
    "Items": [
        {
            "result": {
                "B": "this is the result value"
            },
            "id": {
                "S": "b'id-value-here'"
            },
            "timestamp": {
                "N": "1630340264.7819724"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

但是,我正在尝试通过 python 的 Invoke 任务 运行ner 来执行它。这是完全相同的命令,但我似乎无法将字节字符串的编码正确传递给 shell 。我已经尝试了许多编码组合和转义 id 值周围的内部引号,似乎没有什么能与 shell 命令相同。 (注意:我使用的是 Python 3.6.9)

@task
def get_user(cmd, user_id):
    c1 = f'''aws --endpoint-url=http://localhost:4566 \
            dynamodb query \
            --table-name user_storage \
            --key-condition-expression "id = :v1" \
            --expression-attribute-values '{{":v1": {{"S": "{user_id.encode()}"}}}}'
    '''
    cmd.run(c1, echo=True)

> invoke get-user id-value-here
aws --endpoint-url=http://localhost:4566 dynamodb query --table-name user_storage --key-condition-expression "id = :v1" --expression-attribute-values '{":v1": {"S": "b'id-value-here'"}}'
    
{
    "Items": [],
    "Count": 0,
    "ScannedCount": 0,
    "ConsumedCapacity": null
}

什么给了?一段时间以来,我一直在用头撞墙。似乎无法让它正确传递编码的 id 值。

事实证明,这是 Python 处理 f 弦的方式的一个怪癖:https://www.python.org/dev/peps/pep-0498/#no-binary-f-strings

解决方法是将负载写入 json 文件并将其传递给 awscli:

filename = "key.json"
payload = '{{":v1": {{"S": "{0}"}}}}'.format(user_id.encode())

with open(f"./{filename}", 'w') as f:
    dump(loads(payload), f)

c1 = '''aws --endpoint-url=http://localhost:4566 \
        dynamodb query \
        --table-name user_storage \
        --key-condition-expression "id = :v1" \
        --expression-attribute-values file://{0}
'''.format(filename)

cmd.run(c1, echo=True)