有没有办法确定文件是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)
从看json
和yaml
模块的文档,它看起来像他们没有提供任何适当的模块。然而,一个常见的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_json
或is_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)。
您的上一条语句并不适用,因为OPs'import yaml'指PyYAML,它只支持旧的YAML 1.1规范。 – Anthon
@安永 - 感谢您的纠正。 –
做'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不会)。
YAML不是JSON的超集吗?您应该能够无条件地将文件作为YAML加载。 (我不确定它是否是一个确切的超集 - 我认为以前的版本不是。) – user2357112
难道你只需要YAML文件有一个扩展名和JSON文件有不同的扩展名? – user2357112
user2357112,有两个问题。 1)某些用户可能会在没有.yml或.json后缀的情况下为其配置文件命名,所以我不能通过其配置文件中的后缀 2)仅仅因为文件具有.yml后缀并不一定意味着该文件是YAML格式。 – SQA777