一:配置文件 1. 什么是配置文件 配置文件是为程序配置参数和初始设置的文件。一般为文本文件,以ini
,conf
,cnf
,cfg
,yaml
等作为后缀名。
例如mysql
的配置文件my.cnf
内容如下:
1 2 3 4 5 [mysqld] bind-address = 0.0 .0.0 mysqlx-bind-address = 127.0 .0.1 default_authentication_plugin = mysql_native_password
2.配置文件的作用 通过配置文件可以使得代码中的参数根据配置文件进行动态配置,而不用直接修改代码的内部,减少风险提高代码复用。
经典应用场景
多个函数调用同一参数,这个时候最好进行配置化,改动配置文件就可以修改所有函数
某个参数需要能够动态改变
3.常见配置文件 3.1 ini/conf/cnf
文件 这类配置文件由节(section),键(key),值(value)由一下格式组成。
1 2 3 4 5 [section1] key1 =value1key2 =value2[section2] key1 =value1
3.2 yaml文件 3.2.1 简介 yaml文件本质上是一种标记语言,和普通的配置文件相比它能表示更为复杂的数据结构。
它的基本语法规则如下:
大小写敏感
使用缩进表示层级关系
缩进时不允许使用Tab键,只允许使用空格。
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
#
表示行注释
yaml支持三种数据结构:
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典 (dict)
数组:一组有顺序的值,又称为序列/ 列表(List)
标量:单个值
3.2.2 对象 对象的一组键值对使用冒号结构表示
1 2 name: xinlan person: {name: xinlan , age: 18 }
YAML
3.2.3 数组 一组连字符开头的行,构成一个数组
1 2 3 4 - title- username- passwordargs : [title, username, password]
YAML
3.2.4 组合结构 对象数组可以结合使用,形成组合结构
1 2 3 4 5 6 7 8 9 10 name : xinlan age : 18 hobby : [python, 游戏, sport] ouxiang : - name : 刘德华 age : 60 - name : 任达华 age : 65
YAML
3.2.5 标量 yaml可以表示如下数据类型如下:
字符串 默认字符串不要加引号,如果有特殊字符串,用引号包裹
布尔值 true,false
整数
浮点数
Null - 表示null
时间 iso8601 1949-10-01t09:00:00+08:00
日期 1949-10-01
二:解析配置文件 1.ConfigParser
模块 python提供内置库ConfigParser
用来解析ini
格式的配置文件。
1 2 3 4 5 6 7 8 9 [log] filename =py45.logdebug =false [mysql] host =127.0 .0.1 database =lemonuser =rootpassword =123456 port =3306
Ini
1 2 3 4 5 6 7 8 9 10 from configparser import ConfigParserconfig = ConfigParser() # 实例化config.read('config.ini' ) # 读取配置文件 print (config.sections()) # 返回所有的section名称字符串,一列表返回print (config.options('mysql' )) # 返回指定section下对应的配置项的所有的字符串名称,以列表返回print (config.items('log' )) # 返回指定section下所有的配置项的键值对,二元元组print (config.get ('mysql' , 'port' ))print (config.getint('mysql' , 'port' )) # 指定类型,帮我们转换类型print (config["mysql" ]['host' ]) # 直接以字典取值的方式读取ini文件
Python
输出
1 2 3 4 5 6 7 8 9 C:\Users\12446 \AppData\Local\Programs\Python\Python39\python.exe D:/Lemon/ py45/day19/ read_ini.py ['log' , 'mysql' ] ['host' , 'database' , 'user' , 'password' , 'port' ] [('filename' , 'py45.log' ), ('debug' , 'false' )] 3306 3306 127.0 .0.1 Process finished with exit code 0
Python
2.pyyaml
模块 python解析yaml文件需要安装第三方库pyyaml
。
pip安装pip install pyyaml
pyyaml库的使用非常简单,它会将整个yaml配置文件内容解析成一个python字典返回。
1 2 3 4 5 import yaml with open('config.yaml' , 'r' , encoding ='utf-8' ) as f: config = yaml.load(f, Loader =yaml.FullLoader) print (config)
Python
输出的是字典
1 2 3 4 5 6 {'log': {'filename': 'py45.log', 'debug': False}, 'mysql': {'host': '127.0.0.1', 'database': 'lemon', 'user': 'root', 'password': '123456 ', 'port': 3306 }}
Python
3.配置文件解析模块封装 3.1 功能分析 封装前,我们先考虑一下,这个配置文件解析模块需要哪些功能?
能够处理多种配置文件
返回值数据结构一致
3.2 封装成函数 封装思路:
输入参数为配置文件名,以及配置文件字符编码
根据配置文件名获取配置文件后缀判断配置文件类型,然后分别处理
ini配置文件解析后处理成字典,其实也可以不出处理,ConfigParser
对象支持字典格式的取值
ini配置文件解析的一个重要的问题时,不能自动识别配置类型,所以解耦不是很彻底,有时候需要在引用代码中另外处理。
yaml库直接解析数据为一个字典,且自动识别数据类型,不需要做其他处理。
代码封装如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from configparser import ConfigParserimport yamldef get_config (filename, encoding='utf-8' ): """ 获取yaml/ini配置文件中的配置 @param filename: str 文件名 @param encoding: 文件字符编码 """ suffix = filename.split('.' )[-1 ] if suffix in ['yaml' , 'yml' ]: with open (filename, 'r' , encoding=encoding) as f: data = yaml.load(f, Loader=yaml.FullLoader) else : conf = ConfigParser() conf.read(filename) data = {} for section in conf.sections(): data[section] = dict (conf.items(section)) return data if __name__ == '__main__' : res = get_config(r'D:\config.yaml' ) print (res)
Python
3.3 封装成类 封装思路:
整体思路和上面的函数封装是一致的
将解析ini文件和yaml文件的逻辑分开放到两个私有方法中
因为逻辑本身比较简单,面向对象封装和函数封装没有太多区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 from configparser import ConfigParserimport yamlclass Config : def __init__ (self, filename, encoding='utf-8' ): self .filename = filename self .encoding = encoding self .suffix = self .filename.split('.' )[-1 ] if self .suffix not in ['yaml' , 'yml' , 'cnf' , 'conf' , 'ini' ]: raise ValueError('不能识别的配置文件后缀:{}' .format (self .suffix)) def parse_ini (self ): """ 解析ini :return: """ conf = ConfigParser() conf.read(self .filename) data = {} for section in conf.sections(): data[section] = dict (conf.items(section)) return data def parse_yaml (self ): """ 解析yaml :return: """ with open (self .filename, 'r' , encoding=self .encoding) as f: data = yaml.load(f, Loader=yaml.FullLoader) return data def parse (self ): """ 解析配置文件 :return: """ if self .suffix in ['yaml' , 'yml' ]: return self .parse_yaml() else : return self .parse_ini() if __name__ == '__main__' : cm = Config(r'D:\config.yaml' ) res = cm.parse() print (res)
Python
4.应用到项目中 一个框架封装的彻不彻底的标准是能否复用,也即是另外一个项目来用时,不需要修改框架的源码。
在我们目前封装的框架中,耦合高的点有:
日志器调用时的传参
用例数据文件的路径
生成报告时的传参
配置文件config.yaml
1 2 3 4 5 6 7 8 9 10 11 log: name: ytest filename: 'D:\logs\my.log' debug: true test_cases_dir: 'D:\cases' test_data_file: 'D:\data.xlsx' test_report: report_dir: 'D:\reports' title: '测试报告' desc: '测试报告' tester: 'k'
YAML
get_config
函数解析后:
1 2 3 4 5 6 7 8 9 {'log' : {'name' : 'ytest' , 'filename' : 'D :\\my.log', 'debug' : True }, 'test_cases_dir' : 'D :\\cases', 'test_data_file' : 'D :\\data.xlsx', 'test_report' : {'report_dir' : 'D :\\reports', 'title' : '份测试报告' , 'desc' : '测试报告' , 'tester' : 'chenyongzhi' }}
Python
我们可以将这些写到配置文件中,然后在框架代码中动态的获取配置文件的相对应设置,实现代码的解耦。
在common
文件夹下的 __init__.py
的文件中调用解析配置文件的函数
1 2 3 4 5 6 7 from common.log_handler import get_loggerfrom common.read_excel_tool import get_data_from_excelfrom common.congig_handler import get_configconf = get_config(r'D:\config.yaml' ) logger = get_logger(**conf['log' ])
Python
1 cases = get_data_from_excel(conf['test_data_file' ], 'login' )
Python
1 2 3 4 5 6 7 8 9 import unittestimport unittestreportfrom common import confif __name__ == '__main__' : discover = unittest.defaultTestLoader.discover(conf['test_cases_dir' ]) # 表示收集当前目录下所有用例 runner = unittestreport.TestRunner(discover, **conf['test_report' ]) runner.run()