- importlib
importlib允许程序员创建他们自定义的对象。imp的模块在Python3.4中被去掉。
用途扩展自定义函数
#!/usr/bin/env python
#-*- coding = utf-8 -*-
import importlib
import imp
import sys
# Syntax sugar.
_ver = sys.version_info
#: Python 2.x?
is_py2 = (_ver[0] == 2)
#: Python 3.x?
is_py3 = (_ver[0] == 3)
def get_imported_module_from_file(file_path):
""" import module from python file path and return imported module
"""
if is_py3:
imported_module = importlib.machinery.SourceFileLoader(
'module_name', file_path).load_module()
elif is_py2:
imported_module = imp.load_source('module_name', file_path)
else:
raise RuntimeError("Neither Python 3 nor Python 2.")
return imported_module
if __name__ == "__main__":
imported_module = get_imported_module_from_file("buildin.py")
# 动态引入对象的属性
print(dir(imported_module))
# todo 调用引入文件的方法
phone = imported_module.getPhone()
print(f"手机号 : {phone}")
#!/usr/bin/env python
#-*- coding = utf-8 -*-
def setPhone(phone):
return phone
def getPhone():
return "15365878954"
结果
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'getPhone', 'setPhone']
手机号 : 15365878954
- _import_ 实现
imported_module = __import__("buildin")
print(dir(imported_module))
phone = imported_module.getPhone()
print(f"手机号 : {phone}")
结果
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'getPhone', 'setPhone']
手机号 : 15365878954
备注:
引入参数的getPhone属性直接写死的,但实际更多的是动态的,可以用到Python的属性方法getattr。
# 动态引用模块2
imported_module = __import__("buildin")
print(dir(imported_module))
test = getattr(imported_module, "getPhone")
phone = test()
print(f"手机号 : {phone}")
接口自动化,特殊处理
- 变量替换
- 自定义函数引入
# -*- coding:utf-8 _*-
"""
@author:hszhang
@file: getIPByProject.py
@time: 2019/05/15 21:40
@contact: hszhang@.....
@software: PyCharm
┏┓ ┏┓
┏┛┻━━━┛┻┓
┃ ☃ ┃
┃ ┳┛ ┗┳ ┃
┃ ┻ ┃
┗━┓ ┏━┛
┃ ┗━━━┓
┃ 神兽保佑 ┣┓
┃ 永无BUG! ┏┛
┗┓┓┏━┳┓┏┛
┃┫┫ ┃┫┫
┗┻┛ ┗┻┛
"""
import logging
import re
import ast
logger = logging.getLogger("evalDictVariables")
################# 参数变量替换(start) #################
def getDependVariable(data):
# todo 目前写死了
return "test"
def extractVariables(data):
""" extract all variable names from content, which is in format $variable
@param (str) data
@return (list) variable name list
e.g. $variable => ["variable"]
/blog/$postid => ["postid"]
/$var1/$var2 => ["var1", "var2"]
abc => []
"""
variable_regexp = r"\$([\w_]+)"
try:
return re.findall(variable_regexp, data)
except TypeError:
return []
def evalStringVariables(data):
"""
$variable变量替换
"""
if isinstance(data, str):
for variable_name in extractVariables(data):
variable_value = getDependVariable(data)
if "${}".format(variable_value) == data:
# data is a variable
data = variable_value
else:
# data contains one or many variables
data = data.replace(
"${}".format(variable_name),
str(variable_value), 1
)
elif isinstance(data, list):
for element in data:
evalStringVariables(element)
elif isinstance(data, dict):
for key, value in data.items():
evalStringVariables(key)
evalStringVariables(value)
# else: # todo 可以省略,直接执行下面的return
# return data
return data
################# 参数变量替换(over) #################
################# 自定义方法(start) #################
def parseStringValue(str_value):
""" parse string to number if possible
e.g. "123" => 123
"12.2" => 12.3
"abc" => "abc"
"$var" => "$var"
"""
try:
return ast.literal_eval(str_value)
except ValueError:
return str_value
except SyntaxError:
# e.g. $var, ${func}
return str_value
def parseFunction(content):
""" parse function name and args from string content.
@param (str) content
@return (dict) function name and args
e.g. func() => {'func_name': 'func', 'args': [], 'kwargs': {}}
func(5) => {'func_name': 'func', 'args': [5], 'kwargs': {}}
func(1, 2) => {'func_name': 'func', 'args': [1, 2], 'kwargs': {}}
func(a=1, b=2) => {'func_name': 'func', 'args': [], 'kwargs': {'a': 1, 'b': 2}}
func(1, 2, a=3, b=4) => {'func_name': 'func', 'args': [1, 2], 'kwargs': {'a':3, 'b':4}}
"""
function_meta = {
"args": [],
"kwargs": {}
}
function_regexp_compile = re.compile(r"^([\w_]+)\(([\$\w\.\-_ =,]*)\)$")
matched = function_regexp_compile.match(content)
function_meta["func_name"] = matched.group(1)
args_str = matched.group(2).replace(" ", "")
if args_str == "":
return function_meta
args_list = args_str.split(',')
for arg in args_list:
if '=' in arg:
key, value = arg.split('=')
function_meta["kwargs"][key] = parseStringValue(value)
else:
function_meta["args"].append(parseStringValue(arg))
return function_meta
def extractFunctions(data):
""" extract all functions from string content, which are in format ${fun()}
@param (str) content
@return (list) functions list
e.g. @func(5)@ => ["func(5)"]
${func(a=1, b=2)} => ["func(a=1, b=2)"]
/api/1000?_t=${get_timestamp()} => ["get_timestamp()"]
/api/${add(1, 2)} => ["add(1, 2)"]
"/api/${add(1, 2)}?_t=${get_timestamp()}" => ["add(1, 2)", "get_timestamp()"]
"""
function_regexp = r"\@([\w_]+\([\w\.\-_ =,]*\))\@"
try:
return re.findall(function_regexp, data)
except TypeError:
return []
def callFunc(data):
"""
import module
:param data:
:return:
"""
imported_module = __import__("buildIn")
print(dir(imported_module))
if isinstance(data, str):
for func_content in extractFunctions(data):
function_meta = parseFunction(func_content)
func_name = getattr(imported_module, function_meta['func_name'])
args = function_meta.get('args', [])
kwargs = function_meta.get('kwargs', {})
return func_name(*args, **kwargs)
return data
################# 自定义方法(over) #################
def evalString(data):
if data[:1] == '@' and data[-1:] == '@': # 这个就是匹配入参传的函数的模式,如 {'a':'@methon(参数1,参数2)@'}}
# todo 引入参数
pass
eval_data = callFunc(data)
# logger.debug(f'入参{key}传入函数为:' + value[1:value.find('(')] + f',对应值为:{diction[key]}')
return eval_data
elif data[:6].upper() == 'SELECT': # 这个就是入参传的sql语句模式,如{'a':'select value from a'}
# todo sql 查询
pass
# diction[key] = self.valueTrans(self.db.query(v))
# logger.debug(f'入参{key}传入sql为:' + value + f',对应值为:{diction[key]}')
elif '$' in data: # 这个就是入参引用依赖值的模式,引用前面接口的某个key返回值,如{'a':'$key'} 或 {'a':'$key$'}
# todo 变量
eval_data = evalStringVariables(data)
logger.debug(f'处理前{data},处理后:{eval_data}')
return eval_data
return data
# todo 请求参数转义
def evalDict(diction, default=None):
"""
处理参数
:param diction:
:param default:
:return:
"""
for key, value in diction.items():
if isinstance(key,str) and isinstance(value, str):
diction[key] = evalString(value)
elif isinstance(value, dict): # value为字典值,继续往下递归
evalDict(value, default)
elif isinstance(value, list): # value为列表值,继续往下递归
for data in value:
if isinstance(data, dict):
evalDict(data, default)
return diction
if __name__ == "__main__":
# todo 自测1
data = {"body" : "$postid"}
print(evalDict(data))
# todo 自测2
data1 = {"body": "$postid1/$postid2"}
print(evalDict(data1))
# todo 自测3
data2 = {"body": {"data" : "$postid1/$postid2"}}
print(evalDict(data2))
# todo 自测4
data3 = {"body": {"data": "@getPhone()@"}}
print(evalDict(data3))