Skip to content

Commit e3ab1b0

Browse files
Merge pull request #373 from SoftwareUnderstanding/dev
Dev
2 parents 44911dd + 8efb44c commit e3ab1b0

5 files changed

Lines changed: 94 additions & 35 deletions

File tree

inspect4py/cli.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(self, path, out_control_flow_path, out_json_path, flag_png, control
4747
self.tree = self.parser_file()
4848
if self.tree != "AST_ERROR":
4949
self.nodes = self.walk()
50+
self.class_init=self.find_classDef()
5051
self.fileInfo = self.inspect_file()
5152
self.depInfo = self.inspect_dependencies()
5253
self.funcsInfo, self.classesInfo = self.inspect_classes_funcs()
@@ -61,6 +62,13 @@ def __init__(self, path, out_control_flow_path, out_json_path, flag_png, control
6162
else:
6263
self.fileJson = {}
6364

65+
def find_classDef(self):
66+
classDef_nodes = [node for node in self.nodes if isinstance(node, ast.ClassDef)]
67+
class_init=[]
68+
for node in classDef_nodes:
69+
class_init.append(node.name)
70+
return class_init
71+
6472
def parser_file(self):
6573
""" parse_file method parsers a file as an AST tree
6674
:param self self: represent the instance of the class
@@ -297,10 +305,19 @@ def inspect_body(self):
297305
self.funcsInfo,
298306
self.classesInfo, body_store_vars)
299307

300-
308+
### finding the index of init class ###
309+
index_remove=find_index_init(self.depInfo, body_calls, self.class_init)
310+
#######
301311
body_info["body"]["calls"] = body_calls
302312
body_info["body"]["store_vars_calls"] = body_store_vars
303313
body_info = self._fill_call_name(body_info, self.classesInfo, type=1, additional_info=self.funcsInfo)
314+
315+
#### removing Class init from the calls #####
316+
body_info["body"]["calls"]= update_list_calls(body_info["body"], index_remove)
317+
###############
318+
319+
320+
304321
if self.abstract_syntax_tree:
305322
body_info["body"]["ast"] = [ast_to_json(node) for node in call_nodes]
306323
if self.source_code:
@@ -328,20 +345,29 @@ def inspect_dependencies(self):
328345
continue
329346
for n in node.names:
330347
if "*" in n.name:
331-
functions_classes, type = list_functions_classes_from_module(module, self.path)
332-
for f in functions_classes:
348+
functions, classes, type = list_functions_classes_from_module(module, self.path)
349+
for f in functions:
333350
current_dep = {"from_module": module,
334351
"import": f,
335352
"alias": n.asname,
336-
"type": type}
353+
"type": type,
354+
"type_element": "function"}
355+
dep_info.append(current_dep)
356+
for f in classes:
357+
current_dep = {"from_module": module,
358+
"import": f,
359+
"alias": n.asname,
360+
"type": type,
361+
"type_element": "class"}
337362
dep_info.append(current_dep)
338363
else:
339364
import_name = n.name.split('.')[0]
340365
type = type_module(module, import_name, self.path)
341366
current_dep = {"from_module": module,
342367
"import": import_name,
343368
"alias": n.asname,
344-
"type": type}
369+
"type": type,
370+
"type_element": "module"}
345371
dep_info.append(current_dep)
346372

347373
return dep_info
@@ -522,6 +548,9 @@ def _f_definitions(self, functions_definitions):
522548
# func_name_id = list(dict.fromkeys(func_name_id))
523549

524550
func_name_id = [f_x for f_x in func_name_id if f_x is not None]
551+
552+
### finding the index of init class ###
553+
index_remove=find_index_init(self.depInfo, func_name_id, self.class_init)
525554
funcs_info[f.name]["calls"] = func_name_id
526555

527556
funcs_assigns = [node for node in ast.walk(f) if isinstance(node, ast.Assign)]
@@ -544,6 +573,7 @@ def _f_definitions(self, functions_definitions):
544573
for nested in nested_definitions:
545574
if f.name == nested.name:
546575
nested_definitions.remove(nested)
576+
funcs_info[f.name]["calls"]= update_list_calls(funcs_info[f.name], index_remove)
547577

548578
funcs_info[f.name]["functions"] = self._f_definitions(nested_definitions)
549579

inspect4py/utils.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import requests
66
import subprocess
77
from pathlib import Path
8+
import collections
89

910
from json2html import *
1011
from bigcode_astgen.ast_generator import ASTGenerator
@@ -301,7 +302,8 @@ def parse_module(filename):
301302

302303

303304
def list_functions_classes_from_module(m, path):
304-
functions_classes = []
305+
classes = []
306+
functions = []
305307

306308
try:
307309
# to open a module inside a directory
@@ -311,18 +313,18 @@ def list_functions_classes_from_module(m, path):
311313
file_module = abs_repo_path + "/" + m + ".py"
312314
tree = parse_module(file_module)
313315
for func in top_level_functions(tree.body):
314-
functions_classes.append(func.name)
316+
functions.append(func.name)
315317

316318
for cl in top_level_classes(tree.body):
317-
functions_classes.append(cl.name)
319+
classes.append(cl.name)
318320

319321
type = "internal"
320322
except:
321323

322324
#module = __import__(m)
323325
#functions = dir(module)
324326
type = "external"
325-
return functions_classes, type
327+
return functions, classes, type
326328

327329

328330
def type_module(m, i, path):
@@ -741,3 +743,30 @@ def get_github_metadata(input_path: str) -> dict:
741743
print(f"Error when accessing {api_url}: {e}")
742744

743745
return github_metadata
746+
747+
748+
def find_index_init(depInfo, calls, class_init):
749+
index_remove=[]
750+
for dep in depInfo:
751+
if dep["type_element"] == "class":
752+
if dep["import"] in calls:
753+
index_remove.append(calls.index(dep["import"]))
754+
elif dep["alias"] in calls:
755+
index_remove.append(calls.index(dep["alias"]))
756+
for i in class_init:
757+
if i in calls:
758+
index_remove.append(calls.index(i))
759+
return index_remove
760+
761+
def update_list_calls(info, index_remove):
762+
updated_calls=[]
763+
for i in range(0, len(info["calls"])):
764+
if i in index_remove:
765+
continue
766+
updated_calls.append(info["calls"][i])
767+
### These lines are for removing duplicate calls
768+
res = []
769+
for i in updated_calls :
770+
if i not in res:
771+
res.append(i)
772+
return res
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
def foo(arg1, arg2):
22
print("Hello %s", arg1)
33
return arg2
4+

test/test_files/test_inheritance/test_import.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ def __init__(self):
1515

1616
def funct_D():
1717
print("Function D")
18+
a=MyClass_A()
19+
MyClass_E()
1820
funct_A()
1921

20-
a1=MyClass_A()
22+
MyClass_A()
2123
b1=MyClass_B()
2224
d= MyClass_D()
2325
funct_A()

test/test_inspect4py.py

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_call_list_super(self):
2424

2525
def test_call_list_super_test_5(self):
2626
dictionary = {'functions': {}, 'body': {
27-
'local': ['super_test_5.Cube', 'super_test_5.Cube.surface_area', 'super_test_5.VolumeMixin.volume']},
27+
'local': ['super_test_5.Cube.surface_area', 'super_test_5.VolumeMixin.volume']},
2828
'Rectangle': {}, 'Square': {'__init__': {'local': ['super_test_5.Rectangle.__init__']}},
2929
'VolumeMixin': {'volume': {'local': ['super_test_5.VolumeMixin.area']}},
3030
'Cube': {'__init__': {'local': ['super_test_5.Square.__init__']},
@@ -43,9 +43,9 @@ def test_call_list_super_test_5(self):
4343
assert (call_list_data['body'] == dictionary['body'])
4444

4545
def test_call_list_nested(self):
46-
dictionary = {'functions': {'test': {'local': ['nested_call.MyClass', 'nested_call.MyClass.func']}},
46+
dictionary = {'functions': {'test': {'local': ['nested_call.MyClass.func']}},
4747
'body': {'local': ['nested_call.test']}, 'classes': {'MyClass': {
48-
'func': {'local': ['nested_call.MyClass.func.nested'], 'nested': {'nested': {'local': ['print']}}}}}}
48+
'func': {'local': ['nested_call.MyClass.func.nested'], 'nested': {'nested': {'local': ['print']}}}}}}
4949
input_path = "./test_files/test_inheritance/nested_call.py"
5050
output_dir = "./output_dir"
5151
control_flow = False
@@ -59,13 +59,13 @@ def test_call_list_nested(self):
5959
assert (call_list_data == dictionary)
6060

6161
def test_call_list_super_nested(self):
62-
dictionary = {'functions': {
63-
'func_d': {'local': ['super_nested_call.func_d.func_e'], 'nested': {'func_e': {'local': ['print']}}},
64-
'main': {'local': ['super_nested_call.MyClass', 'super_nested_call.MyClass.func_a',
65-
'super_nested_call.func_d']}}, 'body': {'local': ['super_nested_call.main']}, 'classes': {'MyClass': {
66-
'func_a': {'local': ['print', 'super_nested_call.MyClass.func_a.func_b'], 'nested': {
67-
'func_b': {'local': ['print', 'super_nested_call.MyClass.func_a.func_b.func_c'],
68-
'nested': {'func_c': {'local': ['print']}}}}}}}}
62+
dictionary = {'functions': {'func_d': {'local': ['super_nested_call.func_d.func_e'],
63+
'nested': {'func_e': {'local': ['print']}}},
64+
'main': {'local': ['super_nested_call.MyClass.func_a', 'super_nested_call.func_d']}},
65+
'body': {'local': ['super_nested_call.main']},
66+
'classes': {'MyClass': {'func_a': {'local': ['print', 'super_nested_call.MyClass.func_a.func_b'],
67+
'nested': {'func_b': {'local': ['print', 'super_nested_call.MyClass.func_a.func_b.func_c'],
68+
'nested': {'func_c': {'local': ['print']}}}}}}}}
6969
input_path = "./test_files/test_inheritance/super_nested_call.py"
7070
output_dir = "./output_dir"
7171
control_flow = False
@@ -80,11 +80,9 @@ def test_call_list_super_nested(self):
8080

8181
def test_call_list_import(self):
8282
dictionary = {'functions': {'funct_D': {'local': ['print', 'test_functions.funct_A']}}, 'body': {
83-
'local': ['test_classes.MyClass_A', 'test_classes.MyClass_B', 'test_import.MyClass_D',
84-
'test_functions.funct_A', 'test_import.funct_D', 'test_classes.MyClass_C',
85-
'test_import.funct_D']}, 'classes': {'MyClass_D': {
86-
'__init__': {'local': ['print', 'test_functions.funct_C', 'test_import.funct_D', 'test_import.MyClass_E']}},
87-
'MyClass_E': {'__init__': {'local': ['print', 'test_classes.MyClass_B']}}}}
83+
'local': ['test_functions.funct_A', 'test_import.funct_D']},
84+
'classes': {'MyClass_D': {'__init__': {'local': ['print', 'test_functions.funct_C', 'test_import.funct_D']}},
85+
'MyClass_E': {'__init__': {'local': ['print']}}}}
8886
input_path = "./test_files/test_inheritance/test_import.py"
8987
output_dir = "./output_dir"
9088
control_flow = False
@@ -99,8 +97,7 @@ def test_call_list_import(self):
9997

10098
def test_call_list_external_module(self):
10199
dictionary = {'body': {
102-
'local': ['random.seed', 'print', 'random.random', 'random.random', 'random.random', 'random.seed', 'print',
103-
'random.random', 'random.random', 'random.random']}}
100+
'local': ['random.seed', 'print', 'random.random']}}
104101
input_path = "./test_files/test_random.py"
105102
output_dir = "./output_dir"
106103
control_flow = False
@@ -115,7 +112,7 @@ def test_call_list_external_module(self):
115112

116113
def test_call_list_argument_call(self):
117114
dictionary = {'functions': {'func_1': {'local': ['print', 'argument_call.func_2']}},
118-
'body': {'local': ['print', 'argument_call.func_1', 'argument_call.MyClass.func_a', 'argument_call.MyClass']},
115+
'body': {'local': ['print', 'argument_call.func_1', 'argument_call.MyClass.func_a']},
119116
'classes': {'MyClass': {'func_a': {'local': ['print', 'argument_call.MyClass.func_b']}}}}
120117
input_path = "./test_files/test_dynamic/argument_call.py"
121118
output_dir = "./output_dir"
@@ -209,7 +206,7 @@ def test_call_list_dynamic_import_alias(self):
209206

210207
def test_call_list_dynamic_import_method(self):
211208
dictionary = {'functions': {'func_2': {'local': ['test_dynamic_method.MyClass.func_1']}, 'main': {
212-
'local': ['test_dynamic_method.func_2', 'print', 'test_dynamic_method.MyClass']}}, 'body': {'local': ['test_dynamic_method.main']},
209+
'local': ['test_dynamic_method.func_2', 'print']}}, 'body': {'local': ['test_dynamic_method.main']},
213210
'classes': {'MyClass': {}}}
214211
input_path = "./test_files/test_dynamic/test_dynamic_method.py"
215212
output_dir = "./output_dir"
@@ -224,9 +221,11 @@ def test_call_list_dynamic_import_method(self):
224221
assert (call_list_data == dictionary)
225222

226223
def test_call_list_dynamic_import_method_variable(self):
227-
dictionary = {'functions': {'func_2': {'local': ['test_dynamic_method_variable.MyClass.func_1']}, 'main': {
228-
'local': ['test_dynamic_method_variable.MyClass', 'test_dynamic_method_variable.func_2', 'print']}},
229-
'body': {'local': ['test_dynamic_method_variable.main']}, 'classes': {'MyClass': {}}}
224+
dictionary = {'functions': {'func_2': {'local': ['test_dynamic_method_variable.MyClass.func_1']},
225+
'main': {'local': ['test_dynamic_method_variable.func_2', 'print']}},
226+
'body': {'local': ['test_dynamic_method_variable.main']}, 'classes': {'MyClass': {}}}
227+
228+
230229
input_path = "./test_files/test_dynamic/test_dynamic_method_variable.py"
231230
output_dir = "./output_dir"
232231
control_flow = False
@@ -241,7 +240,7 @@ def test_call_list_dynamic_import_method_variable(self):
241240

242241
def test_call_list_dynamic_class_import(self):
243242
dictionary = {'functions': {}, 'body': {
244-
'local': ['test_dynamic_class_import.MyClass', 'test_dynamic_class_import.MyClass.func_3']},
243+
'local': ['test_dynamic_class_import.MyClass.func_3']},
245244
'classes': {'MyClass': {'func_3': {'local': ['test_dynamic_func.func_1']}}}}
246245
input_path = "./test_files/test_dynamic/test_dynamic_class_import.py"
247246
output_dir = "./output_dir"
@@ -627,7 +626,6 @@ def test_metadata(self):
627626
print(f"Error sending requests to Github API: {e}")
628627
raise e
629628
actual_metadata = dir_info["metadata"]
630-
print("ROSA ACTUAL_METADATA:%s, EXPECTED_METADATA %s" %(dir_info, expected_metadata))
631629
assert expected_metadata == actual_metadata
632630

633631

@@ -706,7 +704,6 @@ def invoke_inspector(input_path, fig, output_dir, ignore_dir_pattern, ignore_fil
706704
if readme:
707705
dir_info["readme_files"] = extract_readme(input_path)
708706
if metadata:
709-
print("ENTRO!!")
710707
dir_info["metadata"] = get_github_metadata(input_path)
711708
return dir_info
712709

0 commit comments

Comments
 (0)