Python Project: To-Do List in Python

Goal

Use append() to_do_list to store tasks, use append(), remove() to marked_tasks_list to filter finished tasks, defined functions to be reused in while-loop, if-elif-else statements to handle user prompts, loops to iterate through the list and try-except to handle ValueError.

Plan

Display the menu from 1 - 5 and the program reacts to the user prompt.

  • Add tasks function - the user can input descriptions and add them to the to-do list.

  • Remove tasks function - takes a task and removes it from the to-do list.

  • View tasks function - displays the whole to-do list and finished tasks.

  • Mark complete tasks - Transfer to another list to mark tasks as completed.

Exit Program function - uses sys module to provide access to the exit() function.


The documentation of this code is written below.

""" To-do list in Python """
# sys module for exit program
import sys

# initialize empty list for to do list
to_do_list = []

# initialize empty list for marked tasks
marked_tasks_list = []

# function to add a task
def add_task():
    task_choice = input("1) 'Add Task' chosen.\nType new task here:  ").casefold()              
    # use append to add "task_choice" in to_do_list
    to_do_list.append(task_choice)                                                              
    print("Successfully task added.\nTo do list updated:", to_do_list)

# function to remove a task
def remove_task():
    print("2) 'Remove task' chosen. This is your current list:", to_do_list)
    erease_input = input("Type the task to remove here:  ").casefold()                                     

    # check if user input available in to_do_list
    if erease_input in to_do_list:                                                              
        to_do_list.remove(erease_input)                                                        
        print(f'{erease_input} successfully removed. To do list updated:', to_do_list)

    else:                                                                                     
        print(f'{erease_input} not found. Choose tasks available in the to do list.')

# function to View 2 different lists
def view_task():
    print(f'3) View task list chosen.\n Current to do list:', to_do_list)
    print(f' This is the finished tasks list:', marked_tasks_list)


# function to mark a completed task.
def mark_complete_task():
    print(f'This is your current list', to_do_list)
    # take input for text to mark
    mark_text = input("Mark this text from the list:  ").casefold()

    # Check if the task to mark exists in the to_do_list
    if mark_text in to_do_list:

        # Transfer mark_text to marked_taskes_list with append function
        marked_tasks_list.append(mark_text)

        # Remove mark_text from to_do_list with remove function
        to_do_list.remove(mark_text)

        print(f'{mark_text} is completed. Moved to marked tasks list.')
        print(f'This is the finished tasks list.\n', marked_tasks_list)

    else: print(f'{mark_text} not found in list. Try a text within the list')


# function to exit the program
def exit_program():
    print("Exiting program")
    sys.exit()


# Start while loop
while True:
    # display menu
    display_menu= "\nTo-do list menu:\n1) Add a task\n2) Remove a task\n3) view list\n4) Mark a task\n5) Exit program\n"
    print(display_menu)

    # Prompt user input
    task_choice = input("Choose the number of task:   ")


    try:
        # converts input into integers, catches non-numeric input.
        task_choice = int(task_choice)

        if task_choice == 1:
            add_task()

            # Ask prompt if user wants to return to main menu
            return_menu = input("***Press 'any key' to return to main menu. Press 'n' to exit***:  \n").lower()
            if return_menu == 'any key':
                print("Go back to main menu")
                continue
            elif return_menu == 'n':
                print("Program stops. Goodbye!")
                break

        elif task_choice == 2:
            remove_task()

            return_menu = input("***Press 'any key' to return to main menu. Press 'n' to exit***:  \n").lower()
            if return_menu == 'any key':
                print("Go back to main menu")
                continue
            elif return_menu == 'n':
                print("Program stops. Goodbye!")
                break

        elif task_choice == 3:
            view_task()

            return_menu = input("***Press 'any key' to return to main menu. Press 'n' to exit***:  \n")
            if return_menu == 'any key':
                print("Go back to main menu")
                continue
            elif return_menu == 'n':
                print("Program stops. Goodbye!")
                break

        elif task_choice == 4:
            mark_complete_task()

            return_menu = input("***Press 'any key' to return to main menu. Press 'n' to exit***:  \n")
            if return_menu == 'any key':
                print("Go back to main menu")
                continue
            elif return_menu == 'n':
                print("Program stops. Goodbye!")
                break

        elif task_choice == 5:
            exit_program()

        else:
            print("Wrong input. Please enter a number from 1-5\n")

    except ValueError:
        # Tells user to try again if ValueError is caught
        print("Value Error. Please enter a number from 1-5\n")

