Projeto Final — CLI de Gerenciamento de Tarefas
Aula 10 de 10
Projeto: Task Manager CLI
Uma aplicação de linha de comando completa que gerencia tarefas com persistência em JSON.
#!/usr/bin/env python3
"""task-cli — Gerenciador de tarefas via terminal."""
import json
import os
import sys
from datetime import datetime
from pathlib import Path
from typing import Optional
import argparse
DATA_DIR = Path.home() / ".task-cli"
DATA_FILE = DATA_DIR / "tasks.json"
class Task:
"""Representa uma tarefa."""
def __init__(self, id: int, titulo: str, descricao: str = "",
prioridade: str = "media", completa: bool = False):
self.id = id
self.titulo = titulo
self.descricao = descricao
self.prioridade = prioridade
self.completa = completa
self.criada_em = datetime.now().isoformat()
self.concluida_em: Optional[str] = None
def to_dict(self):
return self.__dict__
@classmethod
def from_dict(cls, dados: dict):
t = cls(dados["id"], dados["titulo"])
t.__dict__.update(dados)
return t
def __str__(self):
status = "✓" if self.completa else "○"
return f"[{status}] {self.id:03d} | {self.titulo} ({self.prioridade})"
Gerenciamento de Dados
class TaskManager:
def __init__(self):
DATA_DIR.mkdir(parents=True, exist_ok=True)
self.tasks: list[Task] = []
self._carregar()
def _carregar(self):
if DATA_FILE.exists():
with open(DATA_FILE) as f:
dados = json.load(f)
self.tasks = [Task.from_dict(t) for t in dados]
def _salvar(self):
with open(DATA_FILE, "w") as f:
json.dump([t.to_dict() for t in self.tasks], f, indent=2)
def adicionar(self, titulo: str, descricao: str = "",
prioridade: str = "media") -> Task:
max_id = max((t.id for t in self.tasks), default=0)
task = Task(max_id + 1, titulo, descricao, prioridade)
self.tasks.append(task)
self._salvar()
return task
def listar(self, apenas_pendentes: bool = False) -> list[Task]:
tasks = [t for t in self.tasks if not t.completa] \
if apenas_pendentes else self.tasks
return sorted(tasks, key=lambda t: t.id)
def completar(self, task_id: int) -> Optional[Task]:
for task in self.tasks:
if task.id == task_id:
task.completa = True
task.concluida_em = datetime.now().isoformat()
self._salvar()
return task
return None
def remover(self, task_id: int) -> bool:
for i, task in enumerate(self.tasks):
if task.id == task_id:
del self.tasks[i]
self._salvar()
return True
return False
def buscar(self, termo: str) -> list[Task]:
return [t for t in self.tasks if termo.lower() in t.titulo.lower()]
CLI com argparse
def criar_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Gerenciador de Tarefas via Terminal",
epilog="Use 'task-cli comando --help' para ajuda de cada comando"
)
sub = parser.add_subparsers(dest="comando", required=True)
# add
add = sub.add_parser("add", help="Adicionar tarefa")
add.add_argument("titulo", help="Título da tarefa")
add.add_argument("-d", "--descricao", default="", help="Descrição")
add.add_argument("-p", "--prioridade",
choices=["baixa", "media", "alta"], default="media")
# list
ls = sub.add_parser("ls", aliases=["list"], help="Listar tarefas")
ls.add_argument("--pendentes", action="store_true",
help="Apenas pendentes")
# done
done = sub.add_parser("done", help="Completar tarefa")
done.add_argument("id", type=int, help="ID da tarefa")
# rm
rm = sub.add_parser("rm", aliases=["remove"], help="Remover tarefa")
rm.add_argument("id", type=int, help="ID da tarefa")
# search
search = sub.add_parser("search", help="Buscar tarefas")
search.add_argument("termo", help="Termo de busca")
return parser
def main():
parser = criar_parser()
args = parser.parse_args()
tm = TaskManager()
cores = {"alta": "\033[91m", "media": "\033[93m",
"baixa": "\033[92m", "reset": "\033[0m"}
match args.comando:
case "add" | "a":
task = tm.adicionar(args.titulo, args.descricao, args.prioridade)
print(f"{cores[args.prioridade]}✓ Tarefa #{task.id} criada{cores['reset']}")
case "ls" | "list":
tasks = tm.listar(args.pendentes)
for t in tasks:
cor = cores.get(t.prioridade, "")
print(f"{cor}{t}{cores['reset']}")
print(f"\nTotal: {len(tasks)} tarefas")
case "done":
task = tm.completar(args.id)
if task:
print(f"✓ Tarefa #{task.id} concluída!")
else:
print(f"✗ Tarefa #{args.id} não encontrada")
sys.exit(1)
case "rm" | "remove":
if tm.remover(args.id):
print(f"✓ Tarefa #{args.id} removida")
else:
print(f"✗ Tarefa #{args.id} não encontrada")
sys.exit(1)
case "search":
tasks = tm.buscar(args.termo)
for t in tasks:
print(t)
if __name__ == "__main__":
main()
Uso
python task_cli.py add "Estudar Python" -p alta
python task_cli.py ls
python task_cli.py ls --pendentes
python task_cli.py done 1
python task_cli.py search "Python"
Este projeto final une tudo: funções, classes, JSON, argparse, datetime, pathlib, tipagem e organização. Expanda com categorias, data de vencimento e relatórios!