Ferramentas/AjustaFundos/actions/config/config_ini.py

91 lines
3.5 KiB
Python

# Importa o módulo padrão do Python para ler arquivos INI (.ini)
import configparser
# Importa Path, que facilita o trabalho com caminhos de arquivos (mais seguro que strings)
from pathlib import Path
# Importa tipos para anotações — Dict (dicionário) e Any (qualquer tipo)
from typing import Dict, Any
# Define uma classe chamada ConfigIni
class ConfigIni:
@staticmethod
def read(path: str) -> Dict[str, Any]:
"""
Lê um arquivo INI (ignorando comentários iniciados por ';')
e retorna um dicionário com suas seções e pares chave=valor.
Tenta múltiplas codificações comuns no Windows:
- utf-8
- utf-8-sig
- latin-1
- cp1252
"""
# Converte o caminho recebido (string) em um objeto Path (mais seguro e portável)
config_path = Path(path)
# Verifica se o arquivo realmente existe no caminho informado
if not config_path.exists():
# Caso não exista, lança uma exceção com uma mensagem explicativa
raise FileNotFoundError(f"Arquivo não encontrado: {path}")
# Lista de codificações a tentar, em ordem de preferência
encodings_to_try = ["utf-8", "utf-8-sig", "latin-1", "cp1252"]
last_error: Exception | None = None
config: configparser.ConfigParser | None = None
# Tenta ler o arquivo usando diferentes encodings
for enc in encodings_to_try:
try:
tmp_config = configparser.ConfigParser()
# Garante que as chaves mantenham o mesmo formato de maiúsculas/minúsculas
# Por padrão, o configparser converte tudo para minúsculas.
tmp_config.optionxform = str
# Tenta ler o arquivo com a codificação atual
tmp_config.read(config_path, encoding=enc)
# Se chegou aqui sem UnicodeDecodeError, consideramos que deu certo
config = tmp_config
break
except UnicodeDecodeError as e:
# Guarda o último erro para caso nenhuma codificação funcione
last_error = e
continue
# Se nenhuma codificação funcionou, levanta um erro mais amigável
if config is None:
msg = (
f"Não foi possível decodificar o arquivo INI '{path}' "
f"usando as codificações: {', '.join(encodings_to_try)}"
)
if last_error:
raise UnicodeDecodeError(
last_error.encoding or "utf-8",
last_error.object,
last_error.start,
last_error.end,
msg,
)
raise RuntimeError(msg)
# Cria um dicionário vazio que armazenará os dados lidos do INI
data: Dict[str, Dict[str, Any]] = {}
# Percorre cada seção do arquivo INI (exemplo: [Geral], [Banco], etc.)
for section in config.sections():
# Cria um dicionário interno para armazenar as chaves e valores dessa seção
data[section] = {}
# Percorre todas as chaves e valores da seção atual
for key, value in config.items(section):
# .strip() remove espaços no início/fim
# .strip("'\"") remove aspas simples ou duplas em volta do valor (se existirem)
data[section][key] = value.strip().strip("'\"")
# Retorna o dicionário completo contendo todas as seções e seus pares chave=valor
return data