1. ConfigParser类读取config.ini的options全部返回为小写字母
查看configparser.ConfigParser类中,是因为optionxform方法返回了optionstr.lower()
def optionxform(self, optionstr):
return optionstr.lower()
第一种方法是直接修改源码,把return optionstr.lower() 改成return optionstr.
此种解决方案的不足之处是只能在本机生效,换台机器就会出问题
第二种方法是自己封装一个MyConfig类,继承ConfigParser,重写optionxform方法
(方案参考https://blog.csdn.net/Ha_hha/article/details/78965011)
from configparser import ConfigParser
import os
conf = os.path.join(os.path.dirname(__file__), "../config/config.ini")
class MyConfig(ConfigParser):
# 继承ConfigParser,解决读取options自动转换成小写的问题
def __init__(self):
super().__init__()
def optionxform(self, optionstr):
# 重写optionxform方法,解决ConfigParser类读取的options都会转换成小写的问题
return optionstr
config = MyConfig()
# logger.debug("以utf-8编码方式打开配置文件{}".format(conf))
config.read(filenames=conf, encoding="utf-8")
if __name__ == "__main__":
print(config.sections())
print(config.options("LOG"))
2. 日志打印多次
自己封装的日志模块,在多个地方都有调用,用于输出日志,运行runner时发现日志有4条重复记录,百度后发现是因为在多个模块中实例化自定义的log类,每次实例化就会addhandler一次,有4处实例化就会addhandler4次,导致日志输出4次
# filename: log.py
import logging
class MyLogger:
def __new__(self):
# 1. 创建log收集器,设置日志收集级别
mylogger = logging.getLogger("mylogger")
mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))
# 2. 创建输出渠道,设置日志输出级别
sh = logging.StreamHandler()
fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
sh.setLevel(config.get("LOG", "SH_LEVEL"))
fh.setLevel(config.get("LOG", "FH_LEVEL"))
# 3. 设置文件输出格式,添加格式
fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT", raw=True)) # 读取包含%符号时,避免被转义,增加一个参数raw=True
fh.setFormatter(fmt)
# 4. 把输出渠道添加到日志收集器
mylogger.addHandler(sh)
mylogger.addHandler(fh)
return mylogger
其他调用log模块的模块有4个,其中1个代码如下:
# filename: operate_excel.py
import openpyxl
import os
from prac_unittest_3.common.log import MyLogger # 导入MyLogger类
logger = MyLogger() # 每个调用log模块的地方都要实例化一个logger对象
class CaseObj:
def __init__(self, zip_obj):
for i in list(zip_obj):
setattr(self, i[0], i[1])
# 1. 封装一个读取excel的类
class ReadExcel:
def __init__(self, filename, sheetname):
self.filename = filename
self.sheetname = sheetname
self.wb = openpyxl.load_workbook(self.filename)
self.sh = self.wb[self.sheetname]
logger.debug("打开文件{}的{}表单".format(self.filename, self.sheetname))
def read_data_obj(self):
cases = []
# self.sh.rows 是一个生成器,不能通过下标来访问,有2种方案获得表头,一种是self.sh.rows转换成list先,再通过list下标去访问.第二种是通过next()来调用,第一次用next()来调用,第2行及以后的,直接遍历,遍历会自动调用next() 方法
firstrow = next(self.sh.rows)
# 1. 读取第一行作为表头,存放在title列表
titles = [cell.value for cell in firstrow]
logger.debug("读取第一行:{}".format(titles))
# 2. 读取第2--max_row,存放在data列表
for row in self.sh.rows:
datas = [cell.value for cell in row]
logger.debug("读取到的数据为:{}".format(datas))
# 3. 聚合title和data,形成字典形式
case_obj = CaseObj(zip(titles, datas))
logger.debug("组装成用例:{}".format(case_obj))
# 4. 每条用例追加到总的用例列表中
cases.append(case_obj)
return cases
def write_data(self, row, column, data):
logger.debug("第{}行第{}列写入的内容为:{}".format(row, column, data))
self.sh.cell(row=row, column=column).value = data
logger.debug("保存内容到文件{}".format(self.filename))
self.wb.save(self.filename)
修改log模块,先实例化一个logger对象,其他需要用到日志模块的,直接导入这个logger对象即可
# filename: log.py
import logging
class MyLogger:
def __new__(self):
# 1. 创建log收集器,设置日志收集级别
mylogger = logging.getLogger("mylogger")
mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))
# 2. 创建输出渠道,设置日志输出级别
sh = logging.StreamHandler()
fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
sh.setLevel(config.get("LOG", "SH_LEVEL"))
fh.setLevel(config.get("LOG", "FH_LEVEL"))
# 3. 设置文件输出格式,添加格式
fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT", raw=True)) # 读取包含%符号时,避免被转义,增加一个参数raw=True
fh.setFormatter(fmt)
# 4. 把输出渠道添加到日志收集器
mylogger.addHandler(sh)
mylogger.addHandler(fh)
return mylogger
logger = MyLogger() # 在log模块中实例化MyLogger类,其他需要用到log模块的地方直接import这个logger对象即可。实现只需实例化一次即可到处调用
operate_excel.py 只需修改2行代码,import MyLogger改为import logger,把实例化MyLogger类去掉
# filename: operate_excel.py
import openpyxl
import os
from prac_unittest_3.common.log import logger # 修改为直接导入log模块的logger对象,直接调用logger.debug() 就可以输出日志
class CaseObj:
def __init__(self, zip_obj):
for i in list(zip_obj):
setattr(self, i[0], i[1])
# 1. 封装一个读取excel的类
class ReadExcel:
def __init__(self, filename, sheetname):
self.filename = filename
self.sheetname = sheetname
self.wb = openpyxl.load_workbook(self.filename)
self.sh = self.wb[self.sheetname]
logger.debug("打开文件{}的{}表单".format(self.filename, self.sheetname))
def read_data_obj(self):
cases = []
# self.sh.rows 是一个生成器,不能通过下标来访问,有2种方案获得表头,一种是self.sh.rows转换成list先,再通过list下标去访问.第二种是通过next()来调用,第一次用next()来调用,第2行及以后的,直接遍历,遍历会自动调用next() 方法
firstrow = next(self.sh.rows)
# 1. 读取第一行作为表头,存放在title列表
titles = [cell.value for cell in firstrow]
logger.debug("读取第一行:{}".format(titles))
# 2. 读取第2--max_row,存放在data列表
for row in self.sh.rows:
datas = [cell.value for cell in row]
logger.debug("读取到的数据为:{}".format(datas))
# 3. 聚合title和data,形成字典形式
case_obj = CaseObj(zip(titles, datas))
logger.debug("组装成用例:{}".format(case_obj))
# 4. 每条用例追加到总的用例列表中
cases.append(case_obj)
return cases
def write_data(self, row, column, data):
logger.debug("第{}行第{}列写入的内容为:{}".format(row, column, data))
self.sh.cell(row=row, column=column).value = data
logger.debug("保存内容到文件{}".format(self.filename))
self.wb.save(self.filename)
2.封装log模块,从配置文件中读取日志格式参数报错
LOG_FORMAT= "%(asctime)s %(filename)s line:%(lineno)d %(levelname)s: %(message)s",由于含有百分号%导致无法读取
configparser.InterpolationMissingOptionError: Bad value substitution: option 'LOG_FORMAT' in section 'LOG' contains an interpolation key 'asctime' which is not a valid option name. Raw value: '"%(asctime)s %(filename)s line:%(lineno)d %(levelname)s: %(message)s"'
C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\python.exe "D:/Documentss/WeChat Files/wxid_t7usl9w03ogs22/FileStorage/File/2023-02/训练营资料(1)/day01/prac_unittest_3/common/log.py"
Traceback (most recent call last):
File "D:/Documentss/WeChat Files/wxid_t7usl9w03ogs22/FileStorage/File/2023-02/训练营资料(1)/day01/prac_unittest_3/common/log.py", line 34, in <module>
logger = MyLogger()
File "D:/Documentss/WeChat Files/wxid_t7usl9w03ogs22/FileStorage/File/2023-02/训练营资料(1)/day01/prac_unittest_3/common/log.py", line 25, in __new__
fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT")) # 读取包含%符号时,避免被转义,增加一个参数raw=True
File "C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\lib\configparser.py", line 799, in get
d)
File "C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\lib\configparser.py", line 394, in before_get
self._interpolate_some(parser, option, L, value, section, defaults, 1)
File "C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\lib\configparser.py", line 434, in _interpolate_some
option, section, rawval, var) from None
configparser.InterpolationMissingOptionError: Bad value substitution: option 'LOG_FORMAT' in section 'LOG' contains an interpolation key 'asctime' which is not a valid option name. Raw value: '"%(asctime)s %(filename)s line:%(lineno)d %(levelname)s: %(message)s"'
Process finished with exit code 1
代码:
import logging
from prac_unittest_3.common.config import config
class MyLogger:
def __new__(self):
# 1. 创建log收集器,设置日志收集级别
mylogger = logging.getLogger("mylogger")
mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))
# 2. 创建输出渠道,设置日志输出级别
sh = logging.StreamHandler()
fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
sh.setLevel(config.get("LOG", "SH_LEVEL"))
fh.setLevel(config.get("LOG", "FH_LEVEL"))
# 3. 设置文件输出格式,添加格式
fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT"))
fh.setFormatter(fmt)
# 4. 把输出渠道添加到日志收集器
mylogger.addHandler(sh)
mylogger.addHandler(fh)
return mylogger
logger = MyLogger()
if __name__ == "__main__":
logger.debug("------------debug")
logger.error("------------error")
只需在读取config.get("LOG","LOG_FORMAT",raw=True)变量时,增加一个raw=True属性即可,修改为
import logging
from prac_unittest_3.common.config import config
class MyLogger:
def __new__(self):
# 1. 创建log收集器,设置日志收集级别
mylogger = logging.getLogger("mylogger")
mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))
# 2. 创建输出渠道,设置日志输出级别
sh = logging.StreamHandler()
fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
sh.setLevel(config.get("LOG", "SH_LEVEL"))
fh.setLevel(config.get("LOG", "FH_LEVEL"))
# 3. 设置文件输出格式,添加格式
fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT", raw=True)) # 读取包含%符号时,避免被转义,增加一个参数raw=True
fh.setFormatter(fmt)
# 4. 把输出渠道添加到日志收集器
mylogger.addHandler(sh)
mylogger.addHandler(fh)
return mylogger
logger = MyLogger()
if __name__ == "__main__":
logger.debug("------------debug")
logger.error("------------error")
标签:__,LOG,get,python,unittest,接口,logger,config,self
From: https://www.cnblogs.com/xiaozhuangAna/p/17205553.html