diff --git a/__pycache__/todo.cpython-312.pyc b/__pycache__/todo.cpython-312.pyc new file mode 100644 index 0000000..14f4c28 Binary files /dev/null and b/__pycache__/todo.cpython-312.pyc differ diff --git a/python/test/test_to-do.py b/python/test/test_to-do.py index 8494337..bed6601 100644 --- a/python/test/test_to-do.py +++ b/python/test/test_to-do.py @@ -15,7 +15,7 @@ class TestTodoList(): def test_list_tasks(self): todo.TASK_FILE = test_file task_list = todo.list_tasks() - expected_list ="1. Item 1\n2. Item 2\n3. Item 3\n4. Item 4\n5. Item 5" + expected_list ="Your task list:\n1. Item 1\n2. Item 2\n3. Item 3\n4. Item 4\n5. Item 5" assert task_list == expected_list @@ -122,3 +122,6 @@ def test_lint(self): assert score > 7 assert score > 9 +pytest + + diff --git a/python/todo.py b/python/todo.py index a04234e..c708511 100644 --- a/python/todo.py +++ b/python/todo.py @@ -9,12 +9,40 @@ def add_task(task): Input - a task to add to the list Return - nothing """ + with open (TASK_FILE, "a", encoding="utf-8") as file: + file.write(task + "\n") + def list_tasks(): - return + """ + Lists the tasks in the provided task list with their index. + + Args: + list_tasks: A list of strings, where each string represents a task. + + Returns: + str: A formatted string containing the numbered tasks, or an empty string if the todo list is empty. + """ + + # read in the file TASK_FILE + with open (TASK_FILE, "r", encoding="utf-8") as file: + tasks = file.readlines() + + output_string = "Your task list:\n" + formatted_tasks = [] + for index, task in enumerate(tasks): + formatted_tasks.append(f"{index + 1}. {task}") + output_string += "".join(formatted_tasks) + print(output_string) + return output_string.rstrip('\n') + + + + def remove_task(index): + return def main(): @@ -49,3 +77,4 @@ def main(): if __name__ == "__main__": main() + diff --git a/test/__pycache__/test_to-do.cpython-312-pytest-7.4.4.pyc b/test/__pycache__/test_to-do.cpython-312-pytest-7.4.4.pyc new file mode 100644 index 0000000..13749e0 Binary files /dev/null and b/test/__pycache__/test_to-do.cpython-312-pytest-7.4.4.pyc differ diff --git a/test/test_list.txt b/test/test_list.txt new file mode 100644 index 0000000..6934359 --- /dev/null +++ b/test/test_list.txt @@ -0,0 +1,5 @@ +Item 1 +Item 2 +Item 3 +Item 4 +Item 5 diff --git a/test/test_to-do.py b/test/test_to-do.py new file mode 100644 index 0000000..1c54528 --- /dev/null +++ b/test/test_to-do.py @@ -0,0 +1,129 @@ +import pytest +import sys +import os +import shutil +from pylint.lint import Run +from pylint.reporters import CollectingReporter +sys.path.insert(0,"../") +sys.path.insert(0,"./") +from dataclasses import asdict +import todo +test_file = "test/test_list.txt" + +class TestTodoList(): + + def test_list_tasks(self): + todo.TASK_FILE = test_file + task_list = todo.list_tasks() + expected_list ="Your task list:\n1. Item 1\n2. Item 2\n3. Item 3\n4. Item 4\n5. Item 5" + + assert task_list == expected_list + + def test_remove_task(self): + temp_list = ".temp_test.txt" + shutil.copyfile(test_file, temp_list) + todo.TASK_FILE = temp_list + # should error (need to catch?) + todo.remove_task(0) + # list should be the same + task_list = todo.list_tasks() + expected_list ="Your task list:\n1. Item 1\n2. Item 2\n3. Item 3\n4. Item 4\n5. Item 5" + assert task_list == expected_list + # should also error + todo.remove_task(10) + # list should be the same + task_list = todo.list_tasks() + assert task_list == expected_list + # should not error! + todo.remove_task(1) + task_list = todo.list_tasks() + new_expected = "Your task list:\n1. Item 2\n2. Item 3\n3. Item 4\n4. Item 5" + # note assert checks from 1 as we remove line 0 + assert task_list == new_expected + os.remove(temp_list) + + + def test_add_task(self): + temp_list = ".temp_test.txt" + shutil.copyfile(test_file, temp_list) + todo.TASK_FILE = temp_list + todo.add_task("Item 6") + task_list = todo.list_tasks() + + expected_list ="Your task list:\n1. Item 1\n2. Item 2\n3. Item 3\n4. Item 4\n5. Item 5\n6. Item 6" + # add 'Your task list:' to match list_tasks function + assert task_list == expected_list + os.remove(temp_list) + + + def test_main(self): + + temp_list = ".tasks.txt" + shutil.copyfile(test_file, temp_list) + todo.TASK_FILE = temp_list + + from subprocess import run + result = run(["python","todo.py","-l"], capture_output=True, check=True) + #print(result) + assert len(result.stdout) == 72 + #changed number from 50 to account for extra characters from adding "your task list" and r before every \n + expected_list ="Your task list:\r\n1. Item 1\r\n2. Item 2\r\n3. Item 3\r\n4. Item 4\r\n5. Item 5\r\n" + assert result.stdout.decode('UTF-8') == expected_list + from subprocess import run + result = run(["python","todo.py","-a", "Item 6"], capture_output=True, check=True) + assert len(result.stdout) == 0 + + from subprocess import run + result = run(["python","todo.py","-l"], capture_output=True, check=True) + assert len(result.stdout) == 83 + expected_list ="Your task list:\r\n1. Item 1\r\n2. Item 2\r\n3. Item 3\r\n4. Item 4\r\n5. Item 5\r\n6. Item 6\r\n" + assert result.stdout.decode('UTF-8') == expected_list + + + from subprocess import run + result = run(["python","todo.py","-r","6"], capture_output=True, check=True) + assert len(result.stdout) < 40 + + from subprocess import run + result = run(["python","todo.py","-l"], capture_output=True, check=True) + print(result) + assert len(result.stdout) == 72 + expected_list ="Your task list:\r\n1. Item 1\r\n2. Item 2\r\n3. Item 3\r\n4. Item 4\r\n5. Item 5\r\n" + assert result.stdout.decode('UTF-8') == expected_list + + + os.remove(temp_list) + + + def test_lint(self): + files = ["todo.py"] + #pylint_options = ["--disable=line-too-long,import-error,fixme"] + pylint_options = [] + + report = CollectingReporter() + result = Run( + files, + reporter=report, + exit=False, + ) + score = result.linter.stats.global_note + nErrors = len(report.messages) + + print("Score: " + str(score)) + line_format = "{path}:{line}:{column}: {msg_id}: {msg} ({symbol})" + for error in report.messages: + print(line_format.format(**asdict(error))) + + assert nErrors < 500 + assert nErrors < 400 + assert nErrors < 250 + assert nErrors < 100 + assert nErrors < 50 + assert nErrors < 10 + assert nErrors == 0 + assert score > 3 + assert score > 5 + assert score > 7 + assert score > 9 + + diff --git a/todo.py b/todo.py new file mode 100644 index 0000000..47e749c --- /dev/null +++ b/todo.py @@ -0,0 +1,92 @@ +""" This module handles command-line argument parsing using argparse.""" +import argparse +import os + +TASK_FILE = ".tasks.txt" + +def add_task(task): + """Function: add_task + + Input - a task to add to the list + Return - nothing + """ + with open (TASK_FILE, "a", encoding="utf-8") as file: + file.write(task + "\n") + + +def list_tasks(): + """ + Lists the tasks in the provided task list with their index. + + Args: + list_tasks: A list of strings, where each string represents a task. + + Returns: + str: A formatted string containing numbered tasks, or an empty string + if todo list is empty. + """ + + # read in the file TASK_FILE + # used Gemini + with open (TASK_FILE, "r", encoding="utf-8") as file: + tasks = file.readlines() + output_string = "Your task list:\n" + formatted_tasks = [] + for index, task in enumerate(tasks): + formatted_tasks.append(f"{index + 1}. {task}") + output_string += "".join(formatted_tasks) + return output_string.rstrip('\n') + + +def remove_task(index): + """Function: remove_task + Input: index - the number of the task to remove from the list + Return: Nothing + """ + if os.path.exists(TASK_FILE): + with open(TASK_FILE, "r", encoding="utf-8") as file: + tasks = file.readlines() + if 1 <= index <= len(tasks): + with open(TASK_FILE, "w", encoding="utf-8") as file: + for i, task in enumerate(tasks, start=1): + if i != index: + file.write(task) + print(f"Task at index {index} removed.") + else: + print(f"Invalid task number: {index}. Please enter number between 1 and {len(tasks)}.") + else: + print("No tasks found.") + +def main(): + """ Main function to execute the program logic.""" + parser = argparse.ArgumentParser(description="Command-line Todo List") + parser.add_argument( + "-a", + "--add", + help="Add a new task" + ) + parser.add_argument( + "-l", + "--list", + action="store_true", + help="List all tasks") + parser.add_argument( + "-r", + "--remove", + help="Remove a task by index") + + args = parser.parse_args() + + if args.add: + add_task(args.add) + elif args.list: + tasks = list_tasks() + print(tasks) + elif args.remove: + remove_task(int(args.remove)) + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/todo_answers.py b/todo_answers.py new file mode 100644 index 0000000..ec8f4f5 --- /dev/null +++ b/todo_answers.py @@ -0,0 +1,94 @@ +""" +todo.py is a simple to-do list application that +keeps a users to-do list as a text file. + +Users can add, list or remove tasks +""" +import argparse +import os + +TASK_FILE = ".tasks.txt" + +def add_task(task): + """Function: add_task + + Input - a task to add to the list + Return - nothing + """ + with open(TASK_FILE, "a", encoding="utf-8") as file: + file.write(task + "\n") + +def list_tasks(): + """Function: list_tasks + + Input - a task to add to the list + Return - a string of the tasks on the list + """ + + output_string = "" + if os.path.exists(TASK_FILE): + with open(TASK_FILE, "r", encoding="utf-8") as file: + tasks = file.readlines() + for index, task in enumerate(tasks, start=1): + output_string += (f"{index}. {task.strip()}\n") + return output_string.strip() + + + +def remove_task(index): + """Function: remove_task + + Input - a task to add to the list + Return - nothing + """ + + if os.path.exists(TASK_FILE): + with open(TASK_FILE, "r", encoding="utf-8") as file: + tasks = file.readlines() + with open(TASK_FILE, "w", encoding="utf-8") as file: + for i, task in enumerate(tasks, start=1): + if i != index: + file.write(task) + print("Task removed.") + else: + print("No tasks found.") + + +def main(): + """Function: main + + Input - nothing + Return - nothing + """ + + parser = argparse.ArgumentParser(description="Command-line Todo List") + parser.add_argument( + "-a", + "--add", + help="Add a new task" + ) + parser.add_argument( + "-l", + "--list", + action="store_true", + help="List all tasks") + parser.add_argument( + "-r", + "--remove", + help="Remove a task by index") + + args = parser.parse_args() + + if args.add: + add_task(args.add) + elif args.list: + tasks = list_tasks() + print(tasks) + elif args.remove: + remove_task(int(args.remove)) + else: + parser.print_help() + + +if __name__ == "__main__": + main()