code: def document_to_text(filename: str = None,
                       blob: bytes = None,
                       extension: str = None,
                       config: TextProcessingConfig = _DEFAULT_CONFIG) -> str:
      
      if not filename and not blob:
          raise ValueError("document_to_text: no filename and no blob")
      if filename and blob:
          raise ValueError("document_to_text: specify either filename or blob")
      if blob and not extension:
          raise ValueError("document_to_text: need extension hint for blob")
      if filename:
          stub, extension = os.path.splitext(filename)
      else:
          if extension[0] != ".":
              extension = "." + extension
      extension = extension.lower()
  
      # Ensure blob is an appropriate type
      log.debug(
          "filename: {}, blob type: {}, blob length: {}, extension: {}".format(
              filename,
              type(blob),
              len(blob) if blob is not None else None,
              extension))
  
      # If we were given a filename and the file doesn't exist, don't bother.
      if filename and not os.path.isfile(filename):
          raise ValueError("document_to_text: no such file: {!r}".format(
              filename))
  
      # Choose method
      info = ext_map.get(extension)
      if info is None:
          log.warning("Unknown filetype: {}; using generic tool", extension)
          info = ext_map[None]
      func = info[CONVERTER]
      return func(filename, blob, config)
docs: Converts a document to text.
  
      This function selects a processor based on the file extension (either from
      the filename, or, in the case of a BLOB, the extension specified manually
      via the ``extension`` parameter).
  
      Pass either a filename or a binary object.
  
      - Raises an exception for malformed arguments, missing files, bad
        filetypes, etc.
  
      - Returns a string if the file was processed (potentially an empty string).