eb8dbf66a1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
2.9 KiB
Python
85 lines
2.9 KiB
Python
"""Lee una nota de Obsidian (.md) desde disco y la descompone en sus partes.
|
|
|
|
Compone funciones puras del grupo obsidian: parse_obsidian_frontmatter y
|
|
extract_obsidian_wikilinks. Funcion impura: hace I/O de lectura de archivo.
|
|
"""
|
|
|
|
import os
|
|
|
|
from obsidian import extract_obsidian_wikilinks, parse_obsidian_frontmatter
|
|
|
|
|
|
def _normalize_tags(raw) -> list:
|
|
"""Normaliza el campo tags del frontmatter a una lista de strings.
|
|
|
|
Acepta None, un string CSV ("a, b, c") o una lista. Devuelve siempre
|
|
una lista de strings sin espacios sobrantes y sin entradas vacias.
|
|
"""
|
|
if raw is None:
|
|
return []
|
|
if isinstance(raw, str):
|
|
return [t.strip() for t in raw.split(",") if t.strip()]
|
|
if isinstance(raw, (list, tuple)):
|
|
return [str(t).strip() for t in raw if str(t).strip()]
|
|
# Cualquier otro tipo (int, etc.) -> representacion como unico tag.
|
|
return [str(raw).strip()] if str(raw).strip() else []
|
|
|
|
|
|
def read_obsidian_note(path: str) -> dict:
|
|
"""Lee una nota Markdown de Obsidian y devuelve sus partes estructuradas.
|
|
|
|
Args:
|
|
path: ruta al archivo .md a leer.
|
|
|
|
Returns:
|
|
dict con las claves:
|
|
- path: la ruta leida (tal cual fue pasada).
|
|
- frontmatter: dict con el frontmatter YAML parseado.
|
|
- body: str con el cuerpo Markdown sin el frontmatter.
|
|
- wikilinks: list con los destinos de los wikilinks [[...]] del body.
|
|
- tags: list normalizada a partir de frontmatter["tags"].
|
|
|
|
Raises:
|
|
FileNotFoundError: si el archivo no existe.
|
|
IsADirectoryError: si la ruta apunta a un directorio.
|
|
OSError: si la lectura falla por otro motivo de I/O.
|
|
"""
|
|
if not os.path.exists(path):
|
|
raise FileNotFoundError(f"obsidian note not found: {path}")
|
|
if os.path.isdir(path):
|
|
raise IsADirectoryError(f"expected a file, got a directory: {path}")
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
content = f.read()
|
|
|
|
parsed = parse_obsidian_frontmatter(content)
|
|
frontmatter = parsed.get("frontmatter", {}) or {}
|
|
body = parsed.get("body", "") or ""
|
|
|
|
wikilinks = extract_obsidian_wikilinks(body)
|
|
tags = _normalize_tags(frontmatter.get("tags"))
|
|
|
|
return {
|
|
"path": path,
|
|
"frontmatter": frontmatter,
|
|
"body": body,
|
|
"wikilinks": wikilinks,
|
|
"tags": tags,
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import tempfile
|
|
|
|
sample = "---\ntitle: Demo\ntags: [a, b]\n---\n\nHola [[Otra Nota]] y [[Tercera]].\n"
|
|
fd, tmp = tempfile.mkstemp(suffix=".md")
|
|
os.close(fd)
|
|
with open(tmp, "w", encoding="utf-8") as f:
|
|
f.write(sample)
|
|
note = read_obsidian_note(tmp)
|
|
assert note["frontmatter"].get("title") == "Demo", note["frontmatter"]
|
|
assert note["tags"] == ["a", "b"], note["tags"]
|
|
assert "Otra Nota" in note["wikilinks"], note["wikilinks"]
|
|
os.remove(tmp)
|
|
print("read_obsidian_note smoke OK")
|