I used list for the to-do list because:

1. Easier to code and access than a dictionary or tuple for a beginner - I find it easier to use lists with def functions because it is very straightforward. A dictionary needs more functions like .items() or .get() to be able to be used in the while loop. Also, I think accessing “key-values” is more intermediate level. It can make the code more advanced and complicated.. Also, I am not familiar with the use of tuples and dictionaries.

2. A. Adjustability and adaptability to modification - elements in a list can be edited, adjusted and modified. Dictionaries and tuples are more difficult to modify for me. In my To Do List, I used string manipulation. A dictionary will need key-value pairs but lists deal with arrays, which means it always follows the index from [0].

B. String Manipulation (Append and Remove) - The mark_complete_task uses append and remove to manipulate elements in a list. The list enables me to manipulate the elements in a list easier than a dictionary with less code.

3. Order - List is an ordered collection of data. A dictionary stored data in the form of key-value pairs. The display order of the elements in a list is according to the order the elements are added. List is very good to use in a to do list because key-value pairs are not needed. In the Train Booking System, a dictionary would be better, but in a to-do list, lists are better.


Flow chart


Motivation: I like to use defined functions because:

1. Reusable block of code - Each defined function can be called and reused repeatedly in any block of code to carry a specific task. In my code, every task is within separate defined functions. This makes my code less complex and more manageable. As a result, my code needs less repetition to write.

2. Readability of while loop

If the while loop does not iterate properly, I can easily go back to the defined function without editing the whole while loop. I only need to update and fix it in one place. Also, it is easier to create the if and elif statements because the functions only need to be written under that specific code block. Code organization and understandability improves by organizing my code into specific functions in separate blocks of code.

3. Easier for scoping and troubleshooting

Functions create their own scope, so it prevents variables from interfering with each other. It is also easier to troubleshoot my program because each function is isolated. When I troubleshoot my code in this assignment, it was easier for me to find the errors because I don’t destroy my nested code and I know where to find the error.


My defined functions:

  1. Add Task Function

I used the .append() function because it is Python’s built-in functions that are useful to simply add variables in a list. The order of how the variable is added does not matter in my to do list. I also used .casefold() and not .lower() because the prompt might have upper cases anywhere in the string. It is more strict than .lower().

Any word that the user inputs, it will be added to the to_do_list. I created the variable "task_choice" because it will be the storage for the new task. It also became the parameter to append the task in the to_do_list.

B. Remove Task Function

I used the .remove() function logic for this code because there could only be 2 scenarios. I think if and else statement is the best code to use because it is simple, short and straightforward.

IF = The user input is on the list, then I can use the .remove().

ELSE = The user input is NOT on the list. Then, the user is told by the program to view the list and input a correct task that is available in the list.

C. View Tasks Function

In the view_task function, I just decided to use the print statement to show the current to_do_list and marked_tasks_lists.

D. Mark Complete Task Function

The functionality I planned to mark a complete task is by filtering the unfinished tasks and finished tasks into 2 different lists. I am using an if statement ranged in the to_do_list to search if the task is available.

To achieve the functionality described, where marked tasks are removed from to_do_list and transferred to marked_tasks_list: Add a global declaration for marked_tasks_list at the beginning of the code. Note that the marked_tasks_list should be declared as a global variable so that it can be accessed and modified within functions, like in the View_task def function.

Now, when a task is marked as completed using the mark_complete_task function, it will be removed from to_do_list and added to marked_tasks_list.

E. Exit Program Function

sys.exit() function - I want a very simple code that is short and clear to terminate a program from task completion or errors. So, I look for sources online and I learned the sys module. Sys module is the most common method in python. All I need to do is include it in the exit_program function.

Source: https://codedamn.com/news/python/exit-python-program-from-terminal


