Debugging a CDK Python project in Visual Studio Code

September 18, 2020

Debugging a CDK Python project in Visual Studio Code

The most time you spend as a developer is probably in debugging. Nothing can be more annoying than spending hours or maybe days into digging into a problem and not being able to find what on earth is going wrong. Sometimes it could be something as small as misconfiguration. Other times it could be something bigger that might require you to toss out all the code you just wrote. Today we’re going to look at how to setup debugging for CDK python projects in Visual Studio Code.

Let’s start by scaffolding a sample project CDK Python project.

mkdir cdk-debug-project
cd cdk-debug-project
cdk init app --language=python

OK, so now we have a simple project setup by the CDK CLI tool that also includes git and a new virtual Python environment. The git and virtual Python environment might not be added in your case and is something that is only happening from versions 1.61.1 on. In this case it is not a problem. If you don’t have the virtual Python environment (the .env directory) in your project folder, just run python3 -m venv .env and it will be created for you.

Now, open the folder in Visual Studio Code
visual studio code cdk-test initial

By default, Visual Studio Code will list all the python executables that it can find and execute in the button on the bottom left. You need to make sure you’re using the right Python executable. That is the one in you virtual environment, which is ./.env/bin/python. If you do not, then you will run into issues where it will not find your packages.

After selecting the right Python executable, it’s time to add a new run configuration for Visual Studio Code to tell it how it should be run. Click Run > Add Configuration. In the following dropdown select Python as the environment and in the Select debug configuration select Python File for configuration.

This will generate a new launch.json file in the .vscode folder, where all Visual Studio Code related files are stored.

{
    // 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: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal"
        }
    ]
}

This is a basic launch configuration for running Python files. This configuration will run the .py file that you have opened in Visual Studio Code. But for CDK applications you mostly just want to run the app.py file in your project whenever you changed something. So, let’s change the configuration a bit:

{
    // 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": "CDK Synth",
            "type": "python",
            "request": "launch",
            "program": "app.py",
            "console": "integratedTerminal"
        }
    ]
}

By setting program to app.py, it will always run app.py. I also updated the name to CDK Synth, as this configuration is for running a synthesize only. It doesn’t actually deploy your CDK output. You could add a Visual Studio Code build task to do it for you. I’ll leave this part for another blog post.

Before starting the application, make sure you installed all the packages, by running pip install -r requirements.txt.

Time to hit F5. This will fire up the run configuration and run the application in a debug console in Visual Studio Code. But unfortunately, you won’t see the Cloudformation output as you would when you would run cdk synth. This is because normally the CDK CLI tool would get the returned Python objects from app.py and handle the output part in the CDK CLI tool. For debugging this shouldn’t matter in most cases, since it does run the whole application up to app.synth() in your app.py file.

At this point you can start setting breakpoints in Visual Studio Code and running will pause at those breakpoints.

As you can see in the sidepanel on the left you can open the debug panel and inspect the variables, add watch expressions and see the call stack you’re currently in.

When you’re paused at a breakpoint, you can also make use of the Debug Console. This is useful when you want to execute code immediately in the context of the breakpoint, like assigning new values to variables or executing methods.

Env files

The last thing I want to show is how to use custom .env files in you run configuration. Sometimes you need to run a different .env file for a different situation. Or you might have several for different environments and need to test a specific one.

To configure a .env file to use, open up launch.json in the .vscode folder again. Add a envFile property to the configuration and the file use. You should end up with something like this:

{
    // 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": "CDK Synth",
            "type": "python",
            "request": "launch",
            "program": "app.py",
            "console": "integratedTerminal",
            "envFile": "${workspaceFolder}/.env.private"
        }
    ]
}

Here I’m assigning a file named .env.private to this configuration, assuming you have a .env file named like this in your project folder. Of course you could add more running configurations to launch.json if you desire. You can switch between them in Visual Studio Code.

I hope this helps. Let me know what you think. If you have any thoughts to make it better, please let me know as well.

Kah Tang

Kah Tang