docs: def annotations(obj: BioCCollection or BioCDocument or BioCPassage or BioCSentence,
                  docid: str = None, level: int = PASSAGE) -> Generator[BioCAnnotation, None, None]:
      """
      Get all annotations in document id.
  
      Args:
          obj: BioCCollection, BioCDocument, BioCPassage, or BioCSentence
          docid: document id. If None, all documents
          level: one of DOCUMENT, PASSAGE, SENTENCE
  
      Yields:
          one annotation
      """
      if isinstance(obj, BioCCollection):
          for document in filter(lambda d: docid is None or docid == d.id, obj.documents):
              yield from annotations(document, level=level)
      elif isinstance(obj, BioCDocument):
          if level == DOCUMENT:
              yield from obj.annotations
          elif level in (PASSAGE, SENTENCE):
              for passage in obj.passages:
                  yield from annotations(passage, level=level)
          else:
              raise ValueError('level must be DOCUMENT, PASSAGE, or SENTENCE')
      elif isinstance(obj, BioCPassage):
          if level == PASSAGE:
              yield from obj.annotations
          elif level == SENTENCE:
              for sentence in obj.sentences:
                  yield from annotations(sentence, level=level)
          else:
              raise ValueError('level must be PASSAGE or SENTENCE')
      elif isinstance(obj, BioCSentence):
          if level == SENTENCE:
              yield from obj.annotations
          else:
              raise ValueError('level must be SENTENCE')
      else:
          raise TypeError(f'Object of type {obj.__class__.__name__} must be BioCCollection, '
                          f'BioCDocument, BioCPassage, or BioCSentence')