Python之-操作yaml

操作yaml文件

1.yaml介绍

yaml:Yet Another Markup Language的缩写。Yaml是专门用来写配置文件的语言,非常简洁和强大,远比json格式方便。

  • Python搭建yaml环境

pip install PyYaml

pip install –ignore-installed PyYAML

  • yaml的语法规则

大小写敏感   

使用缩进表示层级关系   

缩进时不允许使用Tab键,只允许使用空格。   

缩进的空格数目不重要,只要相同层级的元素左侧对齐即可   

使用#表示注释    字符串可以不用引号标注

  • yaml的样式

1. 对象:键值对的集合(字典形式)

键值对用冒号”:” 间隔,冒号之间需要用空格分隔

如:

phone: 151xxxxxxxx addr: xx路xx号

得到结果:

{“phone”:”151xxxxxxxx”,”addr”:”xx路xx号”}

2. 数组:列表的形式

数组前需要有短横杠”-”符号,符号与值之间需要用空格分隔

如:

– value1 – value2

得到结果:

[“value1”,”value2”]

3. 特殊类型

字符串默认不使用引号表示。但是字符串之中包含空格或特殊字符,需要放在引号之中

str: ‘内容: 字符串’

None值可用null 或 ~ 符号表示

单引号和双引号都可以使用,双引号不会对特殊字符转义。

s1: ‘内容\n字符串’ s2: “内容\n字符串”

其他内容可参考:https://www.ruanyifeng.com/blog/2016/07/yaml.html?f=tt

4.多个yaml在一个文档中,使用—分割

yaml文件示例

---
student:
  - name: lucy,
    age: 18
    class: 19
    grade: { English: 98,Math: 50,Art: 33 }
  - name: momo,
    age: 33
    class: 20
    grade: { English: 55,Math: 100,Art: 98 }
---
reqesttdata:
  - { shouji: 13456755448,appkey: 0c818521d38759e1 }
  - { shouji: 13456755449,appkey: 0c818521d38759e1 }
  - { shouji: 13456755450,appkey: 0c818521d38759e1 }

读取方法示例

def get_more_than_one_yaml_for_one_file():
    f = open(file=data_file_path1,mode="r")
    data = yaml.safe_load_all(f)#读取一个yaml文件中多个文档需要使用yaml.load_all())
    return data
test_data = get_more_than_one_yaml_for_one_file()
for i in test_data:
    print(i)
    """
    结果是:
    {'student': [{'name': 'lucy,', 'age': 18, 'class': 19, 'grade': {'English': 98, 'Math': 50, 'Art': 33}}, {'name': 'momo,', 'age': 33, 'class': 20, 'grade': {'English': 55, 'Math': 100, 'Art': 98}}]}
{'reqesttdata': [{'shouji': 13456755448, 'appkey': '0c818521d38759e1'}, {'shouji': 13456755449, 'appkey': '0c818521d38759e1'}, {'shouji': 13456755450, 'appkey': '0c818521d38759e1'}]}
    """
print(list(get_more_than_one_yaml_for_one_file())) #通过将generator转换为列表来操作列表
"""结果是
[{'student': [{'name': 'lucy,', 'age': 18, 'class': 19, 'grade': {'English': 98, 'Math': 50, 'Art': 33}}, {'name': 'momo,', 'age': 33, 'class': 20, 'grade': {'English': 55, 'Math': 100, 'Art': 98}}]}, {'reqesttdata': [{'shouji': 13456755448, 'appkey': '0c818521d38759e1'}, {'shouji': 13456755449, 'appkey': '0c818521d38759e1'}, {'shouji': 13456755450, 'appkey': '0c818521d38759e1'}]}]
"""

此外有个注意点,如果使用with open去操作一个一个yaml文件中多个文档的时候,会报异常:ValueError: I/O operation on closed file.

比如

def get_more_than_one_yaml_for_one_file_1():
    with open(file=data_file_path1,mode='r') as f:
        data = yaml.safe_load_all(f)
        return data
a = get_more_than_one_yaml_for_one_file_1()
print(a)#生成了generator
for i in a:
    print(i)
    # 循环拿generator的值就会报错ValueError: I/O operation on closed file.,
    # 我猜是因为with open操作完文件流自动关闭了
    # 但是为什么是这样,没有找到原因,如果知道原因麻烦评论留言

