docs: def km_from_string(s=''):
      """create kernel manager from IPKernelApp string
      such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668' for IPython 0.11
      or just 'kernel-12345.json' for IPython 0.12
      """
      try:
          import IPython
      except ImportError:
          raise ImportError("Could not find IPython. " + _install_instructions)
      # Modified by BoPeng
      #
      #from IPython.config.loader import KeyValueConfigLoader
      from traitlets.config.loader import KeyValueConfigLoader
      try:
          # Updated by Bo Peng for module names
          from jupyter_client.manager import  KernelManager
          from jupyter_client import find_connection_file
      except ImportError:
          #  IPython < 1.0
          from IPython.zmq.blockingkernelmanager import BlockingKernelManager as KernelManager
          from IPython.zmq.kernelapp import kernel_aliases
          try:
              from IPython.lib.kernel import find_connection_file
          except ImportError:
              # < 0.12, no find_connection_file
              pass
  
      global km, kc, send
  
      s = s.replace('--existing', '')
      if 'connection_file' in KernelManager.class_trait_names():
          # 0.12 uses files instead of a collection of ports
          # include default IPython search path
          # filefind also allows for absolute paths, in which case the search
          # is ignored
          try:
              # XXX: the following approach will be brittle, depending on what
              # connection strings will end up looking like in the future, and
              # whether or not they are allowed to have spaces. I'll have to sync
              # up with the IPython team to address these issues -pi
              if '--profile' in s:
                  k,p = s.split('--profile')
                  k = k.lstrip().rstrip() # kernel part of the string
                  p = p.lstrip().rstrip() # profile part of the string
                  fullpath = find_connection_file(k,p)
              else:
                  fullpath = find_connection_file(s.lstrip().rstrip())
          except IOError as e:
              echo(":IPython " + s + " failed", "Info")
              echo("^-- failed '" + s + "' not found", "Error")
              return
          km = KernelManager(connection_file = fullpath)
          km.load_connection_file()
      else:
          if s == '':
              echo(":IPython 0.11 requires the full connection string")
              return
          loader = KeyValueConfigLoader(s.split(), aliases=kernel_aliases)
          cfg = loader.load_config()['KernelApp']
          try:
              km = KernelManager(
                  shell_address=(ip, cfg['shell_port']),
                  sub_address=(ip, cfg['iopub_port']),
                  stdin_address=(ip, cfg['stdin_port']),
                  hb_address=(ip, cfg['hb_port']))
          except KeyError as e:
              echo(":IPython " +s + " failed", "Info")
              echo("^-- failed --"+e.message.replace('_port','')+" not specified", "Error")
              return
  
      try:
          kc = km.client()
      except AttributeError:
          # 0.13
          kc = km
      kc.start_channels()
  
      try:
          send = kc.execute
      except AttributeError:
          # < 3.0
          send = kc.shell_channel.execute
  
      #XXX: backwards compatibility for IPython < 0.13
      try:
          import inspect
          sc = kc.shell_channel
          num_oinfo_args = len(inspect.getargspec(sc.object_info).args)
          if num_oinfo_args == 2:
              # patch the object_info method which used to only take one argument
              klass = sc.__class__
              klass._oinfo_orig = klass.object_info
              klass.object_info = lambda s,x,y: s._oinfo_orig(x)
      except Exception:
          pass
  
      #XXX: backwards compatibility for IPython < 1.0
      if not hasattr(kc, 'iopub_channel'):
          kc.iopub_channel = kc.sub_channel
  
      # now that we're connect to an ipython kernel, activate completion
      # machinery, but do so only for the local buffer if the user added the
      # following line the vimrc:
      #   let g:ipy_completefunc = 'local'
      vim.command("""
          if g:ipy_completefunc == 'global'
              set completefunc=CompleteIPython
          elseif g:ipy_completefunc == 'local'
              setl completefunc=CompleteIPython
          endif
          """)
      # also activate GUI doc balloons if in gvim
      vim.command("""
          if has('balloon_eval')
              set bexpr=IPythonBalloonExpr()
          endif
          """)
      set_pid()
      return km