1+ # Author: Bishal Sarang
2+
13import sys
24from functools import wraps
35from collections import OrderedDict
@@ -14,96 +16,104 @@ def __init__(self, ignore_args, show_argument_name=True, show_return_value=True)
1416 self .ignore_args = ignore_args
1517
1618 @classmethod
17- def write_image (self , filename = "out.png" ):
18- self .graph .write_png (f"{ filename } " )
19+ def write_image (cls , filename = "out.png" ):
20+ try :
21+ cls .graph .write_png (f"{ filename } " )
22+ print (f"File { filename } successfully written" )
23+ except Exception :
24+ print (f"Writing { filename } failed" )
25+
26+ def extract_signature_label_arg_string (self , * args , ** kwargs ):
27+ """
28+ Returns function signature arguments as string and function label arguments as string.
29+ label_argument string contains only the arguments that are not in ignore_args
30+ signature_argument_string contains all the arguments available for the function
31+ """
32+ # If show_argument flag is True(default)
33+ # Then argument_string is:
34+ # a=1, b=31, c=0
35+ signature_argument_string = ', ' .join ([repr (a ) for a in args ] +
36+ [f"{ key } ={ repr (value )} " for key , value in kwargs .items ()])
37+
38+ label_argument_string = ', ' .join ([repr (a ) for a in args ] +
39+ [f"{ key } ={ repr (value )} "
40+ for key , value in kwargs .items ()
41+ if key not in self .ignore_args ])
42+
43+ # If show_argument flag is False
44+ # Then argument_string is:
45+ # 1, 31, 0
46+ if not self .show_argument_name :
47+ signature_argument_string = ', ' .join ([repr (value ) for value in args ] +
48+ [f"{ repr (value )} " for key , value in kwargs .items ()])
49+
50+ label_argument_string = ', ' .join ([repr (a ) for a in args ] +
51+ [f"{ repr (value )} "
52+ for key , value in kwargs .items ()
53+ if key not in self .ignore_args ])
54+
55+ return signature_argument_string , label_argument_string
1956
2057 def __call__ (self , fn ):
2158 @wraps (fn )
2259 def wrapper (* args , ** kwargs ):
2360 # Order all the keyword arguments
2461 kwargs = OrderedDict (sorted (kwargs .items ()))
2562
26- # If show_argument flag is True(default)
27- # Then argument_string is:
28- # a=1, b=31, c=0
29- argument_string = ', ' .join (
30- [repr (a ) for a in args ] +
31- [f"{ key } ={ repr (value )} " for key , value in kwargs .items ()])
32-
33- current_function_label_argument_string = ', ' .join (
34- [repr (a ) for a in args ] +
35- [f"{ key } ={ repr (value )} " for key , value in kwargs .items () if key not in self .ignore_args ])
36-
37- # If show_argument flag is False
38- # Then argument_string is:
39- # 1, 31, 0
40- if self .show_argument_name == False :
41- argument_string = ', ' .join (
42- [repr (value ) for value in args ] +
43- [f"{ repr (value )} " for key , value in kwargs .items ()])
44-
45- current_function_label_argument_string = ', ' .join (
46- [repr (a ) for a in args ] +
47- [f"{ repr (value )} " for key , value in kwargs .items () if key not in self .ignore_args ])
63+ """Details about current Function"""
64+ # Get signature and label arguments strings for current function
65+ current_function_argument_string , current_function_label_argument_string = self .extract_signature_label_arg_string (* args , ** kwargs )
4866
4967 # Details about current function
5068 current_function_name = fn .__name__
51- current_function_argument_string = argument_string
69+
5270 # Current function signature looks as follows:
5371 # foo(1, 31, 0) or foo(a=1, b=31, c=0)
54- current_function_signature = f"{ current_function_name } ({ current_function_argument_string } )"
72+ current_function_signature = f"{ current_function_name } (" \
73+ f"{ current_function_argument_string } )"
5574 current_function_label = f"{ current_function_name } ({ current_function_label_argument_string } )"
56-
57- # Caller Function
58- caller_function_name = sys ._getframe (1 ).f_code .co_name
59- # Extract the names of arguments only
60- caller_function_argument_names = sys ._getframe (1 ).f_code .co_varnames [:fn .__code__ .co_argcount ]
61- caller_function_locals = sys ._getframe (1 ).f_locals
62-
75+ """"""
76+
77+ """Details about caller function"""
78+ caller_function_frame = sys ._getframe (1 )
79+ # All the argument names in caller/parent function
80+ caller_function_argument_names = caller_function_frame .f_code .co_varnames [
81+ :fn .__code__ .co_argcount ]
82+ caller_function_locals = caller_function_frame .f_locals
6383 # Sort all the locals of caller function
6484 caller_function_locals = OrderedDict (sorted (caller_function_locals .items ()))
85+ # Extract only those locals that are in arguments
86+ caller_function_kwargs = {key : value for key , value in caller_function_locals .items () if key in caller_function_argument_names }
6587
88+ caller_function_argument_string , caller_function_label_argument_string = self .extract_signature_label_arg_string (** caller_function_kwargs )
6689
67- # Extract only those locals which are in function signature
68- caller_function_argument_string = ', ' .join (
69- [f"{ key } ={ value } " for key , value in caller_function_locals .items () if (key in caller_function_argument_names )])
70- caller_function_label_argument_string = ', ' .join (
71- [f"{ key } ={ value } " for key , value in caller_function_locals .items () if
72- (key in caller_function_argument_names and key not in self .ignore_args )])
73-
74- if self .show_argument_name == False :
75- caller_function_argument_string = ', ' .join (
76- [f"{ value } " for key , value in caller_function_locals .items () if
77- (key in caller_function_argument_names )])
78- caller_function_label_argument_string = ', ' .join (
79- [f"{ value } " for key , value in caller_function_locals .items () if
80- (key in caller_function_argument_names and key not in self .ignore_args )])
90+ # Caller Function
91+ caller_function_name = caller_function_frame .f_code .co_name
8192
93+ # Extract the names of arguments only
8294 caller_func_signature = f"{ caller_function_name } ({ caller_function_argument_string } )"
8395 caller_func_label = f"{ caller_function_name } ({ caller_function_label_argument_string } )"
96+ """"""
8497
8598 if caller_function_name == '<module>' :
8699 print (f"Drawing for { current_function_signature } " )
87100
88101 result = fn (* args , ** kwargs )
89102
90- # #Child Node
91- child_label = current_function_label
103+ # If show_return_value flag is set, display the result
92104 if self .show_return_value :
93- child_label += f" => { result } "
94- child_name = current_function_signature
95- v = pydot .Node (name = child_name , label = child_label )
96- self .graph .add_node (v )
105+ current_function_label += f" => { result } "
97106
98- # Parent Node
99- u = None
107+ child_node = pydot . Node ( name = current_function_signature , label = current_function_label )
108+ self . graph . add_node ( child_node )
100109
110+ # If the function is called by another function
101111 if caller_function_name != '<module>' :
102112 print (f"Called { current_function_label } by { caller_func_label } " )
103- u = pydot .Node (name = caller_func_signature , label = caller_func_label )
104- self .graph .add_node (u )
105- edge = pydot .Edge (u , v )
106- self .graph .add_edge (edge )
107113
114+ parent_node = pydot .Node (name = caller_func_signature , label = caller_func_label )
115+ self .graph .add_node (parent_node )
116+ edge = pydot .Edge (parent_node , child_node )
117+ self .graph .add_edge (edge )
108118 return result
109119 return wrapper
0 commit comments