Python阅读YAML:哪里出错了:使用open()或yaml.load()?

时间:2018-06-27 02:24:17

标签: python pyyaml

我有一个脚本,可以将YAML文件加载为对象。相关部分非常简单:

def run_test_spec(self, file_path):
    try:
        with open(file_path, 'r') as f:
            test_spec = yaml.load(f)
        if test_spec:
            do_test(test_spec)
        else:
            print("empty test_spec")
    except BaseException as err:
        print("error in loading yaml file:", file_path)

在使用for entries in os.scandir(some_directory)(在break循环中没有for语句)对文件条目进行一些比较之后,传入了 file_path

直到最近它一直运行良好。 test_spec在第一次运行后获得值None。我用Pycharm调试了它。如果将断点设置在行if test_spec:上,则test_spec是None,但是如果将断点设置在行with open(...)yaml.load()上,则会加载test_spec正确地。最后,我在time.sleep(0.2)之前添加了with open(...)语句,然后它始终有效。

可能的原因是什么?是with open(...)还是yaml.load()的问题?不睡觉怎么办?

于2018年6月27日编辑,

我做了进一步的调试,并在代码中找到了区别所在的行。在我计算机上的文件/usr/local/lib/python3.5/dist-packages/yaml/reader.py中:

def update_raw(self, size=4096):
    data = self.stream.read(size)
    if self.raw_buffer is None:
        self.raw_buffer = data
    else:
        self.raw_buffer += data
    self.stream_pointer += len(data)
    if not data:
        self.eof = True

如果将断点设置为第一行(data = ...),则将data与文件内容一起很好地读取,但是,将断点设置为第二行({{1 }}),将if self.raw_buffer is None:作为一个空字符串读入,这导致了data,并因此从StreamEndEvent中返回了空值。

我无法进入yaml.load(),只能进入self.stream.read(size)中的某些代码。

我不认为是Python库导致了此问题。可能与我的代码有关。我注意到在运行测试后会发生这种情况,其中涉及产生两个作为管道运行的子进程,并使用/usr/lib/python3.5/codecs.py杀死第二个进程。我用terminate()检查了程序,运行后只有一个线程,没有子进程,没有打开文件。看起来很干净。但是然后无法读取新的请求文件,除非我在读取流之前添加了睡眠或稍作休息。如果同样在管道中的第二个进程本身终止,则不会发生此问题。

如果未设置断点,而只是在调用psutil之前打印f.tell(),则无论yaml.load(f)是否返回None,它始终为0。

1 个答案:

答案 0 :(得分:0)

PyYAML昨天(2018-06-26)收到new release。没有宣布这表明API中断的公告,但是可以预料到主要版本号的更改。

您使用的(不安全的)load()已重命名 danger_load()通过合并this PR

您可以将PyYAML安装固定在3.x(pip install "pyyaml<4")上,或将代码更改为使用danger_load()。最好的解决方案可能是使用!!python/path_to_your_type为现在转储的对象编写显式表示符,以便可以使用safe_load()

我在文档中找不到任何可能损坏的通知。