2. Start the while True loop

I use while True: to keep the code running until a certain condition is met.

2.1 Inside the while loop, nest the prompt user input

task_choice user prompt is inside the loop because:

1. Takes user action: task_choice: the choice of the user will be used in the if and elif statements. This is the driver of my code.

2. Repeated execution : It allows the program to ask for user input repeatedly, not only once. It does not limit the user to one single input.

2.2 Use try-except

Explain use of try-except

Precision in error handling and user friendly code

I learned that the try-except can handle potential errors in some cases better than else statements. The else statement runs only when no exceptions occur. Meanwhile the try except provides a more specific error handling and clearer feedback to the user. For example, I used except: “ValueError”, which specifically tells that user that they have typed an invalid integer.

2.3 If and elif statements

Use the Comparison Operators == to compare two values: the task choice user input number (1,2,3,4 or 5) and the defined function I created. Use the if statement first for the 1st condition, and the rest are elif statements.

I used if and elif statements inside the while True loop that responds to task_choice user input because: Combining the if statements, user input variable, comparison operator and def function are very useful.

1. Organized Code Structure - looks clean, easy to read and understand especially when it is combined with the == operator. Once a condition is met, the block of code is executed and the rest of the conditions are skipped. This makes sure the code only performs one action per user input and prevents other conflicting actions.

2. Efficient Execution and Logical Order - The code checks the condition in the order of (if- elif- elif…). As soon as it finds a True condition, it executes. It is more efficient than using too many if statements.

3. Error Handling and Debugging - If I need to modify or debug something from one of the functions, I can fix it outside the while loop. It helps me make fewer errors. The if and elif statement combined with == operator makes it easy to spot and correct.

4. User - Friendly Code- I think all programmers know that using user prompts and if statements together always makes the program more interactive and gives control of the code’s flow.


Troubleshooting and what I learned:

  1. “Continue” and “break” cannot be used in defined functions

The purpose of this code is to have 2 choices to return to the main menu or exit the program. This is the if-elif statement code in the while loop that I repeatedly use. I failed to create a defined function for this code because the “continue” and “break” can only be used within a loop.

  1. if statement in range

This is a very important line of code because without this, the to-do list will not find the tasksl. Meaning, the tasks will not be properly updated. Inside the defined function mark_complete_task, this checks if the mark_text is present in the to_do_list.

If the task is not found, use the else statement to tell the user the mark_text is not found in the list and prompt the user to try again.

  1. This is my first code for the mark_task_complete task. Too complicated. I learned to keep the code SIMPLE for a beginner.

The text “work”, for example, was manipulated and replaced by an overstrike text “w̶o̶r̶k̶” when the list is updated and printed again. This was a problem because it was too complicated to use the ‘\u0336’ string manipulation. I had many problems with using this code.

List not updating

The code became more complicated to view a task, remove a task or mark a task because the to-do list was not updating.

Finding the index of the original task

I had to use the index method to return the position of the specified value. It was too complicated to fix the WHOLE PROGRAM.

Source: https://stackoverflow.com/questions/25244454/python-create-strikethrough-strikeout-overstrike-string-type

Removal of overstrike text from to_do_list

I am not able to fix the current remove_task function for the removal of an overstrike text, example: w̶o̶r̶k̶. The code becomes too complicated. Once a specific text is overstrike, it is not possible with my current code to remove it.


Programming 1 Python: My Code Reflections:

In conclusion from this course, I learned that coding:

  1. Possibilities and limitations

My code can have possibilities for managing tasks: append, remove, view, etc effortlessly. However, it has some limitations such as a lack of interchangeable flow between different functions.

  1. Impact of Programming Everyday

The to-do list is a good example of task management that can be used in everyday life. Planning the methods, controlling the structure, testing the errors and documenting how the problem is solved are good ways to be an efficient problem solver.

  1. Good Quality Program

Well-defined functions, user-friendly input prompts, error-handling (ValueError) are examples of good programming principles. But I think my code can be improved more if I can write a better pseudo code, learn all the possibilities of Python, solve the errors better and be able to think more like a programmer.

SIMPLE IS BETTER. Don’t over complicate.