From 81de96d1eeaa7240dd1b6011b44811d404ea6f40 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:18:48 +0100 Subject: [PATCH 01/15] Add files via upload --- inspect4py/cli.py | 47 +++- .../models/json_files/__init__.json | 1 + inspect4py/output_dir/directory_info.json | 1 + inspect4py/parse_setup_files.py | 4 +- inspect4py/resources/my-languages.so | Bin 0 -> 408064 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 247 bytes .../__pycache__/builder.cpython-39.pyc | Bin 0 -> 12726 bytes .../staticfg/__pycache__/model.cpython-39.pyc | Bin 0 -> 7447 bytes inspect4py/utils.py | 257 +++++++++++++++++- 9 files changed, 300 insertions(+), 10 deletions(-) create mode 100644 inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json create mode 100644 inspect4py/output_dir/directory_info.json create mode 100644 inspect4py/resources/my-languages.so create mode 100644 inspect4py/staticfg/__pycache__/__init__.cpython-39.pyc create mode 100644 inspect4py/staticfg/__pycache__/builder.cpython-39.pyc create mode 100644 inspect4py/staticfg/__pycache__/model.cpython-39.pyc diff --git a/inspect4py/cli.py b/inspect4py/cli.py index 166b275..6ee07bd 100644 --- a/inspect4py/cli.py +++ b/inspect4py/cli.py @@ -1,13 +1,16 @@ +import ast import json import tokenize import types import builtins import click from docstring_parser import parse as doc_parse +from tree_sitter import Language, Parser from inspect4py import __version__ from inspect4py.staticfg import builder from inspect4py.utils import * +# from utils import * """ Code Inspector @@ -26,7 +29,7 @@ class CodeInspection: - def __init__(self, path, out_control_flow_path, out_json_path, control_flow, abstract_syntax_tree, source_code): + def __init__(self, path, out_control_flow_path, out_json_path, control_flow, abstract_syntax_tree, source_code, data_flow, parser): """ init method initializes the Code_Inspection object :param self self: represent the instance of the class :param str path: the file to inspect @@ -41,6 +44,8 @@ def __init__(self, path, out_control_flow_path, out_json_path, control_flow, abs self.out_json_path = out_json_path self.abstract_syntax_tree = abstract_syntax_tree self.source_code = source_code + self.data_flow = data_flow + self.parser = parser self.tree = self.parser_file() if self.tree != "AST_ERROR": self.nodes = self.walk() @@ -58,6 +63,7 @@ def __init__(self, path, out_control_flow_path, out_json_path, control_flow, abs else: self.fileJson = {} + def find_classDef(self): classDef_nodes = [node for node in self.nodes if isinstance(node, ast.ClassDef)] class_init=[] @@ -466,6 +472,13 @@ def file_json(self): json.dump(prune_json(file_dict), outfile) return [file_dict, json_file] + # def get_parser_data_flow(self): + # parser = Parser() + # LANGUAGE = Language(self.symbol_table, "python") + # parser.set_language(LANGUAGE) + # parser = [parser, DFG_python] + # return parser + def _f_definitions(self, functions_definitions): """_f_definitions extracts the name, args, docstring returns, raises of a list of functions or a methods. @@ -477,11 +490,15 @@ def _f_definitions(self, functions_definitions): :param list functions_definitions: represent a list with all functions or methods nodes :return dictionary: a dictionary with the all the information at function/method level """ - + # print(functions_definitions) funcs_info = {} for f in functions_definitions: + # for node in ast.walk(f): + # print(node.name) + funcs_info[f.name] = {} ds_f = ast.get_docstring(f) + # print(ds_f) try: docstring = doc_parse(ds_f) funcs_info[f.name]["doc"] = {} @@ -577,7 +594,10 @@ def _f_definitions(self, functions_definitions): funcs_info[f.name]["ast"] = ast_to_json(f) if self.source_code: funcs_info[f.name]["source_code"] = ast_to_source_code(f) - + if self.data_flow: + code_tokens, dfg = extract_dataflow(funcs_info[f.name]["source_code"], self.parser, "python") + funcs_info[f.name]["data_flow"] = dfg + funcs_info[f.name]["code_tokens"] = code_tokens return funcs_info def _skip_dynamic_calls(self, funcs_info, classes_info, check_name, name, var_name): @@ -1204,6 +1224,7 @@ def create_output_dirs(output_dir, control_flow): @click.option('-i', '--input_path', type=str, required=True, help="input path of the file or directory to inspect.") @click.option('-o', '--output_dir', type=str, default="output_dir", help="output directory path to store results. If the directory does not exist, the tool will create it.") +@click.option('-st','--symbol_table', type=str, default="my_language.so", help="symbol table for the target function") @click.option('-ignore_dir', '--ignore_dir_pattern', multiple=True, default=[".", "__pycache__"], help="ignore directories starting with a certain pattern. This parameter can be provided multiple times " "to ignore multiple directory patterns.") @@ -1231,16 +1252,28 @@ def create_output_dirs(output_dir, control_flow): help="extract all readme files in the target repository.") @click.option('-md', '--metadata', type=bool, is_flag=True, help="extract metadata of the target repository using Github API. (requires repository to have the .git folder)") +@click.option('-df', '--data_flow', type=bool, is_flag=True, + help="extract data flow graph of every function in the target repository") + def main(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, html_output, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, source_code, license_detection, readme, - metadata): + metadata, data_flow, symbol_table): + if data_flow: + LANGUAGE = Language(symbol_table, "python") + parser = Parser() + parser.set_language(LANGUAGE) + parser = [parser, DFG_python] + else: + parser = [] + + # print(parsers) if (not os.path.isfile(input_path)) and (not os.path.isdir(input_path)): print('The file or directory specified does not exist') sys.exit() if os.path.isfile(input_path): cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) # Generate the call list of a file call_list_data = call_list_file(code_info) @@ -1279,11 +1312,13 @@ def main(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requir for f in files: if ".py" in f and not f.endswith(".pyc"): try: + path = os.path.join(subdir, f) relative_path = Path(subdir).relative_to(Path(input_path).parent) out_dir = str(Path(output_dir) / relative_path) cf_dir, json_dir = create_output_dirs(out_dir, control_flow) - code_info = CodeInspection(path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) + # print(parsers) if code_info.fileJson: if out_dir not in dir_info: dir_info[out_dir] = [code_info.fileJson[0]] diff --git a/inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json b/inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json new file mode 100644 index 0000000..81fe488 --- /dev/null +++ b/inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json @@ -0,0 +1 @@ +{"file": {"path": "D:\\inspect4py-main\\test\\Autumn945_MGNN-SPred\\MGNN-SPred-master\\models\\__init__.py", "fileNameBase": "__init__", "extension": "py"}, "dependencies": [{"from_module": "base", "import": "Base", "type": "internal", "type_element": "class"}, {"from_module": "base", "import": "GNN", "type": "internal", "type_element": "class"}], "is_test": false} \ No newline at end of file diff --git a/inspect4py/output_dir/directory_info.json b/inspect4py/output_dir/directory_info.json new file mode 100644 index 0000000..a934e9c --- /dev/null +++ b/inspect4py/output_dir/directory_info.json @@ -0,0 +1 @@ +{"output_dir\\Autumn945_MGNN-SPred\\MGNN-SPred-master\\models": [{"file": {"path": "D:\\inspect4py-main\\test\\Autumn945_MGNN-SPred\\MGNN-SPred-master\\models\\__init__.py", "fileNameBase": "__init__", "extension": "py"}, "dependencies": [{"from_module": "base", "import": "Base", "type": "internal", "type_element": "class"}, {"from_module": "base", "import": "GNN", "type": "internal", "type_element": "class"}], "is_test": false}]} \ No newline at end of file diff --git a/inspect4py/parse_setup_files.py b/inspect4py/parse_setup_files.py index 593c99e..126130c 100644 --- a/inspect4py/parse_setup_files.py +++ b/inspect4py/parse_setup_files.py @@ -56,7 +56,9 @@ def parse_setup_py(parent_dir): if single_line: elem = setup_content[console_index] cs = elem.split("=") - cs_string = cs[0].strip().replace('\'', '').split('["')[1] + # print(cs) + # print(cs[1].strip()) + cs_string = cs[1].strip().replace('\'', '').split('["')[1] cs_list.append(normalize(cs_string)) setup_info["installation"] = "pip install " + cs_string setup_info["run"].append(cs_string) diff --git a/inspect4py/resources/my-languages.so b/inspect4py/resources/my-languages.so new file mode 100644 index 0000000000000000000000000000000000000000..921ee0bf7e20ede73a280a92f6ef33a8cb1aabae GIT binary patch literal 408064 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¬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 literal 0 HcmV?d00001 diff --git a/inspect4py/staticfg/__pycache__/builder.cpython-39.pyc b/inspect4py/staticfg/__pycache__/builder.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d912845c414fcaf90cdafc77c6459c6a0473576b GIT binary patch literal 12726 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 literal 0 HcmV?d00001 diff --git a/inspect4py/staticfg/__pycache__/model.cpython-39.pyc b/inspect4py/staticfg/__pycache__/model.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e464c6992bdc54e5a56fd4977419479541d0e953 GIT binary patch literal 7447 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 dict: return github_metadata - def find_index_init(depInfo, calls, class_init): index_remove=[] for dep in depInfo: @@ -793,9 +792,261 @@ def update_list_calls(info, index_remove): if i in index_remove: continue updated_calls.append(info["calls"][i]) - ### These lines are for removing duplicate calls + ### These lines are for removing duplicate calls res = [] for i in updated_calls : if i not in res: res.append(i) return res + +def tree_to_variable_index(root_node, index_to_code): + if (len(root_node.children) == 0 or root_node.type == 'string') and root_node.type != 'comment': + index = (root_node.start_point, root_node.end_point) + _, code = index_to_code[index] + if root_node.type != code: + return [(root_node.start_point, root_node.end_point)] + else: + return [] + else: + code_tokens = [] + for child in root_node.children: + code_tokens += tree_to_variable_index(child, index_to_code) + return code_tokens + +def DFG_python(root_node, index_to_code, states): + assignment = ['assignment', 'augmented_assignment', 'for_in_clause'] + if_statement = ['if_statement'] + for_statement = ['for_statement'] + while_statement = ['while_statement'] + do_first_statement = ['for_in_clause'] + def_statement = ['default_parameter'] + states = states.copy() + if (len(root_node.children) == 0 or root_node.type == 'string') and root_node.type != 'comment': + idx, code = index_to_code[(root_node.start_point, root_node.end_point)] + if root_node.type == code: + return [], states + elif code in states: + return [(code, idx, 'comesFrom', [code], states[code].copy())], states + else: + if root_node.type == 'identifier': + states[code] = [idx] + return [(code, idx, 'comesFrom', [], [])], states + elif root_node.type in def_statement: + name = root_node.child_by_field_name('name') + value = root_node.child_by_field_name('value') + DFG = [] + if value is None: + indexs = tree_to_variable_index(name, index_to_code) + for index in indexs: + idx, code = index_to_code[index] + DFG.append((code, idx, 'comesFrom', [], [])) + states[code] = [idx] + return sorted(DFG, key=lambda x: x[1]), states + else: + name_indexs = tree_to_variable_index(name, index_to_code) + value_indexs = tree_to_variable_index(value, index_to_code) + temp, states = DFG_python(value, index_to_code, states) + DFG += temp + for index1 in name_indexs: + idx1, code1 = index_to_code[index1] + for index2 in value_indexs: + idx2, code2 = index_to_code[index2] + DFG.append((code1, idx1, 'comesFrom', [code2], [idx2])) + states[code1] = [idx1] + return sorted(DFG, key=lambda x: x[1]), states + elif root_node.type in assignment: + if root_node.type == 'for_in_clause': + right_nodes = [root_node.children[-1]] + left_nodes = [root_node.child_by_field_name('left')] + else: + if root_node.child_by_field_name('right') is None: + return [], states + left_nodes = [x for x in root_node.child_by_field_name('left').children if x.type != ','] + right_nodes = [x for x in root_node.child_by_field_name('right').children if x.type != ','] + if len(right_nodes) != len(left_nodes): + left_nodes = [root_node.child_by_field_name('left')] + right_nodes = [root_node.child_by_field_name('right')] + if len(left_nodes) == 0: + left_nodes = [root_node.child_by_field_name('left')] + if len(right_nodes) == 0: + right_nodes = [root_node.child_by_field_name('right')] + DFG = [] + for node in right_nodes: + temp, states = DFG_python(node, index_to_code, states) + DFG += temp + + for left_node, right_node in zip(left_nodes, right_nodes): + left_tokens_index = tree_to_variable_index(left_node, index_to_code) + right_tokens_index = tree_to_variable_index(right_node, index_to_code) + temp = [] + for token1_index in left_tokens_index: + idx1, code1 = index_to_code[token1_index] + temp.append((code1, idx1, 'computedFrom', [index_to_code[x][1] for x in right_tokens_index], + [index_to_code[x][0] for x in right_tokens_index])) + states[code1] = [idx1] + DFG += temp + return sorted(DFG, key=lambda x: x[1]), states + elif root_node.type in if_statement: + DFG = [] + current_states = states.copy() + others_states = [] + tag = False + if 'else' in root_node.type: + tag = True + for child in root_node.children: + if 'else' in child.type: + tag = True + if child.type not in ['elif_clause', 'else_clause']: + temp, current_states = DFG_python(child, index_to_code, current_states) + DFG += temp + else: + temp, new_states = DFG_python(child, index_to_code, states) + DFG += temp + others_states.append(new_states) + others_states.append(current_states) + if tag is False: + others_states.append(states) + new_states = {} + for dic in others_states: + for key in dic: + if key not in new_states: + new_states[key] = dic[key].copy() + else: + new_states[key] += dic[key] + for key in new_states: + new_states[key] = sorted(list(set(new_states[key]))) + return sorted(DFG, key=lambda x: x[1]), new_states + elif root_node.type in for_statement: + DFG = [] + for i in range(2): + right_nodes = [x for x in root_node.child_by_field_name('right').children if x.type != ','] + left_nodes = [x for x in root_node.child_by_field_name('left').children if x.type != ','] + if len(right_nodes) != len(left_nodes): + left_nodes = [root_node.child_by_field_name('left')] + right_nodes = [root_node.child_by_field_name('right')] + if len(left_nodes) == 0: + left_nodes = [root_node.child_by_field_name('left')] + if len(right_nodes) == 0: + right_nodes = [root_node.child_by_field_name('right')] + for node in right_nodes: + temp, states = DFG_python(node, index_to_code, states) + DFG += temp + for left_node, right_node in zip(left_nodes, right_nodes): + left_tokens_index = tree_to_variable_index(left_node, index_to_code) + right_tokens_index = tree_to_variable_index(right_node, index_to_code) + temp = [] + for token1_index in left_tokens_index: + idx1, code1 = index_to_code[token1_index] + temp.append((code1, idx1, 'computedFrom', [index_to_code[x][1] for x in right_tokens_index], + [index_to_code[x][0] for x in right_tokens_index])) + states[code1] = [idx1] + DFG += temp + if root_node.children[-1].type == "block": + temp, states = DFG_python(root_node.children[-1], index_to_code, states) + DFG += temp + dic = {} + for x in DFG: + if (x[0], x[1], x[2]) not in dic: + dic[(x[0], x[1], x[2])] = [x[3], x[4]] + else: + dic[(x[0], x[1], x[2])][0] = list(set(dic[(x[0], x[1], x[2])][0] + x[3])) + dic[(x[0], x[1], x[2])][1] = sorted(list(set(dic[(x[0], x[1], x[2])][1] + x[4]))) + DFG = [(x[0], x[1], x[2], y[0], y[1]) for x, y in sorted(dic.items(), key=lambda t: t[0][1])] + return sorted(DFG, key=lambda x: x[1]), states + elif root_node.type in while_statement: + DFG = [] + for i in range(2): + for child in root_node.children: + temp, states = DFG_python(child, index_to_code, states) + DFG += temp + dic = {} + for x in DFG: + if (x[0], x[1], x[2]) not in dic: + dic[(x[0], x[1], x[2])] = [x[3], x[4]] + else: + dic[(x[0], x[1], x[2])][0] = list(set(dic[(x[0], x[1], x[2])][0] + x[3])) + dic[(x[0], x[1], x[2])][1] = sorted(list(set(dic[(x[0], x[1], x[2])][1] + x[4]))) + DFG = [(x[0], x[1], x[2], y[0], y[1]) for x, y in sorted(dic.items(), key=lambda t: t[0][1])] + return sorted(DFG, key=lambda x: x[1]), states + else: + DFG = [] + for child in root_node.children: + if child.type in do_first_statement: + temp, states = DFG_python(child, index_to_code, states) + DFG += temp + for child in root_node.children: + if child.type not in do_first_statement: + temp, states = DFG_python(child, index_to_code, states) + DFG += temp + + return sorted(DFG,key=lambda x:x[1]),states + +def tree_to_variable_index(root_node, index_to_code): + if (len(root_node.children) == 0 or root_node.type == 'string') and root_node.type != 'comment': + index = (root_node.start_point, root_node.end_point) + _, code = index_to_code[index] + if root_node.type != code: + return [(root_node.start_point, root_node.end_point)] + else: + return [] + else: + code_tokens = [] + for child in root_node.children: + code_tokens += tree_to_variable_index(child, index_to_code) + return code_tokens + + +def index_to_code_token(index, code): + start_point = index[0] + end_point = index[1] + if start_point[0] == end_point[0]: + s = code[start_point[0]][start_point[1]:end_point[1]] + else: + s = "" + s += code[start_point[0]][start_point[1]:] + for i in range(start_point[0] + 1, end_point[0]): + s += code[i] + s += code[end_point[0]][:end_point[1]] + return s + +def tree_to_token_index(root_node): + if (len(root_node.children) == 0 or root_node.type == 'string') and root_node.type != 'comment': + return [(root_node.start_point, root_node.end_point)] + else: + code_tokens = [] + for child in root_node.children: + code_tokens += tree_to_token_index(child) + return code_tokens + +def extract_dataflow(code, parser,lang): + #obtain dataflow + if lang=="php": + code="" + try: + tree = parser[0].parse(bytes(code,'utf8')) + root_node = tree.root_node + tokens_index=tree_to_token_index(root_node) + code=code.split('\n') + code_tokens=[index_to_code_token(x,code) for x in tokens_index] + index_to_code={} + for idx,(index,code) in enumerate(zip(tokens_index,code_tokens)): + index_to_code[index]=(idx,code) + try: + DFG,_=parser[1](root_node,index_to_code,{}) + except: + DFG=[] + DFG=sorted(DFG,key=lambda x:x[1]) + indexs=set() + for d in DFG: + if len(d[-1])!=0: + indexs.add(d[1]) + for x in d[-1]: + indexs.add(x) + new_DFG=[] + for d in DFG: + if d[1] in indexs: + new_DFG.append(d) + dfg=new_DFG + except: + dfg=[] + return code_tokens, dfg \ No newline at end of file From 67f475758ec34758fbdc7b2541a3fc21fe7baaf0 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:19:37 +0100 Subject: [PATCH 02/15] Add files via upload --- test/test_files/test_data_flow.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 test/test_files/test_data_flow.py diff --git a/test/test_files/test_data_flow.py b/test/test_files/test_data_flow.py new file mode 100644 index 0000000..8924a86 --- /dev/null +++ b/test/test_files/test_data_flow.py @@ -0,0 +1,8 @@ +def max(a, b): + x = 0 + if a > b: + x = a + else: + x = b + return x + From 9e4e5ce9f4e9bdabf31756d86379359c861edda6 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:19:52 +0100 Subject: [PATCH 03/15] Add files via upload --- test/test_inspect4py.py | 252 +++++++++++++++++++++++----------------- 1 file changed, 145 insertions(+), 107 deletions(-) diff --git a/test/test_inspect4py.py b/test/test_inspect4py.py index ce2ae50..5c1283f 100644 --- a/test/test_inspect4py.py +++ b/test/test_inspect4py.py @@ -15,8 +15,10 @@ def test_call_list_super(self): control_flow = False abstract_syntax_tree = False source_code = False + data_flow = False + parser = [] cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data["classes"]['Rectangle'] == dictionary['Rectangle']) @@ -35,8 +37,10 @@ def test_call_list_super_test_5(self): control_flow = False abstract_syntax_tree = False source_code = False + data_flow = False + parser = [] cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data['body'] == dictionary['body']) @@ -48,11 +52,12 @@ def test_call_list_nested(self): input_path = "./test_files/test_inheritance/nested_call.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -68,11 +73,13 @@ def test_call_list_super_nested(self): input_path = "./test_files/test_inheritance/super_nested_call.py" output_dir = "./output_dir" control_flow = False + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -85,11 +92,13 @@ def test_call_list_import(self): input_path = "./test_files/test_inheritance/test_import.py" output_dir = "./output_dir" control_flow = False + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -100,11 +109,12 @@ def test_call_list_external_module(self): input_path = "./test_files/test_random.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data['body'] == dictionary['body']) @@ -116,11 +126,12 @@ def test_call_list_argument_call(self): input_path = "./test_files/test_dynamic/argument_call.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data['body'] == dictionary['body']) @@ -131,11 +142,12 @@ def test_call_list_dynamic_body(self): input_path = "./test_files/test_dynamic/test_dynamic.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -146,11 +158,12 @@ def test_call_list_dynamic_func(self): input_path = "./test_files/test_dynamic/test_dynamic_func.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -162,11 +175,12 @@ def test_call_list_dynamic_body_import(self): input_path = "./test_files/test_dynamic/test_dynamic_import.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -178,11 +192,12 @@ def test_call_list_dynamic_body_from_import(self): input_path = "./test_files/test_dynamic/test_dynamic_from_import.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -194,11 +209,12 @@ def test_call_list_dynamic_import_alias(self): input_path = "./test_files/test_dynamic/test_dynamic_import_alias.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -210,11 +226,12 @@ def test_call_list_dynamic_import_method(self): input_path = "./test_files/test_dynamic/test_dynamic_method.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -228,11 +245,12 @@ def test_call_list_dynamic_import_method_variable(self): input_path = "./test_files/test_dynamic/test_dynamic_method_variable.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) @@ -244,19 +262,21 @@ def test_call_list_dynamic_class_import(self): input_path = "./test_files/test_dynamic/test_dynamic_class_import.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) call_list_data = call_list_file(code_info) shutil.rmtree(output_dir) assert (call_list_data == dictionary) def test_service(self): - input_path = "./test_files/Chowlk" + input_path = "D:\\inspect4py-main\\test\\test_files\\Chowlk" output_dir = "./output_dir" - + data_flow = False + symbol_table = "" ignore_dir_pattern = [".", "__pycache__"] ignore_file_pattern = [".", "__pycache__"] requirements = False @@ -271,14 +291,14 @@ def test_service(self): metadata = False dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table) current_type = dir_info['software_type'] shutil.rmtree(output_dir) assert current_type[0]["type"] == "service" def test_package(self): - input_path = "./test_files/somef" - output_dir = "./output_dir" + input_path = "D:\\inspect4py-main\\test\\test_files\\somef" + output_dir = "D:\\inspect4py-main\\test\\output_dir" ignore_dir_pattern = [".", "__pycache__"] ignore_file_pattern = [".", "__pycache__"] @@ -292,9 +312,11 @@ def test_package(self): license_detection = False readme = False metadata = False + data_flow = False + symbol_table = "" dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table) current_type = dir_info['software_type'] shutil.rmtree(output_dir) assert current_type[0]["type"] == "package" @@ -315,9 +337,11 @@ def test_library(self): license_detection = False readme = False metadata = False + data_flow = False + symbol_table = "" dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table) current_type = dir_info['software_type'] shutil.rmtree(output_dir) assert current_type[0]["type"] == "library" @@ -339,9 +363,11 @@ def test_multiple_mains(self): license_detection = False readme = False metadata = False + data_flow = False + symbol_table = "" dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table) imports = dir_info['software_invocation'] shutil.rmtree(output_dir) for i in imports: @@ -353,7 +379,7 @@ def test_multiple_mains(self): def test_script(self): - input_path = "./test_files/BoostingMonocularDepth" + input_path = "D:\\inspect4py-main\\test\\test_files\\BoostingMonocularDepth" output_dir = "./output_dir" ignore_dir_pattern = [".", "__pycache__"] @@ -368,9 +394,11 @@ def test_script(self): license_detection = False readme = False metadata = False + data_flow = False + symbol_table = "" dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table) current_type = dir_info['software_type'] shutil.rmtree(output_dir) assert current_type[0]["type"] == "script" @@ -402,8 +430,10 @@ def test_ast_function(self): abstract_syntax_tree = True source_code = False + data_flow = False + parser = [] cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) shutil.rmtree(output_dir) expected_ast = [ @@ -426,15 +456,45 @@ def test_ast_function(self): actual_ast = code_info.fileJson[0]["functions"]["foo"]["ast"] assert expected_ast == actual_ast + def test_data_flow(self): + input_path = "D:\\inspect4py-main\\test\\test_files\\test_data_flow.py" + output_dir = "./output_dir" + control_flow = False + abstract_syntax_tree = False + source_code = True + data_flow=True + LANGUAGE = Language("D:\\inspect4py-main\\my-languages.so", "python") + parser = Parser() + parser.set_language(LANGUAGE) + parser = [parser, DFG_python] + cf_dir, json_dir = create_output_dirs(output_dir, control_flow) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) + expected_dfg = [('a', 3, 'comesFrom', [], []), + ('b', 5, 'comesFrom', [], []), + ('x', 8, 'computedFrom', ['0'], [10]), + ('0', 10, 'comesFrom', [], []), + ('a', 12, 'comesFrom', ['a'], [3]), + ('b', 14, 'comesFrom', ['b'], [5]), + ('x', 16, 'computedFrom', ['a'], [18]), + ('a', 18, 'comesFrom', ['a'], [3]), + ('x', 21, 'computedFrom', ['b'], [23]), + ('b', 23, 'comesFrom', ['b'], [5]), + ('x', 25, 'comesFrom', ['x'], [16, 21])] + actual_dfg = code_info.fileJson[0]["functions"]["max"]["data_flow"] + assert actual_dfg == expected_dfg + + + def test_ast_method(self): input_path = "./test_files/test_basic/test_basic_method.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = True source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) shutil.rmtree(output_dir) expected_ast = [ @@ -467,11 +527,12 @@ def test_ast_body(self): input_path = "./test_files/test_basic/test_basic_body.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = True source_code = False cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) shutil.rmtree(output_dir) expected_ast = [ @@ -490,14 +551,15 @@ def test_ast_body(self): assert expected_ast == actual_ast def test_source_code_function(self): - input_path = "./test_files/test_basic/test_basic_function.py" + input_path = "D:\\inspect4py-main\\test\\test_files\\test_basic\\test_basic_function.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = True cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) shutil.rmtree(output_dir) expected_code = "def foo(arg1, arg2):\n print('Hello %s', arg1)\n return arg2" # Single double quote sensitive @@ -506,14 +568,15 @@ def test_source_code_function(self): def test_source_code_method(self): - input_path = "./test_files/test_basic/test_basic_method.py" + input_path = "D:\\inspect4py-main\\test\\test_files\\test_basic\\test_basic_method.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = True cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) shutil.rmtree(output_dir) expected_code = "def __init__(self, arg):\n self.arg = arg\n print('Hello %s' % self.arg)" @@ -521,14 +584,15 @@ def test_source_code_method(self): assert expected_code == actual_code def test_source_code_body(self): - input_path = "./test_files/test_basic/test_basic_body.py" + input_path = "D:\\inspect4py-main\\test\\test_files\\test_basic\\test_basic_body.py" output_dir = "./output_dir" control_flow = False - + data_flow = False + parser = [] abstract_syntax_tree = False source_code = True cf_dir, json_dir = create_output_dirs(output_dir, control_flow) - code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(input_path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) shutil.rmtree(output_dir) expected_code = ["print('Hello world')", "print(var)"] @@ -537,8 +601,8 @@ def test_source_code_body(self): def test_license_detection(self): - input_paths = ["./test_files/Chowlk", "./test_files/pylops", "./test_files/somef"] - output_dir = "./output_dir" + input_paths = ["D:\\inspect4py-main\\test\\test_files\Chowlk", "D:\\inspect4py-main\\test\\test_files\\pylops", "D:\\inspect4py-main\\test\\test_files\\somef"] + output_dir = "D:\\inspect4py-main\\test\\output_dir" fig = False ignore_dir_pattern = [".", "__pycache__"] ignore_file_pattern = [".", "__pycache__"] @@ -552,7 +616,8 @@ def test_license_detection(self): license_detection = True readme = False metadata = False - + data_flow = False + symbol_table = "" expected_liceses = ['Apache-2.0', 'LGPL-3.0', 'MIT'] first_rank_licenses = [] for input_path in input_paths: @@ -560,7 +625,7 @@ def test_license_detection(self): ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table) first_rank_licenses.append(next(iter(dir_info["license"]["detected_type"][0]))) shutil.rmtree(output_dir) @@ -568,8 +633,8 @@ def test_license_detection(self): def test_license_text_extraction(self): license_text = "A random license." - input_path = "./test_files/test_license_extraction" - output_dir = "./output_dir" + input_path = "D:\\inspect4py-main\\test\\test_files\\test_license_extraction" + output_dir = "D:\\inspect4py-main\\test\\output_dir" fig = False ignore_dir_pattern = [".", "__pycache__"] ignore_file_pattern = [".", "__pycache__"] @@ -583,19 +648,20 @@ def test_license_text_extraction(self): license_detection = True readme = False metadata = False - + data_flow = False + symbol_table = "" dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table=symbol_table) assert dir_info["license"]["extracted_text"] == license_text def test_readme(self): - input_path = "./test_files/test_readme" - output_dir = "./output_dir" + input_path = "D:\\inspect4py-main\\test\\test_files\\test_readme" + output_dir = "D:\\inspect4py-main\\test\\output_dir" ignore_dir_pattern = [".", "__pycache__"] ignore_file_pattern = [".", "__pycache__"] @@ -609,59 +675,31 @@ def test_readme(self): license_detection = False readme = True metadata = False - + data_flow = False + symbol_table = "" dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata) + source_code, license_detection, readme, metadata, data_flow, symbol_table) expected_readme_files = { - f"{output_dir}/test_readme/README.md": "README.md in root dir\n", - f"{output_dir}/test_readme/subdir/README.txt": "README.txt in subdir\n", - f"{output_dir}/test_readme/subdir/subsubdir/README.rst": "README.rst in subsubdir\n" + f"{output_dir}\\test_readme\\README.md": "README.md in root dir\n", + f"{output_dir}\\test_readme\\subdir\\README.txt": "README.txt in subdir\n", + f"{output_dir}\\test_readme\\subdir\\subsubdir\\README.rst": "README.rst in subsubdir\n" } actual_readme_files = dir_info["readme_files"] assert expected_readme_files == actual_readme_files - #def test_metadata(self): - # """ - # Need to execute under test/test_files/: - # `git clone https://github.com/githubtraining/hellogitworld.git` - # to pass this test, as getting metadata requires the local repository - # to have a .git folder. - # """ - # input_path = "./test_files/hellogitworld" - # output_dir = "./output_dir" - # - # ignore_dir_pattern = [".", "__pycache__"] - # ignore_file_pattern = [".", "__pycache__"] - # requirements = False - # call_list = False - # control_flow = False - # directory_tree = False - # software_invocation = False - ## abstract_syntax_tree = False - # source_code = False - # license_detection = False - # readme = False - # metadata = True - # - # dir_info = invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, - # call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - # source_code, license_detection, readme, metadata) - # try: - # response = requests.get("https://api.github.com/repos/githubtraining/hellogitworld") - # expected_metadata = response.json() - # except requests.RequestException as e: - # print(f"Error sending requests to Github API: {e}") - # raise e - # actual_metadata = dir_info["metadata"] - # assert expected_metadata == actual_metadata - - -def invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, - call_list, control_flow, directory_tree, software_invocation, abstract_syntax_tree, - source_code, license_detection, readme, metadata): +def invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pattern, requirements, call_list, + control_flow, directory_tree, software_invocation, abstract_syntax_tree, source_code, license_detection, readme, + metadata, data_flow, symbol_table): + if data_flow: + LANGUAGE = Language(symbol_table, "python") + parser = Parser() + parser.set_language(LANGUAGE) + parser = [parser, DFG_python] + else: + parser = [] dir_info = {} # retrieve readme text at the root level (if any) readme = "" @@ -684,7 +722,7 @@ def invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pat relative_path = Path(subdir).relative_to(Path(input_path).parent) out_dir = str(Path(output_dir) / relative_path) cf_dir, json_dir = create_output_dirs(out_dir, control_flow) - code_info = CodeInspection(path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code) + code_info = CodeInspection(path, cf_dir, json_dir, control_flow, abstract_syntax_tree, source_code, data_flow, parser) if out_dir not in dir_info: dir_info[out_dir] = [code_info.fileJson[0]] else: @@ -700,7 +738,7 @@ def invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pat call_file_html = output_dir + "/call_graph.html" generate_output_html(pruned_call_list_data, call_file_html) call_json_file = output_dir + "/call_graph.json" - with open(call_json_file, 'w') as outfile: + with open(call_json_file, 'rb') as outfile: json.dump(pruned_call_list_data, outfile) # Note:1 for visualising the tree, nothing or 0 for not. if requirements: @@ -729,7 +767,7 @@ def invoke_inspector(input_path, output_dir, ignore_dir_pattern, ignore_file_pat dir_info["software_type"] = rank_software_invocation(soft_invocation_info_list) if license_detection: licenses_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), - "../inspect4py/licenses") + "..\\inspect4py\\licenses") license_text = extract_license(input_path) rank_list = detect_license(license_text, licenses_path) dir_info["license"] = {} From 1297b6e1878cf6d0ae9c03b7d54db5479ef977df Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:20:32 +0100 Subject: [PATCH 04/15] Add files via upload --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d78af49..428c3c9 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,11 @@ Inspect4py currently works **only for Python 3 projects**. ## Background: +`inspect4py` added the functionality of capture [Data Flow Graphs](http://bears.ece.ucsb.edu/research-info/DP/dfg.html) for each function inspired by GraphCodeBERT: [Github](https://github.com/microsoft/CodeBERT) & [Paper](https://arxiv.org/abs/2009.08366). The illustration is given: +|Source Code|List Output|Networkx Image| +|:-:|:-:|:-:| +|
def max(a, b):
x = 0
if a > b:
x = a
else:
x = b
return x
|
('a', 3, 'comesFrom', [], [])
('b', 5, 'comesFrom', [], [])
('x', 8, 'computedFrom', ['0'], [10])
('0', 10, 'comesFrom', [], [])
('a', 12, 'comesFrom', ['a'], [3])
('b', 14, 'comesFrom', ['b'], [5])
('x', 16, 'computedFrom', ['a'], [18])
('a', 18, 'comesFrom', ['a'], [3])
('x', 21, 'computedFrom', ['b'], [23])
('b', 23, 'comesFrom', ['b'], [5])
('x', 25, 'comesFrom', ['x'], [16, 21])
|![image](docs/images/data_flow.png)| + `inspect4py` uses [ASTs](https://en.wikipedia.org/wiki/Abstract_syntax_tree), more specifically the [ast](https://docs.python.org/3/library/ast.html) module in Python, generating a tree of objects (per file) whose classes all inherit from [ast.AST](https://docs.python.org/3/library/ast.html#ast.AST). From f0c0c00419410fe375b58053da4a7cafdb7fd5c3 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:21:22 +0100 Subject: [PATCH 05/15] Add files via upload --- docs/images/data_flow.png | Bin 0 -> 19124 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/data_flow.png diff --git a/docs/images/data_flow.png b/docs/images/data_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..4e993a0c32519485dfdd7039d917a41d215010d0 GIT binary patch literal 19124 zcmb@tWl&sQ6DZ_PC1O%ir_`!zz2!4~20m~2mfpk=s6oIH1 zBRl~Afi@SG6NZ4Ojz)YogaQADxBIH;2myi8{r*7q+ZLHXKuAkTi3xvm(>uw4HTb4_ z+t+?@AdnMC_Eia5>B|>1n4^l;4~gxj)*5rCrzNEo4NZxEo0}L7n2I#es&nDUfS6dq zKqolTpz9G6>DN0xHYOw%Ocv3lhtAw>3)m6KZmXbv@#P}ceY{;CGbKS%36fHXyAR`joSlInKCZYcP3c8K1z zxNe((VZ$UI$JNDARLjLB1*KGsRH`pZxu3!~h006{gskbi(-Xusv~|K9Y$1q~pc*YM z_Sb2UyFJYY1#hC2;svB$*df7Vp!;o(Ac$CcN$KI8z8b(|SI~7nGN=~8&*3AkV!Jda z6Y>4-&5@L6tsq{6@;#mxo|`1?HpVhl$ZgceH1)(a{0$J|^5l3u--9B<17Zaq!Dm*H5> zdn)n2!NRt<((pN7UekpRL31qZ#>O_Qs6@^^+^hU_trl9fOvngLC!_e+st&Ft)@?C~ zF*QU;H&`_&0Ua-|tKz@0`_R{!5^ef&BTdh_yRn-L>K4;&;(cCtITf0aIg|QlaQQCv zUkQeG<=~kJH1|#!$+uy!1Y4Tz0tictUuflmfK5}stC0@tcWu9P6kTyn(#1xej5Wb_ zmY`!QWQA@jyvjr)E=4v?^P~AYKb;H59NUA4WM*~>bC2D>%_ML}7J%pw>BN%jS*k`w z%GasqJjROb0Z$&Rv_ALHClb+Y{=_2I9r~^xq?<=)eslDy0*XtDwF?2B_*l*bqax&K ziH-9lVybeAUZBJs8&V@VPzCbfuhHF~qgdu@L%Y@+w8UBJhsc$Rs_Ll_?@ch|At!!H z6Oh(>qJO$nC4Easi{*XR>A4exPNRNV)!1R|u=xF`02#pcOXQ1E>W6=$5ETvwHR>pD zro#n_Byv$ktQtbM;=41gLaVFc&J_O3W#%)m@e@@(Fb(Fb5u0vjx3UV>a-Mvu-viEY%%u)1Z*s|CF6lGeSL=*0C%bY%P zyQcZW^g$dGSO3jPvcK`&(dQ$~f?`D_^(FqCP$lnv_$TSE3TfZ39tj8%1C-)F3toHR zn#^@Ebjney2@`clIf1nWC--vzNHz>X-G{OcnndW7$ zgw*_KhjUw4C;k;Ca)u0DT|5#VA;$IUcZP3gduu%es% z?1q|;p5~OBeR-as03p==j%}o=)53*j|rJuGb#Y_SDOsC#vy%9kgdxyQAIN z!T}~3{ab$Hd)@6MUZ1#hd|S)5KDm@44k?{{?bw-L3;fk3=eAc6wjZ-8toBR$HYc+* z2z=_~I4{u<+gkeYtIfnUTdHLx65Vf>|GJ$$A!{_$iRro0?55A0D;b5&2K>=)_h|qH z6Kp#&}q)2R8peoXYeX@hI3?_&xEA~a2_+cT_y$90T1;MoSD9&}Q_p2(xiZmCw; zC-i!OsyWxWl&~uyD?{tQE}Z2!8q-f|x0YHvJg95}TSno=|^vUhX@zD^ppd)A9L14F!KDnNFc%#iLKL3uPlVprlcCYkNnu3=73`8mWQU2jjB6Ue=%j6O zjxmjWiK2q2JjX$8QW-uvR`S6sIV>NgjqjEr*Gf6+=iQc~sGXwJm#R)~K7UY4?7|INmc8*SlN zNLMjxp4I6x!0T*%AnV$d{BjnQjvu>~vd+7xabG#E%{07ZSMp3u4Z)5jTfBtm=A+ zIMOoCzH`ZtnTB)VM`(Q|mp;lQ9kPp^x92?}Q+L;HG)D)AL$Q~7tp{KYb*NPFAEe|{ zO)2DE`{MFqiSqW31&(VmeN!zsHeci>wenF2h@!Nk2|Iq^u%ZS<(GXL3MyT4>1&z?L z>8H&~E4u{m=(*p_s#A`6P322DANiIRY44PKKixVDI%jGR=YS7YSdsS4&L7Ceo6X_K z4%nA-r{l+S>bNhODMlLhYT(-UT5f=E@=Y+9lG;k#v{& zDdnY)i6q{$C8`b2m%|q`Dhg86WR@?sz38^PL1EZ8i4c`KBm&kU$%ShIyCA%Kdt=QE zx?r`2)i{W>X$I1WsK9TU{oj+9zR0a&bPlwKHdHnt2qd)!6Q>a8o79PVrAzYqMi2|& z3wYi}EIQLM;2>1pOmOWGz!JNCetlYhd#$K35X# zjH;rh5pG((IcTn> zhk3iJ(HOtb*}OVIR9|MVHKV|P0j=kG!ckr1+8<3E=}a%4VOpM>E0UOoQTE|kULz!V z*JJ38;9{d+#(sMH%)Xld(S96O=6tB$vbuOioBCSIT8o6`M!RaGYC?y#g^!rn`R9Wv zC*IX04&0n3^2k{i4|S7y@_qO;7Wr-8mN{y?GS`n8fR4+eDSBd`&DuzBXD4#9Mi|xt zx{I1l!A)09&xG2oUrdPG3@b96%miMBLnjQ*h94|(j6+Sc&vmfD9{JRY*lNw#Lx$am zzcKLxdQv+piLb9K+UwJfbVODof~%Zvge4V22fV^ak3QAgPlf~z2c&3KE!1jP2}y)e zn2_Tj)JnW4<2%dfYv}sw9`6N3WrjSWodh-GyoY1^C6*#fUcCkb=2JdzUvAkj451d# zn&(+B_=!YhYEkTqZ@J$Lx1Uv2H(aPPG)RM>D>scTo?Uya60>|_ggH!kFx+s}i&5 zz1mD!EVbM2W@9!tjU_DYTJu;SH;$LKXA#nXA52p0Z^DV!ya9D7p)Bf${PKJB|6hac!eAY(b{dgT~U1pVTbi+mC`Ee3o z<)envzVf}3lwjgc((u<;%-j(%)Y~E1o=`o_{qJH&uTQ7F9>q|xFS$9PSEK_?N&EI2 z3E?3_5X*Dj!WNnurqe$Ft6NYCaYR^zr=&(Lab3MbJx4nvwHDJN!kxDRNpvbD;v$X^J*@Ex79dhcV^BAxnm{BA`ZM zBTN#_QsTlHc)Ra60#MI)(`+}pQHA2UU7E}qvTm@^Uknsesapi-F`Q`9ISf(SG=B6f zX~e?Y0F@Vb_r#QHBmB4vk$H;40GG3y5!CGw_rPw{kiMTgW2{J1Y^*UjXwE;fP1BF1 z?w@c?I%=NB?g;Wb-O`$jYrE@x;DJJ~sGRLL3Yfl^`p~q%ZcW8J#>DwEPG{Suho~#* zk^&UYIoIFp$Z}+dlgD3sT(M-18N$RaYr zJlWpz*qpXVd-sI|Un9^QM=|FFC_@wLy&iTEMzr(*wsasaUA7Bbl#hz7KLkbEXd7yp z$TT$lM{OhG?2$~EQwJ_u^jwg1RKA6cCt(dVox8^;O2>tJ7>gJdexIfk_1gnnSTP%O zQ^1OGgQd)&{5z#qH_5+I;W+46`s};j4Vg{g(x-H(6tkh2asDX(nFU6eS6V^BO|ln? z=VIOSS|;Q(M%tc`@XIPU;}mvYR&+^XGSBR>vuU&v`u0Vc@!rB9ZIqYS0W%+ICA1=c$G@1IA3h` zqLv`_Y z945QlKpu3GF*u^r^dMqZk{tYlZS;*wMA3Z!$_1iEv4$W?B&WcVWxkzb4P{Ia4#FaPm-CKnt~=o zQ4=&=smyDhPZERLORF}4wn?;IZ%V`MAa?1%kGcqb4%AN6+!5lZx>ryLYfS`E+p^zY z`4PocNMdgspvc&N%lN4sgF_Yj=PkC24eH^lk_P;W7}Qfmj+zl|XacK)qpaEzxcZi> zykjm`=W0TA{RK@ym);X|cy7LB`CmX=AltB)S4k9u?pD%C zBoUw-3rgSSey+;FH0~SkEW?6vK%VOk+yP>UHwvnOA+P*o?GL98jV5I5g1h5c(dv5c zFut!>S@tt5{n-l9t@h&#T%Rd9oR7N6o`X^vX}V=wK~XsMs*5YGAYC33m)emKVQ=n4 z<~PAE9l7?CW#v>1Pj>lMo{si7td){&HnWiq{kKQ;GW~Wvqt!*kNe?(X;963$su|C7 z3dm(T$p#y=QA$V0LMKt_GRXa7-6fQ3E_bH7$TUvqTU7Q^fM85_%R`8@fcNEi1+=&@a&H`9=!tfOnqq$&hun;*}q(wG#1I z#ytZ#f~%pQCxdD@7mH;Z3>(F)_IXfbx_gX`-S6w4C#E7zg8bcU$E&ESO4*tNi$Vw} zW~_sSdG06ijjxxM7kWMq$QLwlmz9wbU2pTAG;eR?cAJ2-GjZuOwJndoq(&8{$==l( zaaHBs5q6tr@}py$=l|3_*G%n7@<-?>(~bhkk@*5AmBecJetZ$iPWdg$*|&X)waTeP zikF0g`d<9pwvN8Ae$7LMH~yT@fNEe`o=qsvh5jg=hwb$SG=6V2NL5AykTm_Q zlcL#babbeba+sJB$^z@$hehu3^`$;awJ!RGNG`J;#nM&cazNsDjLK%Ew(KWjz2oYiWijq#67srbc7}&w4sVU`j*EM&yv(~#R zlR@<3+HpbUiiS+=d)IYu>djWC17%EXY+%sX^I5CMO&4hhAsMJix5+7XGVQS2i*bBR zul4U%EDuvi75(xL(LYj zlEs-$!j8BOeq;+?Aev(%coQ)Hyj0j%Ty+MGKuz${rl}d2N1RDYrb>PIXDY5Xzcbn< zX=OM|c=AubNlXF?j-XLsIDB25AOzs>sQw!$i~6n?x&IowdaEhJa5XQfT{ED1SMX|7 zCh*tYs7`?E30VW*bs%|ESZlF6*7SLbe=jp1hwC4{++f$!}lt%4qx}wG>ih3*AdeZ8lsuB8-CW_1Z?f|jq zDE^+oQ>XuoQxF{d)|MqcVg9E4v$lV{^CLMn-e8!W8g};iRw1aI9_OOiushLx)~wZR z3y*K4Y72>ukZ($nKEI0w8GRD(3L-+XzKp^hFvN?krSO3^$tNhc7?u1ep8zy=06fO9 zW%qAF4^koaUnRm(Vw1MM@07knW>C~L&+wwwKwaf((`L$v<&W;Lv};m&yg6FnKd7^# zCMN&&!1RV}di6UnDGxeh^=b@Wx?Qm*cVmblOtB5rl?k8*joVGD7J`Wi8-7SlOCBvV}7Rbn> z?4SLYQcIecQWL{}NsTk6M6MOa+r%J+1!V9lVrKJxK=xlj;#2`oD% zBxH4Bu4sB?YB-G)FS>?_-L4}yaLoP9jY?Uohc?_Fo6H#3a$Cb%&6NhxFg6b`3X-Vi>j<0+H7>MW zQG^J+UO%fPLQmA&3Zc1`vczFO=(?^_(i9x187|i1OEG}zHrBgBAgN0uB#bp@>oclI z#)zhRaZv@UHy+f;o-R*1A5lilCE6wgdbWV2ANKceL2VcwLoS(F?P>Gbe{{ah92sI+ zsWI=yr*Ip7*d5CZ!!u3M(EWy2y(UWp!ROXMsg?@m4F;3~hOz{?u-fR+*@!A|yHPx{G4AM1!Z;dbhw!5 zOVEn+pVuT&k0}I=1a%s1%r&%zxLDfUtsRjnJI~@gGueI+4z*=Q07(RenYCmrL zHugx#RS);NG8<@5`(P8sz4wffa@#aQ&@uSJM`khRcD!CL@alZ#tx@gO`0OJuJuH5v z2UVq5>tC%LGtzn|DY4!?k|d7Euj5B{qfhI2QTT=t?mfIWPIk6fs#I$c)PSh52!8|+ z-&_qM*!Dv^H6Txm_fYiO@5+?{O?7)__YhzvL5Tm##V?^n_00+FI<1UiR}P+^6fq^= zJI`F)B&TYhm28pQvclA%^QS|#0=7YMs;A$S`oi4ZJVBk~hYRpf!cb?pkx|K|Qk-xm z-i#j91Kqs0e~qNu!qyXnzuXL?^ufTMQEK8`4YwGzstn+j_j==jE_;ezE{-1p>=ruO zrW8GfM}510`a#*xX_`xQGlcmVD{7(89`be2PLa^-1c+N+_A1zD{-U5~pEYV_@!`Fj zDg=$4{t$b$z{QAAfUU(Tf7Lqp%H}AZ<5WhfCP`pQ_ebj>*p8>WZ7=O@0x=KPDJI$3 zgMzMHv$^v4!c7;cEXdfz9B4$8) zWNmk(V9Ri}i>}i*!>Qu5$lN~-FrWssF`Pdh%vG(>M@H)KRxav%aLg0p-2EckdZ_5- zunKbP3*~B$E>=(5u|(|;yh77jFUaMIm{4*WSQLWx5t17deGb z0WGI?5;6BBv3FB)cBan4kDxu$tK?y{Yc+$bW!K>V%Eu%nRCn*y+V1Z43;c(V-y1cJ zAbp!}m_h4nJmkXAuMvJ3EW6o^+%4)T9@`WtA$dfv=Q0$*C`7;&`3yxB6>?MpGY-?A z5JIH{zfE&pt@*0ZwIVHh69nDM-~Kv}nv$QP6pG<%UZ(gp8sL=Fd^OcdB{z7qA|d%t#dlI`=G zUW>Y^!|TJ_0o}RdpPmipBYE(|`M#<8-&efEI#0==OLeWK@|dqMA~%rg7c>@Vmtu$~ zpr%icxDVLq4B2#B{ub`Ctb!Kw*d#gNv=zWStnt6@is*#QwShiOXif#B-Nfwm*tjddz}@s=_^iWw66f0|1CgNVwgL)KoM` z_tlvq@p`X2C2aqu%nq-XUOny_Coo@FJxk2(4}s((B6>MTGM=0p>du%S7@+bLNeyjg zk4RPSijq9u!7ltlOZoheo+*rV$= zR@MFfs&S{ZHRJk$!;gmmDk&gwS)YGjTgjKQH|0oT` zvT6%Ypi`G7&q&Di`(WG2MRY3aw~{F%d>eNB=2^AEsUEfOhlsK`++xV`QIOuw#RUOq zg(IsO!`@*=#NgEapbdsUR~)5%-o;3ot09Y(KgV8Ybvf+iZ}K#R&SHd4U&ozLTWiSCFJf`=sIDWjlke zFqTJs)jqk=cu&CN>vRp-VAQkr>mn9|1Yo5P>Io%CNjtiL@t;y0Mz|R$g0j0fKfR>i z`^({4cG(|x7jVVYcK<=&`zGPq!!#vYyeA5sV5YDQLnDlaOhHyZitqO`1+udab+Xp* zh~G$gCr`o8>fzmRBwMa3c}G_lIQNqpQ9HXkq!z9nZ`pKaV#mF)g!#2_#wNJJbO!`h z)?^%hdM8ZQHB|S|Kaha^;^JbryH(d6TU!)gu5zoT*Oqt-pGmWBU2yJr2K_9v0H*!<5)lQQiRC}AOpspl@v4A59@?JAtQrpX|b_9tKahA^` z&D8XC0UuAEu!Dnx35keI*!(0uEmod(ay$^(v3}jBIX~T0D|lB6#kKcxS1_NlLB|DV znAI1|`>_MV!%`jwoVg`x>`aH@O=~H-KlO3x=<^H~s)LAh_Jwx7bC>m97hkHTJIZ5v z1T)p(kTP8NkMk;yb@PrNjv)ven(bsa*ryz*Wx4O-p>df3(>bkETOKprHpAZGy^R}> zBi@R0Zg~bQ!5+XqQbsd4yL|qzmld9^B9>aJp&>HrIb6@42)m|Wnc{dltp%M?)pC)^ zta|P|uS?Cy`WsjOmfMm9WC%lU^j_dOysN0j7IguYMg;U`4PI@J{kc+9B0 z`=6^n;F%g~o-%|DSX<9ld7&kiJB|yeZ_Xc3zvL@j&3n5|h;>DL5{Z@vC0 zag%jyjaI{3t}#V?ygOq;EwbP0E6%D*F%J7^=!r_wHu5H)TTdew0Q4aLlCgWlsmr)b zH#T>~bGN7qaA`4|M1!?bEI9MN+#Y1Lq2vpjxRWoPFVW$T%1WDliKuuclmm9xw1N|V zHDz5B&(+s{Qtcm+aDRdU@DB=t5BY*IX^=PKx~g7W+0PTSg-t3gdDK9Gz2{%P(b*Vk z*hd^m7&&JTb;~w!>IO}W`<6mm5p2xgCqCnWAz;_sa_2R>BhbV*vA0uj+^lUhg%>V= z?^>MA<*SkDR>^%$OmL+S&dl&XpLZ+I-3J%3lYE=;g`FWQwI4|ZY^QVmmaP`ypqP>* zcF(_GNqO@)UZ{54isYg=S}QKh1V#%!e!Wc!2`_eA$?`eU2<00en6^2anM;GxWtc8h z=r_;uR-;CrTQ6Yub*pq^;`z)ujKfD&t?xIRUBZs~N8&Ftee7;JR#*Z(9UWqljsyI@ zgmJ#CjZH<5&oo#{KJF%B1f`@k)%31yv0vM;uGV#;WW7{CCK=!xQd(j7x$Wr`L!Z7< z9j4W^tEPX2--|8(FE~$MC_~MA6sc_C@ki~ifkv#xphij=LNA2|I1d$wWaiaR@AvN+Fj+8|j$K^nO*w9~QK#LX8V*eLiBM;iK+YW8XkJjhse3HMftEWu$BNxz9BJ^av#x3Cy9I* zcw2k{SZKj}x?Mz_*L7vEX}y`_9oDsYsA{PyW7cJg`^h4kAn2M%nMiIrZm0_~T zE}@NWf9+i$l$N(#1#9Wz!ufh#C?q9n=`=o@!e%Z_oC;R3$_kz2>9FLu`Q3`{_TLP` zK8>h^0dX#Tbk+QdBOk6(J!Lc6E&?Ilj>d#?JPU7=&yTO*@P%EAvg`5P+Tme>!WN{Z zr76lGsskm$1ZWSfk=E==FU8l_NBjJJ-qW`PWaMW1xrWAcp4F+We&D1dnhz%sCSWB0 zJI>Lwt?kRtF#Ynx*w;~7?k$xOCV0~Aa)^E_N><{+hm0K`;|Co2elApDas(0+)VW3Kue1*Y`#;Ft&sc|;pCUVFPFL92+__NNyY2ltDn?pkXbm85(~+` z&#id&C=Gmf-3#jNlERJZ(5sjIbmdTqbcx`>*;b)cgqVlIY;Ew-rrC>%>RAAFWp-tu zYN6!irC@3Z!f+x(oQVI^T0mK{nrM`2ICJSb&2b~FsEDxA8&D}0Ov7DwfpfdQX{)oaVc}16Gc%*xPQIakI1 zM0@;ilql0ijNlR$>0l!1w%12XdgjE(p@Q((1#@UMYue!9!9K-B4p{)exH{4Ijb&)J z4NB4rVQ8;4dNj@k5z)10r@IiM{AuutbAU{gG+{2pG=(jV{0h@vql;1|v53wLH7~bf zMmPzP?Skc(pMc8Udb?25%@WRfS*1jz(8N#NG*h%&3KK#B?38}}aFjhEB;N~oYQHn$Za>o=4slj(21WeEVvgew zTVL8luy1^po?iUATPpIb2iuV{N9>n-V`q8>V=h5`KgWPQkA%8ijpRW?Um44PCHA-V zhU|oD_dsr)w;#Sr;xczwLD#lgQe1cOqZ)s6bseD#TZ%iFI@kxwPk23g{H|u_o!vJg ztK`7lJw$>u0Qb~h(qX2eRKWDCdE`J{rtkaWTs_5u4UsdM-9@YoW-t={+HjFp zP*Usps=Ep-&IZ#8zA>Z)944%Hru+&h>1CrJqsp1@B)gr2t!AWl|8u3J-BB|K&qu-X z>+rC&vchp3P%R3kaeiWH5CusOR=mYVx07k8B1lSOOSiit67)rjzi!)qRb>U8{N{6O=`+( z=7T?cC9#KG%5r34jcS6Xfz9y0HD3)FF|L5qK0w=V0)1WyInIEgZqA{#{z!LOAR2VZ=m?BFILbDq#AX_;K3TgLd3_t9A*efYwX%MAeM+P`K;Wj-9g@`l^vd_Yh)k@x(2 zWNE(~-e{&nzNV~IdKvq=Sfyi8+Z~*{U{yqbbO{{Z>UR7zKYLsVIL^h&@%^2 zx~s6Jw>RW&c*5+EWj9r2XQWraVA!a`UBOuE%t}U; z?k^J5TK&F8*`A`d-6B2QIdTk`9l^ma4cI(Az-Ib!)VTvRf=AJyT~P7s5D*>Q5R6B2W&Xi+l@K3%0k?Z`@X95tf4!PrR>D*1lzhQ zw~d&Om74N*a zO~cD3GYgX$C+Bt@z)`1c5rCRDY0H+CDUolEk0vMu&>9ae2IOxC1nJGK8$&N32VnD~ zyz-AZF&(h;iNgMB>^&EHR2)N;<~R+-)3CYa2WI?jQ*vp5Y;4~@Rv zk3ju=1!p&FL)ezTM=emp`r^+a>#|~y*#^+tTSq_Up6<^SPYWeKEi7dN_yP(jn#w{? z7=`MzWR*MraMSR0{@`8(dnYj|36XS6jh|M7pCNtUOrWU7bfV;Tyr7)Iw4+l5A2OMk-v8W2bOYNKj`J~|lb)Bf% zR|k?l+2jBc&iGtiX+q^q9iyP>c6qwh)P5c!RsUcgWWeU(l!#K;TE&=7P%2^2hi=>?P&#hLskL4LnTv~GUis8+b-^_F)pxdwp(R=7Ih*|o@3}`#R}nXD%oQP?u^@4R z;qyra_t?MI;8P&3l!`Q*o5}7<^ug(`7~vLYv*;9WlGg*e^j=F4@JvX!)ALPY5NEu5 z_u9%EUkprw{(8%O@z`=xvy#~TT@_pmVBz4iqDXs?A|5gNZTOR=0vT&m3oeiOTGa8h zjl^!Xdal))=Xr&`3H|N)eLeP!n~SuT$yoPf)6#znhEM!d+gUq85GA_)<0paTDoEs^ zifgFPO=Hv%m z0;G=ETx)3HU}^s3*&DJQ#Gr3P~%8c(^qyFgO8(Eee(Z}7i^mC zIxdZ_j+A80Nq)YDKyfVy{o3WcaJ?A`@OmS)N)c4LMSdtTFqV!39A!Sr;dstRK!ZcQ zqq)E0@6{6)tX+vbc1u53$}e`V%LzbHM@u9p607i%%E61{QDqpmV!QV99n(3~A{=W~ zRgxP}IV*epG_c!4muii+o?zPmoHEhK2_g5`%eL*uy#GLo_Pxa0T8@KX_lfjryFFBY zHDL{{Sakenp`(6n`Oq;&B2#97`%4P;qlwH+UfF$J@ISEuu}XcwI1U<8&?h(v)}P7? zt*TRyG>SFwe<4Z01hr*2UJ%>QJS$z-Z%j_Z(wOTlU`{z$LD4V`5T0UAQyQM)eE?Su zV&zr6Hm=YQN#9)_REOO78j7kQus{oLW6D9rK=`(nK z>gF~BDUoaiD822*fdf`%7_YImBkqA9M@V_*uEM45W@B5=7c`-|A`8rZY^7Gbw`J=L zWns7lgFJ{NdTfOKr}M-I@HY14R)As&zv_W2>C$efEb>re*xQb_hv{mYsSKmps|C)A zJ%6x00!Y^iw;b(;m|DO6sYY^C!#1?GFF>;1v*$4x=y~D$y-~Hs16Wm#&}+Tx9IapR zx2$Zfv!N)c3*_jCMKLb~H}CzyzZ&bC9$A8tr%BlI7>FU?alBYN+3x$sNqzht&*><| zo5A*`V~}em6Hui~f2O~kV};51An36DRmX9Z0~gF;MKY5Uo{y0L>z^5%_l^}Va(_ig zZ=21cfjbU3{3p)O&o=c76StK!mZn&6*K>PZ+|&P6nB=-Qm$&50IKqN+UC2)F>LcYICl ze;x7e+ZdirU0*x3JRX+*!ZACTDzNTC{-+eBJqJ!e-kn-T=ZoNO8sZGPY zx8CWWL2%S~y(ufBx8QCC(^;#{M)5By>z%^?t(7wjt9>l?7jCmn5RaA;D+AWQp6D@M zF2UeNZc`IJ*NR;Lef{?Le`{Q#pL90>&(@m%<$C%Z{x~eVPy8nuYy2kd?I)v` z-|f8;QsUpt_;`vgpQG}6X?)1XdF@~SbRt)*D)8mJ8#T$VR1!=KO-;o|yG{Hh@dYeO zOiF|%Bf!R1U!p3&X_399a3mkDNk-i!lBU!b*Y5T`rZS zS?i}h#wR6_3km6a9bq~)r|=zfrbsF0jxT) z$;qMmJ`XVZBgtrM#hii8y{gHzHE?lz<=tQw5sUGnS=oXPr0-|wLNw2k$IL%V)}p~k z#TjhoQ7u3I^e|R~*I6CBDL?Gh*%jorS>10px|7t=HvfhH<^najF&DQKfzE^v`P!fg zdvTDMaET4EkT@oM`lAytJs_6jvRbLS!g{sI`PbS%L7P%5atBC|XT!n^T0eJ9x*&wcSX-10YCG1FnmCU`Dw2G&3wZj-3WYMr#=-<$#%PvP!ff(;n$K_jk#X64P%ejC$o4To8oBSM zsRjcuw|#0MWIW|cFu};N2FJdES`$)?%-IaZ88QthsoswK?r1BsZIQ#Iq3u7cmrA|2 z0Y#ShZqss)ArRQgFDlhAjk?NI2fkj41<~XCagq_06iZZF11JUDzJh%s(6C zy<^x8<(*otEw&>bsE2UmMRzvws-}&i0bJu4XD$ZLhLnPO=}brdEXw~*P5cSk* z4|r`P?E{cA9E{-|MOS7F@E21io7y7>AoG@6WX%E0OoGh*t4DB}FeIAp!iPZTrID#m ztXKF?j3MxzdR0C$vvtVn5@psE+|YGaJ-=~mn5BP69_E;nTK7EI?Kp{+uUp=}{cYhL z6*W{zQ5WP}Xp|Dp8cwGNDw84wZQKBQZ^z17R9Of3#d<&bZB)g}rzsLiYUjbAY$KOnecTeR3B z{d{Pj@kDkrQ45kjGoZiEhHHaixTc84@HC|ys(F03D!0skDx}8KDF%1CD&CMJF#*Ru zOq-sBfl)XDQ7hG3v8)@=CWOv3Q_&4@q)mooKF-17YO~Oj9BgRho~FZ1O;_yy{7JyF zU$Dzh8=Nap{A=T{;es}mg1Wx&FYd8m-aU+nswp}ohIN5TyQM!V;Upgc(bQ(am6Gw^ z&+7l#0C`D`0R@r;c;Dk?VsKb_@by~=nz?D8Tn}Q}duy>hWWedzc%`s3L=jOJ>I0Fc8#QH|Z+pr7yx(#kb^K0&9e9(BP7_ zAs(Y0m;cQZ2GEDOb6afh_H=33aFpM+pAv`U3r57Lt5qg0GRvyF@iJPS>C;(0)BHk>#EvHr7@H@D9wH!Nt-{{HHsgi$I;lQM|!;b z!2(?S1~zu~fHiV4rCjx48~WcZIGka(mk0Af065`Fu*=A`77fP7R!oE|}5oH8~&I?WUNQ z6jU4&J`U3CKS*?p``&8n+)nYgyoqMg$dWpZNQ*b$o=gf-6Pze-Dk|@EJL*^V6&1Gk zHQf0kkXVk9Zi2nRk$0>Ft{kFCg%eMh1Z=R^^r|3fE*MRy8VsUk0_(X^3lN1Q9)M?` zivD&UIOOTpz;ZStqk6R04Q(^shsQN>nWY){D!ZW^a73cO4gL`P!Abak)-brq3 zfk=_ExrY)~`H>E%hMjkx_x9Pn!+zgw5@X+PEucv26?te+A&8t5IY;q}4ijFOjVu`S zedn|FsbIN?hcSTbVgn{%<GsGm&q+=9Q{dDRx>8~- zp;=_uRLRz? z#dymOt9W$a;;}l2v(Qm2;qi_Ha6cKM#_y7EmwvL$gcczMM|0;7H6O}oO3>Gv(j}GR zle2Rx*k#4sl6I2vs=8ncS2Yf6`o5TQlF3`HnDx@7I&+4gU1p=XA^5r}@F17psKQ_^ zeACjcmsg5k05^R`_)#%y?q?VwPd?#c|o%7&eRcIiF_e7N#+#Byms>kHXI}I${5`@D;Bu2YKhRMM8Z~^v*dZd@BU{bn( zFMnjC`VfYb*w)&~SvXHHCfkK}1P4=K$iB5e7t81J0UXG~Z8lwF&}HV@g6tL)wNCoa zi8a9{kK*XC%tu@ap9oyBCk)s)2F#E$5KH1379vvRUZIWnSFeex7Qn^hkSZz#YPFA- zt*KR6Y_OGX4Z?1x%5g&bgZNp&%Kh=5YR)|}^q+(?;=u#%KIV%~aW0&ICM4Kq)h%5# zXaRSihPD&?$Di_>Qm**J;K*PBZ11dahM2q$EZ}YU-ESc%JP3=JyX1#G3DjjVYnBMR zee%Gi@<@lNQDFRzWUc5V4~Xvgju?wv{H|i-dZfca6}R!=2g8L$x3IlG3OVGD(i~k_ zjebCcP(!Z8K!w~5^pqwciOW0aaI-5%I*EtzfX$SA820UW1s|a=Z$1IImPgU7$NMFb z7R+Xr`my$RmyJL{X8t9@@y;H!S{f{)CP~~ZFs!E(-zP39sO*B5H|jih`&*gmH`8jw zY)}HAd z&fPGrBi4+~F)Bw%u7<2*L=4tZ>l}99pT7UV_t*F5^FAK$$LoDOpU?N}8EkxAjsDZp zk%jJ@Qkq@jk$L;(H2(%aFL;ra7z8{Yk~w+Fl^{CLAy!xY>8b;a$B%g+9c$e+5eAsz zLhg!4mTIFX=)xwe$vstiGxj!sYnX+EnIrIP0FD8T z7&lf`KJ^TR8+}e2BbIG4jaRiiST)e}X|$<}e<7ejh9`lEni0k#%NN+)6^yFzccr^b zrK4L(>wlofF--P(G8`h`AI30+O@OX#*_kOUZ!?PhNyrw`u^cO`6P%PqJ8yk=O!s=P zXpX#z%lHTpEuq!|B2BN0jB5kh89Ate3vZ85t-;59`_m+CfBI}ucxirUl&-D#pb-=f2iUnVh2@ixc}CYcr*9-kVt-340+tf*(%i^q*Ek?&lXVGqWyXNHvy$ zWXCckquU#Vh9%W7vnGocr|sFrOMhj*=f~d1PF2!rh>mJV3A~_}MRaybii$C!Bwgn_ z+8ng%V*oBmS*z;~6)#&X3DZ_r=bY+M0R~tFpS~fTFH}mE0qA zN;goj4~VE;z;2}1VN>RUh34DmPn6So!*7?hQIy_lOYDi9kHIh2jy*I?sINnNqN$4D zZqOsN`FGJ?yU|O0%%E?x0k6L}OM^XFDa4vD=nlDgF3C?{fwY`oAAA_rtNN$@j?01U zn3zdUIpQPGp-8e`J^h~&<$E}^rpBmh7I+`KJB39YZ2Pn3-LGrx-GFZe97V9+!OiYV zF_<^4fxNq}HKn|wDVHO%7t5mdA`$dI3?Tnn4YZUvd9jYk9HNDYD-|yDx zN(~DmHTm(KNMACxrDuSjynDtjCr$jMv`aovVM!ArAvt&(S%UySME( zYwQXq*W_iXnvML>EL_zzBRaEhET+fj%ZZE+J$3tdt3jg|7$rEULWm3cegDa}FIS)X zvqQv=-lJZT+~wi%<`EfJ@%qflZUlH30VP)EM@G{G6KIobJ7$2u%K;B1tu#N zt}~LpGni8cKoP{b>M_YUvp6?(d<1d0(;+P}N|z@*M9$oQQ>XxDI(`@5w)9!@Zi{I@6)>zgH~ftgEI=)wUA_6uB3k!JNPsU4^0Ck=|>HLq$ojr>9jKbC!+v+non*}0r&-)M!;zPpY}xnX#66M#ThMB0?^cq)I6jO9I|%~ z)OG|JVW1g=)-iG$bFPy!R;%~TJV{vI>te)sU2hoV$E0@E+xxD#D^je5N~KO(rtJT+ n0u|q3$D5 Date: Mon, 27 Feb 2023 14:22:52 +0100 Subject: [PATCH 06/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 428c3c9..af17272 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Inspect4py currently works **only for Python 3 projects**. `inspect4py` added the functionality of capture [Data Flow Graphs](http://bears.ece.ucsb.edu/research-info/DP/dfg.html) for each function inspired by GraphCodeBERT: [Github](https://github.com/microsoft/CodeBERT) & [Paper](https://arxiv.org/abs/2009.08366). The illustration is given: |Source Code|List Output|Networkx Image| |:-:|:-:|:-:| -|
def max(a, b):
x = 0
if a > b:
x = a
else:
x = b
return x
|
('a', 3, 'comesFrom', [], [])
('b', 5, 'comesFrom', [], [])
('x', 8, 'computedFrom', ['0'], [10])
('0', 10, 'comesFrom', [], [])
('a', 12, 'comesFrom', ['a'], [3])
('b', 14, 'comesFrom', ['b'], [5])
('x', 16, 'computedFrom', ['a'], [18])
('a', 18, 'comesFrom', ['a'], [3])
('x', 21, 'computedFrom', ['b'], [23])
('b', 23, 'comesFrom', ['b'], [5])
('x', 25, 'comesFrom', ['x'], [16, 21])
|![image](docs/images/data_flow.png)| +|
def max(a, b):
x = 0
if a > b:
x = a
else:
x = b
return x
|
('a', 3, 'comesFrom', [], [])
('b', 5, 'comesFrom', [], [])
('x', 8, 'computedFrom', ['0'], [10])
('0', 10, 'comesFrom', [], [])
('a', 12, 'comesFrom', ['a'], [3])
('b', 14, 'comesFrom', ['b'], [5])
('x', 16, 'computedFrom', ['a'], [18])
('a', 18, 'comesFrom', ['a'], [3])
('x', 21, 'computedFrom', ['b'], [23])
('b', 23, 'comesFrom', ['b'], [5])
('x', 25, 'comesFrom', ['x'], [16, 21])
|![image](docs/images/data_flow.png)| `inspect4py` uses [ASTs](https://en.wikipedia.org/wiki/Abstract_syntax_tree), more specifically the [ast](https://docs.python.org/3/library/ast.html) module in Python, generating From 80ed5e495cb09dfd7511c5e91f3ba0e67bcf4d5c Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:29:55 +0100 Subject: [PATCH 07/15] Add files via upload --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af17272..e169faa 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,12 @@ Please cite our MSR 2022 demo paper: ### Preliminaries +Make sure you have tree-sitter installed, C complier is needed, more [info](https://github.com/tree-sitter/tree-sitter): + +``` +pip install tree-sitter +``` + Make sure you have graphviz installed: ``` @@ -76,7 +82,7 @@ We have tested `inspect4py` in Python 3.7+. **Our recommended version is Python ### Operative System -We have tested `inspect4py` in Unix and MacOs. +We have tested `inspect4py` in Unix, MacOS and Windows 11(22621.1265). ### Installation from pypi `inspect4py` is [available in pypi!](https://pypi.org/project/inspect4py/) Just install it like a regular package: @@ -111,6 +117,7 @@ pigar setuptools==54.2.0 json2html configparser +tree-sitter ``` If you want to run the evaluations, do not forget to add `pandas` to the previous set. @@ -223,6 +230,8 @@ Options: -rm, --readme extract all readme files in the target repository. -md, --metadata extract metadata of the target repository using Github API. + -df, --data_flow extract data flow graph for every function + -st, --symbol_table symbol table file location. --help Show this message and exit. ``` From 6d0c754240f6a1012efe2802abf6836ee1b4c4d5 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:30:36 +0100 Subject: [PATCH 08/15] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 82d2c73..28e5068 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ json2html configparser bigcode_astgen GitPython +tree-sitter From c26ab1b445c9051e9d0a7b9d177eaddb415494a4 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:30:55 +0100 Subject: [PATCH 09/15] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e169faa..d4a085f 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,8 @@ pigar setuptools==54.2.0 json2html configparser +bigcode_astgen +GitPython tree-sitter ``` From 7fad3e9672066071c12298213f6871bcfa02eae1 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:31:29 +0100 Subject: [PATCH 10/15] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d4a085f..a5da5a6 100644 --- a/README.md +++ b/README.md @@ -232,8 +232,8 @@ Options: -rm, --readme extract all readme files in the target repository. -md, --metadata extract metadata of the target repository using Github API. - -df, --data_flow extract data flow graph for every function - -st, --symbol_table symbol table file location. + -df, --data_flow extract data flow graph for every function, BOOL + -st, --symbol_table symbol table file location. STR --help Show this message and exit. ``` From 92b736686f75cbe876277281a97915bbb98365e2 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 16:08:56 +0100 Subject: [PATCH 11/15] Delete inspect4py/staticfg/__pycache__ directory --- .../__pycache__/__init__.cpython-39.pyc | Bin 247 -> 0 bytes .../staticfg/__pycache__/builder.cpython-39.pyc | Bin 12726 -> 0 bytes .../staticfg/__pycache__/model.cpython-39.pyc | Bin 7447 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 inspect4py/staticfg/__pycache__/__init__.cpython-39.pyc delete mode 100644 inspect4py/staticfg/__pycache__/builder.cpython-39.pyc delete mode 100644 inspect4py/staticfg/__pycache__/model.cpython-39.pyc diff --git a/inspect4py/staticfg/__pycache__/__init__.cpython-39.pyc b/inspect4py/staticfg/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index 007ff8ec7ecb1f0fd9d57cb6b1c31d108ec94e70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 247 zcmYe~<>g`kg1wX8C%XXY#~=WHo#+K%!+JT%^46=xa5dgE2JBk1R diff --git a/inspect4py/staticfg/__pycache__/builder.cpython-39.pyc b/inspect4py/staticfg/__pycache__/builder.cpython-39.pyc deleted file mode 100644 index d912845c414fcaf90cdafc77c6459c6a0473576b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12726 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 diff --git a/inspect4py/staticfg/__pycache__/model.cpython-39.pyc b/inspect4py/staticfg/__pycache__/model.cpython-39.pyc deleted file mode 100644 index e464c6992bdc54e5a56fd4977419479541d0e953..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7447 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 Date: Mon, 27 Feb 2023 16:09:08 +0100 Subject: [PATCH 12/15] Delete inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files directory --- .../MGNN-SPred-master/models/json_files/__init__.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json diff --git a/inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json b/inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json deleted file mode 100644 index 81fe488..0000000 --- a/inspect4py/output_dir/Autumn945_MGNN-SPred/MGNN-SPred-master/models/json_files/__init__.json +++ /dev/null @@ -1 +0,0 @@ -{"file": {"path": "D:\\inspect4py-main\\test\\Autumn945_MGNN-SPred\\MGNN-SPred-master\\models\\__init__.py", "fileNameBase": "__init__", "extension": "py"}, "dependencies": [{"from_module": "base", "import": "Base", "type": "internal", "type_element": "class"}, {"from_module": "base", "import": "GNN", "type": "internal", "type_element": "class"}], "is_test": false} \ No newline at end of file From 5201992ae9ef694110cca439c856fe3c82d04442 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 16:09:22 +0100 Subject: [PATCH 13/15] Delete directory_info.json --- inspect4py/output_dir/directory_info.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 inspect4py/output_dir/directory_info.json diff --git a/inspect4py/output_dir/directory_info.json b/inspect4py/output_dir/directory_info.json deleted file mode 100644 index a934e9c..0000000 --- a/inspect4py/output_dir/directory_info.json +++ /dev/null @@ -1 +0,0 @@ -{"output_dir\\Autumn945_MGNN-SPred\\MGNN-SPred-master\\models": [{"file": {"path": "D:\\inspect4py-main\\test\\Autumn945_MGNN-SPred\\MGNN-SPred-master\\models\\__init__.py", "fileNameBase": "__init__", "extension": "py"}, "dependencies": [{"from_module": "base", "import": "Base", "type": "internal", "type_element": "class"}, {"from_module": "base", "import": "GNN", "type": "internal", "type_element": "class"}], "is_test": false}]} \ No newline at end of file From 34161acca9d570ef46fd989e6aca3ab926e34a68 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 16:11:00 +0100 Subject: [PATCH 14/15] Create output_dir --- inspect4py/output_dir/output_dir | 1 + 1 file changed, 1 insertion(+) create mode 100644 inspect4py/output_dir/output_dir diff --git a/inspect4py/output_dir/output_dir b/inspect4py/output_dir/output_dir new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/inspect4py/output_dir/output_dir @@ -0,0 +1 @@ +12 From aab6774fe6cfd1f163f71de7117b5b1b04b576e8 Mon Sep 17 00:00:00 2001 From: Clark Wang <107419732+OEG-Clark@users.noreply.github.com> Date: Mon, 27 Feb 2023 16:11:12 +0100 Subject: [PATCH 15/15] Delete output_dir --- inspect4py/output_dir/output_dir | 1 - 1 file changed, 1 deletion(-) delete mode 100644 inspect4py/output_dir/output_dir diff --git a/inspect4py/output_dir/output_dir b/inspect4py/output_dir/output_dir deleted file mode 100644 index 48082f7..0000000 --- a/inspect4py/output_dir/output_dir +++ /dev/null @@ -1 +0,0 @@ -12