Flaskz介绍4--常用函数
为提高开发效率,Flaskz提供了一些常用的工具类函数,下面进行分类介绍。
系统路径&配置
- get_app_path(*path)
- 功能:获取应用文件路径
- 参数:
- *path --需要连接的一个或多个路径列表(关键字参数)
- 返回:应用文件路径
- 示例:
get_app_path('./_log', 'syslog.txt') # 获取_log目录下的syslog.txt文件
- init_app_config(app)
- 功能:初始化应用配置信息,初始化了以后,就可以通过get_app_config方法获取系统配置项,主要目的是方便使用
- 参数:
- app --可以是Flask应用/Config配置类/配置字典
- 示例:
init_app_config(app) # Flask init_app_config(DevelopmentConfig) # Class init_app_config({...}) # dict
- get_app_config(key=None)
- 功能:获取当前应用的指定配置信息
- 参数:
- key --配置属性名,如果为None,返回所有配置项dict
- 返回:指定的应用配置/全部配置项
- 示例:
get_app_config('FLASKZ_LOGGER_FILENAME') # 获取为系统日志配置的文件名
数据缓存
可以把数据在当前应用current_app和请求g应用上下文对象上进行缓存,从而提高数据的访问速度。
- set_app_cache(key, data, expire_minutes=0)
- 功能:在当前应用current_app上缓存数据,一般用于缓存固定不会发生变化的数据
- 参数:
- key --缓存名称
- data --缓存的值
- expire_minutes --过期时间,单位是分钟,>0时起作用,过期以后通过get_app_cache获取到的数据为None
- 示例:
set_app_cache('sys_menus', menus, expire_minutes=60) # 缓存所有菜单信息,并在60分钟以后过期
- get_app_cache(key)
- 功能:获取当前应用上的缓存值
- 参数:
- key --要获取缓存值的key名称
- 返回:当前应用上指定的缓存值,如果没有对应的键值或数据已经过期,则返回None
- 示例:
get_app_cache('sys_menus') # 获取缓存的菜单信息
- clear_app_cache()
- 功能:清空当前应用上所有的缓存值,一般用于数据发生变化以后重新加载缓存数据,比如在数据库中加了一个新的菜单
- 示例:
clear_app_cache()
- set_g_cache(key, data)
- 功能:在当前g应用上下文上设置缓存数据,整个请求处理过程g上的数据可以共享,每次请求都会重置g对象,一般存储数据库session之类的属性
- 参数:
- key --缓存名称
- data --缓存的值
- 示例:
set_g_cache('db_session', DBSession()) # 将session缓存到g上,整个请求处理过程中只需要生成一次session即可
- get_g_cache(key)
- 功能:获取当前g应用上下文上的缓存值
- 参数:
- key --要获取缓存值的key名称
- 返回:前g应用上下文上的缓存值,如果没有,则返回None
- 示例:
def get_db_session(): """ Get the db session from g. If not exist, create a session and return. :return: """ session = get_g_cache('db_session') # 获取数据库session if session is None: session = DBSession() set_g_cache('db_session', session) # 如果没有则生成并缓存,供其他函数调用 return session
- remove_g_cache(key)
- 功能:移除g应用上下文上设置的缓存数据,一般不需要调用,因为请求处理完成以后,flask会重置g变量
- 参数:
- key --要移除键值的名称
周期&定时执行
- set_timeout(interval, function, args=None, kwargs=None, daemon=True)
- 功能:该定时器在定时器到期后执行一个函数或指定的一段代码
- 参数:
- interval --定时器在执行指定的函数或代码之前应该等待的时间,单位是毫秒
- function --当定时器到期后,将要执行的函数
- args --要执行的函数的位置参数
- kwargs --要执行的函数的关键字参数
- daemon --如果为True,计时器将是守护进程(当只剩下守护线程时,整个Python程序退出)
- 示例:
t = set_timeout(10, print, ('Hello, World!',)) # 10ms后调用print函数打印'Hello, World!' # t.cancel() # 取消定时器
- set_interval(interval, function, args=None, kwargs=None, immediately=False, daemon=True)
- 功能:以指定的时间间隔(毫秒)周期性地执行一个函数。如果函数执行结果为False,则循环中断。
- 参数:
- interval --每次间隔的毫秒数
- function --要重复调用的函数
- args --要执行的函数的位置参数
- kwargs --要执行的函数的关键字参数
- immediately --如果为True,则会立即执行函数,如果为False,则会在interval间隔以后执行
- daemon --如果为True,计时器将是守护进程(当只剩下守护线程时,整个Python程序退出)
- 示例:
t = set_interval(10, print, ('Hello, World!',)) # 每10ms调用一次print函数打印'Hello, World!' # t.cancel() # 取消周期性运行
请注意,间隔是从函数执行完开始计时,而不是等间隔
工具类&对象操作
- Attribute
Attribute是为了方便属性存储和访问提供的工具类,可以通过关键字参数任意存放和访问Attribute实例中的数据。
和字典对象的区别就是,Attribute实例的属性值是通过"."进行访问的,而字典对象通过get方法进行访问。
attr = Attribute(**{ 'start_time': start_time, 'end_time': end_time, 'duration': (end_time - start_time) * 1000, # ms 'statement': statement, 'parameters': parameters, 'context': context }) print(attr.start_time) # 通过.进行访问 print(attr.statement) print(attr.any_key) # 可以访问任意属性,而不会报错
- ins_to_dict(ins, option=None)
- 功能:将数据模型类实例对象中的属性值转换为字典对象,一般用于数据交互和序列化传输
- 参数:
- ins --要进行转换的类实例对象,比如查询到的User数据模型类对象
- option --转换选项,级联关系对象相关的转换选项需要以平铺的模式进行设置,有如下选项
选项 类型 说明 实例 cascade int 需要转换的relationship关系层级数,
用于级联数据的转换,默认只转换当前实例对象中的值,
例如:User模型类中包含addresses关系列表,cascade=1,则会将关系中的Address对象也转换为字典,并附加到user字典对象上
请注意,如果对象之间有循环引用,则会在循环引用处中断转换'cascade':1 # 只对第一层级联关系进行转换 'cascade':3 # 向下钻取,对第三层及以内的级联关系进行转换
relationships list 需要转换的relationship关系列表,
用于控制级联数据是否转换,
例如:User模型类中包含addresses和role两个关系,如果relationships=['role'],则只会将关系中的Role对象转换为字典,并附加到user字典对象上
相较于cascade,relationships可以更加精细的控制relationship关系是否转换输出- 如果cascade>=1,则模型类所有的relationship关系都会被转换输出
- 如果cascade==0,relationships=['role'],则只有role对应的relationship被转换输出
'relationships':['role'] # 只对role级联关系进行转换
include list/function 指定需要转换的属性列表或过滤函数 'include':["id","name"] #只有id和name属性会输出到字典中 'include':lambda ins, key: ins.__class__.to_dict_field_filter(key) # 通过to_dict_field_filter函数进行过滤,只有过滤器返回为True的属性才会转换
exclude list/function 指定不需要转换的属性列表或过滤函数
请注意,如果同时指定了include和exclude,会先进行include检测,再进行exclude检测'exclude':["password","email"], # password和email属性不会输出到字典中 'exclude':lambda ins, key: key in ["password","email"] # 通过函数进行过滤,如果过滤器返回为True的属性,则不会转换
getattrs function 指定如何获取实例对象所有的属性集合,
如果不指定,则会从对象的__dict__中获取,
ModelMixin扩展类,默认从get_to_dict_attrs方法中返回属性集合'getattrs': lambda ins, *args, **kwargs: ins.__class__.get_to_dict_attrs(ins, *args, **kwargs) # 通过类的get_to_dict_attrs获取类实例的所有属性集合
recursion_value string 指定循环引用对象的输出替代值
如果不指定则会自动忽略循环引用的对象'{...}' --如果有循环引用,则用{...}字符串代替 aa.bb.cc dict 层级关系的输出选项
请注意级联关系转换配置的键值key采用的是平铺模式
aa.bb.cc表示实例的[aa]关系数据的[bb]关系数据的[cc]关系数据的输出选项
层级关系中也可以设置cascade,如果不设置,子项的cascade=父项的cascade-1'addresses':{ include:["id","city"] # addresses列表中的Address对象只输出id和city属性 #... }
- 返回:包含实例属性的字典
- 示例:
ins_to_dict(user, { 'cascade': 1, # 除了user对象本身的属性,addresses关系数据也会输出到字典中 'exclude': ['password'], # password属性不会输出到字典中 'addresses': { # addresses关系列表中Address对象的转换选项 'include': ['city'] # 只输出Address对象的city属性 } })
发送请求
以下函数用于向其他服务发送API请求
- request(url, method="GET", url_params=None, base_url="", raw_response=False, **kwargs)
- 功能:发送API请求访问,是requests包的封装
- 参数:
- url --请求API的url地址,可以是url字符串或者包含url的字典对象
-'/api/user/register/':url字符串
-{'url':'/api/user/register/', 'method':'POST'}:包含url字符串和method,请注意url对象中包含的method优先级高于method参数
- method --请求使用的method
- url_params --url中用到的参数,会将url中的相关的参数变量替换成具体的值
- base_url --用来生成请求url,适用于对同一个服务器的大量请求场景,可以把url中相同的部分(地址/端口/前缀)放到base_url中,以方便整体修改
- raw_response
-True,返回请求对象<Response>res
-False,返回请求结果(res.text)
- kwargs --其他请求参数(关键字参数),包括请求数据,授权信息等,可以参考requests的Session.request方法,常用参数如下。
- json -请求发送的json数据
- auth -请求的授权信息,例如,auth=HTTPDigestAuth(username='admin', password='cisco123')
- url --请求API的url地址,可以是url字符串或者包含url的字典对象
- 返回:有三种类型的返回值
- 请求结果 --请求结果,即res.text,默认返回值
- 请求对象<Response>res --raw_response=True时返回,拿到请求对象以后再进行处理
- 包含标志位和原因的元组(res_status_codes.api_request_err, result)
- 示例:
# 示例1,返回请求对象 def ncs_request(url, **kwargs): result = request(url, raw_response=True, **ReqConfig, **kwargs) # 返回请求对象 if type(result) == tuple: # 如果返回结果为元组,则表示请求异常 return False, res_status_codes.api_request_err status_code = result.status_code # 获取请求状态 if status_code // 100 == 2: return True, result.text # 返回请求结果 return False, res_status_codes.api_request_err # 示例2,返回请求结果 json_data = request(current_app.config.get('ELASTICSEARCH_URI'), json=query_json) json_data = json.loads(json_data)
- api_request(url, method="GET", url_params=None, base_url="", raw_response=False, **kwargs)
为了方便使用,flaskz>=1.8.0版本添加flaskz.utils.request函数以替代api_request函数,两者区别如下:
- 如果请求成功,api_request返回请求结果,request返回(True,请求结果)
- 如果请求失败,api_request返回(res_status_codes.api_request_err, 失败原因),request返回(False,失败原因)
函数描述
- 功能:发送API请求访问,是requests包的封装
- 参数:
- url --请求API的url地址,可以是url字符串或者包含url的字典对象
-'/api/user/register/':url字符串
-{'url':'/api/user/register/', 'method':'POST'}:包含url字符串和method,请注意url对象中包含的method优先级高于method参数
- method --请求使用的method
- url_params --url中用到的参数,会将url中的相关的参数变量替换成具体的值
- base_url --用来生成请求url,适用于对同一个服务器的大量请求场景,可以把url中相同的部分(地址/端口/前缀)放到base_url中,以方便整体修改
- raw_response
-True,返回请求对象<Response>res
-False,返回请求结果(res.text)
- kwargs --其他请求参数(关键字参数),包括请求数据,授权信息等,可以参考requests的Session.request方法,常用参数如下。
- json -请求发送的json数据
- auth -请求的授权信息,例如,auth=HTTPDigestAuth(username='admin', password='cisco123')
- url --请求API的url地址,可以是url字符串或者包含url的字典对象
- 返回:有三种类型的返回值
- 请求结果 --请求结果,即res.text,默认返回值
- 请求对象<Response>res --raw_response=True时返回,拿到请求对象以后再进行处理
- 包含标志位和原因的元组(res_status_codes.api_request_err, result)
- 示例:
# 示例1,返回请求对象 def ncs_request(url, **kwargs): result = api_request(url, raw_response=True, **ReqConfig, **kwargs) # 返回请求对象 if type(result) == tuple: # 如果返回结果为元组,则表示请求异常 return False, res_status_codes.api_request_err status_code = result.status_code # 获取请求状态 if status_code // 100 == 2: return True, result.text # 返回请求结果 return False, res_status_codes.api_request_err # 示例2,返回请求结果 json_data = api_request(current_app.config.get('ELASTICSEARCH_URI'), json=query_json) json_data = json.loads(json_data)
- forward_request(url, payload=None, raw_response=False, error_code=500, **kwargs)
- 功能:将收到的请求发送到其他url,并将结果返回,内部是通过调用api_request函数进行的转发,一般用于不同系统间通过API进行对接调用的场景
- 参数:
- url --转发要请求的url,参考api_request的url参数说明
- payload --需要转发的payload属性列表,默认转发的属性列表为['method', 'data', 'json', 'headers', 'cookies']
程序会对payload列表中的值进行遍历,然后将request请求上下文中的相关数据转发出去
- raw_response --是否返回请求对象,参考api_request的raw_response参数说明
- error_code --发生异常时要返回的状态码,默认为500
- kwargs --请求的其他参数,请参考api_request函数
- 返回:有三种类型的返回值
- 请求结果&状态码&header信息组成的元组,(res.text, res.status_code, res.headers.items()),默认返回值
- 请求对象<Response>res --raw_response=True时返回
- 发生异常时,返回异常原因和error_code组成的元组,(reason, error_code)
- 示例:
# 将收到的/auth/tokens/请求转发到其他服务器 @forward_api_bp.route('/auth/tokens/', methods=['POST']) def remote_auth_token(): return forward_request({'url': 'http://10.124.4.235:8080/api/v1.1/auth/tokens', 'method': 'POST'}) # 通过正则表达式转发所有请求 HTTP_METHODS = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH'] @api_bp.route('/<regex(".*"):path>/', methods=HTTP_METHODS) def remote(path): remote_res = forward_request(base_url + path) res = make_response(remote_res[0], remote_res[1]) # for k, v in remote_res[2]: # if k not in ['Transfer-Encoding']: # res.headers[k] = v return res
- append_url_search_params(url, params)
- 功能:生成带查询参数的url
- 参数:
- url --要附加参数的url
- params --要附加的查询参数
- 返回:附加了查询参数的url
- 示例:
append_url_search_params('https://example.com',{'foo':1,'bar':2, 'xx': None}) # 'https://example.com?foo=1&bar=2&xx' # append append_url_search_params('https://example.com?foo=1&bar=2',{'baz':3}) # 'https://example.com?foo=1&bar=2&baz=3' # append append_url_search_params('https://example.com?foo=1&bar=2',{'bar':3}) # 'https://example.com?foo=1&bar=3' # replace append_url_search_params('a/b',{'c':3,'d':None}) # 'a/b?c=3&d' append_url_search_params('https://example.com', ['a', 'b', 'c=2']) # 'https://example.com?a&b&c=2' append_url_search_params('https://example.com', 'a=1&b=2&c') # 'https://example.com?a=1&b=2&c'
请求数据处理
以下数据用于请求数据和信息的获取
- get_remote_addr()
- 功能:获取当前请求的IP地址信息,可用于日志记录等
- 返回:发送请求的客户端IP地址信息
- 示例:
def _get_user_info(): # 获取当前登录用户的相关信息 if current_user.is_anonymous: return { 'user_ip': get_remote_addr(), } return { 'username': current_user.username, 'user_name': current_user.name, 'user_ip': get_remote_addr() }
- is_ajax()
- 功能:判断当前的请求是否是ajax调用,是通过header中的X-Requested-With是否等于'XMLHttpRequest'字符串进行的判断
- 返回:
-True,如果是ajax请求
-False,如果不是ajax请求
- 示例:
def _return_error(app_code, http_code): # 应用异常处理 app_msg = str(get_status_msg(app_code)) flaskz_logger.error(get_rest_log_msg(request.url + ' request ' + app_msg, None, False, app_code)) if is_ajax() or (request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html): #如果是ajax请求,则返回状态码 return create_response(False, app_code) return get_status_msg(app_msg) # 如果是其他请求,比如页面html请求,则返回异常信息
- get_pss(cls, pss_config=None)
将对模型数据的分页,排序,搜索等查询参数进行解析并生成对应的方法和参数,请参考 flaskz.models.parse_pss
请求响应
以下函数用于生成请求处理结果信息
- create_response(success, data, wrapper=False)
- 功能:将请求结果数据进行封装,添加status/message等信息,封装以后的数据用于返回到请求客户端,
一般所有的路由处理函数都会调用create_response生成响应结果数据
- 参数:
- success --请求处理是否成功
- data -返回到请求端的数据,可能是成功数据,也可能是失败原因
- data_wrapped -返回的请求数据是否已经进行了封装,默认为False(没有进行封装),逻辑如下
if data_wrapped is True: # 如果已经进行了封装, _data = { 'status': status, # 附加status信息到封装了以后的数据上 } _data.update(data) return _data else: # 如果没有进行封装 return { 'status': status, # 将status和data封装成一个对象并返回 'data': data }
- 返回:可用于返回到客户端的封装数据
- 处理成功,返回数据格式如下
# 客户端获取到的成功数据示例 { "status": "success", # 成功status标志,可以通过FLASKZ_RES_SUCCESS_STATUS配置,默认为"success" "data": { # 成功返回的数据 "token": "eyJhbGciO......" } }
- 处理失败,返回数据格式如下,
请注意为了方便客户端使用,此处返回的status_code是系统定义好的状态码(res_status_codes.db_add_err/res_status_codes.db_data_not_found/...), 而不是像200/400/500一样的网络请求状态码
{ "status": "fail", # 失败status标志,可以通过FLASKZ_RES_FAIL_STATUS配置,默认为"fail" "message": "Wrong Password", # 失败消息信息 "status_code": "account_verify_err" # 失败状态代码,用于客户端的逻辑处理, # 例如,如果客户端接收到status="fail"而且status_code="uri_unauthorized"的消息,就会提示用户登录 }
- 处理成功,返回数据格式如下
- 示例:
@sys_mgmt_bp.route('/auth/token/', methods=['POST']) # 用户登录token获取 def sys_auth_get_token(): request_json = request.json result = User.verify_password(request_json.get('username'), request_json.get('password')) # 账号/密码校验 success = result[0] # 处理结果 if success is False: res_data = model_to_dict(result[1]) # 校验失败,则返回失败原因 else: res_data = {'token': generate_token({'id': result[1].get_id()})} # 校验成功,返回token flaskz_logger.info(get_rest_log_msg('User get login token', {'username': request_json.get('username')}, success, res_data)) return create_response(success, res_data) # 创建返回结果,并返回
- 功能:将请求结果数据进行封装,添加status/message等信息,封装以后的数据用于返回到请求客户端,
- get_status_msg(status_code)
- 功能:根据状态码,返回message消息文本,
- 参数:
- status_code --状态码,默认提供的状态码定义于res_status_codes模块中
- 返回:状态码对应的message消息
- 示例:
def _return_error(app_code, http_code): # 应用全局异常处理 app_msg = str(get_status_msg(app_code)) # 获取到状态码对应的异常消息 flaskz_logger.error(get_rest_log_msg(request.url + ' request ' + app_msg, None, False, app_code)) if is_ajax() or (request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html): return create_response(False, app_code) # return (app_code, http_code) return get_status_msg(app_msg) # 将异常消息发送到客户端
字典操作
以下函数对于字典操作进行了扩展
- get_deep(d, key, key_split='.', default=None, raising=False)
- 功能:根据层次键路径,逐层获取对应的键值,目前只有对属性值是dict的层次处理,如果属性值是list,则不会进行处理
- 参数:
- d --要获取的字典对象
- key -层级型键路径,一般是用.连接的字符串,例如,"address.city",代表的就是获取字典的address对象(字典)的city值
- key_split -层级型键路径的拆分字符串,通过key_split将字符串拆分成层级数据,默认是.
- default -如果层级数据不存在,返回的默认值,类似于字典get方法的default用法,默认是None
- raising -如果层级数据不存在,是否引发异常,默认不会引发异常
- 返回:层级键路径对应的属性值,如果路径对应的属性值不存在,则返回默认值,或引发异常
- 示例:
user = { "name": "taozh", "age": 18, "address": { "city":"Shanghai", "district":"Changning" } } print(get_deep(user,"address.city")) # 返回结果为"Shanghai"
- set_deep(d, key, value, key_split='.')
- 功能:为字典设置层级键值数据,如果对的层级不存在,则会自动创建并设置属性
- 参数:
- d --要设置的字典对象
- key -层级型键路径,一般是用.连接的字符串,例如,"address.city",代表的就是字典的address对象(字典)的city属性
- value -要进行设置的键值数据.
- key_split -层级型键路径的拆分字符串,通过key_split将字符串拆分成层级数据,默认是.
- 示例:
user = { "name": "taozh", "age": 18 } set_deep(user, "address.city", "Shanghai") # 为user的address设置city属性,因为address不存在,所以会先创建一个address字典 # {'name': 'taozh', 'age': 18, 'address': {'city': 'Shanghai'}}
- get_ins_mapping(ins_list, attr, deep=False)
- 功能:根据指定属性值对实例对象进行分类,并返回分类映射字典
- 参数:
- ins_list --要进行分类的实例对象列表
- attr -指定的分类属性
- deep -是否使用层级属性进行分类,如果为True,则会逐层获取到对应的值用于分类
- 返回:根据指定属性生成的分类映射字典
- 示例:
device_id_map = get_ins_mapping(devices, 'model_id') # 根据设备的型号id进行分类,此处的devices是Device类对象列表 device_lb_addr_map = get_ins_mapping(devices, 'ext.loopback_address', True) # 根据设备的ext级联属性的loopback_address地址进行分类
- get_dict_mapping(dict_list, key='id', key_join="+")
- 功能:根据一个或多个指定的属性值对字典对象进行分类,并返回分类映射字典
- 参数:
- dict_list --要进行分类的字典对象列表
- key -指定的分类属性,默认通过id属性进行分类,key可以是某个属性也可以是一个由多个属性组成的列表
如果key是多个属性组成的列表,则会从字典中将多个值取出合并成一个分类键值,类似于联合主键
- key_join -当key是多个属性组成的列表时,用于合并多个键值并生成分类键值的连接字符
- 返回:根据指定属性生成的分类映射字典
- 示例:
device_id_map = get_dict_map(devices) # 根据设备的id进行分类,此处的devices是包含字典对象的列表 device_name_map = get_dict_map(devices,"name") # 根据设备的name进行分类 policy_device_map = get_dict_map(sr_policies, ['device_id', 'policy_name']) # 根据policy对象的device_id和policy_name进行分类
- merge_dict(d, *to_merged_dict)
- 功能:将多个字典的值合并到一个字典中,和字典的update方法主要区别是
-update方法只会对顶层属性进行合并
-merge_dict函数会遍历层级属性,并进行合并
- 参数:
- d --目标字典,其他字典的属性都会合并到目标字典中
- *to_merged_dict --一个或多个源字典(位置参数)
- 示例:
user = { "name": "taozh", "address": { "city": "Shanghai" } } merge_dict(user, {"age": 18}, {"address": { "district": "Changning" # 会将district属性合并到user的address中 }}) print(user) # {'name': 'taozh', 'address': {'city': 'Shanghai', 'district': 'Changning'}, 'age': 18} user1 = { "name": "taozh", "address": { "city": "Shanghai" } } user1.update({ "address": { "district": "Changning" # 会将user1的address属性进行整体替换 } }) print(user1) # {'name': 'taozh', 'address': {'district': 'Changning'}}
- 功能:将多个字典的值合并到一个字典中,和字典的update方法主要区别是
- del_dict_keys(d, keys)
- 功能:一次性从字典对象中删除多个键值
- 参数:
- d --要进行删除属性的字典对象
- keys --要删除的键值列表
- 示例:
del_dict_keys(json_, ['model', 'vendor']) # 将model和vendor属性从json_中删除
- pop_dict_keys(d, keys)
- 功能:一次性从字典对象中pop多个键值
- 参数:
- d --要进行pop的字典对象
- keys --要pop的键值列表
- 返回:由pop的键值组成的字典
- 示例:
pop_dict_keys(a_dict, ['name', 'age']) pop_dict_keys(a_dict, 'name')
其他
- filter_list(items, func=None, with_index=False, not_none=False)
- 功能:过滤指定列表,并返回由符合条件的项组成的列表
- 参数:
- items --指定的列表
- func --过滤函数,返回True表示列表项符合条件
- with_index --过滤函数是否使用index参数
- not_none --是否过滤非空列表项
- 返回:由符合条件的项组成的列表
- 示例:
filter_list(items, not_none=True) # 返回非空列表项 filter_list(items, lambda item: item is not None) filter_list(items, lambda index, item: index > 10 and item is not None, True)
- find_list(items, func, with_index=False)
- 功能:从列表中查找第一个符合条件的列表项
- 参数:
- items --指定的列表
- func --查找函数,返回True表示列表项符合条件
- with_index --查找函数是否使用index参数
- 返回:第一个符合条件的列表项
- 示例:
find_list(items, lambda item: item.get('id') == 10) find_list(items, lambda index, item: index > 0 and item.get('id') == 10 , True)
- each_list(items, func, with_index=True)
- 功能:遍历列表中的列表项,并执行指定的函数
- 参数:
- items --指定的列表
- func --要执行的函数,如果返回False会中断遍历
- with_index --执行的函数是否使用index参数
- 返回:第一个符合条件的列表项
- 示例:
each_list(items, lambda item: item['selected'] = True)
- merge_list(target_list, *merged_list)
- 功能:将多个列表中的对象并到目标列表中
- 参数:
- target_list --目标列表,其他列表中的对象都会合并到目标列表中
- *merged_list --一个或多个源列表(位置参数)
- 返回:目标列表lst
- 示例:
nums = [0, 1] merge_list(nums, [2, 3], [4, 5]) # nums = [0, 1, 2, 3, 4, 5]
SSH操作
flaskz.ext.ssh是基于Paramiko封装的SSH操作类(pip install paramiko),对命令执行和返回结果等进行了处理
- ssh_run_command(connect_kwargs: dict, command: Union[str, list], run_kwargs: Optional[dict] = None) -> Tuple[bool, str]
- 功能:在指定的host上执行的command
- 参数:
- connect_kwargs --主机参数,例如){'hostname': hostname, 'username': username, 'password': password}
- hostname --主机地址
- username --登录账号
- password --登录密码
- port --端口(默认为22)
- recv_endswith --返回信息的结束符号(默认为['# ', '$ ', ': ', '? ']),用于判断recv是否完成
- recv_start_delay --开始接收数据的延迟(秒),默认为0.1,一般不需要设置,如果因为网络较差而导致数据接收不全时,可以考虑将delay调大,过大的delay会影响效率
- pre_commands --在命令正式执行之前预先执行的命令,例如)['terminal length 0', 'term width 512']
- timeout --ssh建立连接的timeout时间(默认为10s),如果超出timeout还未建立连接,会抛出异常
- retries --ssh连接失败的重试次数(默认不重试)
- secondary_password --二级enable登录密码,用于enable/sudo等操作,如果命令需要enable登录时,如果secondary_password不为None,会自动输入secondary_password
- channel_kwargs --channel窗口相关参数,例如){'width': 100000, 'height': 100000, 'timeout':2}
- command --要执行的命令,例如)show running-config
- run_kwargs --执行命令&结果处理的相关参数,例如){'recv': False, 'prompt': False}
- recv --是否等待返回结果(默认为True)
- clean --是否对返回结果进行clean(默认为True),如果为False,结果可能会包含Welcome info/Last login info/Path promote等信息
- prompt --跟指定主机交互的prompt(默认为None),prompt主要用于判断recv是否完成和对返回结果进行clean, 如果为None,会先获取prompt执行对应的命令,如果为False,则表示禁用prompt功能
- connect_kwargs --主机参数,例如){'hostname': hostname, 'username': username, 'password': password}
- 返回:(success, result)
- success --如果运行命令成功为True,否则为False
- result --如果成功返回command运行结果,否则返回异常信息
- 示例:
ssh_run_command({'hostname': hostname, 'username': username, 'password': password},'show running-config') ssh_run_command( # connect_kwargs {'hostname': 'host', 'username': 'username', 'password': 'password', # host 'timeout': 10, 'retries': 3, # connect timeout and retry 'secondary_password': 'enable_pwd', # enable password 'pre_commands': ['terminal length 0', 'term width 512'], # pre_commands 'channel_kwargs': {'width': 1000, 'timeout': 2}}, # channel kwargs # command 'show running-config', # run_kwargs { 'clean': False, # not clean output info 'prompt': False, # disable prompt })
-
ssh_run_command_list(connect_kwargs: dict, command_list: list, run_kwargs: Optional[dict] = None) -> Tuple[bool, Union[list, str]]
- 功能:在指定的host上执行多个command
- 参数:
- connect_kwargs --主机参数,例如){'hostname': hostname, 'username': username, 'password': password}
- hostname --主机地址
- username --登录账号
- password --登录密码
- port --端口(默认为22)
- recv_endswith --返回信息的结束符号(默认为['# ', '$ ', ': ', '? ']),用于判断recv是否完成
- recv_start_delay --开始接收数据的延迟(秒),默认为0.1,一般不需要设置,如果因为网络较差而导致数据接收不全时,可以考虑将delay调大,过大的delay会影响效率
- pre_commands --在命令正式执行之前预先执行的命令,例如)['terminal length 0', 'term width 512']
- timeout --ssh建立连接的timeout时间(默认为10s),如果超出timeout还未建立连接,会抛出异常
- retries --ssh连接失败的重试次数(默认不重试)
- secondary_password --二级enable登录密码,用于enable/sudo等操作,如果命令需要enable登录时,如果secondary_password不为None,会自动输入secondary_password
- channel_kwargs --channel窗口相关参数,例如){'width': 100000, 'height': 100000, 'timeout':2}
- command_list --要执行的命令列表,例如)['show version', 'show running-config']
- run_kwargs --执行命令&结果处理的相关参数,例如){'recv': False, 'prompt': False, 'last_result': True}
- recv --是否等待返回结果(默认为True)
- clean --是否对返回结果进行clean(默认为True),如果为False,结果可能会包含Welcome info/Last login info/Path promote等信息
- prompt --跟指定主机交互的prompt(默认为None),prompt主要用于判断recv是否完成和对返回结果进行clean, 如果为None,会先获取prompt执行对应的命令,如果为False,则表示禁用prompt功能
- last_result --是否值返回最后一个command的结果(默认为False),如果为True,只返回最后一个命令的结果
- connect_kwargs --主机参数,例如){'hostname': hostname, 'username': username, 'password': password}
- 返回:(success, result_list)
- success --如果运行命令成功为True,否则为False
- result_list --如果成功返回command运行结果列表,否则返回异常信息
- 示例:
ssh.run_command_list({'hostname': hostname, 'username': username, 'password': password}, ['show version', 'show running-config']) ssh_run_command_list( # connect_kwargs {'hostname': 'host', 'username': 'username', 'password': 'password', # host 'timeout': 10, 'retries': 3, # connect timeout and retry 'secondary_password': 'enable_pwd', # enable password 'pre_commands': ['terminal length 0', 'term width 512'], # pre_commands 'channel_kwargs': {'width': 1000, 'timeout': 2}}, # channel kwargs # command ['enable', 'show version'], # run_kwargs { 'last_result': True, # not clean output info 'prompt': False, # disable prompt })
-
ssh_session(hostname: str, username: str, password: str = None, port: Optional[int] = 22, **kwargs)
- 功能:ssh操作上下文管理器
- 参数:
- hostname --主机地址
- username --登录账号
- password --登录密码
- port --端口(默认为22)
- recv_endswith --返回信息的结束符号(默认为['# ', '$ ', ': ', '? ']),用于判断recv是否完成
- recv_start_delay --开始接收数据的延迟(秒),默认为0.1,一般不需要设置,如果因为网络较差而导致数据接收不全时,可以考虑将delay调大,过大的delay会影响效率
- pre_commands --在命令正式执行之前预先执行的命令,例如)['terminal length 0', 'term width 512']
- timeout --ssh建立连接的timeout时间(默认为10s),如果超出timeout还未建立连接,会抛出异常
- secondary_password --二级enable登录密码,用于enable/sudo等操作,如果命令需要enable登录时,如果secondary_password不为None,会自动输入secondary_password
- channel_kwargs --channel窗口相关参数,例如){'width': 100000, 'height': 100000, 'timeout':2}
- 返回:flaskz.ext.ssh.SSH对象
- 示例:
with ssh_session(host, username, password, timeout=20) as ssh: ssh.run_command('ls -l') with ssh_session(host, username, password, timeout=20) as ssh: ssh.run_command_list(['show version', 'show running-config']) with ssh_session(host, username, password, timeout=20, secondary_password=enable_pwd, recv_endswith=['# ', '$ ', ': ', '? ', '#']) as ssh: ssh.run_command_list(['enable', 'show run'])
注意事项
- 一次获取全部结果
有些设备对于命令的返回结果会强制分页(空格/回车继续),即便命令终端窗口设置的足够大也可能会发生,可以通过执行terminal length 0命令强制不分页
- 数据/结果接收不全
paramiko执行SSH命令的结果不是一次性返回的,而是类似一个池,ssh一直往里写数据,客户端要从池中循环&分批读取数据,所以判断何时接收完成就很重要
flaskz.ext.ssh通过对读取的结果跟命令提示符和recv_endswith(['# ', '$ ', ': ', '? '])列表项进行对比来检查接收是否完成
由于不同的系统和命令返回的结果差异较大,有可能正好匹配到recv_endswith默认列表中的项,从而可能导致数据接收不全的情况
例如) 执行 `show int | json`,分批获取的命令执行结果时,获取到的某段文本最后可能正好是[冒号+空格](: ),而(: )在recv_endswith列表中,如果此时写入数据稍有延迟,就可能导致程序认为数据已经接收完毕
可以通过设置recv_endswith列表以避免这种接收不全的情况,例如)设置recv_endswith=['# ', '$ ', ':', '? ']