diff options
Diffstat (limited to 'lldb/utils/lui/lldbutil.py')
-rw-r--r-- | lldb/utils/lui/lldbutil.py | 344 |
1 files changed, 242 insertions, 102 deletions
diff --git a/lldb/utils/lui/lldbutil.py b/lldb/utils/lui/lldbutil.py index 8bdb074..b88a10a4 100644 --- a/lldb/utils/lui/lldbutil.py +++ b/lldb/utils/lui/lldbutil.py @@ -1,9 +1,9 @@ ##===-- lldbutil.py ------------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## @@ -14,17 +14,20 @@ They can also be useful for general purpose lldb scripting. """ import lldb -import os, sys +import os +import sys import StringIO # =================================================== # Utilities for locating/checking executable programs # =================================================== + def is_exe(fpath): """Returns True if fpath is an executable.""" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + def which(program): """Returns the full path to a program; None otherwise.""" fpath, fname = os.path.split(program) @@ -42,6 +45,7 @@ def which(program): # Disassembly for an SBFunction or an SBSymbol object # =================================================== + def disassemble(target, function_or_symbol): """Disassemble the function or symbol given a target. @@ -57,6 +61,7 @@ def disassemble(target, function_or_symbol): # Integer (byte size 1, 2, 4, and 8) to bytearray conversion # ========================================================== + def int_to_bytearray(val, bytesize): """Utility function to convert an integer into a bytearray. @@ -82,6 +87,7 @@ def int_to_bytearray(val, bytesize): packed = struct.pack(fmt, val) return bytearray(map(ord, packed)) + def bytearray_to_int(bytes, bytesize): """Utility function to convert a bytearray into an integer. @@ -137,7 +143,7 @@ def get_description(obj, option=None): if not success: return None return stream.GetData() - + # ================================================= # Convert some enum value to its string counterpart @@ -172,6 +178,7 @@ def state_type_to_str(enum): else: raise Exception("Unknown StateType enum") + def stop_reason_to_str(enum): """Returns the stopReason string given an enum.""" if enum == lldb.eStopReasonInvalid: @@ -195,6 +202,7 @@ def stop_reason_to_str(enum): else: raise Exception("Unknown StopReason enum") + def symbol_type_to_str(enum): """Returns the symbolType string given an enum.""" if enum == lldb.eSymbolTypeInvalid: @@ -246,6 +254,7 @@ def symbol_type_to_str(enum): elif enum == lldb.eSymbolTypeUndefined: return "undefined" + def value_type_to_str(enum): """Returns the valueType string given an enum.""" if enum == lldb.eValueTypeInvalid: @@ -273,12 +282,12 @@ def value_type_to_str(enum): # ================================================== def sort_stopped_threads(process, - breakpoint_threads = None, - crashed_threads = None, - watchpoint_threads = None, - signal_threads = None, - exiting_threads = None, - other_threads = None): + breakpoint_threads=None, + crashed_threads=None, + watchpoint_threads=None, + signal_threads=None, + exiting_threads=None, + other_threads=None): """ Fills array *_threads with threads stopped for the corresponding stop reason. """ @@ -307,8 +316,16 @@ def sort_stopped_threads(process, # Utility functions for setting breakpoints # ================================================== -def run_break_set_by_file_and_line (test, file_name, line_number, extra_options = None, num_expected_locations = 1, loc_exact=False, module_name=None): - """Set a breakpoint by file and line, returning the breakpoint number. + +def run_break_set_by_file_and_line( + test, + file_name, + line_number, + extra_options=None, + num_expected_locations=1, + loc_exact=False, + module_name=None): + """Set a breakpoint by file and line, returning the breakpoint number. If extra_options is not None, then we append it to the breakpoint set command. @@ -316,10 +333,10 @@ def run_break_set_by_file_and_line (test, file_name, line_number, extra_options If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.""" - if file_name == None: - command = 'breakpoint set -l %d'%(line_number) + if file_name is None: + command = 'breakpoint set -l %d' % (line_number) else: - command = 'breakpoint set -f "%s" -l %d'%(file_name, line_number) + command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) if module_name: command += " --shlib '%s'" % (module_name) @@ -327,20 +344,36 @@ def run_break_set_by_file_and_line (test, file_name, line_number, extra_options if extra_options: command += " " + extra_options - break_results = run_break_set_command (test, command) + break_results = run_break_set_command(test, command) if num_expected_locations == 1 and loc_exact: - check_breakpoint_result (test, break_results, num_locations=num_expected_locations, file_name = file_name, line_number = line_number, module_name=module_name) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations, + file_name=file_name, + line_number=line_number, + module_name=module_name) else: - check_breakpoint_result (test, break_results, num_locations = num_expected_locations) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) - return get_bpno_from_match (break_results) -def run_break_set_by_symbol (test, symbol, extra_options = None, num_expected_locations = -1, sym_exact = False, module_name=None): +def run_break_set_by_symbol( + test, + symbol, + extra_options=None, + num_expected_locations=-1, + sym_exact=False, + module_name=None): """Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line. If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.""" - command = 'breakpoint set -n "%s"'%(symbol) + command = 'breakpoint set -n "%s"' % (symbol) if module_name: command += " --shlib '%s'" % (module_name) @@ -348,16 +381,30 @@ def run_break_set_by_symbol (test, symbol, extra_options = None, num_expected_lo if extra_options: command += " " + extra_options - break_results = run_break_set_command (test, command) + break_results = run_break_set_command(test, command) if num_expected_locations == 1 and sym_exact: - check_breakpoint_result (test, break_results, num_locations = num_expected_locations, symbol_name = symbol, module_name=module_name) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations, + symbol_name=symbol, + module_name=module_name) else: - check_breakpoint_result (test, break_results, num_locations = num_expected_locations) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) - return get_bpno_from_match (break_results) -def run_break_set_by_selector (test, selector, extra_options = None, num_expected_locations = -1, module_name=None): +def run_break_set_by_selector( + test, + selector, + extra_options=None, + num_expected_locations=-1, + module_name=None): """Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line.""" command = 'breakpoint set -S "%s"' % (selector) @@ -368,42 +415,68 @@ def run_break_set_by_selector (test, selector, extra_options = None, num_expecte if extra_options: command += " " + extra_options - break_results = run_break_set_command (test, command) + break_results = run_break_set_command(test, command) if num_expected_locations == 1: - check_breakpoint_result (test, break_results, num_locations = num_expected_locations, symbol_name = selector, symbol_match_exact=False, module_name=module_name) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations, + symbol_name=selector, + symbol_match_exact=False, + module_name=module_name) else: - check_breakpoint_result (test, break_results, num_locations = num_expected_locations) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) - return get_bpno_from_match (break_results) + return get_bpno_from_match(break_results) -def run_break_set_by_regexp (test, regexp, extra_options=None, num_expected_locations=-1): + +def run_break_set_by_regexp( + test, + regexp, + extra_options=None, + num_expected_locations=-1): """Set a breakpoint by regular expression match on symbol name. Common options are the same as run_break_set_by_file_and_line.""" - command = 'breakpoint set -r "%s"'%(regexp) + command = 'breakpoint set -r "%s"' % (regexp) if extra_options: command += " " + extra_options - - break_results = run_break_set_command (test, command) - - check_breakpoint_result (test, break_results, num_locations=num_expected_locations) - return get_bpno_from_match (break_results) + break_results = run_break_set_command(test, command) + + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) -def run_break_set_by_source_regexp (test, regexp, extra_options=None, num_expected_locations=-1): + +def run_break_set_by_source_regexp( + test, + regexp, + extra_options=None, + num_expected_locations=-1): """Set a breakpoint by source regular expression. Common options are the same as run_break_set_by_file_and_line.""" - command = 'breakpoint set -p "%s"'%(regexp) + command = 'breakpoint set -p "%s"' % (regexp) if extra_options: command += " " + extra_options - - break_results = run_break_set_command (test, command) - - check_breakpoint_result (test, break_results, num_locations=num_expected_locations) - return get_bpno_from_match (break_results) + break_results = run_break_set_command(test, command) + + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) -def run_break_set_command (test, command): - """Run the command passed in - it must be some break set variant - and analyze the result. + +def run_break_set_command(test, command): + """Run the command passed in - it must be some break set variant - and analyze the result. Returns a dictionary of information gleaned from the command-line results. Will assert if the breakpoint setting fails altogether. @@ -420,11 +493,12 @@ def run_break_set_command (test, command): module - module address - address at which the breakpoint was set.""" - patterns = [r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$", - r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", - r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$", - r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"] - match_object = test.match (command, patterns) + patterns = [ + r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$", + r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", + r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$", + r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"] + match_object = test.match(command, patterns) break_results = match_object.groupdict() # We always insert the breakpoint number, setting it to -1 if we couldn't find it @@ -433,7 +507,7 @@ def run_break_set_command (test, command): break_results['bpno'] = -1 else: break_results['bpno'] = int(break_results['bpno']) - + # We always insert the number of locations # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1... # We also make sure it is an integer. @@ -448,61 +522,101 @@ def run_break_set_command (test, command): num_locations = int(break_results['num_locations']) break_results['num_locations'] = num_locations - + if 'line_no' in break_results: break_results['line_no'] = int(break_results['line_no']) return break_results -def get_bpno_from_match (break_results): - return int (break_results['bpno']) -def check_breakpoint_result (test, break_results, file_name=None, line_number=-1, symbol_name=None, symbol_match_exact=True, module_name=None, offset=-1, num_locations=-1): +def get_bpno_from_match(break_results): + return int(break_results['bpno']) + + +def check_breakpoint_result( + test, + break_results, + file_name=None, + line_number=-1, + symbol_name=None, + symbol_match_exact=True, + module_name=None, + offset=-1, + num_locations=-1): out_num_locations = break_results['num_locations'] if num_locations == -1: - test.assertTrue (out_num_locations > 0, "Expecting one or more locations, got none.") + test.assertTrue(out_num_locations > 0, + "Expecting one or more locations, got none.") else: - test.assertTrue (num_locations == out_num_locations, "Expecting %d locations, got %d."%(num_locations, out_num_locations)) + test.assertTrue( + num_locations == out_num_locations, + "Expecting %d locations, got %d." % + (num_locations, + out_num_locations)) if file_name: out_file_name = "" if 'file' in break_results: out_file_name = break_results['file'] - test.assertTrue (file_name == out_file_name, "Breakpoint file name '%s' doesn't match resultant name '%s'."%(file_name, out_file_name)) + test.assertTrue( + file_name == out_file_name, + "Breakpoint file name '%s' doesn't match resultant name '%s'." % + (file_name, + out_file_name)) if line_number != -1: out_file_line = -1 if 'line_no' in break_results: out_line_number = break_results['line_no'] - test.assertTrue (line_number == out_line_number, "Breakpoint line number %s doesn't match resultant line %s."%(line_number, out_line_number)) + test.assertTrue( + line_number == out_line_number, + "Breakpoint line number %s doesn't match resultant line %s." % + (line_number, + out_line_number)) if symbol_name: out_symbol_name = "" - # Look first for the inlined symbol name, otherwise use the symbol name: + # Look first for the inlined symbol name, otherwise use the symbol + # name: if 'inline_symbol' in break_results and break_results['inline_symbol']: out_symbol_name = break_results['inline_symbol'] elif 'symbol' in break_results: out_symbol_name = break_results['symbol'] if symbol_match_exact: - test.assertTrue(symbol_name == out_symbol_name, "Symbol name '%s' doesn't match resultant symbol '%s'."%(symbol_name, out_symbol_name)) + test.assertTrue( + symbol_name == out_symbol_name, + "Symbol name '%s' doesn't match resultant symbol '%s'." % + (symbol_name, + out_symbol_name)) else: - test.assertTrue(out_symbol_name.find(symbol_name) != -1, "Symbol name '%s' isn't in resultant symbol '%s'."%(symbol_name, out_symbol_name)) + test.assertTrue( + out_symbol_name.find(symbol_name) != - + 1, + "Symbol name '%s' isn't in resultant symbol '%s'." % + (symbol_name, + out_symbol_name)) if module_name: out_nodule_name = None if 'module' in break_results: out_module_name = break_results['module'] - - test.assertTrue (module_name.find(out_module_name) != -1, "Symbol module name '%s' isn't in expected module name '%s'."%(out_module_name, module_name)) + + test.assertTrue( + module_name.find(out_module_name) != - + 1, + "Symbol module name '%s' isn't in expected module name '%s'." % + (out_module_name, + module_name)) # ================================================== # Utility functions related to Threads and Processes # ================================================== + def get_stopped_threads(process, reason): """Returns the thread(s) with the specified stop reason in a list. @@ -514,6 +628,7 @@ def get_stopped_threads(process, reason): threads.append(t) return threads + def get_stopped_thread(process, reason): """A convenience function which returns the first thread with the given stop reason or None. @@ -542,31 +657,34 @@ def get_stopped_thread(process, reason): return None return threads[0] -def get_threads_stopped_at_breakpoint (process, bkpt): + +def get_threads_stopped_at_breakpoint(process, bkpt): """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" stopped_threads = [] threads = [] - stopped_threads = get_stopped_threads (process, lldb.eStopReasonBreakpoint) + stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint) if len(stopped_threads) == 0: return threads - + for thread in stopped_threads: # Make sure we've hit our breakpoint... - break_id = thread.GetStopReasonDataAtIndex (0) + break_id = thread.GetStopReasonDataAtIndex(0) if break_id == bkpt.GetID(): threads.append(thread) return threads -def continue_to_breakpoint (process, bkpt): + +def continue_to_breakpoint(process, bkpt): """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" process.Continue() if process.GetState() != lldb.eStateStopped: return None else: - return get_threads_stopped_at_breakpoint (process, bkpt) + return get_threads_stopped_at_breakpoint(process, bkpt) + def get_caller_symbol(thread): """ @@ -617,7 +735,8 @@ def get_filenames(thread): Returns a sequence of file names from the stack frames of this thread. """ def GetFilename(i): - return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename() + return thread.GetFrameAtIndex( + i).GetLineEntry().GetFileSpec().GetFilename() return map(GetFilename, range(thread.GetNumFrames())) @@ -637,7 +756,8 @@ def get_module_names(thread): Returns a sequence of module names from the stack frames of this thread. """ def GetModuleName(i): - return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename() + return thread.GetFrameAtIndex( + i).GetModule().GetFileSpec().GetFilename() return map(GetModuleName, range(thread.GetNumFrames())) @@ -652,7 +772,7 @@ def get_stack_frames(thread): return map(GetStackFrame, range(thread.GetNumFrames())) -def print_stacktrace(thread, string_buffer = False): +def print_stacktrace(thread, string_buffer=False): """Prints a simple stack trace of this thread.""" output = StringIO.StringIO() if string_buffer else sys.stdout @@ -668,7 +788,7 @@ def print_stacktrace(thread, string_buffer = False): addrs = get_pc_addresses(thread) if thread.GetStopReason() != lldb.eStopReasonInvalid: - desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) + desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) else: desc = "" print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format( @@ -687,16 +807,15 @@ def print_stacktrace(thread, string_buffer = False): num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset) else: print >> output, " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format( - num=i, addr=load_addr, mod=mods[i], - func='%s [inlined]' % funcs[i] if frame.IsInlined() else funcs[i], - file=files[i], line=lines[i], - args=get_args_as_string(frame, showFuncName=False) if not frame.IsInlined() else '()') + num=i, addr=load_addr, mod=mods[i], func='%s [inlined]' % + funcs[i] if frame.IsInlined() else funcs[i], file=files[i], line=lines[i], args=get_args_as_string( + frame, showFuncName=False) if not frame.IsInlined() else '()') if string_buffer: return output.getvalue() -def print_stacktraces(process, string_buffer = False): +def print_stacktraces(process, string_buffer=False): """Prints the stack traces of all the threads.""" output = StringIO.StringIO() if string_buffer else sys.stdout @@ -713,6 +832,7 @@ def print_stacktraces(process, string_buffer = False): # Utility functions related to Frames # =================================== + def get_parent_frame(frame): """ Returns the parent frame of the input frame object; None if not available. @@ -728,6 +848,7 @@ def get_parent_frame(frame): # If we reach here, no parent has been found, return None. return None + def get_args_as_string(frame, showFuncName=True): """ Returns the args of the input frame object as a string. @@ -736,8 +857,8 @@ def get_args_as_string(frame, showFuncName=True): # locals => False # statics => False # in_scope_only => True - vars = frame.GetVariables(True, False, False, True) # type of SBValueList - args = [] # list of strings + vars = frame.GetVariables(True, False, False, True) # type of SBValueList + args = [] # list of strings for var in vars: args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), @@ -752,37 +873,43 @@ def get_args_as_string(frame, showFuncName=True): return "%s(%s)" % (name, ", ".join(args)) else: return "(%s)" % (", ".join(args)) - -def print_registers(frame, string_buffer = False): + + +def print_registers(frame, string_buffer=False): """Prints all the register sets of the frame.""" output = StringIO.StringIO() if string_buffer else sys.stdout print >> output, "Register sets for " + str(frame) - registerSet = frame.GetRegisters() # Return type of SBValueList. - print >> output, "Frame registers (size of register set = %d):" % registerSet.GetSize() + registerSet = frame.GetRegisters() # Return type of SBValueList. + print >> output, "Frame registers (size of register set = %d):" % registerSet.GetSize( + ) for value in registerSet: - #print >> output, value - print >> output, "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()) + #print >> output, value + print >> output, "%s (number of children = %d):" % ( + value.GetName(), value.GetNumChildren()) for child in value: - print >> output, "Name: %s, Value: %s" % (child.GetName(), child.GetValue()) + print >> output, "Name: %s, Value: %s" % ( + child.GetName(), child.GetValue()) if string_buffer: return output.getvalue() + def get_registers(frame, kind): """Returns the registers given the frame and the kind of registers desired. Returns None if there's no such kind. """ - registerSet = frame.GetRegisters() # Return type of SBValueList. + registerSet = frame.GetRegisters() # Return type of SBValueList. for value in registerSet: if kind.lower() in value.GetName().lower(): return value return None + def get_GPRs(frame): """Returns the general purpose registers of the frame as an SBValue. @@ -796,6 +923,7 @@ def get_GPRs(frame): """ return get_registers(frame, "general purpose") + def get_FPRs(frame): """Returns the floating point registers of the frame as an SBValue. @@ -809,6 +937,7 @@ def get_FPRs(frame): """ return get_registers(frame, "floating point") + def get_ESRs(frame): """Returns the exception state registers of the frame as an SBValue. @@ -826,8 +955,10 @@ def get_ESRs(frame): # Utility classes/functions for SBValues # ====================================== + class BasicFormatter(object): """The basic formatter inspects the value object and prints the value.""" + def format(self, value, buffer=None, indent=0): if not buffer: output = StringIO.StringIO() @@ -836,25 +967,28 @@ class BasicFormatter(object): # If there is a summary, it suffices. val = value.GetSummary() # Otherwise, get the value. - if val == None: + if val is None: val = value.GetValue() - if val == None and value.GetNumChildren() > 0: + if val is None and value.GetNumChildren() > 0: val = "%s (location)" % value.GetLocation() print >> output, "{indentation}({type}) {name} = {value}".format( - indentation = ' ' * indent, - type = value.GetTypeName(), - name = value.GetName(), - value = val) + indentation=' ' * indent, + type=value.GetTypeName(), + name=value.GetName(), + value=val) return output.getvalue() + class ChildVisitingFormatter(BasicFormatter): """The child visiting formatter prints the value and its immediate children. The constructor takes a keyword arg: indent_child, which defaults to 2. """ + def __init__(self, indent_child=2): """Default indentation of 2 SPC's for the children.""" self.cindent = indent_child + def format(self, value, buffer=None): if not buffer: output = StringIO.StringIO() @@ -863,21 +997,25 @@ class ChildVisitingFormatter(BasicFormatter): BasicFormatter.format(self, value, buffer=output) for child in value: - BasicFormatter.format(self, child, buffer=output, indent=self.cindent) + BasicFormatter.format( + self, child, buffer=output, indent=self.cindent) return output.getvalue() + class RecursiveDecentFormatter(BasicFormatter): """The recursive decent formatter prints the value and the decendents. The constructor takes two keyword args: indent_level, which defaults to 0, and indent_child, which defaults to 2. The current indentation level is determined by indent_level, while the immediate children has an additional - indentation by inden_child. + indentation by inden_child. """ + def __init__(self, indent_level=0, indent_child=2): self.lindent = indent_level self.cindent = indent_child + def format(self, value, buffer=None): if not buffer: output = StringIO.StringIO() @@ -887,13 +1025,15 @@ class RecursiveDecentFormatter(BasicFormatter): BasicFormatter.format(self, value, buffer=output, indent=self.lindent) new_indent = self.lindent + self.cindent for child in value: - if child.GetSummary() != None: - BasicFormatter.format(self, child, buffer=output, indent=new_indent) + if child.GetSummary() is not None: + BasicFormatter.format( + self, child, buffer=output, indent=new_indent) else: if child.GetNumChildren() > 0: rdf = RecursiveDecentFormatter(indent_level=new_indent) rdf.format(child, buffer=output) else: - BasicFormatter.format(self, child, buffer=output, indent=new_indent) + BasicFormatter.format( + self, child, buffer=output, indent=new_indent) return output.getvalue() |