2.读取yaml文件

step1:导入yaml包

import yaml

step2:打开目标文件,读取内容(以字典内容嵌套的格式为例)

打开目标文件的时候,要找yaml文件所在目录

yaml的内容

student:
   - name: lucy,
     age: 18
     class: 19
     grade: { English: 98,Math: 50,Art: 33 }
   - name: momo,
     age: 33
     class: 20
     grade: { English: 55,Math: 100,Art: 98 }

1、为了全局使用考虑,一般在项目的根目录下面,写一个方法,获取跟目录的路径

conftest.py 在项目的根目录下

import os
def get_project_path():
    return os.path.dirname(os.path.abspath(__file__))
PROJECT_PATH = get_project_path()
print(PROJECT_PATH)

结果是:

2. 然后在读取的时候,先导入这个PROJECT_PATH,拼接yaml文件所在的路径

from conftest import PROJECT_PATH
import os
data_file_path = PROJECT_PATH + "\data\student.yaml"
data_file_path1 = os.path.join(PROJECT_PATH,"data","student.yaml")
print("data_file_path是: ",data_file_path)
print("data_file_path1是:",data_file_path1)
# data_file_path 和data_file_path1 是同样的结果

结果是

3.读取yaml的内容

import os
import yaml
from conftest import PROJECT_PATH
data_file_path1 = os.path.join(PROJECT_PATH,"data","student.yaml")
def get_yaml_data():
    with open(file=data_file_path1, mode='r') as f:
        data = yaml.safe_load(f)
        return data
students_info = get_yaml_data()
print(students_info)

结果是

{'student': 
    [
    	{'name': 'lucy,', 'age': 18, 'class': 19, 'grade': {'English': 98, 'Math': 50, 'Art': 33}}, 
     	{'name': 'momo,', 'age': 33, 'class': 20, 'grade': {'English': 55, 'Math': 100, 'Art': 98}}
    ]
}

如果要获取student列表,可通过key去拿值,然后获取相关的内容

students_info["student"]

3.yaml文件的写入

写入是使用yaml.dump()来完成的,要传入两个参数,一个是写入的内容,一个是文件流

import os
import yaml
from conftest import PROJECT_PATH
data_file_path2 = os.path.join(PROJECT_PATH, "data", "student1.yaml")
data = {'reqesttdata': [{'shouji': 13456755448, 'appkey': '0c818521d38759e1'},
                        {'shouji': 13456755449, 'appkey': '0c818521d38759e1'},
                        {'shouji': 13456755450, 'appkey': '0c818521d38759e1'}]}

def write_yaml(data,file_path):
    with open(file=file_path,mode='w',encoding='utf8') as f:
        yaml.dump(data,f)

def read_yaml(data,file_path):
    write_yaml(data,file_path)
    f = open(file=file_path, mode='r', encoding='utf8')
    return yaml.safe_load(f)
print(read_yaml(data,data_file_path2))

运行结果是:成功写入

注意“w”和“a”的区别

with open(yaml_path, "w", encoding="utf-8")   这里w是将文件数据清除后重新写入
with open(yaml_path, "a", encoding="utf-8")   这里a是追加写入

现在数据已经可以正常写入了,如果想要修改数据怎么办呢?也很简单,大体思路就是 读取–>修改–>重写

yaml文件内容

reqesttdata:
- appkey: 0c818521d38759e1
  shouji: '13456755448'
- appkey: 0c818521d38759e1
  shouji: '13456755449'
- appkey: 0c818521d38759e1
  shouji: '13456755450'
data_file_path2 = os.path.join(PROJECT_PATH, "data", "student2.yaml")
data = {'reqesttdata': [{'shouji': "13456755448", 'appkey': '0c818521d38759e1'},
                        {'shouji': "13456755449", 'appkey': '0c818521d38759e1'},
                        {'shouji': "13456755450", 'appkey': '0c818521d38759e1'}]}

def write_yaml(data, file_path):
    """
    写入yaml文件,需要写入的内容和写入的路径
    :param data:
    :param file_path:
    :return:
    """
    with open(file=file_path, mode='w', encoding='utf8') as f:
        yaml.dump(data, f)

