有没有办法确定文件是YAML还是JSON格式?

时间:2017-06-02 23:53:10

标签: python json yaml

我有一个需要配置文件的Python测试脚本。配置文件应采用JSON格式。

但是我的测试脚本的一些用户不喜欢JSON格式,因为它不可读。

所以我更改了我的测试脚本,以便它需要YAML格式的配置文件,然后将YAML文件转换为JSON文件。

我更喜欢加载配置文件以处理JSON和YAML的函数。如果配置文件是JSON或YAML,yaml或json模块中是否有一个方法可以给我一个布尔响应?

我现在的解决方法是使用两个try / except子句:

import os
import json
import yaml

# This is the configuration file - my script gets it from argparser but in
# this example, let's just say it is some file that I don't know what the format
# is
config_file = "some_config_file"

in_fh = open(config_file, "r")

config_dict = dict()
valid_json = True
valid_yaml = True

try:
    config_dict = json.load(in_fh)
except:
    print "Error trying to load the config file in JSON format"
    valid_json = False

try:
    config_dict = yaml.load(in_fh)
except:
    print "Error trying to load the config file in YAML format"
    valid_yaml = False

in_fh.close()

if not valid_yaml and not valid_json:
    print "The config file is neither JSON or YAML"
    sys.exit(1)

现在,我在Internet上找到一个名为isityaml的Python模块,可用于测试YAML。但是我不想安装另一个软件包,因为我必须在几个测试主机上安装它。

json和yaml模块是否有一个方法可以返回一个布尔值来测试各自的格式?

config_file = "sample_config_file"

# I would like some method like this
if json.is_json(in_fh):
    config_dict = json.load(in_fh)

3 个答案:

答案 0 :(得分:5)

来自你的

import yaml

我的结论是你使用旧的PyYAML。该软件包仅支持YAML 1.1(从2005年开始),并且指定的格式不是JSON的完整超集。使用YAML 1.2(2009年发布),YAML格式成为JSON的超集。

ruamel.yaml(免责声明:我是该包的作者)支持YAML 1.2。因此,通过ruamel.yaml替换PyYAML(而不是添加包),您可以这样做:

import os
from ruamel import yaml

config_file = "some_config_file"

with open(config_file, "r") as in_fh:
    config_dict = yaml.safe_load(in_fh)

并将文件加载到config_dict,不关心输入是YAML还是JSON,也不需要对这两种格式进行测试。

请注意,我使用safe_load()在您无法100%控制的YAML文件上使用load()(并且您没有)是不安全的。 (ruamel.yaml会警告你,PyYAML没有)。

答案 1 :(得分:0)

通过查看jsonyaml模块'文档,看起来他们没有提供任何适当的模块。但是,一个常见的Python习语是EAFP(“更容易请求宽恕而非许可”);换句话说,继续尝试进行操作,并在出现异常时处理。

def load_config(config_file):
    with open(config_file, "r") as in_fh:
        # Read the file into memory as a string so that we can try
        # parsing it twice without seeking back to the beginning and
        # re-reading.
        config = in_fh.read()

    config_dict = dict()
    valid_json = True
    valid_yaml = True

    try:
        config_dict = json.loads(config)
    except:
        print "Error trying to load the config file in JSON format"
        valid_json = False

    try:
        config_dict = yaml.safe_load(config)
    except:
        print "Error trying to load the config file in YAML format"
        valid_yaml = False

如果您愿意,可以创建自己的is_jsonis_yaml功能。这将涉及两次处理配置,但这可能适合您的目的。

def try_as(loader, s, on_error):
    try:
        loader(s)
        return True
    except on_error:
        return False

def is_json(s):
    return try_as(json.loads, s, ValueError)

def is_yaml(s):
    return try_as(yaml.safe_load, s, yaml.scanner.ScannerError)

最后,正如@ user2357112所提到的,"every JSON file is also a valid YAML file"(从YAML 1.2开始),所以你应该能够无条件地处理所有内容为YAML(假设你有一个兼容YAML 1.2的解析器; Python的默认值{{1 }}模块不是。)

答案 2 :(得分:0)

几年后,我遇到了同样的麻烦。我完全同意EAFP,但是如果配置文件为JSON格式或YAML,我仍然在尝试寻找最佳检测方法。 在代码中,我有一些方法可以通知用户中他确实在json文件中发布以及在YAML中的哪个位置发布。 try / except没有按照我真正想要的处理,当我看到这些嵌套的块时,我的眼睛在流血。

这并不完美,仍然存在一些小问题,但是对我来说,基本概念符合我的需求。我会说“足够好”。

我的解决方案是:在配置文件中找到所有可能的独立逗号。如果配置文件包含独立的逗号(json中的分隔符),则我们有json文件,如果找不到任何逗号,则为yaml。 在我的yaml文件中,仅在注释(在“”之间)和列表(在[]之间)中使用逗号。 也许有人会觉得有用。

IWebElement channel = driver.FindElement(By.XPath("//*[@id=\"text\"]/a[contains(@href, '/channel/UCV1Nlv5cOSB--hEjRVo4mUA')]"));