Entrega Incremental 1 - Base del Proyecto TaskFlow
TaskFlow es un sistema de gestión de tareas que construirás durante todo el semestre. Esta entrega (E1) es la base. Todo lo que construyas aquí lo usarás en E2, E3, E4, E5 y E6. Es fundamental que quede bien.
Estas clases preparan los conocimientos necesarios para esta evaluación:
Implementar la capa de dominio del sistema TaskFlow utilizando Programación Orientada a Objetos avanzada en Python. Aplicar encapsulamiento, herencia, polimorfismo y clases abstractas.
Individual o en parejas (máximo 2 personas).
Formato de entrega: Repositorio GitHub con código fuente + README.md con instrucciones de ejecución. El repositorio debe ser privado y compartir acceso al docente.
Descripción: Representa un usuario del sistema TaskFlow que puede crear proyectos y tareas.
username (str, inmutable): Identificador único, mínimo 3 caracteres, solo letras y númerosemail (str): Correo electrónico validado (debe contener @ y .)nombre_completo (str, opcional): Nombre real del usuarioactivo (bool): Estado de la cuenta, por defecto Truefecha_registro (datetime): Se asigna automáticamente al crearactivar() -> None: Activa la cuenta del usuariodesactivar() -> None: Desactiva la cuenta__str__() -> str: Retorna @username__repr__() -> str: Retorna Usuario('username', 'email')ValueError con mensaje descriptivo si fallaDescripción: Un proyecto agrupa múltiples tareas y tiene un líder (Usuario).
nombre (str): Nombre del proyecto, mínimo 3 caracteresdescripcion (str, opcional): Descripción del proyectolider (Usuario): Referencia al usuario líder del proyectotareas (list[Tarea]): Lista de tareas, inicia vacía (composición)fecha_creacion (datetime): Se asigna automáticamenteagregar_tarea(tarea: Tarea) -> None: Agrega una tarea al proyectoobtener_tareas_pendientes() -> list[Tarea]: Retorna tareas no completadasobtener_tareas_por_prioridad(prioridad: PrioridadTarea) -> list[Tarea]__str__() -> str: Retorna el nombre del proyectoDescripción: Una tarea individual dentro de un proyecto con estado y prioridad.
titulo (str): Título de la tarea, mínimo 3 caracteresdescripcion (str, opcional): Detalles de la tareaprioridad (PrioridadTarea): Enum con valores ALTA, MEDIA, BAJAestado (EstadoTarea): Enum con valores PENDIENTE, EN_PROGRESO, COMPLETADAfecha_creacion (datetime): Se asigna automáticamentefecha_completado (datetime, opcional): Se asigna al completarcompletar() -> None: Marca la tarea como completada y registra fechacambiar_prioridad(nueva_prioridad: PrioridadTarea) -> Noneiniciar() -> None: Cambia estado a EN_PROGRESO__str__() -> str: Retorna [PRIORIDAD] titulo (estado)Descripción: Definir enumeraciones para tipos seguros usando enum.Enum.
ALTA = 1MEDIA = 2BAJA = 3PENDIENTE = "pendiente"EN_PROGRESO = "en_progreso"COMPLETADA = "completada"black o autopep8)ValueError con mensajes claros y descriptivos_, acceso vía @propertydef agregar_tarea(self, tarea: Tarea) -> None:
"""Agrega una tarea al proyecto.
Args:
tarea: La tarea a agregar. No puede ser None.
Raises:
ValueError: Si la tarea es None o ya existe en el proyecto.
"""
from datetime import datetime
from typing import Optional
class Usuario:
"""Representa un usuario en el sistema TaskFlow.
Attributes:
username: Identificador único del usuario (inmutable).
email: Correo electrónico validado.
nombre_completo: Nombre completo del usuario (opcional).
activo: Estado de la cuenta.
fecha_registro: Fecha de creación de la cuenta.
"""
def __init__(
self,
username: str,
email: str,
nombre_completo: Optional[str] = None
) -> None:
"""Inicializa un nuevo usuario.
Args:
username: Identificador único (mínimo 3 caracteres, alfanumérico).
email: Correo electrónico válido.
nombre_completo: Nombre completo opcional.
Raises:
ValueError: Si el username tiene menos de 3 caracteres.
ValueError: Si el email no tiene formato válido.
"""
if len(username) < 3:
raise ValueError("Username debe tener al menos 3 caracteres")
if not username.isalnum():
raise ValueError("Username solo puede contener letras y números")
self._username = username # Atributo privado (inmutable)
self._email = None
self.email = email # Usa el setter para validar
self.nombre_completo = nombre_completo
self.activo = True
self.fecha_registro = datetime.now()
@property
def username(self) -> str:
"""Username inmutable del usuario."""
return self._username
@property
def email(self) -> str:
"""Email del usuario."""
return self._email
@email.setter
def email(self, valor: str) -> None:
"""Valida y asigna el email.
Args:
valor: Email a validar.
Raises:
ValueError: Si el email no contiene @ o punto.
"""
if "@" not in valor or "." not in valor:
raise ValueError(f"Email inválido: {valor}")
self._email = valor
def activar(self) -> None:
"""Activa la cuenta del usuario."""
self.activo = True
def desactivar(self) -> None:
"""Desactiva la cuenta del usuario."""
self.activo = False
def __str__(self) -> str:
return f"@{self.username}"
def __repr__(self) -> str:
return f"Usuario('{self.username}', '{self.email}')"
Crear src/domain/ con los archivos __init__.py
Crear PrioridadTarea y EstadoTarea en enums.py
Con validaciones, properties y type hints
Usando los enums para prioridad y estado
Con la relación de composición con Tarea
Verificar que todo funcione correctamente
Cómo ejecutar el código y ejemplos de uso
| Criterio | Excelente (5.0) | Aceptable (3.5) | Insuficiente | Peso |
|---|---|---|---|---|
| Funcionalidad | Todas las clases funcionan correctamente, validaciones robustas, manejo de errores completo | Funciona pero validaciones básicas, algunos edge cases sin manejar | No funciona o faltan clases principales | 30% |
| Arquitectura POO | Excelente encapsulamiento, properties bien usadas, herencia aplicada donde corresponde | Uso básico de clases, algunos atributos públicos sin razón | No aplica POO, todo procedural o atributos públicos | 25% |
| Type Hints | 100% del código tipado correctamente, incluyendo Optional, Union donde corresponde | Mayoría tipado, algunos métodos sin tipar | Sin type hints o solo algunos | 20% |
| Documentación | Docstrings Google style completos en todas las clases y métodos públicos | Algunos docstrings presentes, formato inconsistente | Sin documentación o solo comentarios | 15% |
| Tests (bonus) | Tests exhaustivos con pytest, cubren edge cases y validaciones | Tests básicos funcionales, cobertura parcial | Sin tests | 10% |
El dominio que construyas aquí será la base para E2: Testing y Calidad. Asegúrate de que funcione correctamente porque lo testearás en la siguiente entrega.