python实战-编写请求方法重试(用途:请求重试、也可用于其他场景)、日志、执行耗时、手机号与邮箱校验装饰器
更新日志
2023.2.9 增加重试装饰器
防止函数原信息被改变使用:@functools.wraps(func)装饰执行函数
# _*_ coding: UTF-8 _*_
"""
@project -> file : city-test -> wrapper_util
@Author : qinmin.vendor
@Date : 2023/1/28 11:05
@Desc :
"""
import re
import time
import functools
import traceback
from utils.operation_logging import operationLogging
# 注意事项:装饰器不能装饰classmethod
log=operationLogging()
def logger_wrapper(log_level,module_obj=None,class_obj=None,is_send_email=False):
def logger_wrapper_main(func):
@functools.wraps(func) #防止函数原信息被改变
def wrapper(*args,**kwargs):
log_content=f' func_obj:{func.__name__}'
if module_obj:
log_content = f' module_obj:{module_obj},' + log_content
if class_obj:
log_content = f' class_obj:{class_obj},' + log_content
log.log_main(log_level,is_send_email,f' start call {log_content}, call params: {func.__code__.co_cellvars}')
exec_result=func(*args,**kwargs)
log.log_main(log_level,is_send_email,f' end call {log_content},call result: {exec_result}')
return exec_result
return wrapper
return logger_wrapper_main
def exec_time_wrapper(round_num:int,module_obj=None,class_obj=None,is_send_email=False):
def exec_time_wrapper_main(func):
@functools.wraps(func) #防止函数原信息被改变
def wrapper(*args, **kwargs):
s_time = time.perf_counter()
# 需要定义一个值来接收函数的返回值,否则函数return是无效的
exec_result=func(*args, **kwargs)
e_time=time.perf_counter()
log_content = f' func_obj:{func.__name__} 执行耗时,{round(e_time - s_time, round_num)}s'
if module_obj:
log_content = f' module_obj:{module_obj},' + log_content
if class_obj:
log_content = f' class_obj:{class_obj},' + log_content
log.log_main('info', is_send_email, log_content)
return exec_result
return wrapper
return exec_time_wrapper_main
def phone_validation_check_wapper(func):
'''手机号验证装饰器'''
@functools.wraps(func)
def wrapper(*args,**kwargs):
is_all_match = all([re.search('1[345789][0-9]{9}$', str(i)) for i in args])
if not is_all_match :
raise Exception('输入的手机号格式不合法')
func(*args,**kwargs)
return wrapper
def email_validation_check_wapper(func):
'''邮箱格式验证装饰器'''
@functools.wraps(func)
def wrapper(*args,**kwargs):
is_all_match=all([ re.search('\S+@\S+\.com$',str(i)) for i in args])
if not is_all_match :
raise Exception('输入的邮箱格式不合法')
func(*args,**kwargs)
return wrapper
def retry_wrapper(retry_num,retry_conditon,retry_conditon_judge:str='==',retry_sleep_time:(int,float)=1,module_obj=None,class_obj=None,is_send_email=False):
'''
Args:
retry_num: 重试次数
retry_conditon: 触发重试的条件
retry_conditon_judge: 重试条件的判断值,可以是:==、not in、in、!=、括号里面的字符只支持相同类型的比较(>= <= > < %=)
module_obj: 模块对象
class_obj: 类对象
is_send_email: 是否触发发送邮件
Returns:
'''
if not isinstance(retry_conditon_judge,str):
raise Exception("retry_conditon_judge(重试判断条件)必须是str类型")
if not isinstance(retry_sleep_time,(int,float)):
raise Exception("retry_sleep_time(重试等待时间)必须是int、float类型")
judge_retry_conditon_type=retry_conditon_judge.lower().strip()
group_response_status='response_status_match'
group_response_content='response_content_match'
py_builtin_types = (str, int, float, list, set, tuple, dict, bool, bytes, type) #定义python内置类型,用于判断
def retry_wrapper_main(func):
@functools.wraps(func) #防止函数原信息被改变
def wrapper(*args,**kwargs):
def retry_func(judge_condition_statement,retry_conditon_str,judge_retry_conditon_type,group_type):
'''函数重试逻辑'''
func_exec_result=None
for i in range(retry_num):
# 重试等待时间随重试次数增加而增加
log.log_main('info',False,f"retry前等待:{retry_sleep_time+i}s")
time.sleep(retry_sleep_time+i)
func_exec_result=func(*args,**kwargs)
judge_condition_statement=judge_condition_statement_dispose(group_type=group_type,judge_retry_conditon_type=judge_retry_conditon_type,
judge_condition_statement=judge_condition_statement,exec_result=func_exec_result,retry_conditon_str=retry_conditon_str)
log.log_main('info',False,f"retry_第{i+1}次:{judge_condition_statement}")
if eval(judge_condition_statement):
log.log_main('info', is_send_email, f' {log_content},请求重试成功,重试次数为:{i + 1}')
# print("func_exec_result:",func_exec_result)
return func_exec_result
log.log_main('error', is_send_email, f' {log_content},请求重试失败,返回函数最新执行结果')
return func_exec_result
def check_retry_conditon_judge_and_return_group(judge_retry_conditon_type,exec_result,legal_chars):
'''校验重试判断条件字符合法性'''
if not judge_retry_conditon_type in legal_chars:
log_content = f'judge_retry_conditon_type只能是:{legal_chars}中的任意一个字符'
log.log_main('error', is_send_email, log_content)
raise Exception(log_content)
'''校验重试判断条件in not in时重试条件的数据类型是否合法'''
if judge_retry_conditon_type in ('in', 'not in'):
if (not isinstance(retry_conditon, (list, set, tuple, dict))):
log_content = f'judge_retry_conditon_type为in或者not in时,retry_conditon必须可迭代'
log.log_main('error', is_send_email, log_content)
raise Exception(log_content)
elif judge_retry_conditon_type in ('<','>','>=','<='):
if ( isinstance(exec_result,py_builtin_types)) and (type(exec_result)!=type(retry_conditon)):
log_content = f'judge_retry_conditon_type为(<,>,>=,<=)时,retry_conditon与exec_result的类型必须一致'
log.log_main('error', is_send_email, log_content)
raise Exception(log_content)
elif judge_retry_conditon_type=='size':
if not isinstance(retry_conditon,(int,float)):
log_content = f'judge_retry_conditon_type为size时,retry_conditon类型必须为int、float'
log.log_main('error', is_send_email, log_content)
raise Exception(log_content)
if judge_retry_conditon_type in ('==','!=', '>=', '<=', '>', '<', 'in','not in'):
return group_response_status
return group_response_content
def retry_condition_and_exec_result_dispose(retry_condition,exec_result):
'''处理重试条件与函数执行结果'''
def response_dispose(response:requests.models.Response,attribute='status_code'):
'''如果类型是response且包含特定属性,返回属性'''
is_status_code = hasattr(response, attribute)
args_obj_str = eval(f'int(response.{attribute})') if is_status_code else response
return args_obj_str
def retry_condition_and_exec_result_dispose_main(args_obj):
if not isinstance(args_obj,py_builtin_types):
return args_obj
args_obj_str=args_obj
if isinstance(args_obj_str, str):
args_obj_str=data_util.class_type_str_dispose(str_in=args_obj_str)
import_module_dict = data_util.dynamic_import_module(module_name=args_obj_str)
if import_module_dict:
globals().update(import_module_dict)
if all([i in import_module_dict.keys() for i in args_obj_str.split('.') ]):
args_obj_str=eval(args_obj_str)
else:
args_obj_str = data_util.build_str_obj(args_obj)
else:
args_obj_str = eval(args_obj) if \
data_util.isevaluatable_unsafety(args_obj, is_dynamic_import_module=False) \
else data_util.build_str_obj(args_obj)
return args_obj_str
if isinstance(retry_condition,str):
retry_condition = retry_condition_and_exec_result_dispose_main(retry_condition)
exec_result=retry_condition_and_exec_result_dispose_main(exec_result)
elif isinstance(retry_condition,(int,list,tuple,set,dict)):
exec_result=response_dispose(exec_result)
if type(retry_condition) != type and type(exec_result) != type:
'''处理重试条件类型与函数执行结果类型不一致任意一方是类型的字符串形式的情况'''
if type(retry_condition)!=type(exec_result):
if isinstance(retry_condition,str) and '<class ' in retry_condition:
exec_result=str(type(exec_result))
exec_result=data_util.build_str_obj(exec_result)
elif isinstance(exec_result,str) and '<class ' in exec_result:
retry_condition = str(type(retry_condition))
retry_condition = data_util.build_str_obj(retry_condition)
else:
exec_result = type(exec_result) if type(exec_result) != type else exec_result
retry_condition = type(retry_condition) if type(
retry_condition) != type else retry_condition
retry_condition = data_util.build_str_obj(f'{retry_condition}')
exec_result = data_util.build_str_obj(f'{exec_result}')
return retry_condition,exec_result
def judge_condition_statement_dispose(group_type:str,judge_retry_conditon_type:str,judge_condition_statement:str,
exec_result,retry_conditon_str:str):
'''根据重试判断条件、重试判断类型,处理为最终需要的重试判断语句'''
# '''用于函数执行结果为type的情况(例如:requests.request的执行结果是requests.models.Response)'''
if group_type==group_response_status:
retry_conditon_str, exec_result = retry_condition_and_exec_result_dispose(retry_conditon,exec_result)
judge_condition_statement = f"{exec_result}{judge_retry_conditon_type}{retry_conditon_str}"
# '''用于函数结果是str、dict、bytes的情况(常规情况下建议使用此方式)'''
elif group_type==group_response_content:
if judge_retry_conditon_type == 'json_path':
exec_result = data_util.json_path_parse_public(json_path=retry_conditon, json_obj=exec_result)
judge_condition_statement = f'{exec_result}'
elif judge_retry_conditon_type == 'regex':
exec_result_match = re.search(retry_conditon_str, str(exec_result))
if exec_result_match:
return str(exec_result)
else:
exec_result = None
judge_condition_statement = f'{exec_result}'
elif judge_retry_conditon_type == 'size':
exec_result_size = len(str(exec_result).encode('utf-8')) if not \
isinstance(exec_result,bytes) else len(exec_result)
retry_conditon_str = int(retry_conditon_str)
judge_condition_statement = f'{exec_result_size} >= {retry_conditon_str}'
return judge_condition_statement
log_content=f'func_obj:{func.__name__}'
if module_obj:
log_content = f' module_obj:{module_obj},' + log_content
if class_obj:
log_content = f' class_obj:{class_obj},' + log_content
legal_chars=('==','!=', '>=', '<=', '>', '<', 'in','not in','json_path','regex','size')
'''检查重试判断条件是否合法'''
exec_result=func(*args,**kwargs)
group_type=check_retry_conditon_judge_and_return_group(judge_retry_conditon_type=judge_retry_conditon_type,exec_result=exec_result,legal_chars=legal_chars)
judge_condition_statement="True"
retry_conditon_str=retry_conditon
judge_condition_statement = judge_condition_statement_dispose(group_type=group_type,judge_retry_conditon_type=judge_retry_conditon_type,
judge_condition_statement=judge_condition_statement,exec_result=exec_result,retry_conditon_str=retry_conditon_str)
# log.log_main('info',False,f'before: {judge_condition_statement}')
try:
if eval("not "+judge_condition_statement):
exec_result=retry_func(judge_condition_statement=judge_condition_statement,retry_conditon_str=retry_conditon_str,group_type=group_type,
judge_retry_conditon_type=judge_retry_conditon_type)
except:
log_content='exec_result与retry_conditon类型不一致时只能使用==、!=,退出重试并返回函数原始执行结果,具体异常信息:\n'
log.log_main('error', is_send_email, log_content+traceback.format_exc())
finally:
return exec_result
return wrapper
return retry_wrapper_main
class demo():
num=0
@request_retry_wrapper(retry_num=5,retry_conditon=1,judge_retry_conditon_type='==')
def demo1(self):
self.num += 1
return self.num
@classmethod
def demo2(cls):
cls.num=2
# print(cls.num)
if __name__=="__main__":
demo().demo1()
python实战-编写请求方法重试(用途:请求重试、也可用于其他场景)、日志、执行耗时、手机号与邮箱校验装饰器的更多相关文章
- python unittest单元测试框架-3用例执行顺序、多级目录、装饰器、fixtures
1.用例执行顺序 unittest默认会按照ascii码的顺序,依次执行.类名--方法名排序,使用discover也是默认排序.如果不想使用默认排序,就使用testsuite测试集的方式. impor ...
- http请求方法之options请求方法
需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求. https://developer.mozilla.org/zh-CN/docs/W ...
- guxh的python笔记三:装饰器
1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) tot ...
- swift网络数据请求方法
搭建一个apache服务器,用php编写一个返回给客户端请求数据的脚本 <?php // header("Content-type:text/html;charset=utf-8&qu ...
- HTTP请求方法详解
HTTP请求方法详解 请求方法:指定了客户端想对指定的资源/服务器作何种操作 下面我们介绍HTTP/1.1中可用的请求方法: [GET:获取资源] GET方法用来请求已被URI识别的资源.指定 ...
- httpclient请求方法
/** * httpclient请求方法 * @param url 请求地址 * @param paramMap 请求参数 * @param ent 编码格式 gbk.utf-8 * @return ...
- HTTP/1.1 请求方法
HTTP(Hypertext Transfer Protocol,超文本传输协议)是一种用于分布式.协作式和超媒体信息系统的 应用层协议.HTTP 是万维网的数据通信的基础.默认端口为 80. ...
- 全面了解HTTP请求方法说明
超文本传输协议(HTTP, HyperText Transfer Protocol)是一种无状态的协议,它位于OSI七层模型的传输层.HTTP客户端会根据需要构建合适的HTTP请求方法,而HTTP服务 ...
- flask系列八之请求方法、g对象和钩子函数
一.get方法 ,post方法 post请求在模板中要注意几点: (1)input标签中,要写name来标识这个value的key,方便后台获取. (2)在写form表单的时候,要指定method=' ...
- Http协议请求方法及body类型(思路比较清晰的)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u010244522/article/de ...
随机推荐
- 台式机电脑散热之狂想曲——主机机箱散热的另类方法(纯空想中ing)
本博文是一篇狂想曲,之所以叫狂想曲是因为本文只是博主在无聊时突发奇想,而且仅停留于想的阶段,所以本文内容不用太过认真. 事情是这样的,博主有一台式机,有事没事的就喜欢宅在宿舍里面,有时候还能偶然用这台 ...
- 【安装】SQL SERVER 彻底卸载清除
-----2024年8月6日09:40:13 -----bayaim, 以下内容纯属百度网络搜到,如有侵权请联系及时删除 SQL SERVER 如果卸载不干净,就会导致下一次安装失败,下面是卸载的步 ...
- 利用标准IO函数接口实现文件拷贝
把本地磁盘的文件A中的数据完整的拷贝到另一个文本B中,如果文本B不存在则创建,要求文本A的名称和文本B的名称通过命令行传递,并进行验证是否正确. /************************** ...
- RabbitMQ普通集群同一宿主机docker搭建
1.准备3个节点安装rabbitmq,搭建集群(注意:每个节点启动间隔15~20s,如果启动失败,需删除宿主机文件重新启动) 2.宿主机文件目录手动创建,并设置可操作权限 准备宿主机文件目录 cd / ...
- 进击的AI工具集:全能AI阅读软件Walles AI
在信息爆炸的时代,快速而准确地阅读大量内容,对于每个人都是一种常态挑战. 这些海量信息资讯和知识的涌入,可能导致信息过载,手忙脚乱,且分神费力. 好消息是,我们已经进入了 AIGC时代,随着ChatG ...
- SMU Summer 2023 Contest Round 15
SMU Summer 2023 Contest Round 15 A. AB Balance 其实就只会更改一次 #include <bits/stdc++.h> #define int ...
- 一文带你理解URI 和 URL 有什么区别?
当我们打开浏览器,要访问一个网站或者一个ftp服务器的时候,一定要输入一串字符串, 比如: https://blog.csdn.net/ 或者: ftp://192.168.0.111/ 这样我们就可 ...
- MOGA-Net: 多目标遗传算法求解复杂网络中的社区《A Multiobjective Genetic Algorithm to Find Communities in Complex Networks》(遗传算法、多目标优化算法、帕累托最优)
论文:A Multiobjective Genetic Algorithm to Find Communities in Complex Networks GitHub: IEEE 2012的论文. ...
- JAVAEE——navicat安装
Navicat Premium 15激活步骤 准备 Navicat Premium 15.Navicat Premium 15注册机 用到的都放在这里了: 链接:https://pan.baidu.c ...
- 基于语义增强的少样本检测,突破新类别偏见 | ICIP'24
Few-shot目标检测(FSOD)旨在在有限标注实例的情况下检测新颖对象,在近年取得了显著进展.然而,现有方法仍然存在偏见表示问题,特别是在极低标注情况下的新颖类别.在微调过程中,一种新颖类别可能会 ...