[IMPROVED] Mejorar manejo de dependencias en rate_update.py

- Añadir detección robusta de pip y manejo de errores
- Incluir lista predefinida de códigos de país cuando pycountry no está disponible
- Corregir problemas de inicialización de logging
- Mejor manejo de errores y mensajes informativos
- Funcionamiento garantizado incluso sin pycountry instalado

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mauro Rosero P. 2025-03-12 08:55:00 -05:00
parent b8ae14fbe3
commit 83c9049cf5
Signed by: mrosero
GPG key ID: 83BD2A5F674B7E26

View file

@ -20,22 +20,6 @@ import subprocess
import importlib.util import importlib.util
from pathlib import Path from pathlib import Path
# Verificar si pycountry está instalado, si no, instalarlo
def check_install_pycountry():
"""Verifica si pycountry está instalado y lo instala si es necesario."""
if importlib.util.find_spec("pycountry") is None:
logger.info("Instalando la biblioteca pycountry...")
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "pycountry"])
logger.info("Biblioteca pycountry instalada correctamente.")
except subprocess.CalledProcessError as e:
logger.error(f"Error al instalar pycountry: {e}")
sys.exit(1)
# Ahora importamos pycountry
global pycountry
import pycountry
# Configuración de logging # Configuración de logging
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
@ -44,6 +28,48 @@ logging.basicConfig(
) )
logger = logging.getLogger('rate_update') logger = logging.getLogger('rate_update')
# Verificar si pycountry está instalado, si no, instalarlo
def check_install_pycountry():
"""Verifica si pycountry está instalado y lo instala si es necesario."""
if importlib.util.find_spec("pycountry") is None:
logger.info("La biblioteca pycountry no está instalada.")
# Verificar si pip está disponible
try:
# Primero comprobamos si pip está instalado
pip_check = subprocess.run([sys.executable, "-m", "pip", "--version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
if pip_check.returncode == 0:
logger.info("Instalando la biblioteca pycountry...")
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "pycountry"])
logger.info("Biblioteca pycountry instalada correctamente.")
except subprocess.CalledProcessError as e:
logger.error(f"Error al instalar pycountry: {e}")
logger.warning("Continuando sin validación de códigos de país.")
return False
else:
logger.warning("pip no está instalado. No se puede instalar pycountry automáticamente.")
logger.warning("Por favor, instale pycountry manualmente: sudo apt-get install python3-pycountry")
logger.warning("Continuando sin validación de códigos de país.")
return False
except FileNotFoundError:
logger.warning("No se pudo ejecutar pip. Por favor instale pycountry manualmente.")
logger.warning("Continuando sin validación de códigos de país.")
return False
# Intentamos importar pycountry
try:
global pycountry
import pycountry
return True
except ImportError:
logger.warning("No se puede importar pycountry. Continuando sin validación de códigos de país.")
return False
# Directorio base del proyecto # Directorio base del proyecto
BASE_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) BASE_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
CONFIG_DIR = BASE_DIR / 'bin' / 'config' CONFIG_DIR = BASE_DIR / 'bin' / 'config'
@ -118,21 +144,59 @@ def query_perplexity(prompt, model="o1"):
logger.error(f"Error al conectar con la API de Perplexity: {e}") logger.error(f"Error al conectar con la API de Perplexity: {e}")
return None return None
# Variable global para indicar si pycountry está disponible
pycountry_available = False
def is_valid_country_code(code): def is_valid_country_code(code):
""" """
Verifica si un código de país de 2 letras es válido según pycountry. Verifica si un código de país de 2 letras es válido.
Usa pycountry si está disponible, o una lista básica de códigos comunes.
También acepta códigos especiales 'ww' y 'la'. También acepta códigos especiales 'ww' y 'la'.
""" """
if code in ['ww', 'la']: # Códigos especiales: worldwide y Latin America # Códigos especiales para propósitos internos
if code in ['ww', 'la']: # worldwide y Latin America
return True return True
try: # Lista básica de códigos de país comunes (ISO 3166-1 alpha-2)
# Verifica si el código existe en pycountry common_country_codes = [
return pycountry.countries.get(alpha_2=code.upper()) is not None 'af', 'al', 'dz', 'as', 'ad', 'ao', 'ai', 'aq', 'ag', 'ar',
except AttributeError: 'am', 'aw', 'au', 'at', 'az', 'bs', 'bh', 'bd', 'bb', 'by',
# Si hay un error con pycountry, asumimos que el código es válido 'be', 'bz', 'bj', 'bm', 'bt', 'bo', 'ba', 'bw', 'br', 'bn',
logger.warning(f"No se pudo validar el código de país '{code}' con pycountry") 'bg', 'bf', 'bi', 'cv', 'kh', 'cm', 'ca', 'ky', 'cf', 'td',
return True 'cl', 'cn', 'co', 'km', 'cg', 'cd', 'ck', 'cr', 'ci', 'hr',
'cu', 'cy', 'cz', 'dk', 'dj', 'dm', 'do', 'ec', 'eg', 'sv',
'gq', 'er', 'ee', 'et', 'fk', 'fo', 'fj', 'fi', 'fr', 'gf',
'pf', 'ga', 'gm', 'ge', 'de', 'gh', 'gi', 'gr', 'gl', 'gd',
'gp', 'gu', 'gt', 'gn', 'gw', 'gy', 'ht', 'va', 'hn', 'hk',
'hu', 'is', 'in', 'id', 'ir', 'iq', 'ie', 'il', 'it', 'jm',
'jp', 'jo', 'kz', 'ke', 'ki', 'kp', 'kr', 'kw', 'kg', 'la',
'lv', 'lb', 'ls', 'lr', 'ly', 'li', 'lt', 'lu', 'mo', 'mk',
'mg', 'mw', 'my', 'mv', 'ml', 'mt', 'mh', 'mq', 'mr', 'mu',
'yt', 'mx', 'fm', 'md', 'mc', 'mn', 'me', 'ms', 'ma', 'mz',
'mm', 'na', 'nr', 'np', 'nl', 'nc', 'nz', 'ni', 'ne', 'ng',
'nu', 'nf', 'mp', 'no', 'om', 'pk', 'pw', 'ps', 'pa', 'pg',
'py', 'pe', 'ph', 'pn', 'pl', 'pt', 'pr', 'qa', 're', 'ro',
'ru', 'rw', 'bl', 'sh', 'kn', 'lc', 'mf', 'pm', 'vc', 'ws',
'sm', 'st', 'sa', 'sn', 'rs', 'sc', 'sl', 'sg', 'sx', 'sk',
'si', 'sb', 'so', 'za', 'gs', 'ss', 'es', 'lk', 'sd', 'sr',
'sj', 'sz', 'se', 'ch', 'sy', 'tw', 'tj', 'tz', 'th', 'tl',
'tg', 'tk', 'to', 'tt', 'tn', 'tr', 'tm', 'tc', 'tv', 'ug',
'ua', 'ae', 'gb', 'us', 'uy', 'uz', 'vu', 've', 'vn', 'vg',
'vi', 'wf', 'eh', 'ye', 'zm', 'zw'
]
# Si pycountry está disponible, lo usamos para validación
global pycountry_available
if pycountry_available:
try:
# Verifica si el código existe en pycountry
return pycountry.countries.get(alpha_2=code.upper()) is not None
except (AttributeError, Exception) as e:
logger.warning(f"Error al validar el código de país '{code}' con pycountry: {e}")
# Fallback a la lista básica
# Si pycountry no está disponible o falló, usamos la lista básica
return code.lower() in common_country_codes
def parse_rate_filename(filename): def parse_rate_filename(filename):
""" """
@ -254,10 +318,18 @@ def update_rate_files():
(f" en región {region_code}" if region_code else "")) (f" en región {region_code}" if region_code else ""))
if __name__ == "__main__": if __name__ == "__main__":
logger.info("Iniciando actualización de tarifas...") logger.info("Iniciando actualización de tarifas...")
# Verificar e instalar pycountry si es necesario # Verificar e instalar pycountry si es necesario
check_install_pycountry() global pycountry_available
pycountry_available = check_install_pycountry()
# Mostrar estado de validación de países
if pycountry_available:
logger.info("Validación de códigos de país habilitada con pycountry.")
else:
logger.info("Usando lista interna para validación básica de códigos de país.")
# Actualizar los archivos de tarifas # Actualizar los archivos de tarifas
update_rate_files() update_rate_files()