【问题标题】:'JSONDecodeError("Expecting value", s, err.value) from None' - but string does have a value'JSONDecodeError("Expecting value", s, err.value) from None' - 但字符串确实有值
【发布时间】:2021-11-26 13:05:37
【问题描述】:

我正在将旧的 Python 2 应用程序转换为使用 amoffat sh 模块的 Python 3。

它通过 sh 命令加载 JSON,该命令已停止工作。

我从 docs 了解到,json.loads 之类的方法不适用于 sh RunningCommand 类的实例,即使它类似于字符串。

但是,我似乎无法获得有效的字符串值!

这是有效的原始代码。

aws = sh.aws 
......
data = aws.s3api("list-objects", bucket=s3url.bucket, prefix=s3url.path, max_keys=1)
data.wait()
items = json.loads(data)

但是现在抛出TypeError: the JSON object must be str, bytes or bytearray, not RunningCommand

所以我尝试同时使用bytesstr,但似乎没有任何效果...

转换为字符串:

....
data.wait()
jsonStr = str(data)
print (type(jsonStr))
print (jsonStr)
items = json.loads(jsonStr)

输出

<class 'str'>
{
    "IsTruncated": true,
    "Marker": "",
    "Contents": [
        {
            "Key": "a/path/to/object/",
            "LastModified": "2021-10-06T10:45:45+00:00",
            "ETag": "\"g41d8gd98f10b204g9800998gcf8527e\"",
            "Size": 100,
            "StorageClass": "STANDARD"
        }
    ],
    "Name": "bucket-name",
    "Prefix": "a/path/to/object/",
    "MaxKeys": 1,
    "EncodingType": "url"
}

Traceback (most recent call last):
.....
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

使用标准输出字节:

....
jsonBytes = data.stdout
print (type(jsonBytes))
print (jsonBytes)
items = json.loads(jsonBytes)

输出

<class 'bytes'>
b'\x1b[?1h\x1b=\r{\x1b[m\n    "IsTruncated": true,\x1b[m\n    "Marker": "",\x1b[m\n    "Contents": [\x1b[m\n        {\x1b[m\n            "Key": "a/path/to/object//",\x1b[m\n            "LastModified": "2021-10-06T10:45:45+00:00",\x1b[m\n            "ETag": "\\"g41d8gd98f10b204g9800998gcf8527e\\"",\x1b[m\n            "Size": 100,\x1b[m\n            "StorageClass": "STANDARD",\x1b[m\n      }\x1b[m\n    ],\x1b[m\n    "Name": "idetailaid-demo",\x1b[m\n    "Prefix": "a/path/to/object//",\x1b[m\n    "MaxKeys": 1,\x1b[m\n    "EncodingType": "url"\x1b[m\n}\x1b[m\n\r\x1b[K\x1b[?1l\x1b>'

Traceback (most recent call last):
.....
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

【问题讨论】:

  • 我不明白为什么,但json.loads() 声称您的问题中 JSON 数据的字符串版本无效,生成了JSONDecodeError。错误出现在第一个反斜杠转义双引号字符的 "ETag" 行上。它看起来对我有效,并在我通过在线 JSON 验证器工具运行它时进行了检查——所以我很困惑。也是。
  • 是的 - 我也注意到了这一点,但这与我得到的错误不同!所以我打算稍后解决这个问题!目前它认为字符串值为None,而不是格式错误。很奇怪。

标签: python json python-3.x


【解决方案1】:

这不是一个真正的答案,因为我不知道如何解决这个问题——我发布它主要是为了解释为什么 sh 模块生成的字符串值中的 JSON 实际上无效。问题是反斜杠本身必须被反斜杠转义,因为它们需要在传递给json.loads()进行解码的字符串中。

修复方法是在 "Contents" 列表中的 "ETag" 键的值中用反斜杠替换它们,如下所示:

import json

json_str = """\
{
    "IsTruncated": true,
    "Marker": "",
    "Contents": [
        {
            "Key": "a/path/to/object/",
            "LastModified": "2021-10-06T10:45:45+00:00",
            "ETag": "\\"g41d8gd98f10b204g9800998gcf8527e\\"",
            "Size": 100,
            "StorageClass": "STANDARD"
        }
    ],
    "Name": "bucket-name",
    "Prefix": "a/path/to/object/",
    "MaxKeys": 1,
    "EncodingType": "url"
}
"""

items = json.loads(json_str)
print(items["Contents"][0]["ETag"])  # -> "g41d8gd98f10b204g9800998gcf8527e"

【讨论】:

  • 那么使用json.loads(json_str.replace('\', '\\')) 会起作用吗?
  • 它可能会,但可能会有一些边缘情况,因为它是如此的蛮力。我也不明白为什么 Python 2 接受字符串(因为 JSON 在这方面没有改变)。
  • 有道理。替换反斜杠后的问题是ETag里面还有两个双引号。
  • @Noah:包含嵌入双引号的字符串仍然是有效的 JSON 字符串——发明了转义以允许它们被表示。
  • @Noah:因为这不是它需要表达的方式。要从字面上嵌入双引号,它必须用反斜杠转义,但反斜杠必须自己转义,因此"\\"g41d8gd98f10b204g9800998gcf8527e\\""
【解决方案2】:

Sorted it 感谢amoffat

查看 AWS 命令​​的字节输出,其中包含用于格式化终端的 ASCII Esc 字符。

原来sh 有一个标志来阻止底层命令认为它在终端中运行,从而返回原始输出(如果它支持的话)。

_tty_out=FALSE

您只需将其作为 arg 传递给 sh

data = aws.s3api("list-objects", bucket=s3url.bucket, prefix=s3url.path, _tty_out=FALSE) 

或者您可以将其烘焙到别名中...

aws = sh.aws.bake(_tty_out=False)
cmd = aws.s3api("list-objects", bucket=s3url.bucket, prefix=s3url.path)
items = json.loads(cmd.stdout)
.....

我假设较新的 AWS CLI 添加了这种格式,而旧版本没有。

【讨论】:

    猜你喜欢
    • 2022-06-11
    • 2020-04-19
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 2021-09-29
    • 2019-08-06
    • 2019-09-18
    相关资源
    最近更新 更多