def MultiDelete(self, urns, token=None):
    """Drop all the information about given objects.

    DANGEROUS! This recursively deletes all objects contained within the
    specified URN.

    Args:
      urns: Urns of objects to remove.
      token: The Security Token to use for opening this item.
    Raises:
      RuntimeError: If one of the urns is too short. This is a safety check to
      ensure the root is not removed.
    """
    urns = [rdfvalue.RDFURN(urn) for urn in urns]

    if token is None:
      token = data_store.default_token

    for urn in urns:
      if urn.Path() == "/":
        raise RuntimeError("Can't delete root URN. Please enter a valid URN")

    deletion_pool = DeletionPool(token=token)
    for urn in urns:
      deletion_pool.MarkForDeletion(urn)

    marked_root_urns = deletion_pool.root_urns_for_deletion
    marked_urns = deletion_pool.urns_for_deletion

    logging.debug(
        u"Found %d objects to remove when removing %s",
        len(marked_urns), urns)

    logging.debug(
        u"Removing %d root objects when removing %s: %s",
        len(marked_root_urns), urns, marked_root_urns)

    for root in marked_root_urns:
      # Only the index of the parent object should be updated. Everything
      # below the target object (along with indexes) is going to be
      # deleted.
      self._DeleteChildFromIndex(root, token)

    for urn_to_delete in marked_urns:
      try:
        self.intermediate_cache.ExpireObject(urn_to_delete.Path())
      except __HOLE__:
        pass

      data_store.DB.DeleteSubject(urn_to_delete, token=token, sync=False)
      logging.debug(u"%s deleted from data store", urn_to_delete)

    # Ensure this is removed from the cache as well.
    self.Flush()

    logging.debug("Removed %d objects", len(marked_urns))
dataset/ETHPy150Open google/grr/grr/lib/aff4.py/Factory.MultiDelete