От някоко месеца се опитвам да направя продукт (казва се PyTak), чрез която лесно да се правят сценарии
за тесване на REST API и тяхното оркестиране. Целия код може да си го свалите от GitHub
Получава се добре за сега - Python-a си покза силата. Ето един примерен (от лесните):
def main(): login() scenario = [ CreateTag(assign={"name" : "new-tag"}), DeleteTag(bind={"name" : "0.data.name"}) ] run(scenario) validate(CreateTag(), {'xy.1.y.1.y2.0.y22': 3})
Нищо работа - създаваме tag с име new-tag и после го изтриваме като използваме върнатия резултат. Трудността идва, когато трябва да се промени request body.
За целта предефинирах <<. Целта е максимално да се улесни нашия QA Team. Примерен фрагмент:
create_post = CreateAPost() << { "title" : "New Employee - [XXXX]", "body" : "Please welcome our new employee. [XXXX]", "type" : "TEXT", "tags" : [{"name" : "tag2"}, {"name" : "tag3"}, {"name" : "tag4"}] }
По време на тестването често се налага да се слагат случайни стойности, за да се избегнат колизии. Въведох правилото - ако някой постави [XXXX] да се замени автоматично с случайно число.
От тук се получи задачата, която искам да споделя.
Да се заменят вскички стойности в JSON, които съдържат дадена стрингова стойност
Важно е да се уточни, че пропускаме ключове, чиито стойност е масив и обхождаме ключовете в самия масив. Ето моето решение, в което използвам mutual recursion.
import re def extract_paths(json): """Select all JSON keys using mutual recursion""" _path = [] _query = [] def __form_path(in_dict, in_list): if _path: _query.append(_path[:]) del _path[:] if in_list: for el in in_list: _path.append(el) if in_dict: for el in in_dict: _path.append(el) def dict_update(json, in_list=None, in_dict=None): if isinstance(json, dict): for key, value in json.iteritems(): _path.append(key) dict_update(value, in_dict=_path[:-1]) if isinstance(json, list): list_update(json, in_list=_path[:-1]) else: __form_path(in_dict, in_list) return _query def list_update(inner_list, in_list=None, in_dict=None): if isinstance(inner_list, list): for idx, value in enumerate(inner_list): _path.append(idx) list_update(value, in_list=_path[:-1]) if isinstance(inner_list, dict): dict_update(inner_list, in_dict=_path[:-1]) else: __form_path(in_dict, in_list) return _query return dict_update(json) def update_leaf_if_value_func(json, change_func): """Apply 'change_func' to every leaf using the leaf as an argument""" all_leafs = [path for path in extract_paths(json)] for query in all_leafs: selected = __upto_key_for_change(json, query) if isinstance(selected[query[-1]], dict) or isinstance(selected[query[-1]], list): continue selected[query[-1]] = change_func(selected[query[-1]]) return json def update_leaf_if_value(json, value_pattern, new_value): """Replace 'value_pattern' in a JSON leaf with new_value""" all_leafs = [path for path in extract_paths(json)] for query in all_leafs: selected = __upto_key_for_change(json, query) if isinstance(selected[query[-1]], dict) or isinstance(selected[query[-1]], list): continue selected[query[-1]] = re.sub(value_pattern, new_value, selected[query[-1]]) return json def update(json, key, new_value): """Update *all* JSON keys that match 'key' with a given 'value' Algorithm explanation: 1. Select path to JSON key referred by the given key 2. Fold the JSON structure up to this key (not included) 3. Update the leaf of folded JSON using given key """ matched = [path for path in extract_paths(json) if path[-1] == key] for query in matched: selected = __upto_key_for_change(json, query) selected[query[-1]] = new_value return json def update_leaf(json, key, new_value): """Update *all* JSON leafs that match 'key' with a given 'value' Algorithm explanation: 1. Select path to JSON leaf referred by the given key 2. Fold the JSON structure up to this key (not included) 3. Update the leaf of folded JSON using given key """ matched = [path for path in extract_paths(json) if path[-1] == key] for query in matched: selected = __upto_key_for_change(json, query) # skip keys that refer dictionary or list if isinstance(selected[query[-1]], dict) or isinstance(selected[query[-1]], list): continue # update only leafs selected[query[-1]] = new_value return json #___________________________________________________________ # Helper functions def __upto_key_for_change(data, query): def __select(data, query): return data[query] return reduce(__select, query[:-1], data)
Ще стане добре - сигурен съм. Ако ми остане време ще разкрия и още интересни части от този проект, който е само в зародиш.
No comments:
Post a Comment