parameters: (self)
return_statement: return chunks
docstring: Split the code object into a list of `Chunk` objects.
  
          Each chunk is only entered at its first instruction, though there can
          be many exits from a chunk.
  
          Returns a list of `Chunk` objects.
docstring_summary: Split the code object into a list of `Chunk` objects.
docstring_tokens: Split the code object into a list of Chunk objects .
function: def _split_into_chunks(self):
          """Split the code object into a list of `Chunk` objects.
  
          Each chunk is only entered at its first instruction, though there can
          be many exits from a chunk.
  
          Returns a list of `Chunk` objects.
  
          """
  
          # The list of chunks so far, and the one we're working on.
          chunks = []
          chunk = None
          bytes_lines_map = dict(self._bytes_lines())
  
          # The block stack: loops and try blocks get pushed here for the
          # implicit jumps that can occur.
          # Each entry is a tuple: (block type, destination)
          block_stack = []
  
          # Some op codes are followed by branches that should be ignored.  This
          # is a count of how many ignores are left.
          ignore_branch = 0
  
          # We have to handle the last two bytecodes specially.
          ult = penult = None
  
          for bc in ByteCodes(self.code.co_code):
              # Maybe have to start a new chunk
              if bc.offset in bytes_lines_map:
                  # Start a new chunk for each source line number.
                  if chunk:
                      chunk.exits.add(bc.offset)
                  chunk = Chunk(bc.offset, bytes_lines_map[bc.offset])
                  chunks.append(chunk)
              elif bc.op in OPS_CHUNK_BEGIN:
                  # Jumps deserve their own unnumbered chunk.  This fixes
                  # problems with jumps to jumps getting confused.
                  if chunk:
                      chunk.exits.add(bc.offset)
                  chunk = Chunk(bc.offset)
                  chunks.append(chunk)
  
              if not chunk:
                  chunk = Chunk(bc.offset)
                  chunks.append(chunk)
  
              # Look at the opcode
              if bc.jump_to >= 0 and bc.op not in OPS_NO_JUMP:
                  if ignore_branch:
                      # Someone earlier wanted us to ignore this branch.
                      ignore_branch -= 1
                  else:
                      # The opcode has a jump, it's an exit for this chunk.
                      chunk.exits.add(bc.jump_to)
  
              if bc.op in OPS_CODE_END:
                  # The opcode can exit the code object.
                  chunk.exits.add(-self.code.co_firstlineno)
              if bc.op in OPS_PUSH_BLOCK:
                  # The opcode adds a block to the block_stack.
                  block_stack.append((bc.op, bc.jump_to))
              if bc.op in OPS_POP_BLOCK:
                  # The opcode pops a block from the block stack.
                  block_stack.pop()
              if bc.op in OPS_CHUNK_END:
                  # This opcode forces the end of the chunk.
                  if bc.op == OP_BREAK_LOOP:
                      # A break is implicit: jump where the top of the
                      # block_stack points.
                      chunk.exits.add(block_stack[-1][1])
                  chunk = None
              if bc.op == OP_END_FINALLY:
                  if block_stack:
                      # A break that goes through a finally will jump to whatever
                      # block is on top of the stack.
                      chunk.exits.add(block_stack[-1][1])
                  # For the finally clause we need to find the closest exception
                  # block, and use its jump target as an exit.
                  for iblock in range(len(block_stack)-1, -1, -1):
                      if block_stack[iblock][0] in OPS_EXCEPT_BLOCKS:
                          chunk.exits.add(block_stack[iblock][1])
                          break
              if bc.op == OP_COMPARE_OP and bc.arg == COMPARE_EXCEPTION:
                  # This is an except clause.  We want to overlook the next
                  # branch, so that except's don't count as branches.
                  ignore_branch += 1
  
              penult = ult
              ult = bc
  
          if chunks:
              # The last two bytecodes could be a dummy "return None" that
              # shouldn't be counted as real code. Every Python code object seems
              # to end with a return, and a "return None" is inserted if there
              # isn't an explicit return in the source.
              if ult and penult:
                  if penult.op == OP_LOAD_CONST and ult.op == OP_RETURN_VALUE:
                      if self.code.co_consts[penult.arg] is None:
                          # This is "return None", but is it dummy?  A real line
                          # would be a last chunk all by itself.
                          if chunks[-1].byte != penult.offset:
                              ex = -self.code.co_firstlineno
                              # Split the last chunk
                              last_chunk = chunks[-1]
                              last_chunk.exits.remove(ex)
                              last_chunk.exits.add(penult.offset)
                              chunk = Chunk(penult.offset)
                              chunk.exits.add(ex)
                              chunks.append(chunk)
  
              # Give all the chunks a length.
              chunks[-1].length = bc.next_offset - chunks[-1].byte
              for i in range(len(chunks)-1):
                  chunks[i].length = chunks[i+1].byte - chunks[i].byte
  
          return chunks
