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

问题描述:

我有一个需要配置文件的Python测试脚本。预计配置文件将采用JSON格式。有没有办法确定文件是YAML格式还是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) 

现在,有一个Python模块我在互联网上被称为isityaml可用于测试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

YAML不是JSON的超集吗?您应该能够无条件地将文件作为YAML加载。 (我不确定它是否是一个确切的超集 - 我认为以前的版本不是。) – user2357112

+1

难道你只需要YAML文件有一个扩展名和JSON文件有不同的扩展名? – user2357112

+0

user2357112,有两个问题。 1)某些用户可能会在没有.yml或.json后缀的情况下为其配置文件命名,所以我不能通过其配置文件中的后缀 2)仅仅因为文件具有.yml后缀并不一定意味着该文件是YAML格式。 – SQA777

从看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的默认yaml模块ISN “T)。

+0

您的上一条语句并不适用,因为OPs'import yaml'指PyYAML,它只支持旧的YAML 1.1规范。 – Anthon

+0

@安永 - 感谢您的纠正。 –

+0

做'try'和'except'而不指定例外是不好的做法。在JSON中遇到的异常是**'ValueError **。 yaml模块甚至不会引发异常。 –

从你

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()作为在YAML文件上使用load(),您没有100%的控制权(并且您没有)是不安全的。 (ruamel。yaml会提醒你,PyYAML不会)。