DEV Community

Cover image for Docket – A CLI application
Diya Vijay
Diya Vijay

Posted on

Docket – A CLI application

Let's build a docket cli application. A docket is just a list of tasks that must be done. It functions similarly to a to-do application in that you may add tasks, browse a list of tasks, and mark them as completed once they are completed.
You must first install Python on your machine. Python is generally installed by default on most current systems. Open a terminal and type the following command to see which version of Python is installed on your machine.

python3 –version

It will give you information about the Python version that is currently installed. You can also install Python by visiting this website: https://installpython3.com/.
To begin, make an empty folder in which to save our project's files.
Now, open your favorite code editor and begin developing our program. Open the empty folder we made for our project. Now, activate the Python environment; if you have Python 3.4 or higher, execute the following command.

$ python -m venv [directory]

Bingo! Our Python environment is now active. Now, let's create our python file and name it "'docket.py"', but it's not required to use the same name; you're smart, and I know you can come up with a better one.
Before we begin coding in our Python file, we must first generate four other files. Wait! I know you're excited, but let me explain you what kind of files we'll be making and why. So, we'll need to make two text files: one for entering our tasks (task.txt) and another for keeping completed tasks (completed.txt). Let us now discuss the last two files. We must write one “.bat” (docket.bat) file (which will allow us to run the software on Windows) and one “.sh” (docket.sh) file (helps us to run the program on Linux). However, you must include the following code in these files.

docket.bat

@echo off

Python3 docket.py %1 %2 %3
Enter fullscreen mode Exit fullscreen mode

docket.sh

#!/usr/bin/env bash

Python3 docket.py “$@”
Enter fullscreen mode Exit fullscreen mode

Finally! Now take off!!!! for our python file, which will be used to code our fantastic program. For constructing our application's CLI interface, we will use Python's argparse module. The argparse module simplifies the creation of user-friendly command line interfaces. The argparse module also generates help and usage messages automatically and generates errors when users provide invalid arguments to the program. You may install argparse on your terminal by typing "' pip install argparse"'.

Import argparse and use the code below to open our txt files.

import argparse

task = open("task.txt","r+")
completed_task = open("completed.txt", "r+")
Enter fullscreen mode Exit fullscreen mode

Create some variables to read lines from and the length of our txt files.

task_data = task.readlines()
completed_data = completed_task.readlines()
c=len(completed_data)
t= len(task_data)
Enter fullscreen mode Exit fullscreen mode

Let's begin our argparse module now.

parser= argparse.ArgumentParser()
Enter fullscreen mode Exit fullscreen mode

We need to add arguments to the CLI in order to accept user input. We basically need two arguments. One is input1 for writing instructions, and the other is input2 for writing assignments. This is how you use argparse to declare variables and take input from the cli.

parser.add_argument('input1',
action='store', type=str, nargs='?', default='default')

parser.add_argument('input2', action = 'store',
                    nargs='?',
                    default='-1')

args = parser.parse_args()
Enter fullscreen mode Exit fullscreen mode

Let's get started on the conditions for our commands now. First, we specify whether we want to use the default mode or enter the command "'./docket help"', which will display the application's usage.

if(args.input1 == 'default' or args.input1 == 'help'):
    print('''Usage :-
$ ./docket add "hello world"    # Add a new item with priority 2 and text "hello world" to the list
$ ./docket ls                   # Show incomplete list items
$ ./docket del INDEX            # Delete the incomplete item with the given index
$ ./docket done INDEX           # Mark the incomplete item with the given index as complete
$ ./docket help                 # Show usage
$ ./docket report               # Statistics''')
Enter fullscreen mode Exit fullscreen mode

Next, we'll define our program for adding new items. Put a condition that says if our input1 is "add" and our input2 is default (which is -1 for input2, which helps us write our task), then write and store the input2 string in our task.txt file. The task's text should be enclosed by double quotations (otherwise only the first word is considered as the item text, and the remaining words are treated as different arguments).

# Add a new item

elif(args.input1 == 'add' and args.input2 != '-1'):
    task.write(str(args.input2) +"\n")
    print('Added task: '+ (args.input2))
Enter fullscreen mode Exit fullscreen mode

The following step is to write code to display a list of all pending items. If input1 is "ls" (which represents a list) and the length of our line in task.txt is larger than 0, then read each line in task.txt with relevant indexes. If your input1 is ls but the length of the line in task.txt is not defined or 0 then print the no pending task message.

# List all pending items

elif(args.input1 == 'ls'and t>0):
    for i in range(t,0,-1):
        line = task_data[i-1].strip()
        print(str(i)+'. '+line)

elif(args.input1 == 'ls'):
    print("There are no pending tasks!")
Enter fullscreen mode Exit fullscreen mode

We've reached the halfway. Bingo!! Begin by defining our condition for removing an item from a list. Put a condition that says if our input1 is del (which means delete) and our input2 is not default but is an integer larger than 0 and less than the length of the line in task.txt, then delete that index line from task.txt. If the index does not exist, an error message is displayed.

# Delete an item

elif(args.input1 == 'del' and args.input2 != '-1' and int(args.input2) <= t and int(args.input2)>0):
    task_data.remove(task_data[int(args.input2)-1])
    task.truncate(0)
    task.seek(0)
    for line in task_data:
        line = line.strip()
        task.write(line+"\n")
    print('Deleted item with index '+(args.input2))

elif(args.input1 == 'del'):
    print("Error: item with index "+str(int(args.input2))+" does not exist. Nothing deleted.")
Enter fullscreen mode Exit fullscreen mode

Its time to mark our task as completed. Lets put a condition if input1 is done and input2 is not default but it is integer greater than 0 and less than equal to the length of line present in task.txt then mark that line as done and remove it from task.txt and store it in completed.txt file, use relevant index to remove and store line. And if index does not exist then show error.

# Mark a task as complete

elif(args.input1 == 'done' and args.input2 != '-1' and int(args.input2) <= t and int(args.input2)>0):
    line = task_data[int(args.input2)-1]
    completed_task.write(task_data[int(args.input2)-1])
    task_data.remove(task_data[int(args.input2)-1])
    task.truncate(0)
    task.seek(0)
    for line in task_data:
        line = line.strip()
        task.write(line+"\n")
    print('Marked item as done.')

elif(args.input1 == 'done'):
    print("Error: no incomplete item with index "+str(int(args.input2))+" exists.")
Enter fullscreen mode Exit fullscreen mode

Finally! We are now ready to generate our report. Huhhh…
Put a condition that says if our input1 is a report, then show all the data in task.txt and completed.txt.

# Generate a Report 

elif(args.input1 == 'report'):
    print("Pending tasks: "+ str(t))
    for i in range(t,0,-1):
        line = task_data[i-1].strip()
        print(str(i)+'. '+ line )
    print("Completed tasks: "+ str(c))
    for i in range(c,0,-1):
        line = completed_data[i-1].strip()
        print(str(i)+'. '+ line )
Enter fullscreen mode Exit fullscreen mode

Tada!! Our cli application is now ready to use. You did it, and I'm delighted it came in handy. The complete source code is available on my github repo. Visit it Once.

party gif

Top comments (0)