helpers.py 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. """Document loader helpers."""
  2. import concurrent.futures
  3. from pathlib import Path
  4. from typing import NamedTuple, Optional, cast
  5. class FileEncoding(NamedTuple):
  6. """A file encoding as the NamedTuple."""
  7. encoding: Optional[str]
  8. """The encoding of the file."""
  9. confidence: float
  10. """The confidence of the encoding."""
  11. language: Optional[str]
  12. """The language of the file."""
  13. def detect_file_encodings(file_path: str, timeout: int = 5) -> list[FileEncoding]:
  14. """Try to detect the file encoding.
  15. Returns a list of `FileEncoding` tuples with the detected encodings ordered
  16. by confidence.
  17. Args:
  18. file_path: The path to the file to detect the encoding for.
  19. timeout: The timeout in seconds for the encoding detection.
  20. """
  21. import chardet
  22. def read_and_detect(file_path: str) -> list[dict]:
  23. rawdata = Path(file_path).read_bytes()
  24. return cast(list[dict], chardet.detect_all(rawdata))
  25. with concurrent.futures.ThreadPoolExecutor() as executor:
  26. future = executor.submit(read_and_detect, file_path)
  27. try:
  28. encodings = future.result(timeout=timeout)
  29. except concurrent.futures.TimeoutError:
  30. raise TimeoutError(f"Timeout reached while detecting encoding for {file_path}")
  31. if all(encoding["encoding"] is None for encoding in encodings):
  32. raise RuntimeError(f"Could not detect encoding for {file_path}")
  33. return [FileEncoding(**enc) for enc in encodings if enc["encoding"] is not None]