linvest21's picture
download
raw
3.24 kB
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
def load_structured(path: Path) -> dict[str, Any]:
text = path.read_text(encoding="utf-8")
if path.suffix.lower() == ".json":
return json.loads(text)
return parse_simple_yaml(text)
def write_json(path: Path, payload: dict[str, Any]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
def parse_scalar(value: str) -> Any:
value = value.strip()
if value == "":
return ""
if value in {"true", "True"}:
return True
if value in {"false", "False"}:
return False
if value in {"null", "None"}:
return None
if value.startswith("[") and value.endswith("]"):
inner = value[1:-1].strip()
if not inner:
return []
return [parse_scalar(part.strip()) for part in inner.split(",")]
if (value.startswith('"') and value.endswith('"')) or (value.startswith("'") and value.endswith("'")):
return value[1:-1]
try:
if "." in value:
return float(value)
return int(value)
except ValueError:
return value
def parse_simple_yaml(text: str) -> dict[str, Any]:
"""Parse the controlled YAML subset used by SHFT configs.
Supports nested mappings, scalar values, and simple list items. This is not
a general YAML parser; it is intentionally small to keep the MVP dependency-free.
"""
root: dict[str, Any] = {}
stack: list[tuple[int, Any]] = [(-1, root)]
last_key_at_indent: dict[int, str] = {}
for raw in text.splitlines():
if not raw.strip() or raw.lstrip().startswith("#"):
continue
indent = len(raw) - len(raw.lstrip(" "))
line = raw.strip()
while stack and indent <= stack[-1][0]:
stack.pop()
parent = stack[-1][1]
if line.startswith("- "):
item_text = line[2:].strip()
if not isinstance(parent, list):
raise ValueError(f"List item without list parent: {raw}")
if ":" in item_text and not item_text.startswith(("http://", "https://")):
key, value = item_text.split(":", 1)
item: dict[str, Any] = {key.strip(): parse_scalar(value)}
parent.append(item)
stack.append((indent, item))
else:
parent.append(parse_scalar(item_text))
continue
key, sep, value = line.partition(":")
if not sep:
raise ValueError(f"Invalid config line: {raw}")
key = key.strip()
value = value.strip()
if value == "":
next_container: dict[str, Any] | list[Any] = {}
parent[key] = next_container
last_key_at_indent[indent] = key
stack.append((indent, next_container))
else:
parent[key] = parse_scalar(value)
last_key_at_indent[indent] = key
# Second pass for blocks that should be lists but started as empty mappings.
# The MVP config files avoid ambiguous empty-list blocks; this hook exists for clarity.
return root

Xet Storage Details

Size:
3.24 kB
·
Xet hash:
b7fcd60f98684ea525ced8ba70b5869b66fc05b43c9c11d04278c48a0412fdc2

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.