Image by author
Creating simple projects is a great way to learn Python and any programming language in general. You can learn the syntax for writing for loops, using built-in functions, reading files, and much more. But only when you start building something do you really “learn.”
Following the “learn by building” approach, let's code a simple to-do list application that we can run on the command line. Along the way, we'll explore concepts like parsing command line arguments and working with files and file paths. We will also review basic concepts such as defining custom functions.
Then let's get started!
By coding this tutorial, you will be able to create a to-do list application that you can run on the command line. Well, what would you like the app to do?
Just like paper to-do lists, you should be able to add tasks, search for all tasks, and delete tasks (yes, cross them off or mark them as done on paper) after you've completed them, right? Then we will create an application that allows us to do the following.
Add tasks to the list:
Image by author
Get a list of all the tasks in the list:
Image by author
And also delete a task (using its index) after you've finished it:
Image by author
Now let's start coding!
First, create a directory for your project. And inside the project directory, create a Python script file. This will be the main file for our to-do list app. let's call it todo.py
.
You don't need any third party libraries for this project. So just make sure you're using a recent version of Python. This tutorial uses Python 3.11.
In it todo.py
file, start by importing the necessary modules. For our simple to-do list app, we will need the following:
- parse arguments for parsing command line arguments
- OS for file operations
So let's import both:
import argparse
import os
Remember that we will use command line flags to add, list, and delete tasks. We can use both short and long options for each argument. For our application, let's use the following:
-a
either--add
to add tasks-l
either--list
to list all tasks-r
either--remove
to delete tasks using the index
This is where we will use the argparse module to parse the arguments provided on the command line. We define the create_parser()
function that does the following:
- Initialize a
ArgumentParser
object (let's call itparser
). - Adds arguments to add, list, and delete tasks by calling
add_argument()
method on the parser object.
When adding arguments we add both the short and long options, as well as the corresponding help message. So here is the create_parser()
function:
def create_parser():
parser = argparse.ArgumentParser(description="Command-line Todo List App")
parser.add_argument("-a", "--add", metavar="", help="Add a new task")
parser.add_argument("-l", "--list", action="store_true", help="List all tasks")
parser.add_argument("-r", "--remove", metavar="", help="Remove a task by index")
return parser
Now we need to define functions to perform the following task management operations:
- Add a task
- List all tasks
- Delete a task by its index
The next function add_task
Interacts with a simple text file to manage items in the to-do list. Open the file in 'add' mode and add the task to the end of the list:
def add_task(task):
with open("tasks.txt", "a") as file:
file.write(task + "\n")
Notice how we have used the with
statement to manage the file. Doing so ensures that the file is closed after the operation even if there is an error, minimizing resource leaks.
For more information, read the section on context managers for efficient resource management in this tutorial on writing efficient Python code.
He list_tasks
The function lists all tasks checking if the file exists. The file is created only when you add the first task. We first check if the file exists and then read and print the tasks. If there are currently no tasks, we receive a useful message. :
def list_tasks():
if os.path.exists("tasks.txt"):
with open("tasks.txt", "r") as file:
tasks = file.readlines()
for index, task in enumerate(tasks, start=1):
print(f"{index}. {task.strip()}")
else:
print("No tasks found.")
We also implemented a remove_task
function to delete tasks by index. Opening the file in 'write' mode overwrites the existing file. Then we delete the corresponding task from the index and write the updated to-do list to the file:
def remove_task(index):
if os.path.exists("tasks.txt"):
with open("tasks.txt", "r") as file:
tasks = file.readlines()
with open("tasks.txt", "w") as file:
for i, task in enumerate(tasks, start=1):
if i != index:
file.write(task)
print("Task removed successfully.")
else:
print("No tasks found.")
We have configured the parser to parse command line arguments. And we have also defined the functions to perform the tasks of adding, listing and deleting tasks. What's next?
You probably guessed it. We just need to call the correct function based on the command line argument received. Let's define a main()
function to parse command line arguments using the ArgumentParser
object that we created in step 3.
Based on the provided arguments, call the appropriate task management functions. This can be done using a simple if-elif-else ladder like this:
def main():
parser = create_parser()
args = parser.parse_args()
if args.add:
add_task(args.add)
elif args.list:
list_tasks()
elif args.remove:
remove_task(int(args.remove))
else:
parser.print_help()
if __name__ == "__main__":
main()
You can now run the to-do list app from the command line. Use the short option h
or the long option help
For information on usage:
$ python3 todo.py --help
usage: todo.py (-h) (-a) (-l) (-r)
Command-line Todo List App
options:
-h, --help show this help message and exit
-a , --add Add a new task
-l, --list List all tasks
-r , --remove Remove a task by index
Initially, there are no tasks in the list, so use --list
To list all tasks, print “No tasks found”:
$ python3 todo.py --list
No tasks found.
Now we add an item to the to-do list like this:
$ python3 todo.py -a "Walk 2 miles"
When you list the items now, you should be able to see the added task:
$ python3 todo.py --list
1. Walk 2 miles
Because we added the first element, the task.txt file was created (see the definition of list_tasks
function in step 4):
Let's add another task to the list:
$ python3 todo.py -a "Grab evening coffee!"
And other:
$ python3 todo.py -a "Buy groceries"
And now let's get the list of all tasks:
$ python3 todo.py -l
1. Walk 2 miles
2. Grab evening coffee!
3. Buy groceries
Now let's delete a task by its index. Let's say we're done with our afternoon (and hopefully daytime) coffee, so we delete it as shown:
$ python3 todo.py -r 2
Task removed successfully.
The modified to-do list is as follows:
$ python3 todo.py --list
1. Walk 2 miles
2. Buy groceries
Ok, the simplest version of our application is ready. So how do we take this further? Here are some things you can try:
- What happens when you use an invalid command line option (e.g.
-w
either--wrong
)? The default behavior (if you remember the if-elif-else ladder) is to print the help message, but there will also be an exception. Try to implement error handling using try-except blocks. - Test your application by defining test cases that include edge cases. To get started, you can use the built-in unittest module.
- Improve the existing version by adding an option to specify the priority of each task. Also try sorting and retrieving tasks by priority.
The code for this tutorial is on GitHub..
In this tutorial, we create a simple command line to-do list application. In doing so, we learned how to use the built-in argparse module to parse command line arguments. We also use command line input to perform corresponding operations on a simple text file.
So where do we go now? Well, Python libraries like Guys Make building command line applications a breeze. And we'll build one using Typer in an upcoming Python tutorial. Until then, keep coding!
twitter.com/balawc27″ rel=”noopener”>Bala Priya C. is a developer and technical writer from India. He enjoys working at the intersection of mathematics, programming, data science, and content creation. His areas of interest and expertise include DevOps, data science, and natural language processing. He likes to read, write, code and drink coffee! Currently, he is working to learn and share his knowledge with the developer community by creating tutorials, how-to guides, opinion pieces, and more. Bala also creates engaging resource descriptions and coding tutorials.
<script async src="//platform.twitter.com/widgets.js” charset=”utf-8″>