def read_yaml(file_path):
    """
    读取yaml文件,需要读取的路径参数file_path
    :param file_path:
    :return:
    """
    f = open(file=file_path, mode='r', encoding='utf8')
    return yaml.safe_load(f)


# 修改shouji=13456755448 为15091757825
def update(k, old_v, new_v):
    """
    修改yaml中列表嵌套字典的值,通过键值对去修改
    :param k:
    :param old_v:
    :param new_v:
    :return:
    """
    yam_data = read_yaml(data_file_path2)#先读取内容
    #yaml文件是字典嵌套列表,所以要通过 yam_data["reqesttdata"]拿到里面的字典列表
    new_data_list = []
    for item in yam_data["reqesttdata"]:
        for i in item:
            # 然后判断对应的键值对是否存在{'shouji': '13456755448'}
            if i==k and item[i]==old_v:
                item[i]=new_v
        # 如果存在修改值,放到修的列表中
        new_data_list.append(item)
    #把新的列表再赋值给字典yam_data["reqesttdata"]
    yam_data["reqesttdata"]=new_data_list
    #调用写入yaml的方法重新写入文件
    write_yaml(yam_data,data_file_path2)
#先写入才能读取
write_yaml(data,data_file_path2)

update("shouji", "13456755448", "15091757825")
print(read_yaml(data_file_path2))

运行结果

4.yaml文件的引用

(1)内部引用

锚点&和引用*对于重复的数据,可以单独写到yaml文件的开头位置,其它的地方用到的可以用*引用

读取

import os
import pprint
import yaml
from conftest import PROJECT_PATH
def read_yaml(file_path):
    """
    读取yaml文件,需要读取的路径参数file_path
    :param file_path:
    :return:
    """
    f = open(file=file_path, mode='r', encoding='utf8')
    return yaml.safe_load(f)
data_file_path3 = os.path.join(PROJECT_PATH, "data", "test_yaml_refer.yaml")
yamldata = read_yaml(data_file_path3)
#pprint用于美化打印的字典
pprint.pprint(yamldata)

读取结果

(2)外部引用

-未理解,需要找时间进一步学习

使用关键字:!include

4.yaml的应用场景

自动化测试框架的配置文件或用例文件

用例文件和pytest结合使用示例:

import configparser
import yaml
from conftest import PROJECT_PATH

ini_file = PROJECT_PATH + "\config\setting.ini"
yaml_file = PROJECT_PATH + "\data\yaml_test_data.yaml"


class GetData:
    # ini_file = PROJECT_PATH + "\config\setting.ini"
    # yaml_file = PROJECT_PATH + "\data\yaml_test_data.yaml"
    def __init__(self):
        self.ini_file = ini_file
        self.yaml_file = yaml_file

    def get_ini_data(self):
        con = configparser.ConfigParser()
        con.read(self.ini_file, encoding="utf8")
        return con

    def get_yaml_data(self):
        with open(self.yaml_file, encoding="utf8") as f:
            data = yaml.safe_load(f)
            return data
my_data = GetData()
get_ini_data = my_data.get_ini_data()
get_yaml_data = my_data.get_yaml_data()

setting.ini

[host] api_sit_url=https://api.binstd.com

yaml_test_data.yaml

reqesttdata:
   - {shouji: 13456755448,appkey: 0c818521d38759e1}
   - {shouji: 13456755449,appkey: 0c818521d38759e1}
   - {shouji: 13456755450,appkey: 0c818521d38759e1}

testcase代码

import requests
from util.read_data import get_ini_data,get_yaml_data
import pytest
url = get_ini_data["host"]["api_sit_url"]
request_data = get_yaml_data["reqesttdata"]

@pytest.mark.parametrize("testdata",request_data)
def test_mobie(testdata):
    res = requests.get(url=url+"/shouji/query",params=testdata)
    assert res.status_code==200
    assert res.json()["result"]["shouji"]=="13456755448"
    assert res.json()["result"]["province"]=="浙江"
    assert res.json()["result"]["city"]=="杭州"
    assert res.json()["result"]["company"]=="中国移动"
    assert res.json()["result"]["areacode"]=="0571"

执行结果

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年11月14日
下一篇 2023年11月14日

相关推荐