function_tokens: def _split_into_chunks ( self ) : # The list of chunks so far, and the one we're working on. chunks = [ ] chunk = None bytes_lines_map = dict ( self . _bytes_lines ( ) ) # The block stack: loops and try blocks get pushed here for the # implicit jumps that can occur. # Each entry is a tuple: (block type, destination) block_stack = [ ] # Some op codes are followed by branches that should be ignored.  This # is a count of how many ignores are left. ignore_branch = 0 # We have to handle the last two bytecodes specially. ult = penult = None for bc in ByteCodes ( self . code . co_code ) : # Maybe have to start a new chunk if bc . offset in bytes_lines_map : # Start a new chunk for each source line number. if chunk : chunk . exits . add ( bc . offset ) chunk = Chunk ( bc . offset , bytes_lines_map [ bc . offset ] ) chunks . append ( chunk ) elif bc . op in OPS_CHUNK_BEGIN : # Jumps deserve their own unnumbered chunk.  This fixes # problems with jumps to jumps getting confused. if chunk : chunk . exits . add ( bc . offset ) chunk = Chunk ( bc . offset ) chunks . append ( chunk ) if not chunk : chunk = Chunk ( bc . offset ) chunks . append ( chunk ) # Look at the opcode if bc . jump_to >= 0 and bc . op not in OPS_NO_JUMP : if ignore_branch : # Someone earlier wanted us to ignore this branch. ignore_branch -= 1 else : # The opcode has a jump, it's an exit for this chunk. chunk . exits . add ( bc . jump_to ) if bc . op in OPS_CODE_END : # The opcode can exit the code object. chunk . exits . add ( - self . code . co_firstlineno ) if bc . op in OPS_PUSH_BLOCK : # The opcode adds a block to the block_stack. block_stack . append ( ( bc . op , bc . jump_to ) ) if bc . op in OPS_POP_BLOCK : # The opcode pops a block from the block stack. block_stack . pop ( ) if bc . op in OPS_CHUNK_END : # This opcode forces the end of the chunk. if bc . op == OP_BREAK_LOOP : # A break is implicit: jump where the top of the # block_stack points. chunk . exits . add ( block_stack [ - 1 ] [ 1 ] ) chunk = None if bc . op == OP_END_FINALLY : if block_stack : # A break that goes through a finally will jump to whatever # block is on top of the stack. chunk . exits . add ( block_stack [ - 1 ] [ 1 ] ) # For the finally clause we need to find the closest exception # block, and use its jump target as an exit. for iblock in range ( len ( block_stack ) - 1 , - 1 , - 1 ) : if block_stack [ iblock ] [ 0 ] in OPS_EXCEPT_BLOCKS : chunk . exits . add ( block_stack [ iblock ] [ 1 ] ) break if bc . op == OP_COMPARE_OP and bc . arg == COMPARE_EXCEPTION : # This is an except clause.  We want to overlook the next # branch, so that except's don't count as branches. ignore_branch += 1 penult = ult ult = bc if chunks : # The last two bytecodes could be a dummy "return None" that # shouldn't be counted as real code. Every Python code object seems # to end with a return, and a "return None" is inserted if there # isn't an explicit return in the source. if ult and penult : if penult . op == OP_LOAD_CONST and ult . op == OP_RETURN_VALUE : if self . code . co_consts [ penult . arg ] is None : # This is "return None", but is it dummy?  A real line # would be a last chunk all by itself. if chunks [ - 1 ] . byte != penult . offset : ex = - self . code . co_firstlineno # Split the last chunk last_chunk = chunks [ - 1 ] last_chunk . exits . remove ( ex ) last_chunk . exits . add ( penult . offset ) chunk = Chunk ( penult . offset ) chunk . exits . add ( ex ) chunks . append ( chunk ) # Give all the chunks a length. chunks [ - 1 ] . length = bc . next_offset - chunks [ - 1 ] . byte for i in range ( len ( chunks ) - 1 ) : chunks [ i ] . length = chunks [ i + 1 ] . byte - chunks [ i ] . byte return chunks