Nanny7's picture
Phase 4: Infrastructure, Docker, Kubernetes, Chatbot with Qwen API
e566277
"""Main CLI interface for Todo application."""
import sys
from datetime import datetime
from ..models.todo import TodoStatus
from ..services.todo_service import (
AlreadyCompletedError,
InvalidTitleError,
TodoNotFoundError,
TodoService,
)
# =============================================================================
# CLI Helper Functions
# =============================================================================
def format_todo(todo) -> str:
"""Format todo for display.
Args:
todo: Todo object to format
Returns:
Formatted string representation
"""
description = todo.description if todo.description else "No description"
created_str = todo.created_at.strftime("%Y-%m-%d %H:%M:%S")
return (
f"ID: {todo.id}\n"
f"Title: {todo.title}\n"
f"Description: {description}\n"
f"Status: {todo.status.value}\n"
f"Created: {created_str}"
)
def format_todo_list_item(todo) -> str:
"""Format todo for list display.
Args:
todo: Todo object to format
Returns:
Formatted string for list view
"""
return f"ID: {todo.id} | Title: {todo.title} | Status: {todo.status.value}"
# =============================================================================
# CLI Commands
# =============================================================================
def cmd_create_todo(service: TodoService) -> None:
"""Create a new todo.
Args:
service: TodoService instance
"""
print("\n=== Create Todo ===")
title = input("Enter title (required): ").strip()
if not title:
print("\nERROR: Title cannot be empty.")
return
description = input("Enter description (optional, press Enter to skip): ").strip()
description = description if description else None
try:
todo = service.create_todo(title, description)
print("\n=== Todo Created Successfully ===")
print(format_todo(todo))
except (InvalidTitleError, Exception) as e:
print(f"\nERROR: {e}")
def cmd_list_todos(service: TodoService) -> None:
"""List all todos.
Args:
service: TodoService instance
"""
print("\n=== Your Todos ===")
todos = service.list_todos()
if not todos:
print("\nNo todos found.")
return
for todo in todos:
print(format_todo_list_item(todo))
def cmd_view_todo(service: TodoService) -> None:
"""View details of a specific todo.
Args:
service: TodoService instance
"""
print("\n=== View Todo ===")
todo_id_str = input("Enter todo ID: ").strip()
try:
todo_id = int(todo_id_str)
except ValueError:
print("\n❌ Error: Todo ID must be a number.")
return
try:
todo = service.get_todo_by_id(todo_id)
print("\n=== Todo Details ===")
print(format_todo(todo))
except TodoNotFoundError as e:
print(f"\nERROR: {e}")
def cmd_update_todo(service: TodoService) -> None:
"""Update an existing todo.
Args:
service: TodoService instance
"""
print("\n=== Update Todo ===")
todo_id_str = input("Enter todo ID: ").strip()
try:
todo_id = int(todo_id_str)
except ValueError:
print("\n❌ Error: Todo ID must be a number.")
return
# First, retrieve the todo to show current values
try:
current_todo = service.get_todo_by_id(todo_id)
except TodoNotFoundError as e:
print(f"\nERROR: {e}")
return
print(f"\nCurrent title: {current_todo.title}")
new_title = input("Enter new title (press Enter to keep current): ").strip()
print(f"\nCurrent description: {current_todo.description or 'No description'}")
new_description = input("Enter new description (press Enter to keep current): ").strip()
new_description = new_description if new_description else None
# If user provided empty input for both, nothing to update
if not new_title and new_description is None:
print("\nNo changes provided.")
return
try:
updated_todo = service.update_todo(
todo_id,
title=new_title if new_title else None,
description=new_description,
)
print("\n✅ Todo updated successfully!")
print(format_todo(updated_todo))
except (TodoNotFoundError, InvalidTitleError, Exception) as e:
print(f"\nERROR: {e}")
def cmd_complete_todo(service: TodoService) -> None:
"""Mark a todo as completed.
Args:
service: TodoService instance
"""
print("\n=== Complete Todo ===")
todo_id_str = input("Enter todo ID: ").strip()
try:
todo_id = int(todo_id_str)
except ValueError:
print("\n❌ Error: Todo ID must be a number.")
return
try:
todo = service.complete_todo(todo_id)
print("\n✅ Todo marked as completed!")
print(format_todo(todo))
except AlreadyCompletedError as e:
print(f"\nERROR: {e}")
except TodoNotFoundError as e:
print(f"\nERROR: {e}")
def cmd_delete_todo(service: TodoService) -> None:
"""Delete a todo.
Args:
service: TodoService instance
"""
print("\n=== Delete Todo ===")
todo_id_str = input("Enter todo ID: ").strip()
try:
todo_id = int(todo_id_str)
except ValueError:
print("\n❌ Error: Todo ID must be a number.")
return
try:
service.delete_todo(todo_id)
print(f"\n✅ Todo {todo_id} deleted successfully!")
except TodoNotFoundError as e:
print(f"\nERROR: {e}")
# =============================================================================
# Main Menu
# =============================================================================
def main_menu(service: TodoService) -> None:
"""Display main menu and handle user choices.
Args:
service: TodoService instance
"""
while True:
print("\n" + "=" * 40)
print("=== Todo App ===")
print("=" * 40)
print("1. Create Todo")
print("2. List Todos")
print("3. View Todo")
print("4. Update Todo")
print("5. Complete Todo")
print("6. Delete Todo")
print("7. Exit")
print("=" * 40)
choice = input("\nEnter choice (1-7): ").strip()
if choice == "1":
cmd_create_todo(service)
elif choice == "2":
cmd_list_todos(service)
elif choice == "3":
cmd_view_todo(service)
elif choice == "4":
cmd_update_todo(service)
elif choice == "5":
cmd_complete_todo(service)
elif choice == "6":
cmd_delete_todo(service)
elif choice == "7":
print("\n=== Goodbye! ===")
sys.exit(0)
else:
print("\nERROR: Invalid choice. Please enter a number between 1 and 7.")
# =============================================================================
# Entry Point
# =============================================================================
def main() -> None:
"""Main entry point for the CLI application."""
print("Welcome to Phase-1 In-Memory Todo App!")
print("All data is stored in memory and will be lost on exit.\n")
service = TodoService()
main_menu(service)
if __name__ == "__main__":
main()