text: import inspect
  from collections import OrderedDict
  
  from coalib.misc.Enum import enum
  
  
  class DocstringMetadata:
      _ParseMode = enum('DESCRIPTION', 'PARAM', 'RETVAL')
  
      def __init__(self, desc, param_dict, retval_desc):
          """
          Represents a docstring of a python class or function.
  
          :param desc:        A description as string.
          :param param_dict:  A dictionary containing parameter names as key and
                              their description as value. To preserve the order,
                              use OrderedDict.
          :param retval_desc: A string describing the return value.
          """
          self.desc = desc
          self.param_dict = param_dict
          self.retval_desc = retval_desc
  
      @classmethod
      def from_docstring(cls, docstring):
          """
          Parses a python docstring. Usable attributes are:
          :param
          @param
          :return
          @return
          """
          lines = inspect.cleandoc(docstring).split('\n')
  
          parse_mode = cls._ParseMode.DESCRIPTION
          cur_param = ''
  
          desc = ''
          param_dict = OrderedDict()
          retval_desc = ''
          for line in lines:
              line = line.strip()
  
              if line.startswith(':param ') or line.startswith('@param '):
                  parse_mode = cls._ParseMode.PARAM
                  splitted = line[7:].split(':', 1)
                  cur_param = splitted[0]
                  param_dict[cur_param] = splitted[1].strip()
  
                  continue
  
              if line.startswith(':return: ') or line.startswith('@return: '):
                  parse_mode = cls._ParseMode.RETVAL
                  retval_desc = line[9:].strip()
  
                  continue
  
              def concat_doc_parts(old: str, new: str):
                  if new != '' and not old.endswith('\n'):
                      return (old + ' ' + new).strip()
  
                  return old + (new if new != '' else '\n')
  
              if parse_mode == cls._ParseMode.RETVAL:
                  retval_desc = concat_doc_parts(retval_desc, line)
              elif parse_mode == cls._ParseMode.PARAM:
                  param_dict[cur_param] = concat_doc_parts(param_dict[cur_param],
                                                           line)
              else:
                  desc = concat_doc_parts(desc, line)
  
          return (cls(desc=desc.strip(),
                      param_dict=param_dict,
                      retval_desc=retval_desc.strip()))
  
      def __str__(self):
          return str(self.desc)
  