From 0db5d144e39b987799f875d1b5a3b14509b5e746 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 6 Apr 2026 12:46:14 +0200 Subject: [PATCH 1/7] Sample code for the article on Gemini CLI vs Claude Code --- gemini-cli-vs-claude-code/README.md | 3 + .../claude-code/test_todo.py | 206 ++++++++++++++++++ gemini-cli-vs-claude-code/claude-code/todo.py | 130 +++++++++++ .../claude-code/todo_store.py | 92 ++++++++ .../gemini-cli/test_todo.py | 72 ++++++ gemini-cli-vs-claude-code/gemini-cli/todo.py | 138 ++++++++++++ 6 files changed, 641 insertions(+) create mode 100644 gemini-cli-vs-claude-code/README.md create mode 100644 gemini-cli-vs-claude-code/claude-code/test_todo.py create mode 100644 gemini-cli-vs-claude-code/claude-code/todo.py create mode 100644 gemini-cli-vs-claude-code/claude-code/todo_store.py create mode 100644 gemini-cli-vs-claude-code/gemini-cli/test_todo.py create mode 100644 gemini-cli-vs-claude-code/gemini-cli/todo.py diff --git a/gemini-cli-vs-claude-code/README.md b/gemini-cli-vs-claude-code/README.md new file mode 100644 index 0000000000..90c3104f34 --- /dev/null +++ b/gemini-cli-vs-claude-code/README.md @@ -0,0 +1,3 @@ +# Gemini CLI vs Claude Code: Which to Choose for Python Tasks + +This folder provides the code examples for the Real Python tutorial [Gemini CLI vs Claude Code: Which to Choose for Python Tasks](https://realpython.com/gemini-cli-vs-claude-code/). diff --git a/gemini-cli-vs-claude-code/claude-code/test_todo.py b/gemini-cli-vs-claude-code/claude-code/test_todo.py new file mode 100644 index 0000000000..bda73cb183 --- /dev/null +++ b/gemini-cli-vs-claude-code/claude-code/test_todo.py @@ -0,0 +1,206 @@ +"""Unit tests for the to-do application.""" + +import json +import os +import sys # noqa: F401 +import tempfile +import unittest +from unittest.mock import patch + +import todo + +# Point store at a temp file for every test +import todo_store as store + + +class BaseTest(unittest.TestCase): + """Set up a temporary tasks file for each test.""" + + def setUp(self): + self._tmp = tempfile.NamedTemporaryFile( + suffix=".json", + delete=False, + mode="w", + ) + self._tmp.write("[]") + self._tmp.close() + self._orig = store.TASKS_FILE + store.TASKS_FILE = self._tmp.name + + def tearDown(self): + store.TASKS_FILE = self._orig + os.unlink(self._tmp.name) + + +# ── store tests ───────────────────────────────────────────────────────────── + + +class TestAddTask(BaseTest): + def test_add_returns_task(self): + task = store.add_task("Buy milk") + self.assertEqual(task["description"], "Buy milk") + self.assertFalse(task["completed"]) + self.assertEqual(task["id"], 1) + + def test_ids_increment(self): + t1 = store.add_task("First") + t2 = store.add_task("Second") + self.assertEqual(t1["id"], 1) + self.assertEqual(t2["id"], 2) + + def test_empty_description_raises(self): + with self.assertRaises(ValueError): + store.add_task("") + + def test_whitespace_only_raises(self): + with self.assertRaises(ValueError): + store.add_task(" ") + + def test_persists_to_disk(self): + store.add_task("Persisted") + with open(store.TASKS_FILE) as f: + data = json.load(f) + self.assertEqual(len(data), 1) + self.assertEqual(data[0]["description"], "Persisted") + + +class TestCompleteTask(BaseTest): + def test_complete_task(self): + store.add_task("Write tests") + task = store.complete_task(1) + self.assertTrue(task["completed"]) + self.assertIsNotNone(task["completed_at"]) + + def test_complete_nonexistent_raises(self): + with self.assertRaises(KeyError): + store.complete_task(999) + + def test_complete_already_done_raises(self): + store.add_task("Already done") + store.complete_task(1) + with self.assertRaises(ValueError): + store.complete_task(1) + + +class TestDeleteTask(BaseTest): + def test_delete_task(self): + store.add_task("To delete") + deleted = store.delete_task(1) + self.assertEqual(deleted["description"], "To delete") + self.assertEqual(store.load_tasks(), []) + + def test_delete_nonexistent_raises(self): + with self.assertRaises(KeyError): + store.delete_task(42) + + def test_remaining_tasks_intact(self): + store.add_task("Keep me") + store.add_task("Delete me") + store.delete_task(2) + tasks = store.load_tasks() + self.assertEqual(len(tasks), 1) + self.assertEqual(tasks[0]["description"], "Keep me") + + +class TestFilterTasks(BaseTest): + def setUp(self): + super().setUp() + store.add_task("Pending task") + store.add_task("Completed task") + store.complete_task(2) + self.tasks = store.load_tasks() + + def test_filter_all(self): + self.assertEqual(len(store.filter_tasks(self.tasks, "all")), 2) + + def test_filter_pending(self): + result = store.filter_tasks(self.tasks, "pending") + self.assertEqual(len(result), 1) + self.assertFalse(result[0]["completed"]) + + def test_filter_completed(self): + result = store.filter_tasks(self.tasks, "completed") + self.assertEqual(len(result), 1) + self.assertTrue(result[0]["completed"]) + + def test_filter_unknown_raises(self): + with self.assertRaises(ValueError): + store.filter_tasks(self.tasks, "invalid") + + +class TestCorruptedFile(BaseTest): + def test_corrupted_json_raises(self): + with open(store.TASKS_FILE, "w") as f: + f.write("not valid json{{{") + with self.assertRaises(ValueError): + store.load_tasks() + + def test_non_array_json_raises(self): + with open(store.TASKS_FILE, "w") as f: + json.dump({"key": "value"}, f) + with self.assertRaises(ValueError): + store.load_tasks() + + def test_missing_file_returns_empty(self): + os.unlink(store.TASKS_FILE) + self.assertEqual(store.load_tasks(), []) + # restore so tearDown doesn't crash + with open(store.TASKS_FILE, "w") as f: + f.write("[]") + + +# ── CLI integration tests ─────────────────────────────────────────────────── + + +class TestCLI(BaseTest): + def _run(self, argv): + """Run CLI with given argv list, return exit code.""" + with patch("sys.argv", ["todo"] + argv): + parser = todo.build_parser() + args = parser.parse_args() + return args.func(args) + + def test_add_command(self): + code = self._run(["add", "CLI task"]) + self.assertEqual(code, 0) + self.assertEqual(len(store.load_tasks()), 1) + + def test_list_command(self): + store.add_task("Listed task") + code = self._run(["list"]) + self.assertEqual(code, 0) + + def test_list_pending_filter(self): + store.add_task("Pending") + store.add_task("Done") + store.complete_task(2) + code = self._run(["list", "--status", "pending"]) + self.assertEqual(code, 0) + + def test_done_command(self): + store.add_task("Mark done") + code = self._run(["done", "1"]) + self.assertEqual(code, 0) + self.assertTrue(store.load_tasks()[0]["completed"]) + + def test_delete_command(self): + store.add_task("Remove me") + code = self._run(["delete", "1"]) + self.assertEqual(code, 0) + self.assertEqual(store.load_tasks(), []) + + def test_done_missing_id_returns_error(self): + code = self._run(["done", "99"]) + self.assertEqual(code, 1) + + def test_delete_missing_id_returns_error(self): + code = self._run(["delete", "99"]) + self.assertEqual(code, 1) + + def test_add_empty_returns_error(self): + code = self._run(["add", ""]) + self.assertEqual(code, 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/gemini-cli-vs-claude-code/claude-code/todo.py b/gemini-cli-vs-claude-code/claude-code/todo.py new file mode 100644 index 0000000000..b1a72bb7e1 --- /dev/null +++ b/gemini-cli-vs-claude-code/claude-code/todo.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +"""CLI to-do application. + +Usage: + todo.py add "Buy groceries" + todo.py list + todo.py list --status pending + todo.py list --status completed + todo.py done + todo.py delete +""" + +import argparse +import sys + +import todo_store as store + +# ── Formatting helpers ────────────────────────────────────────────────────── + +CHECK = "[x]" +EMPTY = "[ ]" + + +def _fmt_task(task: dict) -> str: + status = CHECK if task["completed"] else EMPTY + suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" # noqa: E501 + return f" {task['id']:>3} {status} {task['description']}{suffix}" + + +# ── Command handlers ──────────────────────────────────────────────────────── + + +def cmd_add(args: argparse.Namespace) -> int: + try: + task = store.add_task(args.description) + print(f"Added task #{task['id']}: {task['description']}") + return 0 + except ValueError as e: + print(f"Error: {e}", file=sys.stderr) + return 1 + + +def cmd_list(args: argparse.Namespace) -> int: + try: + tasks = store.load_tasks() + filtered = store.filter_tasks(tasks, args.status) + except ValueError as e: + print(f"Error: {e}", file=sys.stderr) + return 1 + + if not filtered: + label = "" if args.status == "all" else f"{args.status} " + print(f"No {label}tasks found.") + return 0 + + label = "" if args.status == "all" else f"{args.status} " + print(f"\n--- {label}tasks ({len(filtered)}) ---") + for task in filtered: + print(_fmt_task(task)) + print() + return 0 + + +def cmd_done(args: argparse.Namespace) -> int: + try: + task = store.complete_task(args.id) + print(f"Completed task #{task['id']}: {task['description']}") + return 0 + except (KeyError, ValueError) as e: + print(f"Error: {e}", file=sys.stderr) + return 1 + + +def cmd_delete(args: argparse.Namespace) -> int: + try: + task = store.delete_task(args.id) + print(f"Deleted task #{task['id']}: {task['description']}") + return 0 + except KeyError as e: + print(f"Error: {e}", file=sys.stderr) + return 1 + + +# ── Argument parsing ──────────────────────────────────────────────────────── + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + prog="todo", + description="A simple CLI to-do application.", + ) + sub = parser.add_subparsers(dest="command", metavar="") + sub.required = True + + # add + p_add = sub.add_parser("add", help="Add a new task") + p_add.add_argument("description", help="Task description") + p_add.set_defaults(func=cmd_add) + + # list + p_list = sub.add_parser("list", help="List tasks") + p_list.add_argument( + "--status", + choices=["all", "pending", "completed"], + default="all", + help="Filter by status (default: all)", + ) + p_list.set_defaults(func=cmd_list) + + # done + p_done = sub.add_parser("done", help="Mark a task as completed") + p_done.add_argument("id", type=int, help="Task ID") + p_done.set_defaults(func=cmd_done) + + # delete + p_del = sub.add_parser("delete", help="Delete a task") + p_del.add_argument("id", type=int, help="Task ID") + p_del.set_defaults(func=cmd_delete) + + return parser + + +def main() -> int: + parser = build_parser() + args = parser.parse_args() + return args.func(args) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/gemini-cli-vs-claude-code/claude-code/todo_store.py b/gemini-cli-vs-claude-code/claude-code/todo_store.py new file mode 100644 index 0000000000..581959799a --- /dev/null +++ b/gemini-cli-vs-claude-code/claude-code/todo_store.py @@ -0,0 +1,92 @@ +"""Task persistence layer — reads/writes tasks to a local JSON file.""" + +import json +import os +from datetime import datetime, timezone + +TASKS_FILE = "tasks.json" + + +def _load_raw() -> list[dict]: + if not os.path.exists(TASKS_FILE): + return [] + try: + with open(TASKS_FILE, "r", encoding="utf-8") as f: + data = json.load(f) + if not isinstance(data, list): + raise ValueError( + "Corrupted tasks file: expected a JSON array.", + ) + return data + except json.JSONDecodeError as e: + raise ValueError(f"Corrupted tasks file: {e}") from e + + +def _save_raw(tasks: list[dict]) -> None: + with open(TASKS_FILE, "w", encoding="utf-8") as f: + json.dump(tasks, f, indent=2) + + +def _next_id(tasks: list[dict]) -> int: + return max((t["id"] for t in tasks), default=0) + 1 + + +def load_tasks() -> list[dict]: + """Return all tasks from disk.""" + return _load_raw() + + +def add_task(description: str) -> dict: + """Create a new task and persist it. Returns the new task.""" + description = description.strip() + if not description: + raise ValueError("Task description cannot be empty.") + tasks = _load_raw() + task = { + "id": _next_id(tasks), + "description": description, + "completed": False, + "created_at": datetime.now(timezone.utc).isoformat(), + "completed_at": None, + } + tasks.append(task) + _save_raw(tasks) + return task + + +def complete_task(task_id: int) -> dict: + """Mark a task as completed. Returns the updated task.""" + tasks = _load_raw() + for task in tasks: + if task["id"] == task_id: + if task["completed"]: + raise ValueError(f"Task {task_id} is already completed.") + task["completed"] = True + task["completed_at"] = datetime.now(timezone.utc).isoformat() + _save_raw(tasks) + return task + raise KeyError(f"Task {task_id} not found.") + + +def delete_task(task_id: int) -> dict: + """Delete a task by ID. Returns the deleted task.""" + tasks = _load_raw() + for i, task in enumerate(tasks): + if task["id"] == task_id: + deleted = tasks.pop(i) + _save_raw(tasks) + return deleted + raise KeyError(f"Task {task_id} not found.") + + +def filter_tasks(tasks: list[dict], status: str) -> list[dict]: + """Filter tasks by status: 'all', 'pending', or 'completed'.""" + if status == "all": + return tasks + if status == "pending": + return [t for t in tasks if not t["completed"]] + if status == "completed": + return [t for t in tasks if t["completed"]] + raise ValueError( + f"Unknown status filter '{status}'. Use: all, pending, completed.", + ) diff --git a/gemini-cli-vs-claude-code/gemini-cli/test_todo.py b/gemini-cli-vs-claude-code/gemini-cli/test_todo.py new file mode 100644 index 0000000000..4758614c8a --- /dev/null +++ b/gemini-cli-vs-claude-code/gemini-cli/test_todo.py @@ -0,0 +1,72 @@ +import json # noqa: F401 +import os +import unittest + +from todo import TodoManager + + +class TestTodoManager(unittest.TestCase): + def setUp(self): + self.test_file = "test_tasks.json" + # Ensure a clean slate for each test + if os.path.exists(self.test_file): + os.remove(self.test_file) + self.manager = TodoManager(filename=self.test_file) + + def tearDown(self): + if os.path.exists(self.test_file): + os.remove(self.test_file) + + def test_add_task(self): + task = self.manager.add_task("Test task") + self.assertEqual(task["description"], "Test task") + self.assertEqual(task["id"], 1) + self.assertFalse(task["completed"]) + self.assertEqual(len(self.manager.tasks), 1) + + def test_complete_task(self): + self.manager.add_task("Test task") + success = self.manager.complete_task(1) + self.assertTrue(success) + self.assertTrue(self.manager.tasks[0]["completed"]) + + def test_complete_non_existent_task(self): + success = self.manager.complete_task(999) + self.assertFalse(success) + + def test_delete_task(self): + self.manager.add_task("Task 1") + self.manager.add_task("Task 2") + success = self.manager.delete_task(1) + self.assertTrue(success) + self.assertEqual(len(self.manager.tasks), 1) + self.assertEqual(self.manager.tasks[0]["id"], 2) + + def test_list_tasks_filtering(self): + self.manager.add_task("Pending task") + self.manager.add_task("Completed task") + self.manager.complete_task(2) + + all_tasks = self.manager.list_tasks() + pending_tasks = self.manager.list_tasks(filter_status="pending") + completed_tasks = self.manager.list_tasks(filter_status="completed") + + self.assertEqual(len(all_tasks), 2) + self.assertEqual(len(pending_tasks), 1) + self.assertEqual(len(completed_tasks), 1) + self.assertEqual(pending_tasks[0]["description"], "Pending task") + self.assertEqual(completed_tasks[0]["description"], "Completed task") + + def test_persistence(self): + self.manager.add_task("Persistent task") + # Create a new manager instance pointing to the same file + new_manager = TodoManager(filename=self.test_file) + self.assertEqual(len(new_manager.tasks), 1) + self.assertEqual( + new_manager.tasks[0]["description"], + "Persistent task", + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/gemini-cli-vs-claude-code/gemini-cli/todo.py b/gemini-cli-vs-claude-code/gemini-cli/todo.py new file mode 100644 index 0000000000..aa9c30e218 --- /dev/null +++ b/gemini-cli-vs-claude-code/gemini-cli/todo.py @@ -0,0 +1,138 @@ +import argparse +import json +import os +import sys + + +class TodoManager: + def __init__(self, filename="tasks.json"): + self.filename = filename + self.tasks = self.load_tasks() + + def load_tasks(self): + if not os.path.exists(self.filename): + return [] + try: + with open(self.filename, "r") as f: + return json.load(f) + except (json.JSONDecodeError, IOError) as e: + print(f"Error loading tasks: {e}", file=sys.stderr) + return [] + + def save_tasks(self): + try: + with open(self.filename, "w") as f: + json.dump(self.tasks, f, indent=4) + except IOError as e: + print(f"Error saving tasks: {e}", file=sys.stderr) + + def add_task(self, description): + task_id = 1 + if self.tasks: + task_id = max(task["id"] for task in self.tasks) + 1 + + new_task = {"id": task_id, "description": description, "completed": False} + self.tasks.append(new_task) + self.save_tasks() + return new_task + + def complete_task(self, task_id): + for task in self.tasks: + if task["id"] == task_id: + task["completed"] = True + self.save_tasks() + return True + return False + + def list_tasks(self, filter_status=None): + if filter_status == "completed": + return [t for t in self.tasks if t["completed"]] + elif filter_status == "pending": + return [t for t in self.tasks if not t["completed"]] + return self.tasks + + def delete_task(self, task_id): + initial_count = len(self.tasks) + self.tasks = [t for t in self.tasks if t["id"] != task_id] + if len(self.tasks) < initial_count: + self.save_tasks() + return True + return False + + +def main(): + parser = argparse.ArgumentParser(description="CLI To-Do Application") + subparsers = parser.add_subparsers( + dest="command", + help="Available commands", + ) + + # Add command + add_parser = subparsers.add_parser("add", help="Add a new task") + add_parser.add_argument("description", help="Description of the task") + + # Complete command + complete_parser = subparsers.add_parser( + "complete", + help="Mark a task as completed", + ) + complete_parser.add_argument( + "id", + type=int, + help="ID of the task to complete", + ) + + # List command + list_parser = subparsers.add_parser("list", help="List tasks") + list_parser.add_argument( + "--filter", + choices=["all", "completed", "pending"], + default="all", + help="Filter tasks by status", + ) + + # Delete command + delete_parser = subparsers.add_parser("delete", help="Delete a task") + delete_parser.add_argument( + "id", + type=int, + help="ID of the task to delete", + ) + + args = parser.parse_args() + manager = TodoManager() + + if args.command == "add": + task = manager.add_task(args.description) + print(f"Added task: [{task['id']}] {task['description']}") + + elif args.command == "complete": + if manager.complete_task(args.id): + print(f"Marked task {args.id} as completed.") + else: + print(f"Error: Task {args.id} not found.", file=sys.stderr) + + elif args.command == "list": + filter_status = args.filter if args.filter != "all" else None + tasks = manager.list_tasks(filter_status) + if not tasks: + print("No tasks found.") + else: + print(f"{'ID':<5} {'Status':<10} {'Description'}") + print("-" * 30) + for task in tasks: + status = "Done" if task["completed"] else "Pending" + print(f"{task['id']:<5} {status:<10} {task['description']}") + + elif args.command == "delete": + if manager.delete_task(args.id): + print(f"Deleted task {args.id}.") + else: + print(f"Error: Task {args.id} not found.", file=sys.stderr) + + else: + parser.print_help() + + +if __name__ == "__main__": + main() From d9cfb736be7347a2e605fae38d4cc529cf33d02b Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 6 Apr 2026 12:51:10 +0200 Subject: [PATCH 2/7] Fix linter issues --- gemini-cli-vs-claude-code/claude-code/todo.py | 2 +- gemini-cli-vs-claude-code/gemini-cli/todo.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gemini-cli-vs-claude-code/claude-code/todo.py b/gemini-cli-vs-claude-code/claude-code/todo.py index b1a72bb7e1..6ea46cfc6a 100644 --- a/gemini-cli-vs-claude-code/claude-code/todo.py +++ b/gemini-cli-vs-claude-code/claude-code/todo.py @@ -23,7 +23,7 @@ def _fmt_task(task: dict) -> str: status = CHECK if task["completed"] else EMPTY - suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" # noqa: E501 + suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" # noqa return f" {task['id']:>3} {status} {task['description']}{suffix}" diff --git a/gemini-cli-vs-claude-code/gemini-cli/todo.py b/gemini-cli-vs-claude-code/gemini-cli/todo.py index aa9c30e218..50f88e8402 100644 --- a/gemini-cli-vs-claude-code/gemini-cli/todo.py +++ b/gemini-cli-vs-claude-code/gemini-cli/todo.py @@ -31,7 +31,11 @@ def add_task(self, description): if self.tasks: task_id = max(task["id"] for task in self.tasks) + 1 - new_task = {"id": task_id, "description": description, "completed": False} + new_task = { + "id": task_id, + "description": description, + "completed": False, + } self.tasks.append(new_task) self.save_tasks() return new_task From ed3225ef7974469d9338b16bdb118984566df3c8 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 6 Apr 2026 12:55:01 +0200 Subject: [PATCH 3/7] More fixes --- gemini-cli-vs-claude-code/claude-code/todo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemini-cli-vs-claude-code/claude-code/todo.py b/gemini-cli-vs-claude-code/claude-code/todo.py index 6ea46cfc6a..8685445edc 100644 --- a/gemini-cli-vs-claude-code/claude-code/todo.py +++ b/gemini-cli-vs-claude-code/claude-code/todo.py @@ -23,7 +23,7 @@ def _fmt_task(task: dict) -> str: status = CHECK if task["completed"] else EMPTY - suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" # noqa + suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" # noqa E501 return f" {task['id']:>3} {status} {task['description']}{suffix}" From cf7be2172c6bdc62c80fff5f3e7237ccabedd6b7 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 6 Apr 2026 12:58:20 +0200 Subject: [PATCH 4/7] Another attempt --- gemini-cli-vs-claude-code/claude-code/todo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemini-cli-vs-claude-code/claude-code/todo.py b/gemini-cli-vs-claude-code/claude-code/todo.py index 8685445edc..b88ba20ccd 100644 --- a/gemini-cli-vs-claude-code/claude-code/todo.py +++ b/gemini-cli-vs-claude-code/claude-code/todo.py @@ -23,7 +23,7 @@ def _fmt_task(task: dict) -> str: status = CHECK if task["completed"] else EMPTY - suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" # noqa E501 + suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" return f" {task['id']:>3} {status} {task['description']}{suffix}" From 6f7db2597555670fc38ee29273f332a43a150cc6 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 6 Apr 2026 13:02:14 +0200 Subject: [PATCH 5/7] Remove unused import of sys Removed unused import of sys in test_todo.py --- gemini-cli-vs-claude-code/claude-code/test_todo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemini-cli-vs-claude-code/claude-code/test_todo.py b/gemini-cli-vs-claude-code/claude-code/test_todo.py index bda73cb183..e28df9a6c6 100644 --- a/gemini-cli-vs-claude-code/claude-code/test_todo.py +++ b/gemini-cli-vs-claude-code/claude-code/test_todo.py @@ -2,7 +2,7 @@ import json import os -import sys # noqa: F401 +# import sys import tempfile import unittest from unittest.mock import patch From 3f637451268942c6b99fa0a3eda6ac73db279972 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 6 Apr 2026 13:02:53 +0200 Subject: [PATCH 6/7] Comment out unused json import in test_todo.py Comment out the unused import of json. --- gemini-cli-vs-claude-code/gemini-cli/test_todo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemini-cli-vs-claude-code/gemini-cli/test_todo.py b/gemini-cli-vs-claude-code/gemini-cli/test_todo.py index 4758614c8a..179609123f 100644 --- a/gemini-cli-vs-claude-code/gemini-cli/test_todo.py +++ b/gemini-cli-vs-claude-code/gemini-cli/test_todo.py @@ -1,4 +1,4 @@ -import json # noqa: F401 +# import json import os import unittest From de6b40ebeafea62d0af244549a127168cedc3f09 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 6 Apr 2026 13:09:48 +0200 Subject: [PATCH 7/7] Another round --- gemini-cli-vs-claude-code/claude-code/test_todo.py | 1 + gemini-cli-vs-claude-code/claude-code/todo.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gemini-cli-vs-claude-code/claude-code/test_todo.py b/gemini-cli-vs-claude-code/claude-code/test_todo.py index e28df9a6c6..9e1bc5ecb0 100644 --- a/gemini-cli-vs-claude-code/claude-code/test_todo.py +++ b/gemini-cli-vs-claude-code/claude-code/test_todo.py @@ -2,6 +2,7 @@ import json import os + # import sys import tempfile import unittest diff --git a/gemini-cli-vs-claude-code/claude-code/todo.py b/gemini-cli-vs-claude-code/claude-code/todo.py index b88ba20ccd..1baa002279 100644 --- a/gemini-cli-vs-claude-code/claude-code/todo.py +++ b/gemini-cli-vs-claude-code/claude-code/todo.py @@ -23,7 +23,9 @@ def _fmt_task(task: dict) -> str: status = CHECK if task["completed"] else EMPTY - suffix = f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" + suffix = ( + f" (done {task['completed_at'][:10]})" if task["completed_at"] else "" + ) return f" {task['id']:>3} {status} {task['description']}{suffix}"