When creating a quick script for Linux most people use a simple shell script. But, as they often do, small scripts get big very fast. Things then get complicated and hard to maintain. So why not shoot for a maintainable and readable script from the beginning? With the help of Python and the Click framework.

Let’s create a simple application in Python to talk to an API. You do not need to install Python; with VS code editor and the Remote Development plugin all the code runs directly in Docker. It will work on any OS as long as you have VS code and Docker installed. Later, when programming, testing and debugging is done, you can of course also run your application like a normal app.

Setup your environment

First download and install VS code. After installing you need to add the remote debugging plugin. To install it start VS code, go to Extensions, search for ‘Remote Development’, and simply click install.

Also, you need to install Docker, go to https://hub.docker.com/search/?type=edition&offering=community and pick the right one for your OS. Follow the instructions provided by Docker.

After VS code and Docker are installed, we can configure VS code. First, we need to create a project folder. In my case, I use C:\Users\jeroe\python as my project folder. In it create a file called ‘script.py’. You can do this in VS code or from your file explorer.

To use VS code on a remote server, click on the ‘Quick actions Status Bar’ item in the lower-left corner of the window. Click on ‘Remote-Containers: Open Folder in Container…’ This will open a new window where you need to select your project folder. After that you choose an environment for the Docker container.

In this case we need Python, so enter Python in the search area and select Python 3. VS code should then be restarted in a remote session.

Which will give you just enough time to get a cup of coffee.

CLI program with Python and the Click framework

Now we can edit the Python file and test if everything works. Add the following to the file:

print(“This runs in docker”)

Now just F5 and select ‘Python File’, it should output something like:

root@a1dd1d7083b5:/workspaces/python# cd /workspaces/python ; env PYTHONIOENCODING=UTF-8 PYTHONUNBUFFERED=1 /usr/local/bin/python /root/.vscode-server/extensions/ms-python.python-2019.10.41019/pythonFiles/ptvsd_launcher.py –default –client –host localhost –port 34125 /workspaces/python/script.py
This runs in docker

You can see that it runs in Docker by looking at the hostname root@a1dd1d7083b5 , this is clearly a Docker hostname not a Windows hostname.

Using the Click framework

Up next, the Click framework. With this framework it is really easy to create a CLI application with options and parameters. No need to script it by yourself. We are going to develop an application that can talk to an API and print the output. The API has different endpoints so our application needs to have different functions as well.

First, we configure the Docker container to install the Click framework with PIP. To do this create a file called ‘requirements.txt’ in the root of our project. The content of the file will be ‘click’. Also, edit the file called ‘devcontainer.json’ and uncomment the following line (around line 23):

// “postCreateCommand”: “pip install -r requirements.txt”,

Then click on the ‘quick actions Status Bar’ item in the lower-left corner of the window again and choose Rebuild Container. Now we are ready to create our program.

Open the ‘script.py’ file and remove everything in it. Add the following:

import click
import urllib.request as request
import json
 
print("This is our CLI program created in Python with the use of Click")
 
@click.group()
def cli():
    pass
 
@click.command()
def todo():
    """Simple program that gets all the todo's from https://jsonplaceholder.typicode.com/todos."""
    url = "https://jsonplaceholder.typicode.com/todos"
    with request.urlopen(url) as response:
        if response.getcode() == 200:
            source = response.read()
            data = json.loads(source)
        else:
            print('An error occurred while attempting to retrieve data from the API.')
    print(json.dumps(data, indent=4, sort_keys=True))
 
 
cli.add_command(todo)
 
if __name__ == '__main__':
    cli()

With this code we created a todo function which will fetch the todo items from the API and then print them. If you want to call this function from the command line you need to execute ‘python script.py todo’.

Let’s quickly go through the code. For this blog I will not focus on everything from the Click framework so let’s just focus on the todo function. With the line @click.command()  we specify that this is a Click function. Before we can call this function from the command line we need to add it. For this we use the line cli.add_command(todo) .

From now on you can call the program with the todo option.

Test the code in VS code

To test we need to change the launch.json file first. This file defines how VS code tests your script. To open the file go to the debug panel on the left side. Then click on the settings icon.

CLI program with Python and the Click framework

Change the content of the file to the following:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Run the program without options",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "args": [],
        },
        {
            "name": "Python: Run the program with the todo option",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "args": [
                "todo"
            ],
        },      
    ]
}

We now have two test configurations – one without options and one with the todo option. Now go back to the script.py file and hit F5. That should start the script, probably the option without options. So again in the debug panel change the dropdown menu from ‘Python: Run the program without options’ to ‘Python: Run the program with the todo parameter’ now click on run or hit F5 again.

You should now see a long list of todo items: congratulations, your first Python script with the Click framework works!

Extend the program with parameters

Now let’s extend the todo function with some parameters. For example give all todo items which are not completed yet. The url for this will be “https://jsonplaceholder.typicode.com/todos?completed=false”. Let’s change our code. First we add the parameter option to the todo function. To do this add the following line below @click.command()

@click.option(‘–show-not-completed-only’, is_flag=True)

With this line we define the parameter ‘- -show-not-completed-only’. When this click.option is defined, we then define the variable in the function. Change the function to:

def todo(show_not_completed_only):

We can now use the variable ‘show_not_completed_only’. Let’s add a simple if-statement to the function that if ‘show_only_open_items’ it needs to use the url with the ‘completed=false’ at the end. It can look something like this, but go ahead and create your own implementation.

@click.command()
@click.option('--show-not-completed-only', is_flag=True)
def todo(show_not_completed_only):
    """Simple program that gets all the todo's from https://jsonplaceholder.typicode.com/todos."""
    if (show_not_completed_only):
        url = "https://jsonplaceholder.typicode.com/todos?completed=false"
    else:
        url = "https://jsonplaceholder.typicode.com/todos"
    with request.urlopen(url) as response:
        if response.getcode() == 200:
            source = response.read()
            data = json.loads(source)
        else:
            print('An error occurred while attempting to retrieve data from the API.')
    print(json.dumps(data, indent=4, sort_keys=True))

Test with the debug option from VS code. Hit F5 to run the code again. Remember to add another configuration to the launch.json file to include the new parameter. Something like this:

        {
            "name": "Python: Run the program with the todo option not completed only",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "args": [
                "todo",
                "--show-not-completed-only"
            ],
        },

You can now run this new configuration and you should see the not completed items.

CLI program with Python and the Click framework

Wrap-up

If you followed all the steps you now have your first Python application up and running. Of course this is just an example with only one parameter, but it shows how simple it is to create a simple Python application, with parameters, without complex if-statements.

I hope you appreciate how easy it is to develop code with the use of an editor like VS code in combination with Docker, with all the tools and libraries already pre-installed. If you do, follow Techforce1 here, because in a follow-up blog I’ll extend the program with more complex options like prompting for input, choice options, feature switches and more 🙂