| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546 | """Document loader helpers."""import concurrent.futuresfrom typing import NamedTuple, Optional, castclass FileEncoding(NamedTuple):    """A file encoding as the NamedTuple."""    encoding: Optional[str]    """The encoding of the file."""    confidence: float    """The confidence of the encoding."""    language: Optional[str]    """The language of the file."""def detect_file_encodings(file_path: str, timeout: int = 5) -> list[FileEncoding]:    """Try to detect the file encoding.    Returns a list of `FileEncoding` tuples with the detected encodings ordered    by confidence.    Args:        file_path: The path to the file to detect the encoding for.        timeout: The timeout in seconds for the encoding detection.    """    import chardet    def read_and_detect(file_path: str) -> list[dict]:        with open(file_path, "rb") as f:            rawdata = f.read()        return cast(list[dict], chardet.detect_all(rawdata))    with concurrent.futures.ThreadPoolExecutor() as executor:        future = executor.submit(read_and_detect, file_path)        try:            encodings = future.result(timeout=timeout)        except concurrent.futures.TimeoutError:            raise TimeoutError(                f"Timeout reached while detecting encoding for {file_path}"            )    if all(encoding["encoding"] is None for encoding in encodings):        raise RuntimeError(f"Could not detect encoding for {file_path}")    return [FileEncoding(**enc) for enc in encodings if enc["encoding"] is not None]
 |