docs: def returnLabelState(peptide, labelDescriptor, labelSymbols=None,
                       labelAminoacids=None):
      """Calculates the label state of a given peptide for the label setup
      described in labelDescriptor
  
      :param peptide: peptide which label state should be calcualted
      :param labelDescriptor: :class:`LabelDescriptor`, describes the label setup
          of an experiment.
      :param labelSymbols: modifications that show a label, as returned by
          :func:`modSymbolsFromLabelInfo`.
      :param labelAminoacids: amino acids that can bear a label, as returned by
          :func:`modAminoacidsFromLabelInfo`.
  
      :returns: integer that shows the label state:
          >=0: predicted label state of the peptide
           -1: peptide sequence can't bear any labelState modifications
           -2: peptide modifications don't fit to any predicted labelState
           -3: peptide modifications fit to a predicted labelState, but not all
               predicted labelStates are distinguishable
      """
      if labelSymbols is None:
          labelSymbols = modSymbolsFromLabelInfo(labelDescriptor)
      if labelAminoacids is None:
          labelAminoacids = modAminoacidsFromLabelInfo(labelDescriptor)
  
      sequence = maspy.peptidemethods.removeModifications(peptide)
      modPositions = maspy.peptidemethods.returnModPositions(peptide,
                                                             indexStart=0,
                                                             removeModString=False)
  
      labelState = None
      #No amino acids in sequence which can bear a label modification
      #Note: at the moment presence of excluding modifications are ignored
      _validator = lambda seq, aa: (True if seq.find(aa) == -1 else False)
      if all([_validator(sequence, aa) for aa in labelAminoacids]):
          #No terminal label modifications specified by labelDescriptor
          if 'nTerm' not in labelAminoacids and 'cTerm' not in labelAminoacids:
              labelState = -1
  
      # Check if the peptide mofidifcations fit to any predicted label state
      if labelState is None:
          peptideLabelPositions = dict()
          for labelSymbol in labelSymbols:
              if labelSymbol in viewkeys(modPositions):
                  for sequencePosition in modPositions[labelSymbol]:
                      peptideLabelPositions.setdefault(sequencePosition, list())
                      peptideLabelPositions[sequencePosition].append(labelSymbol)
          for sequencePosition in list(viewkeys(peptideLabelPositions)):
              peptideLabelPositions[sequencePosition] = \
                  sorted(peptideLabelPositions[sequencePosition])
  
          predictedLabelStates = dict()
          for predictedLabelState, labelStateInfo in viewitems(labelDescriptor.labels):
              expectedLabelMods = expectedLabelPosition(peptide, labelStateInfo,
                                                        sequence=sequence,
                                                        modPositions=modPositions)
              predictedLabelStates[predictedLabelState] = expectedLabelMods
              if peptideLabelPositions == expectedLabelMods:
                  #If another expectedLabel state has already been matched, then
                  #there is an ambiguity between label states ...
                  labelState = predictedLabelState
  
      if labelState is None:
          # Peptide mofidifcations don't fit to any predicted label state
          labelState = -2
      elif labelState != -1:
          # Check if all predicted label states are distinguishable
          _comb = set(itertools.combinations(range(len(predictedLabelStates)), 2))
          for state1, state2 in _comb:
              if predictedLabelStates[state1] == predictedLabelStates[state2]:
                  labelState = -3
                  break
  
      return labelState