From 0dc04716dc1902047ac02e01ce47052f5e26d9ed Mon Sep 17 00:00:00 2001 From: Kaia-Alenia Date: Tue, 21 Jul 2026 14:41:05 -0600 Subject: [PATCH 1/2] refactor(01-lista-de-tareas-cli): mejoras de UX, rutas CSV e IDs 1-based en CesarAAR-python --- .../soluciones/CesarAAR-python/Functions.py | 57 ++++---- .../soluciones/CesarAAR-python/Main.py | 129 +++++++++++------- .../soluciones/CesarAAR-python/Model.py | 2 +- .../soluciones/CesarAAR-python/test.csv | 6 - 4 files changed, 108 insertions(+), 86 deletions(-) delete mode 100644 retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/test.csv diff --git a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py index 798b7ad..f836b16 100644 --- a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py +++ b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py @@ -2,29 +2,34 @@ from pathlib import Path -def validar_ruta_csv(ruta): - try: - clean_path = ruta.strip("'\"") - path = Path(clean_path) - - if path.is_file(): - return True - else: - raise FileNotFoundError(f"Archivo no encontrado en la ruta: {path}") - except Exception as e: - raise e - - -def validar_contenido_csv(ruta): - try: - df = pd.read_csv(ruta) - required_columns = ["id", "titulo", "description", "estado"] - - if all(column in df.columns for column in required_columns): - return True - else: - raise ValueError( - f"El archivo CSV no contiene la estructura requerida: {required_columns}" - ) - except Exception as e: - raise e +BASE_DIR = Path(__file__).parent.resolve() + + +def obtener_ruta_absoluta(ruta: str) -> Path: + clean_path = ruta.strip("'\"") + path = Path(clean_path) + if not path.is_absolute(): + path = BASE_DIR / path + return path + + +def validar_ruta_csv(ruta: str) -> str: + path = obtener_ruta_absoluta(ruta) + + if path.is_file(): + return str(path) + raise FileNotFoundError(f"Archivo no encontrado en la ruta: {path}") + + +def validar_contenido_csv(ruta: str) -> bool: + # 2.- Leer la ruta ya limpia para validar su estructura + df = pd.read_csv(ruta, encoding="utf-8") + required_columns = ["id", "titulo", "description", "estado"] + + if all(column in df.columns for column in required_columns): + return True + + raise ValueError( + f"El archivo CSV no contiene la estructura requerida: {required_columns}" + ) + diff --git a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py index 42a17eb..c1efa36 100644 --- a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py +++ b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py @@ -1,10 +1,10 @@ from Model import Tareas import pandas as pd -from Functions import validar_ruta_csv, validar_contenido_csv +from Functions import validar_ruta_csv, validar_contenido_csv, obtener_ruta_absoluta df = pd.DataFrame(columns=["id", "titulo", "description", "estado"]) -id_task = 0 +id_task = 1 ruta_csv = "" @@ -12,6 +12,7 @@ def option1(): # Insertar Tarea try: global id_task + global df titulo_tarea = input("Ingrese el titulo de la tarea: ") description_tarea = input("Descripción de la tarea: ") estado_tarea = False @@ -22,7 +23,13 @@ def option1(): # Insertar Tarea estado=estado_tarea, ) id_task += 1 - df.loc[len(df)] = [tarea.id, tarea.titulo, tarea.description, tarea.estado] + nueva_fila = pd.DataFrame([{ + "id": tarea.id, + "titulo": tarea.titulo, + "description": tarea.description, + "estado": tarea.estado, + }]) + df = pd.concat([df, nueva_fila], ignore_index=True) print(f"Tarea creada: {tarea}\n") except Exception as e: print(f"Error al crear tarea: {e}") @@ -110,7 +117,11 @@ def option5(): # Ver tarea especifica def option6(): # ver lista de tareas - print(df) + if df.empty: + print("No hay tareas registradas.") + else: + print(df.to_string(index=False)) + def option7(): @@ -121,15 +132,15 @@ def option7(): if df.empty: ruta = input("Ingrese la ruta del archivo CSV: ") try: - if validar_ruta_csv(ruta): - if validar_contenido_csv(ruta): - ruta_csv = ruta - df_csv = pd.read_csv(ruta) - df = pd.concat([df, df_csv], ignore_index=True) - df["id"] = df["id"].astype(int) - df["estado"] = df["estado"].astype(bool) - id_task = df["id"].max() + 1 - print(df) + ruta_limpia = validar_ruta_csv(ruta) + if validar_contenido_csv(ruta_limpia): + ruta_csv = ruta_limpia + df_csv = pd.read_csv(ruta_limpia) + df = pd.concat([df, df_csv], ignore_index=True) + df["id"] = df["id"].astype(int) + df["estado"] = df["estado"].astype(bool) + id_task = df["id"].max() + 1 + print(df.to_string(index=False)) except Exception as e: print(f"Error durante el proceso de CSV:\n{e}") else: @@ -150,31 +161,21 @@ def option7(): print("Fusionando registros existentes con los del CSV...") ruta = input("Ingrese la ruta del archivo CSV: ") try: - if validar_ruta_csv(ruta): - if validar_contenido_csv(ruta): - ruta_csv = ruta - df_csv = pd.read_csv(ruta) - ultimo_id_df = df["id"].max() - primer_id_csv = df_csv["id"].min() - df_csv["id"] = ( - df_csv["id"] - primer_id_csv + (ultimo_id_df + 1) - ) - """ - Ejemplo del ajuste de IDs: - ultimo id del dataframe = 21 - primer id del csv = 0 - - id= 0 ; 0 - 0 + 21 + 1 = 22 - id= 1 ; 1 - 0 + 21 + 1 = 23 - ... - id= x; x - 0 + Y + 1 = Z - """ - df = pd.concat([df, df_csv], ignore_index=True) - df["id"] = df["id"].astype(int) - df["estado"] = df["estado"].astype(bool) - id_task = df["id"].max() + 1 - print(df) - break + ruta_limpia = validar_ruta_csv(ruta) + if validar_contenido_csv(ruta_limpia): + ruta_csv = ruta_limpia + df_csv = pd.read_csv(ruta_limpia) + ultimo_id_df = df["id"].max() + primer_id_csv = df_csv["id"].min() + df_csv["id"] = ( + df_csv["id"] - primer_id_csv + (ultimo_id_df + 1) + ) + df = pd.concat([df, df_csv], ignore_index=True) + df["id"] = df["id"].astype(int) + df["estado"] = df["estado"].astype(bool) + id_task = df["id"].max() + 1 + print(df.to_string(index=False)) + break except Exception as e: print(f"Error durante el proceso de CSV:\n{e}") break @@ -183,19 +184,19 @@ def option7(): "Eliminando registros existentes y reemplazando con los del CSV..." ) df = df.iloc[0:0] - id_task = 0 + id_task = 1 ruta = input("Ingrese la ruta del archivo CSV: ") try: - if validar_ruta_csv(ruta): - if validar_contenido_csv(ruta): - ruta_csv = ruta - df_csv = pd.read_csv(ruta) - df = pd.concat([df, df_csv], ignore_index=True) - df["id"] = df["id"].astype(int) - df["estado"] = df["estado"].astype(bool) - id_task = df["id"].max() + 1 - print(df) - break + ruta_limpia = validar_ruta_csv(ruta) + if validar_contenido_csv(ruta_limpia): + ruta_csv = ruta_limpia + df_csv = pd.read_csv(ruta_limpia) + df = pd.concat([df, df_csv], ignore_index=True) + df["id"] = df["id"].astype(int) + df["estado"] = df["estado"].astype(bool) + id_task = df["id"].max() + 1 + print(df.to_string(index=False)) + break except Exception as e: print(f"Error durante el proceso de CSV:\n{e}") else: @@ -205,13 +206,35 @@ def option7(): def option8(): global df global ruta_csv - print("Exportando información a archivo CSV...") + + if df.empty: + print("No hay datos para exportar. ¡Hasta luego!") + return + + destino = ruta_csv + + if ruta_csv: + print(f"Ruta actual configurada: {ruta_csv}") + print("1. Sobrescribir en el archivo importado") + print("2. Exportar a un nuevo archivo CSV") + opc = input("Seleccione una opción (1 o 2, por defecto 1): ").strip() + if opc == "2": + destino = input("Ingrese la nueva ruta o nombre del archivo CSV: ").strip("'\"") + else: + destino = input("Ingrese el nombre o ruta del archivo CSV para exportar (ej: tareas.csv): ").strip("'\"") + + if not destino: + destino = "tareas.csv" + + path_destino = obtener_ruta_absoluta(destino) + + print(f"Exportando información a archivo CSV: {path_destino}...") try: - df.to_csv(ruta_csv, index=False) - print(f"Información exportada correctamente: {ruta_csv}") + df.to_csv(path_destino, index=False, encoding="utf-8") + print(f"Información exportada correctamente en: {path_destino}") print("Bye Bye!") except Exception as e: - return f"Error al exportar a CSV: {e}" + print(f"Error al exportar a CSV: {e}") def menu(): diff --git a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py index 80e0654..6ea24b5 100644 --- a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py +++ b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py @@ -2,7 +2,7 @@ class Tareas(BaseModel): - id: int = Field(minimum=0) + id: int = Field(ge=1) # ge = greater than or equal to, mayor o igual a 1 titulo: str description: str estado: StrictBool # Se limita a solo True o False; True = Completado, False = Pendiente. diff --git a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/test.csv b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/test.csv deleted file mode 100644 index e921a7a..0000000 --- a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/test.csv +++ /dev/null @@ -1,6 +0,0 @@ -id,titulo,description,estado -0,test1,test1,False -1,test2,test2,False -2,s,s,False -3,s,s,True -4,test,test,False From f7ca4d662744a61b1eb5d7ad13e8ecdfa05ecac0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 21 Jul 2026 20:43:57 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=20[KAIA]=20Formateo=20m=C3=A1gico=20de=20c?= =?UTF-8?q?=C3=B3digo=20(Linter=20Compasivo)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../soluciones/CesarAAR-python/Functions.py | 2 -- .../soluciones/CesarAAR-python/Main.py | 29 +++++++++++-------- .../soluciones/CesarAAR-python/Model.py | 2 +- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py index f836b16..3ae267f 100644 --- a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py +++ b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Functions.py @@ -1,7 +1,6 @@ import pandas as pd from pathlib import Path - BASE_DIR = Path(__file__).parent.resolve() @@ -32,4 +31,3 @@ def validar_contenido_csv(ruta: str) -> bool: raise ValueError( f"El archivo CSV no contiene la estructura requerida: {required_columns}" ) - diff --git a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py index c1efa36..1f8c304 100644 --- a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py +++ b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Main.py @@ -23,12 +23,16 @@ def option1(): # Insertar Tarea estado=estado_tarea, ) id_task += 1 - nueva_fila = pd.DataFrame([{ - "id": tarea.id, - "titulo": tarea.titulo, - "description": tarea.description, - "estado": tarea.estado, - }]) + nueva_fila = pd.DataFrame( + [ + { + "id": tarea.id, + "titulo": tarea.titulo, + "description": tarea.description, + "estado": tarea.estado, + } + ] + ) df = pd.concat([df, nueva_fila], ignore_index=True) print(f"Tarea creada: {tarea}\n") except Exception as e: @@ -123,7 +127,6 @@ def option6(): # ver lista de tareas print(df.to_string(index=False)) - def option7(): global id_task global df @@ -167,9 +170,7 @@ def option7(): df_csv = pd.read_csv(ruta_limpia) ultimo_id_df = df["id"].max() primer_id_csv = df_csv["id"].min() - df_csv["id"] = ( - df_csv["id"] - primer_id_csv + (ultimo_id_df + 1) - ) + df_csv["id"] = df_csv["id"] - primer_id_csv + (ultimo_id_df + 1) df = pd.concat([df, df_csv], ignore_index=True) df["id"] = df["id"].astype(int) df["estado"] = df["estado"].astype(bool) @@ -219,9 +220,13 @@ def option8(): print("2. Exportar a un nuevo archivo CSV") opc = input("Seleccione una opción (1 o 2, por defecto 1): ").strip() if opc == "2": - destino = input("Ingrese la nueva ruta o nombre del archivo CSV: ").strip("'\"") + destino = input("Ingrese la nueva ruta o nombre del archivo CSV: ").strip( + "'\"" + ) else: - destino = input("Ingrese el nombre o ruta del archivo CSV para exportar (ej: tareas.csv): ").strip("'\"") + destino = input( + "Ingrese el nombre o ruta del archivo CSV para exportar (ej: tareas.csv): " + ).strip("'\"") if not destino: destino = "tareas.csv" diff --git a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py index 6ea24b5..0e685c4 100644 --- a/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py +++ b/retos/general/01-lista-de-tareas-cli/soluciones/CesarAAR-python/Model.py @@ -2,7 +2,7 @@ class Tareas(BaseModel): - id: int = Field(ge=1) # ge = greater than or equal to, mayor o igual a 1 + id: int = Field(ge=1) # ge = greater than or equal to, mayor o igual a 1 titulo: str description: str estado: StrictBool # Se limita a solo True o False; True = Completado, False = Pendiente.