[ADDED] Implementar parámetro --type para seleccionar tipo de programador

🤖 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 14:15:17 -05:00
parent 08dfaef620
commit a656592601
Signed by: mrosero
GPG key ID: 83BD2A5F674B7E26

View file

@ -257,21 +257,70 @@ def determine_cocomo_model(loc):
else: else:
return 'embedded' # Proyectos grandes (más de 300K líneas) return 'embedded' # Proyectos grandes (más de 300K líneas)
def get_fullstack_rate(): def get_available_programmer_types():
""" """
Obtiene la tarifa por hora de un desarrollador fullstack desde el archivo de configuración. Obtiene una lista de los tipos de programadores disponibles
Si el archivo no existe, devuelve un valor predeterminado de 45.00 USD/hora. basados en los archivos .rate existentes en el directorio de tarifas.
Returns:
List: Lista de tipos de programadores disponibles
"""
if not RATES_DIR.exists():
logger.warning(f"El directorio de tarifas no existe: {RATES_DIR}")
return ['fullstack'] # Por defecto solo fullstack si no hay directorio
try:
# Buscar archivos .rate en el directorio
rate_files = list(RATES_DIR.glob('*.rate'))
# Extraer nombres de programadores de los nombres de archivo
programmer_types = [file.stem for file in rate_files]
if not programmer_types:
logger.warning("No se encontraron archivos de tarifas. Usando solo 'fullstack' por defecto.")
return ['fullstack']
return sorted(programmer_types)
except Exception as e:
logger.error(f"Error al buscar tipos de programadores disponibles: {e}")
return ['fullstack'] # En caso de error, devolver tipo por defecto
def get_programmer_rate(programmer_type='fullstack'):
"""
Obtiene la tarifa por hora de un tipo específico de programador desde el archivo de configuración.
Si el archivo no existe, devuelve un valor predeterminado según el tipo.
Args:
programmer_type: Tipo de programador (por defecto: 'fullstack')
Returns: Returns:
Float: Tarifa por hora en USD Float: Tarifa por hora en USD
""" """
rate_file = RATES_DIR / "fullstack.rate" rate_file = RATES_DIR / f"{programmer_type}.rate"
# Valores predeterminados por tipo de programador
default_rates = {
'fullstack': 45.00,
'frontend': 40.00,
'backend': 42.00,
'devops': 50.00,
'python': 35.00,
'java': 40.00,
'php': 30.00,
'mobile': 45.00,
'data': 55.00,
'ml': 65.00,
'cloud': 60.00,
'bash': 20.00
}
default_rate = default_rates.get(programmer_type, 40.00)
# Comprobar si existe el archivo # Comprobar si existe el archivo
if not rate_file.exists(): if not rate_file.exists():
logger.warning(f"No se encontró el archivo de tarifa: {rate_file}") logger.warning(f"No se encontró el archivo de tarifa: {rate_file}")
logger.warning("Usando tarifa predeterminada de 45.00 USD/hora") logger.warning(f"Usando tarifa predeterminada de {default_rate:.2f} USD/hora para {programmer_type}")
return 45.00 return default_rate
# Leer la tarifa del archivo # Leer la tarifa del archivo
try: try:
@ -281,8 +330,8 @@ def get_fullstack_rate():
return rate return rate
except (FileNotFoundError, ValueError, IOError) as e: except (FileNotFoundError, ValueError, IOError) as e:
logger.warning(f"Error al leer el archivo de tarifa {rate_file}: {e}") logger.warning(f"Error al leer el archivo de tarifa {rate_file}: {e}")
logger.warning("Usando tarifa predeterminada de 45.00 USD/hora") logger.warning(f"Usando tarifa predeterminada de {default_rate:.2f} USD/hora para {programmer_type}")
return 45.00 return default_rate
def print_results(results): def print_results(results):
""" """
@ -307,13 +356,19 @@ def print_results(results):
print("=====================================================\n") print("=====================================================\n")
if __name__ == "__main__": if __name__ == "__main__":
# Obtener los tipos de programadores disponibles para el parámetro --type
available_types = get_available_programmer_types()
available_types_str = ', '.join(available_types)
# Parámetros de línea de comandos # Parámetros de línea de comandos
parser = argparse.ArgumentParser(description='Calculadora COCOMO para estimar costos de proyectos de software') parser = argparse.ArgumentParser(description='Calculadora COCOMO para estimar costos de proyectos de software')
parser.add_argument('--project', required=True, help='Ruta del directorio del proyecto a analizar') parser.add_argument('--project', required=True, help='Ruta del directorio del proyecto a analizar')
parser.add_argument('--model', choices=['organic', 'semi-detached', 'embedded', 'auto'], parser.add_argument('--model', choices=['organic', 'semi-detached', 'embedded', 'auto'],
default='auto', help='Tipo de modelo COCOMO a utilizar (por defecto: auto)') default='auto', help='Tipo de modelo COCOMO a utilizar (por defecto: auto)')
parser.add_argument('--type', choices=available_types, default='fullstack',
help=f'Tipo de programador para calcular costos (por defecto: fullstack). Disponibles: {available_types_str}')
parser.add_argument('--cost', type=float, parser.add_argument('--cost', type=float,
help='Costo por persona-mes en USD (por defecto: tarifa fullstack × 176)') help='Costo por persona-mes en USD (por defecto: tarifa del tipo de programador × 176)')
parser.add_argument('--ignore', action='append', parser.add_argument('--ignore', action='append',
help='Patrones adicionales de archivos a ignorar') help='Patrones adicionales de archivos a ignorar')
parser.add_argument('--ext', action='append', parser.add_argument('--ext', action='append',
@ -348,16 +403,18 @@ if __name__ == "__main__":
except Exception as e: except Exception as e:
logger.error(f"Error al crear el directorio de tarifas: {e}") logger.error(f"Error al crear el directorio de tarifas: {e}")
# Obtener costo por hora desde fullstack.rate y convertir a costo por persona-mes # Obtener tipo de programador y su tarifa
programmer_type = 'fullstack' # Por defecto usamos la tarifa de fullstack programmer_type = args.type # Usar el tipo especificado por el usuario
# Obtener costo por hora desde el archivo .rate y convertir a costo por persona-mes
if args.cost is None: if args.cost is None:
# Obtener la tarifa por hora y multiplicar por las horas mensuales # Obtener la tarifa por hora y multiplicar por las horas mensuales
hourly_rate = get_fullstack_rate() hourly_rate = get_programmer_rate(programmer_type)
cost_per_pm = hourly_rate * HOURS_PER_MONTH cost_per_pm = hourly_rate * HOURS_PER_MONTH
logger.info(f"Costo por hora ({programmer_type}): ${hourly_rate:.2f} × {HOURS_PER_MONTH} horas = ${cost_per_pm:.2f} por persona-mes") logger.info(f"Costo por hora ({programmer_type}): ${hourly_rate:.2f} × {HOURS_PER_MONTH} horas = ${cost_per_pm:.2f} por persona-mes")
else: else:
cost_per_pm = args.cost cost_per_pm = args.cost
programmer_type = 'personalizado' # Si se especifica manualmente programmer_type = f"{programmer_type} (personalizado)" # Indicar que es un valor personalizado
hourly_rate = cost_per_pm / HOURS_PER_MONTH hourly_rate = cost_per_pm / HOURS_PER_MONTH
logger.info(f"Usando costo por persona-mes especificado: ${cost_per_pm:.2f} (${hourly_rate:.2f}/hora)") logger.info(f"Usando costo por persona-mes especificado: ${cost_per_pm:.2f} (${hourly_rate:.2f}/hora)")