code: def interaction(
              self,
              frame,
              tb=None,
              exception='Wdb',
              exception_description='Stepping',
              init=None,
              shell=False,
              shell_vars=None,
              source=None,
              iframe_mode=False,
              timeout=None,
              post_mortem=False
      ):
          
          log.info(
              'Interaction %r %r %r %r' %
              (frame, tb, exception, exception_description)
          )
          self.reconnect_if_needed()
          self.stepping = not shell
  
          if not iframe_mode:
              opts = {}
              if shell:
                  opts['type_'] = 'shell'
              if post_mortem:
                  opts['type_'] = 'pm'
              self.open_browser(**opts)
  
          lvl = len(self.interaction_stack)
          if lvl:
              exception_description += ' [recursive%s]' % (
                  '^%d' % lvl if lvl > 1 else ''
              )
  
          interaction = Interaction(
              self,
              frame,
              tb,
              exception,
              exception_description,
              init=init,
              shell=shell,
              shell_vars=shell_vars,
              source=source,
              timeout=timeout
          )
  
          self.interaction_stack.append(interaction)
  
          # For meta debugging purpose
          self._ui = interaction
  
          if self.begun:
              # Each new state sends the trace and selects a frame
              interaction.init()
          else:
              self.begun = True
  
          interaction.loop()
          self.interaction_stack.pop()
          if lvl:
              self.interaction_stack[-1].init()
docs: User interaction handling blocking on socket receive