再帰関数1#
参考#
- はてなの金次郎 - 複雑なJSONから特定のデータを再帰で取り出せるようになるための4ステップ
- Qiita - 複雑なJSONから特定のデータを取り出す
- はてなの金次郎 - Pythonで再帰関数を理解するための最も簡単な例
sample.py
import json
import os,re,yaml
from pprint import pprint
# 対象ファイルを検索する関数
def search_file(ptrn, target_dir):
path_list = [
os.path.join(dirPath + os.sep + file)
for dirPath, dirs, files in os.walk(target_dir)
for file in files
# パターンにマッチしたファイルのみ抽出
if ptrn.search(file)
]
return path_list
# yaml ファイルを読み込み、辞書を返す関数
def read_datafile(yaml_file):
with open(yaml_file, 'r',encoding="utf-8") as f:
datafile = yaml.safe_load(f)
return datafile
# 解析結果をファイルに書き込む関数
def write_file(filename, parse_result):
with open(filename, "w", encoding='utf-8') as f:
for i in parse_result:
f.write(i)
f.write("\n")
# yaml ファイル内のアイテムを選別する関数
def select_item(arg):
if arg == 'failed':
return None
elif arg == 'device':
return None
elif arg == '%VARIABLES{device}':
return None
elif re.search(r'\!= passed',arg):
return None
else:
return arg
# 再帰的にyaml ファイルを解析する関数
def get_procedure(datafile):
result =[]
if isinstance(datafile, str):
datafile = select_item(datafile)
if datafile != None:
result.append(datafile)
elif isinstance(datafile, int):
result.append(f"sleep time : {datafile}")
elif isinstance(datafile, list):
for item in datafile:
result += get_procedure(item)
elif isinstance(datafile, dict):
for value in datafile.values():
result += get_procedure(value)
return result
# yaml ファイル解析後のリストから不要な文字列を削除する関数
def remove_strings(procedure):
# 試験項番(!!! )を '%VARIABLES{device_list}'に打つ、といった不要な手順は削除
arranged_list = []
for index,content in enumerate(procedure):
if content == '%VARIABLES{device_list}':
if '!!!' in procedure[(index+1)]:
continue
else:
arranged_list.append(content)
else:
arranged_list.append(content)
return arranged_list
# !!! ごとに2次元配列に変換する関数
def arranged_list(procedure):
procedure_number = re.compile(r'!!! \d+ at \d+-\d+-\d+|!!! \d+ at \d+-\d+-\d+_\S+')
arranged_list = []
for content in procedure:
if procedure_number.search(content):
testcase_number = procedure_number.search(content).group()
arranged_list.append([testcase_number])
continue
else:
arranged_list[(len(arranged_list)-1)].append(content)
return arranged_list
# topology 情報の解析関数
def read_topology(topology_file):
topology = read_datafile(topology_file)
devices = {}
links = {}
for device in topology['devices']:
alias = topology['devices'][device]['alias']
devices[alias] = device
if 'IXIA' in device:
ixia_port_list = topology['devices'][device]['connections']['tgn']['ixia_port_list']
for alias in topology['topology']:
links[alias] = {}
port_info = topology['topology'][alias]['interfaces']
for key,value in port_info.items():
links[alias].update({value['link'] :key})
return [devices,links,ixia_port_list]
# 手順書内変数を取り出し関数
def takeout_vars(vars_list):
ptrn1 = re.compile(r'{vars_\d+_\d+_(\d+|\d+_\w+)\.nodes\.|}\||}')
ptrn2 = re.compile(r'%{vars_\d+_\d+_(\d+|\d+_\w+)\.(nodes|links)\.|}\||}')
ptrn3 = re.compile(
r'%VARIABLES{\w+\.\w+\.\w+\[%{vars_\d+_\d+_\d+.nodes\.|}\].name}|'
r'(%VARIABLES{|})|'
r'(%{vars_\d+_\d+_\d+.nodes\.|})'
)
port_var_dict = {}
template_vars_dict = {}
for vars_dict in vars_list:
if vars_dict['function'] == 'get_devices':
device_list = vars_dict['arguments']['regex'].split('%')
device_list = [device for device in device_list if device != '']
device_list = [ptrn1.sub('',device) for device in device_list]
elif vars_dict['function'] == 'get_single_interface':
port_var = vars_dict['save'][0]['variable_name']
arguments = vars_dict['arguments']
arguments['device'] = ptrn2.sub('',arguments['device'])
arguments['link_name'] = ptrn2.sub('',arguments['link_name'])
port_var_dict[port_var] = arguments
elif vars_dict['function'] == 'configure_by_jinja2':
template_vars = vars_dict['arguments']
del template_vars['templates_dir']
for k,v in template_vars.items():
template_vars[k] = ptrn3.sub('',v)
template_vars_dict[template_vars['device']] = template_vars
return [device_list, port_var_dict, template_vars_dict]
def translate_vars():
pass
if __name__ == '__main__':
file_ptrn = re.compile(r"yaml")
sep_str = os.sep
target_dir = f'.{sep_str}testcases{sep_str}'
path_list = search_file(file_ptrn, target_dir)
topology = read_topology('testbed_topology.yaml')
# topology内変数
devices = topology[0]
links = topology[1]
ixia_port_list = topology[2]
for i in path_list:
testnumber = i.split(sep_str)[3]
testnumber_underbar = re.sub(r"-", r"_",testnumber)
yaml_file = read_datafile(i)
test_sections = yaml_file[f'TriggerBlitz_tc{testnumber}']['test_sections']
procedure_vars = yaml_file[f'vars_{testnumber_underbar}']
# 変数定義部分解析
def_secition = test_sections.pop(0)['tc3_init_configuration'] # 変数定義セクションを取り出す
vars_list = [(i['api']) for i in def_secition if 'api' in i]
# 手順書内変数
vars_list = takeout_vars(vars_list)
device_list = vars_list[0]
port_vars = vars_list[1]
template_vars = vars_list[2]
# TODO: link 変数の変換方法を検討
"""_summary_
# topology 内変数
devices:
links:
ixia_port_list:
# 手順書内変数
vars_list:
device_list:
port_vars:
template_vars:
"""
# TODO: (1) procedure_vars を vars_list と紐付け
# TODO: (1) での紐付け後に topology 情報補と紐付けた辞書の作成
# 手順部分解析
# TODO: 手順書内変数変換
procedure = get_procedure(test_sections)
procedure = remove_strings(procedure)
procedure = arranged_list(procedure)