2727import copy
2828import re
2929
30+ import numpy as np
3031from six .moves import xrange # pylint: disable=redefined-builtin
3132
3233from tensorflow .python .debug .cli import cli_shared
3334from tensorflow .python .debug .cli import command_parser
3435from tensorflow .python .debug .cli import debugger_cli_common
3536from tensorflow .python .debug .cli import ui_factory
3637from tensorflow .python .debug .lib import debug_data
38+ from tensorflow .python .debug .lib import source_utils
3739
40+ RL = debugger_cli_common .RichLine
3841
3942# String constants for the depth-dependent hanging indent at the beginning
4043# of each line.
@@ -89,7 +92,7 @@ def _add_main_menu(output,
8992 menu .append (
9093 debugger_cli_common .MenuItem (
9194 "node_info" ,
92- "node_info -a -d %s" % node_name ,
95+ "node_info -a -d -t %s" % node_name ,
9396 enabled = enable_node_info ))
9497 menu .append (
9598 debugger_cli_common .MenuItem (
@@ -303,7 +306,6 @@ def __init__(self, debug_dump):
303306 help = "Numerical ranges to highlight tensor elements in. "
304307 "Examples: -r 0,1e-8, -r [-0.1,0.1], "
305308 "-r \" [[-inf, -0.1], [0.1, inf]]\" " )
306-
307309 ap .add_argument (
308310 "-a" ,
309311 "--all" ,
@@ -312,6 +314,37 @@ def __init__(self, debug_dump):
312314 help = "Print the tensor in its entirety, i.e., do not use ellipses." )
313315 self ._arg_parsers ["print_tensor" ] = ap
314316
317+ # Parser for print_source.
318+ ap = argparse .ArgumentParser (
319+ description = "Print a Python source file with overlaid debug "
320+ "information, including the nodes (ops) or Tensors created at the "
321+ "source lines." ,
322+ usage = argparse .SUPPRESS )
323+ ap .add_argument (
324+ "source_file_path" ,
325+ type = str ,
326+ help = "Path to the source file." )
327+ ap .add_argument (
328+ "-t" ,
329+ "--tensors" ,
330+ dest = "tensors" ,
331+ action = "store_true" ,
332+ help = "Label lines with dumped Tensors, instead of ops." )
333+ ap .add_argument (
334+ "-m" ,
335+ "--max_elements_per_line" ,
336+ type = int ,
337+ default = 10 ,
338+ help = "Maximum number of elements (ops or Tensors) to show per source "
339+ "line." )
340+ ap .add_argument (
341+ "-b" ,
342+ "--line_begin" ,
343+ type = int ,
344+ default = 1 ,
345+ help = "Print source beginning at line number (1-based.)" )
346+ self ._arg_parsers ["print_source" ] = ap
347+
315348 # TODO(cais): Implement list_nodes.
316349
317350 def add_tensor_filter (self , filter_name , filter_callable ):
@@ -709,15 +742,20 @@ def _render_node_traceback(self, node_name):
709742 construction.
710743 """
711744
712- lines = ["" , "" , "Traceback of node construction:" ]
713- font_attr_segs = {len (lines ) - 1 : [(0 , len (lines [- 1 ]), "bold" )]}
745+ lines = [RL ("" ), RL ("" ), RL ("Traceback of node construction:" , "bold" )]
714746
715747 try :
716748 node_stack = self ._debug_dump .node_traceback (node_name )
717749 for depth , (file_path , line , function_name , text ) in enumerate (
718750 node_stack ):
719751 lines .append ("%d: %s" % (depth , file_path ))
720- lines .append (" Line: %d" % line )
752+
753+ attribute = debugger_cli_common .MenuItem (
754+ "" , "ps %s -b %d" % (file_path , line )) if text else None
755+ line_number_line = RL (" " )
756+ line_number_line += RL ("Line: %d" % line , attribute )
757+ lines .append (line_number_line )
758+
721759 lines .append (" Function: %s" % function_name )
722760 lines .append (" Text: " + (("\" %s\" " % text ) if text else "None" ))
723761 lines .append ("" )
@@ -726,8 +764,7 @@ def _render_node_traceback(self, node_name):
726764 except LookupError :
727765 lines .append ("(Unavailable because no Python graph has been loaded)" )
728766
729- return debugger_cli_common .RichTextLines (lines ,
730- font_attr_segs = font_attr_segs )
767+ return debugger_cli_common .rich_text_lines_from_rich_line_list (lines )
731768
732769 def list_inputs (self , args , screen_info = None ):
733770 """Command handler for inputs.
@@ -942,6 +979,63 @@ def list_outputs(self, args, screen_info=None):
942979
943980 return output
944981
982+ def print_source (self , args , screen_info = None ):
983+ """Print the content of a source file."""
984+ del screen_info # Unused.
985+
986+ parsed = self ._arg_parsers ["print_source" ].parse_args (args )
987+
988+ source_annotation = source_utils .annotate_source (
989+ self ._debug_dump ,
990+ parsed .source_file_path ,
991+ do_dumped_tensors = parsed .tensors ,
992+ min_line = parsed .line_begin )
993+
994+ with open (parsed .source_file_path , "rU" ) as f :
995+ source_text = f .read ()
996+
997+ source_lines = source_text .split ("\n " )
998+ num_lines = len (source_lines )
999+ line_num_width = int (np .ceil (np .log10 (num_lines ))) + 3
1000+
1001+ labeled_source_lines = []
1002+ if parsed .line_begin > 1 :
1003+ labeled_source_lines .append (
1004+ RL ("(... Omitted %d source lines ...)" % (parsed .line_begin - 1 ),
1005+ "bold" ))
1006+
1007+ for i , line in enumerate (source_lines [parsed .line_begin - 1 :]):
1008+ annotated_line = RL ("L%d" % (i + parsed .line_begin ), "yellow" )
1009+ annotated_line += " " * (line_num_width - len (annotated_line ))
1010+ annotated_line += line
1011+ labeled_source_lines .append (annotated_line )
1012+
1013+ if i + parsed .line_begin in source_annotation :
1014+ sorted_elements = sorted (source_annotation [i + parsed .line_begin ])
1015+ for k , element in enumerate (sorted_elements ):
1016+ if k >= parsed .max_elements_per_line :
1017+ labeled_source_lines .append (
1018+ " (... Omitted %d of %d %s ...)" % (
1019+ len (sorted_elements ) - parsed .max_elements_per_line ,
1020+ len (sorted_elements ),
1021+ "tensor(s)" if parsed .tensors else "op(s)" ))
1022+ break
1023+
1024+ label = RL (" " * 4 )
1025+ if self ._debug_dump .debug_watch_keys (
1026+ debug_data .get_node_name (element )):
1027+ attribute = debugger_cli_common .MenuItem ("" , "pt %s" % element )
1028+ else :
1029+ attribute = "blue"
1030+
1031+ label += RL (element , attribute )
1032+ labeled_source_lines .append (label )
1033+
1034+ output = debugger_cli_common .rich_text_lines_from_rich_line_list (
1035+ labeled_source_lines )
1036+ _add_main_menu (output , node_name = None )
1037+ return output
1038+
9451039 def _list_inputs_or_outputs (self ,
9461040 recursive ,
9471041 node_name ,
@@ -1292,6 +1386,11 @@ def create_analyzer_ui(debug_dump, tensor_filters=None, ui_type="curses"):
12921386 analyzer .print_tensor ,
12931387 analyzer .get_help ("print_tensor" ),
12941388 prefix_aliases = ["pt" ])
1389+ cli .register_command_handler (
1390+ "print_source" ,
1391+ analyzer .print_source ,
1392+ analyzer .get_help ("print_source" ),
1393+ prefix_aliases = ["ps" ])
12951394
12961395 dumped_tensor_names = []
12971396 for datum in debug_dump .dumped_tensor_data :
0 commit comments