Archive
This commit is contained in:
1 parent
206997510c
commit
251bd3e65f
14 files changed
+836
No files matched your search
@@ -0,0 +1,213 @@
|
||||
"""Main entry point and CLI interface for the Todo CLI application.
|
||||
|
||||
This module defines the TodoCLI class that handles command-line argument
|
||||
parsing and user interaction, as well as the main() function to start
|
||||
the application.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from typing import List, Optional
|
||||
|
||||
from todo import TodoManager
|
||||
from storage import Storage
|
||||
|
||||
|
||||
class TodoCLI:
|
||||
"""Command-line interface for managing todo items.
|
||||
|
||||
Attributes:
|
||||
manager: The TodoManager instance handling business logic.
|
||||
parser: The ArgumentParser for parsing command-line arguments.
|
||||
"""
|
||||
|
||||
def __init__(self, manager: TodoManager) -> None:
|
||||
"""Initialize the CLI with a TodoManager.
|
||||
|
||||
Args:
|
||||
manager: A TodoManager instance for data operations.
|
||||
"""
|
||||
self.manager = manager
|
||||
self.parser = argparse.ArgumentParser(
|
||||
description="A simple CLI todo list manager."
|
||||
)
|
||||
self._setup_parser()
|
||||
|
||||
def _setup_parser(self) -> None:
|
||||
"""Configure subparsers for each command."""
|
||||
subparsers = self.parser.add_subparsers(dest="command", help="Available commands")
|
||||
|
||||
# add command
|
||||
add_parser = subparsers.add_parser("add", help="Add a new todo item")
|
||||
add_parser.add_argument("title", type=str, help="Title of the task")
|
||||
add_parser.add_argument("-d", "--description", type=str, default="",
|
||||
help="Description of the task")
|
||||
add_parser.add_argument("-due", "--due_date", type=str, default="",
|
||||
help="Due date (e.g., 2025-01-01)")
|
||||
|
||||
# list command
|
||||
list_parser = subparsers.add_parser("list", help="List all todo items")
|
||||
list_parser.add_argument("-s", "--status", type=str, choices=["done", "pending"],
|
||||
help="Filter by completion status")
|
||||
|
||||
# done command
|
||||
done_parser = subparsers.add_parser("done", help="Mark a todo item as completed")
|
||||
done_parser.add_argument("item_id", type=int, help="ID of the item to mark done")
|
||||
|
||||
# undone command
|
||||
undone_parser = subparsers.add_parser("undone", help="Mark a todo item as not completed")
|
||||
undone_parser.add_argument("item_id", type=int, help="ID of the item to mark undone")
|
||||
|
||||
# delete command
|
||||
delete_parser = subparsers.add_parser("delete", help="Delete a todo item")
|
||||
delete_parser.add_argument("item_id", type=int, help="ID of the item to delete")
|
||||
|
||||
# edit command
|
||||
edit_parser = subparsers.add_parser("edit", help="Edit a todo item")
|
||||
edit_parser.add_argument("item_id", type=int, help="ID of the item to edit")
|
||||
edit_parser.add_argument("--title", type=str, default=None,
|
||||
help="New title (leave unchanged if omitted)")
|
||||
edit_parser.add_argument("--description", type=str, default=None,
|
||||
help="New description (leave unchanged if omitted)")
|
||||
edit_parser.add_argument("--due_date", type=str, default=None,
|
||||
help="New due date (leave unchanged if omitted)")
|
||||
edit_parser.add_argument("--completed", type=str, choices=["true", "false"],
|
||||
default=None,
|
||||
help="Set completion status (true/false)")
|
||||
|
||||
def run(self, args: Optional[List[str]] = None) -> None:
|
||||
"""Parse arguments and execute the corresponding command.
|
||||
|
||||
Args:
|
||||
args: Command-line arguments (defaults to sys.argv[1:]).
|
||||
"""
|
||||
parsed_args = self.parser.parse_args(args)
|
||||
|
||||
if parsed_args.command is None:
|
||||
self.parser.print_help()
|
||||
return
|
||||
|
||||
command_handlers = {
|
||||
"add": self._handle_add,
|
||||
"list": self._handle_list,
|
||||
"done": self._handle_done,
|
||||
"undone": self._handle_undone,
|
||||
"delete": self._handle_delete,
|
||||
"edit": self._handle_edit,
|
||||
}
|
||||
|
||||
handler = command_handlers.get(parsed_args.command)
|
||||
if handler:
|
||||
handler(parsed_args)
|
||||
else:
|
||||
self.parser.print_help()
|
||||
|
||||
def _handle_add(self, args: argparse.Namespace) -> None:
|
||||
"""Handle the 'add' command.
|
||||
|
||||
Args:
|
||||
args: Parsed arguments containing title, description, due_date.
|
||||
"""
|
||||
item = self.manager.add(args.title, args.description, args.due_date)
|
||||
print(f"Added todo item #{item.id}: {item.title}")
|
||||
|
||||
def _handle_list(self, args: argparse.Namespace) -> None:
|
||||
"""Handle the 'list' command.
|
||||
|
||||
Args:
|
||||
args: Parsed arguments (may contain status filter).
|
||||
"""
|
||||
if args.status == "done":
|
||||
items = self.manager.list_by_status(True)
|
||||
elif args.status == "pending":
|
||||
items = self.manager.list_by_status(False)
|
||||
else:
|
||||
items = self.manager.list_all()
|
||||
|
||||
if not items:
|
||||
print("No todo items found.")
|
||||
return
|
||||
|
||||
# Print header
|
||||
print(f"{'ID':<4} {'Title':<30} {'Completed':<10} {'Due Date':<12} {'Description'}")
|
||||
print("-" * 80)
|
||||
for item in items:
|
||||
completed_str = "✓" if item.completed else "✗"
|
||||
due = item.due_date if item.due_date else "-"
|
||||
desc = item.description if item.description else ""
|
||||
print(f"{item.id:<4} {item.title:<30} {completed_str:<10} {due:<12} {desc}")
|
||||
|
||||
def _handle_done(self, args: argparse.Namespace) -> None:
|
||||
"""Handle the 'done' command.
|
||||
|
||||
Args:
|
||||
args: Parsed arguments containing item_id.
|
||||
"""
|
||||
success = self.manager.mark_done(args.item_id)
|
||||
if success:
|
||||
print(f"Marked item #{args.item_id} as completed.")
|
||||
else:
|
||||
print(f"Error: Item #{args.item_id} not found.")
|
||||
|
||||
def _handle_undone(self, args: argparse.Namespace) -> None:
|
||||
"""Handle the 'undone' command.
|
||||
|
||||
Args:
|
||||
args: Parsed arguments containing item_id.
|
||||
"""
|
||||
success = self.manager.mark_undone(args.item_id)
|
||||
if success:
|
||||
print(f"Marked item #{args.item_id} as not completed.")
|
||||
else:
|
||||
print(f"Error: Item #{args.item_id} not found.")
|
||||
|
||||
def _handle_delete(self, args: argparse.Namespace) -> None:
|
||||
"""Handle the 'delete' command.
|
||||
|
||||
Args:
|
||||
args: Parsed arguments containing item_id.
|
||||
"""
|
||||
success = self.manager.delete(args.item_id)
|
||||
if success:
|
||||
print(f"Deleted item #{args.item_id}.")
|
||||
else:
|
||||
print(f"Error: Item #{args.item_id} not found.")
|
||||
|
||||
def _handle_edit(self, args: argparse.Namespace) -> None:
|
||||
"""Handle the 'edit' command.
|
||||
|
||||
Args:
|
||||
args: Parsed arguments containing item_id and optional fields.
|
||||
"""
|
||||
# Convert --completed string to bool if provided
|
||||
completed = None
|
||||
if args.completed is not None:
|
||||
completed = args.completed.lower() == "true"
|
||||
|
||||
success = self.manager.edit(
|
||||
args.item_id,
|
||||
title=args.title,
|
||||
description=args.description,
|
||||
due_date=args.due_date,
|
||||
completed=completed,
|
||||
)
|
||||
if success:
|
||||
print(f"Updated item #{args.item_id}.")
|
||||
else:
|
||||
print(f"Error: Item #{args.item_id} not found.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Application entry point.
|
||||
|
||||
Creates a Storage instance with default path, initializes TodoManager,
|
||||
and runs the CLI.
|
||||
"""
|
||||
storage = Storage()
|
||||
manager = TodoManager(storage)
|
||||
cli = TodoCLI(manager)
|
||||
cli.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user