Coverage for src/local_deep_research/document_loaders/toml_loader.py: 100%
23 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-22 21:20 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-22 21:20 +0000
1"""Load TOML with Python's bundled parser, within the shared TOML limits."""
3import json
4from pathlib import Path
5from typing import Iterator
7from langchain_core.document_loaders import BaseLoader
8from langchain_core.documents import Document
10from ..security import toml_limits
13def _read_limited_text(path: Path) -> str:
14 """Return *path*'s text without reading past the TOML size limit."""
15 with path.open("rb") as stream:
16 content = stream.read(toml_limits.MAX_TOML_BYTES + 1)
17 # Checked before decoding, so a read cut off inside a multi-byte
18 # character is reported as too large rather than as invalid UTF-8.
19 toml_limits.check_toml_size(len(content))
20 return content.decode()
23class TOMLLoader(BaseLoader):
24 """Load a TOML file or directory without requiring the tomli backport.
26 Each file is refused with TOMLLimitError, before tomllib parses it, when
27 it is larger than MAX_TOML_BYTES or has a key or table header of more
28 than MAX_TOML_KEY_PARTS dotted parts (see security.toml_limits).
29 """
31 def __init__(self, source: str | Path):
32 # nosemgrep: semgrep.rules.path-traversal-risk, reason: load_from_bytes passes the temp file it wrote; no route passes a request path
33 self.source = Path(source)
35 def lazy_load(self) -> Iterator[Document]:
36 if self.source.is_file() and self.source.suffix.lower() == ".toml":
37 files = [self.source]
38 elif self.source.is_dir():
39 files = sorted(self.source.rglob("*.toml"))
40 else:
41 raise ValueError("Invalid source path or file type")
43 for file_path in files:
44 data = toml_limits.loads_toml_within_limits(
45 _read_limited_text(file_path)
46 )
47 yield Document(
48 page_content=json.dumps(data, ensure_ascii=False, default=str),
49 metadata={"source": str(file_path)},
50 )