"""
Configuración de rutas de datos.
Cada encuesta vive en su propia carpeta raíz, con la misma estructura que
generan los descargadores originales:
GEIH (serie principal) : <raiz>/datos_csv/<año>/<mes>/*.csv|*.txt|*.dta
GEIH (serie empalme) : <raiz>/datos_csv/<año>/<mes>/*.csv
EAM : <raiz>/datos/<año>/*.csv|*.txt|*.dta
Prioridad para resolver cada ruta:
1. ``set_paths(...)`` en la sesión actual.
2. Variables de entorno ``DANE_DATA_GEIH``, ``DANE_DATA_GEIH_EMPALME``, ``DANE_DATA_EAM``.
3. Archivo ``~/.config/dane_data/config.json`` (lo escribe ``save()`` y la app).
4. Valor por defecto bajo ``~/dane_data_datos/``.
"""
from __future__ import annotations
import json
import os
from pathlib import Path
CONFIG_FILE = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "dane_data" / "config.json"
CACHE_DIR = Path(os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache")) / "dane_data"
DEFAULT_HOME = Path.home() / "dane_data_datos"
_KEYS = {
"geih": ("DANE_DATA_GEIH", DEFAULT_HOME / "geih"),
"geih_empalme": ("DANE_DATA_GEIH_EMPALME", DEFAULT_HOME / "geih" / "empalme"),
"eam": ("DANE_DATA_EAM", DEFAULT_HOME / "eam"),
}
_session: dict[str, Path] = {}
def _read_file() -> dict:
try:
data = json.loads(CONFIG_FILE.read_text(encoding="utf-8"))
except (OSError, ValueError):
return {}
return data if isinstance(data, dict) else {} # un JSON que no es un objeto: como si no existiera
[documentos]
def get_path(key: str) -> Path:
"""
Carpeta raíz de una encuesta.
Se resuelve en este orden: ``set_paths`` en la sesión actual, la variable de entorno
(``DANE_DATA_GEIH``, ``DANE_DATA_GEIH_EMPALME`` o ``DANE_DATA_EAM``), el archivo
``~/.config/dane_data/config.json`` y, si nada de eso existe, ``~/dane_data_datos/``.
Parámetros
----------
key
``"geih"``, ``"geih_empalme"`` o ``"eam"``.
Devuelve
--------
Path
La carpeta, aunque todavía no exista.
Lanza
-----
KeyError
Si ``key`` no es una de las tres claves.
Véase también
-------------
set_paths : Cambiar las carpetas.
show_paths : Las tres carpetas a la vez.
Ejemplos
--------
>>> import dane_data as dd
>>> dd.get_path("geih") # doctest: +SKIP
PosixPath('/home/ana/dane_data_datos/geih')
"""
if key not in _KEYS:
raise KeyError(f"Clave desconocida {key!r}. Opciones: {list(_KEYS)}")
if key in _session:
return _session[key]
env, default = _KEYS[key]
if os.environ.get(env):
return Path(os.environ[env]).expanduser()
stored = _read_file().get(key)
if stored:
return Path(stored).expanduser()
return default
[documentos]
def set_paths(geih=None, geih_empalme=None, eam=None, save: bool = False) -> None:
"""
Fija las carpetas raíz de los datos.
Cada carpeta es la raíz de una encuesta: la GEIH queda en ``<raíz>/datos_csv/<año>/<mes>/`` y la EAM en
``<raíz>/datos/<año>/``. Las carpetas que no se indican no cambian.
Parámetros
----------
geih
Carpeta de la serie principal de la GEIH.
geih_empalme
Carpeta de la serie de empalme de la GEIH (2010–2020).
eam
Carpeta de la EAM.
save
Si True, guarda las carpetas indicadas en esta llamada en ``~/.config/dane_data/config.json``:
valen para las próximas sesiones, para la línea de comandos y para la aplicación. Si False, solo
para esta sesión.
Lanza
-----
ValueError
Si alguna carpeta es un texto vacío (sería la carpeta desde donde se ejecuta Python).
Véase también
-------------
get_path : Carpeta efectiva de una encuesta.
show_paths : Las tres carpetas efectivas.
Ejemplos
--------
>>> import dane_data as dd
>>> dd.set_paths(geih="~/datos/GEIH", eam="~/datos/EAM", save=True) # doctest: +SKIP
"""
nuevas = {k: v for k, v in (("geih", geih), ("geih_empalme", geih_empalme), ("eam", eam)) if v is not None}
if vacias := [k for k, v in nuevas.items() if not str(v).strip()]:
raise ValueError(f"Carpeta vacía para {', '.join(vacias)}: indique una ruta.")
for key, val in nuevas.items():
_session[key] = Path(val).expanduser()
if save:
# Solo las de esta llamada: las fijadas antes solo para la sesión no se vuelven permanentes
data = _read_file()
data.update({k: str(_session[k]) for k in nuevas})
CONFIG_FILE.parent.mkdir(parents=True, exist_ok=True)
tmp = CONFIG_FILE.with_name(f"{CONFIG_FILE.name}.tmp")
tmp.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
tmp.replace(CONFIG_FILE) # un corte a mitad de escritura no deja el archivo vacío
[documentos]
def show_paths() -> dict[str, str]:
"""
Carpetas efectivas de las tres encuestas.
Útil para revisar de dónde está leyendo la librería.
Devuelve
--------
dict
``{"geih": ..., "geih_empalme": ..., "eam": ...}`` con las rutas como texto.
Véase también
-------------
set_paths : Cambiar las carpetas.
Ejemplos
--------
>>> import dane_data as dd
>>> dd.show_paths() # doctest: +SKIP
{'geih': '/home/ana/datos/GEIH', 'geih_empalme': '/home/ana/dane_data_datos/geih/empalme', 'eam': '/home/ana/datos/EAM'}
"""
return {k: str(get_path(k)) for k in _KEYS}