一:配置文件
1. 什么是配置文件
配置文件是為程序配置參數和初始設置的文件。一般為文本文件,以ini
,conf
,cnf
,cfg
,yaml
等作為后綴名。
例如MySQL
的配置文件my.cnf
內容如下:
[mysqld]
# Only allow connections from localhost
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)由一下格式組成。
[section1]
key1=value1
key2=value2
[section2]
key1=value1
3.2 yaml文件
3.2.1 簡介
yaml文件本質上是一種標記語言,和普通的配置文件相比它能表示更為復雜的數據結構。
它的基本語法規則如下:
-
大小寫敏感
-
使用縮進表示層級關系
-
縮進時不允許使用Tab鍵,只允許使用空格。
-
縮進的空格數目不重要,只要相同層級的元素左側對齊即可
#
表示行注釋
yaml支持三種數據結構:
-
對象:鍵值對的集合,又稱為映射(mApping)/ 哈希(hashes) / 字典 (dict)
-
數組:一組有順序的值,又稱為序列/ 列表(List)
-
標量:單個值
3.2.2 對象
對象的一組鍵值對使用冒號結構表示
name: xinlan
person: {name: xinlan, age: 18}
YAML
3.2.3 數組
一組連字符開頭的行,構成一個數組
- title
- username
- password
args: [title, username, password]
YAML
3.2.4 組合結構
對象數組可以結合使用,形成組合結構
name: xinlan
age: 18
hobby: [Python/ target=_blank class=infotextkey>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
格式的配置文件。
[log]
filename=py45.log
debug=false
[mysql]
host=127.0.0.1
database=lemon
user=root
password=123456
port=3306
Ini
from configparser import ConfigParser
config = 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
輸出
C:Users12446AppDataLocalProgramsPythonPython39python.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字典返回。
import yaml
with open('config.yaml', 'r', encoding='utf-8') as f:
config = yaml.load(f, Loader=yaml.FullLoader)
print(config)
Python
輸出的是字典
{'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庫直接解析數據為一個字典,且自動識別數據類型,不需要做其他處理。
代碼封裝如下
from configparser import ConfigParser
import yaml
def get_config(filename, encoding='utf-8'):
"""
獲取yaml/ini配置文件中的配置
@param filename: str 文件名
@param encoding: 文件字符編碼
"""
# 1. 獲取配置文件后綴
suffix = filename.split('.')[-1]
# 2.判斷類型
# 3.分別處理
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))
# 4. 返回
return data
if __name__ == '__mAIn__':
res = get_config(r'D:config.yaml')
print(res)
Python
3.3 封裝成類
封裝思路:
-
整體思路和上面的函數封裝是一致的
-
將解析ini文件和yaml文件的邏輯分開放到兩個私有方法中
-
因為邏輯本身比較簡單,面向對象封裝和函數封裝沒有太多區別
from configparser import ConfigParser
import yaml
class 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
log:
name: ytest
filename: 'D:logsmy.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
函數解析后:
{'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
的文件中調用解析配置文件的函數
from common.log_handler import get_logger
from common.read_Excel_tool import get_data_from_excel
from common.congig_handler import get_config
conf = get_config(r'D:config.yaml') # 在這里將配置文件解析成字典格式返回
logger = get_logger(**conf['log']) # 在這里創建日志器----日志器調用時的傳參
Python
cases = get_data_from_excel(conf['test_data_file'], 'login') # ---測試用例數據的路徑
Python
import unittest
import unittestreport
from common import conf
if __name__ == '__main__':
discover = unittest.defaultTestLoader.discover(conf['test_cases_dir']) # 表示收集當前目錄下所有用例
runner = unittestreport.TestRunner(discover, **conf['test_report'])
runner.run()