text: """Management of iteration stack for recording."""
  import weakref
  
  from openmdao.utils.mpi import MPI
  
  _norec_funcs = frozenset(['_run_apply', '_compute_totals'])
  
  
  class _RecIteration(object):
      """
      A class that encapsulates the iteration stack.
  
      Some tests needed to reset the stack and this avoids issues
      with data left over from other tests.
  
      Attributes
      ----------
      stack : list
          A list that holds the stack of iteration coordinates.
      prefix : str or None
          Prefix to prepend to iteration coordinates.
      """
  
      def __init__(self):
          """
          Initialize.
          """
          self.stack = []
          self.prefix = None
          self._norec_refcount = 0
  
      def print_recording_iteration_stack(self):
          """
          Print the record iteration stack.
  
          Used for debugging.
          """
          print()
          for name, iter_count in reversed(self.stack):
              print('^^^', name, iter_count)
          print(60 * '^')
  
      def get_formatted_iteration_coordinate(self):
          """
          Format the iteration coordinate into human-readable form.
  
          'rank0:pyoptsparsedriver|6|root._solve_nonlinear|6|mda._solve_nonlinear|6|mda.d1._solve_nonlinear|45'
  
          Returns
          -------
          str :
              the iteration coordinate formatted in our proprietary way.
          """
          separator = '|'
  
          # prefix
          if self.prefix:
              prefix = '%s_' % self.prefix
          else:
              prefix = ''
  
          if MPI:
              prefix += 'rank%d:' % MPI.COMM_WORLD.rank
          else:
              prefix += 'rank0:'
  
          # iteration hierarchy
          coord_list = []
          for name, iter_count in self.stack:
              coord_list.append('{}{}{}'.format(name, separator, iter_count))
  
          return prefix + separator.join(coord_list)
  
      def push(self, iter_coord):
          """
          Push the current iteration coordinate onto the stack.
  
          Parameters
          ----------
          iter_coord : tuple
              (func_name, iter_count) for the current iteration.
          """
          self.stack.append(iter_coord)
          if iter_coord[0] in _norec_funcs:
              self._norec_refcount += 1
  
      def pop(self):
          """
          Pop the current iteration coordinate off of the stack.
  
          Returns
          -------
          tuple
              (function_name, iter_count) for current iteration.
          """
          iter_coord = self.stack.pop()
          if iter_coord[0] in _norec_funcs:
              self._norec_refcount -= 1
          return iter_coord
  
  
  class Recording(object):
      """
      A class that acts as a context manager.
  
      But with properly-timed values for abs and rel,
      where solvers are concerned.
  
      Parameters
      ----------
      name : str
          Name of object getting recorded.
      iter_count : int
          Current counter of iterations completed.
      recording_requester : object
          The object that wants to be recorded.
  
      Attributes
      ----------
      name : str
          Name of object getting recorded.
      iter_count : int
          Current counter of iterations completed.
      recording_requester : weakref to object
          The object that wants to be recorded.
      stack : list
          Stack containing names and iteration counts.
      abs : float
          Absolute error.
      rel : float
          Relative error.
      _is_solver : bool
          True if recording_requester is a Solver.
      """
  
      def __init__(self, name, iter_count, recording_requester):
          """
          Initialize Recording.
          """
          self.name = name
          self.iter_count = iter_count
          self.recording_requester = weakref.ref(recording_requester)
          self.abs = 0
          self.rel = 0
  
          from openmdao.solvers.solver import Solver
          self._is_solver = isinstance(recording_requester, Solver)
  
      def __enter__(self):
          """
          Do things before the code inside the 'with Recording' block.
  
          Returns
          -------
          self : object
              self
          """
          self.recording_requester()._recording_iter.push((self.name, self.iter_count))
          return self
  
      def __exit__(self, *args):
          """
          Do things after the code inside the 'with Recording' block.
  
          Parameters
          ----------
          *args : array
              Solver recording requires extra args.
          """
          requester = self.recording_requester()
          if requester._recording_iter._norec_refcount == 0:
              if self._is_solver:
                  requester.record_iteration(abs=self.abs, rel=self.rel)
              else:
                  requester.record_iteration()
  
          # Enable the following line for stack debugging.
          # print_recording_iteration_stack()
  
          requester._recording_iter.pop()
  