docs: def get_exdesc():
      """
      Retrieve contract exception(s) message(s).
  
      If the custom contract is specified with only one exception the return
      value is the message associated with that exception; if the custom contract
      is specified with several exceptions, the return value is a dictionary
      whose keys are the exception names and whose values are the exception
      messages.
  
      :raises: RuntimeError (Function object could not be found for
       function *[function_name]*)
      :rtype: string or dictionary
  
      For example:
  
      .. =[=cog
      .. import docs.support.incfile
      .. docs.support.incfile.incfile('pcontracts_example_2.py', cog.out)
      .. =]=
      .. code-block:: python
  
          # pcontracts_example_2.py
          import pexdoc.pcontracts
  
          @pexdoc.pcontracts.new_contract('Only one exception')
          def custom_contract_a(name):
              msg = pexdoc.pcontracts.get_exdesc()
              if not name:
                  raise ValueError(msg)
  
          @pexdoc.pcontracts.new_contract(ex1='Empty name', ex2='Invalid name')
          def custom_contract_b(name):
              msg = pexdoc.pcontracts.get_exdesc()
              if not name:
                  raise ValueError(msg['ex1'])
              elif name.find('[') != -1:
                  raise ValueError(msg['ex2'])
  
      .. =[=end=]=
  
  
      In :code:`custom_contract1()` the variable :code:`msg` contains the string
      ``'Only one exception'``, in :code:`custom_contract2()` the variable
      :code:`msg` contains the dictionary
      :code:`{'ex1':'Empty name', 'ex2':'Invalid name'}`.
  
      """
      # First frame is own function (get_exdesc), next frame is the calling
      # function, of which its name is needed
      fname = inspect.getframeinfo(sys._getframe(1))[2]
      # Find function object in stack
      count = 0
      fobj = None
      while not (fobj and hasattr(fobj, "exdesc")):
          count = count + 1
          try:
              sitem = sys._getframe(count)
          except ValueError:
              # Got to top of stack
              raise RuntimeError(
                  "Function object could not be found for function `{0}`".format(fname)
              )
          fobj = (
              sitem.f_locals[fname]
              if fname in sitem.f_locals
              else (sitem.f_globals[fname] if fname in sitem.f_globals else None)
          )
      # Return function attribute created by new contract decorator
      exdesc = getattr(fobj, "exdesc")
      return exdesc if len(exdesc) > 1 else exdesc[next(iter(exdesc))]