1313dot_str_body = ""
1414dot_str_end = "}"
1515
16+
1617class Visualiser (object ):
1718 # Total number of nodes
1819 node_count = 0
@@ -22,8 +23,9 @@ class Visualiser(object):
2223 edges = []
2324 nodes = []
2425
25- def __init__ (self , ignore_args = None , show_argument_name = True , show_return_value = True , node_properties_kwargs = {}):
26- #If enabled shows keyword arguments ordered by keys
26+ def __init__ (self , ignore_args = None , show_argument_name = True ,
27+ show_return_value = True , node_properties_kwargs = {}):
28+ # If enabled shows keyword arguments ordered by keys
2729 self .show_argument_name = show_argument_name
2830 # If enables shows the return value at every nodes
2931 self .show_return_value = show_return_value
@@ -36,8 +38,6 @@ def __init__(self, ignore_args=None, show_argument_name=True, show_return_value=
3638 else :
3739 self .ignore_args = ['node_num' ] + ignore_args
3840
39-
40-
4141 @classmethod
4242 def write_image (cls , filename = "out.png" ):
4343 try :
@@ -78,8 +78,15 @@ def make_frames(cls):
7878 @classmethod
7979 def write_gif (cls , name = "out.gif" , delay = 3 ):
8080 images = []
81- imgs = glob .glob ("frames/*.png" )
82- for filename in sorted (imgs , key = lambda fn : int (fn .split ("_" )[1 ].split ("." )[0 ])):
81+
82+ # sort frames images in ascending order to number in image filename
83+ # image filename: frames/temp_1.png
84+ sorted_images = sorted (
85+ glob .glob ("frames/*.png" ),
86+ key = lambda fn : int (fn .split ("_" )[1 ].split ("." )[0 ])
87+ )
88+
89+ for filename in sorted_images :
8390 images .append (imageio .imread (filename ))
8491 print ("Writing gif..." )
8592 imageio .mimsave (name , images , duration = delay )
@@ -107,114 +114,138 @@ def make_animation(cls, filename="out.gif", delay=3):
107114 except :
108115 print ("Error saving gif." )
109116
110-
111- def extract_signature_label_arg_string (self , * args , ** kwargs ):
117+ def extract_arg_strings (self , * args , ** kwargs ):
112118 """
113- Returns function signature arguments as string and function label arguments as string.
114- label_argument string contains only the arguments that are not in ignore_args
115- signature_argument_string contains all the arguments available for the function
119+ Returns function signature arguments function label arguments as
120+ string.
121+ label_args_string contains only the arguments that are not in
122+ ignore_args.
123+ signature_args_string contains all the arguments available for the
124+ function.
116125 """
117- # If show_argument flag is True(default)
118- # Then argument_string is:
119- # a=1, b=31, c=0
120- signature_argument_string = ', ' .join ([repr (a ) for a in args ] +
121- [f"{ key } ={ repr (value )} " for key , value in kwargs .items ()])
122-
123- label_argument_string = ', ' .join ([repr (a ) for a in args ] +
124- [f"{ key } ={ repr (value )} "
125- for key , value in kwargs .items ()
126- if key not in self .ignore_args ])
127-
128- # If show_argument flag is False
129- # Then argument_string is:
130- # 1, 31, 0
131- if not self .show_argument_name :
132- signature_argument_string = ', ' .join ([repr (value ) for value in args ] +
133- [f"{ repr (value )} " for key , value in kwargs .items ()])
134-
135- label_argument_string = ', ' .join ([repr (a ) for a in args ] +
136- [f"{ repr (value )} "
137- for key , value in kwargs .items ()
138- if key not in self .ignore_args ])
139-
140- return signature_argument_string , label_argument_string
126+
127+ def get_kwargs_strings (ignore_args = []):
128+ """Returns list of kwargs in string format from given kwargs items
129+
130+ Args:
131+ ignore_args (list, optional) : list of ignored arguments.
132+ Default to [].
133+
134+ Returns:
135+ strings_list: list of kwargs in string format
136+ """
137+
138+ strings_list = []
139+
140+ for key , value in kwargs .items ():
141+ if key not in ignore_args :
142+ if not self .show_argument_name :
143+ strings_list .append (f"{ repr (value )} " )
144+ else :
145+ strings_list .append (f"{ key } ={ repr (value )} " )
146+
147+ return strings_list
148+
149+ args_string = [repr (a ) for a in args ]
150+ signature_kwargs_string = get_kwargs_strings ()
151+ label_kwargs_string = get_kwargs_strings (ignore_args = self .ignore_args )
152+
153+ signature_args_string = ', ' .join (
154+ args_string + signature_kwargs_string )
155+ label_args_string = ', ' .join (args_string + label_kwargs_string )
156+
157+ return signature_args_string , label_args_string
141158
142159 def __call__ (self , fn ):
143- @wraps (fn )
160+ @ wraps (fn )
144161 def wrapper (* args , ** kwargs ):
145162 global dot_str_body
146163 # Increment total number of nodes when a call is made
147164 self .node_count += 1
148165
149- # Update kwargs by adding dummy keyword node_num which helps to uniquely identify each node
166+ # Update kwargs by adding dummy keyword node_num which helps to
167+ # uniquely identify each node
150168 kwargs .update ({'node_num' : self .node_count })
151169 # Order all the keyword arguments
152170 kwargs = OrderedDict (sorted (kwargs .items ()))
153171
154-
155172 """Details about current Function"""
156173 # Get signature and label arguments strings for current function
157- current_function_argument_string , current_function_label_argument_string = self .extract_signature_label_arg_string (* args , ** kwargs )
174+ (signature_args_string ,
175+ label_args_string ) = self .extract_arg_strings (
176+ * args , ** kwargs )
158177
159178 # Details about current function
160- current_function_name = fn .__name__
179+ function_name = fn .__name__
161180
162181 # Current function signature looks as follows:
163182 # foo(1, 31, 0) or foo(a=1, b=31, c=0)
164- current_function_signature = f"{ current_function_name } (" \
165- f"{ current_function_argument_string } )"
166- current_function_label = f"{ current_function_name } ({ current_function_label_argument_string } )"
183+ function_signature = f"{ function_name } ({ signature_args_string } )"
184+ function_label = f"{ function_name } ({ label_args_string } )"
167185 """"""
168186
169187 """Details about caller function"""
170- caller_function_frame = sys ._getframe (1 )
188+ caller_func_frame = sys ._getframe (1 )
171189 # All the argument names in caller/parent function
172- caller_function_argument_names = caller_function_frame .f_code .co_varnames [
173- : fn .__code__ .co_argcount ]
174- caller_function_locals = caller_function_frame .f_locals
190+ caller_func_arg_names = caller_func_frame .f_code .co_varnames [
191+ : fn .__code__ .co_argcount ]
192+ caller_func_locals = caller_func_frame .f_locals
175193 # Sort all the locals of caller function
176- caller_function_locals = OrderedDict (sorted (caller_function_locals .items ()))
194+ caller_func_locals = OrderedDict (
195+ sorted (caller_func_locals .items ()))
196+
197+ caller_func_kwargs = dict ()
198+
177199 # Extract only those locals that are in arguments
178- caller_function_kwargs = {key : value for key , value in caller_function_locals .items () if key in caller_function_argument_names }
200+ for key , value in caller_func_locals .items ():
201+ if key in caller_func_arg_names :
202+ caller_func_kwargs [key ] = value
179203
180204 # If the nodes has parent node get node_num from parent node
181205 if self .stack :
182- caller_function_kwargs .update ({'node_num' : self .stack [- 1 ]})
183- caller_function_kwargs = OrderedDict (sorted (caller_function_kwargs .items ()))
206+ caller_func_kwargs .update ({'node_num' : self .stack [- 1 ]})
207+
208+ caller_func_kwargs = OrderedDict (
209+ sorted (caller_func_kwargs .items ()))
184210
185- caller_function_argument_string , caller_function_label_argument_string = self .extract_signature_label_arg_string (** caller_function_kwargs )
211+ (caller_func_args_string ,
212+ caller_func_label_args_string ) = self .extract_arg_strings (
213+ ** caller_func_kwargs )
186214
187215 # Caller Function
188- caller_function_name = caller_function_frame .f_code .co_name
216+ caller_func_name = caller_func_frame .f_code .co_name
189217
190218 # Extract the names of arguments only
191- caller_func_signature = f"{ caller_function_name } ({ caller_function_argument_string } )"
192- caller_func_label = f"{ caller_function_name } ({ caller_function_label_argument_string } )"
219+ caller_func_signature = "{}({})" .format (
220+ caller_func_name , caller_func_args_string )
221+ caller_func_label = "{}({})" .format (
222+ caller_func_name , caller_func_label_args_string )
193223 """"""
194224
195- if caller_function_name == '<module>' :
196- print (f"Drawing for { current_function_signature } " )
225+ if caller_func_name == '<module>' :
226+ print (f"Drawing for { function_signature } " )
197227
198228 # Push node_count to stack
199229 self .stack .append (self .node_count )
200230 # Before actual function call delete keyword 'node_num' from kwargs
201231 del kwargs ['node_num' ]
202232
203- self .edges .append (f'"{ caller_func_signature } " -> "{ current_function_signature } "' )
233+ self .edges .append (
234+ f'"{ caller_func_signature } " -> "{ function_signature } "' )
204235
205236 # Construct node string to be rendered in graphviz
206- node_string = f'"{ current_function_signature } " [label="{ current_function_label } "'
237+ node_string = f'"{ function_signature } " [label="{ function_label } "'
207238
208239 if self .node_properties_kwargs :
209- node_string += ", " + ", " .join ([f'{ key } ="{ value } "' for key , value in self .node_properties_kwargs .items ()])
240+ node_string += ", " + \
241+ ", " .join ([f'{ key } ="{ value } "' for key ,
242+ value in self .node_properties_kwargs .items ()])
210243
211- # current_function_label = current_function_label + ", ".join([f"{key}={value}" for key, value in self.node_properties_kwargs.items()])
212244 self .nodes .append (node_string )
213245
214246 # Return after function call
215247 result = fn (* args , ** kwargs )
216248
217-
218249 # Pop from tha stack after returning
219250 self .stack .pop ()
220251
@@ -223,20 +254,24 @@ def wrapper(*args, **kwargs):
223254 # If shape is set to record
224255 # Then separate function label and return value by a row
225256 if "record" in self .node_properties_kwargs .values ():
226- current_function_label = "{" + current_function_label + f"|{ result } }}"
257+ function_label = "{" + \
258+ function_label + f"|{ result } }}"
227259 else :
228- current_function_label += f"\n => { result } "
260+ function_label += f"\n => { result } "
229261
230- child_node = pydot .Node (name = current_function_signature , label = current_function_label , ** self .node_properties_kwargs )
262+ child_node = pydot .Node (name = function_signature ,
263+ label = function_label ,
264+ ** self .node_properties_kwargs )
231265 self .graph .add_node (child_node )
232266
233267 # If the function is called by another function
234- if caller_function_name not in ['<module>' , 'main' ]:
235- parent_node = pydot .Node (name = caller_func_signature , label = caller_func_label , ** self .node_properties_kwargs )
268+ if caller_func_name not in ['<module>' , 'main' ]:
269+ parent_node = pydot .Node (name = caller_func_signature ,
270+ label = caller_func_label ,
271+ ** self .node_properties_kwargs )
236272 self .graph .add_node (parent_node )
237273 edge = pydot .Edge (parent_node , child_node )
238274 self .graph .add_edge (edge )
239275
240-
241276 return result
242- return wrapper
277+ return wrapper
0 commit comments