Files
cli/rscli/config.py
T
elordenador 7f1cb97742 Add new dependencies and update existing packages in uv.lock
- Added `certifi` version 2026.4.22 and `charset-normalizer` version 3.4.7 with multiple wheel options.
- Introduced `idna` version 3.14 and `prettytable` version 3.17.0 with their respective wheel files.
- Updated `requests` to version 2.34.0, including its dependencies.
- Added `urllib3` version 2.7.0 and `wcwidth` version 0.7.0 with their wheel files.
- Updated `cli` package metadata to include new dependencies: `prettytable` and `requests`.
2026-05-12 18:39:03 +02:00

137 lines
3.6 KiB
Python

from __future__ import annotations
import json
import re
from pathlib import Path
from typing import Any
class Config:
def __init__(self, file_path: str | Path | None = None) -> None:
default_path = Path.home() / ".config" / "rs-cli" / "config.json"
self.file_path = Path(file_path).expanduser() if file_path else default_path
self.data: dict[str, Any] = {}
def load(self) -> dict[str, Any]:
self.file_path.parent.mkdir(parents=True, exist_ok=True)
if not self.file_path.exists():
self.data = {}
self.save()
return self.data
content = self.file_path.read_text(encoding="utf-8").strip()
if not content:
self.data = {}
self.save()
return self.data
parsed = json.loads(content)
if not isinstance(parsed, dict):
raise ValueError("El archivo de configuracion debe contener un objeto JSON.")
self.data = parsed
return self.data
def save(self) -> None:
self.file_path.parent.mkdir(parents=True, exist_ok=True)
self.file_path.write_text(
json.dumps(self.data, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8",
)
def get(self, path: str, default: Any = None) -> Any:
tokens = self._parse_path(path)
current: Any = self.data
for token in tokens:
if isinstance(token, str):
if not isinstance(current, dict) or token not in current:
return default
current = current[token]
continue
if not isinstance(current, list) or token >= len(current):
return default
current = current[token]
return current
def set(self, path: str, value: Any) -> None:
tokens = self._parse_path(path)
current: Any = self.data
for idx, token in enumerate(tokens):
is_last = idx == len(tokens) - 1
next_token = None if is_last else tokens[idx + 1]
if isinstance(token, str):
if not isinstance(current, dict):
raise TypeError(f"No se puede usar clave '{token}' en un nodo no-dict.")
if is_last:
current[token] = value
break
expected_type = list if isinstance(next_token, int) else dict
if token not in current or current[token] is None:
current[token] = [] if expected_type is list else {}
elif not isinstance(current[token], expected_type):
current[token] = [] if expected_type is list else {}
current = current[token]
continue
if not isinstance(current, list):
raise TypeError(f"No se puede usar indice [{token}] en un nodo no-list.")
while len(current) <= token:
current.append(None)
if is_last:
current[token] = value
break
expected_type = list if isinstance(next_token, int) else dict
if current[token] is None or not isinstance(current[token], expected_type):
current[token] = [] if expected_type is list else {}
current = current[token]
self.save()
def _parse_path(self, path: str) -> list[str | int]:
if not path or not isinstance(path, str):
raise ValueError("La ruta no puede estar vacia.")
tokens: list[str | int] = []
for segment in path.split("."):
if not segment:
raise ValueError(f"Ruta invalida: '{path}'")
index = 0
if segment[0] != "[":
match = re.match(r"[^\[\]]+", segment)
if not match:
raise ValueError(f"Ruta invalida: '{path}'")
key = match.group(0)
tokens.append(key)
index = len(key)
while index < len(segment):
if segment[index] != "[":
raise ValueError(f"Ruta invalida: '{path}'")
end = segment.find("]", index)
if end == -1:
raise ValueError(f"Ruta invalida: '{path}'")
raw_index = segment[index + 1 : end]
if not raw_index.isdigit():
raise ValueError(f"Indice invalido en ruta: '{path}'")
tokens.append(int(raw_index))
index = end + 1
return tokens