Intro

I have been medically diagnosed with an inability to use the same editor for more than a year (or, If I stay with the same, delete my configuration and start from scratch).

For a while, I thought that I had solved my problem when I settled in a VIM + Tmux configuration that served me well. There was a single issue with it: I could not plot images using Matplotlib inside my Tmux split. That sounds like a minor issue to most people, and for a while, I was convinced that this was a minor issue for me as well.

IPython does not render inline plots when using Tmux and iTerm2

Unfortunately, working in machine learning and data science, creating plots is a big part of my daily flow. With time, what started as a minor inconvenience developed into a full-blown annoyance, and I could not ignore the problem anymore. This is how I ended up using VSCode.

Plotting inline using VSCode and Matplotlib

I started using VSCode and quickly realized that my traditional workflow required a bit of tweaking. I do not like to install applications on my local machine, so I tend to work inside docker containers. VSCode has the ability to open the workspace inside a docker container (nice), which in theory is everything that I might want.

Overall, I must say that it works fairly well, once you manage to understand how to configure it properly, that is. Properly configuring a custom docker container for python development can take a while, at least if you don’t know what you are doing, which was my case when I started.

What follows is the result of this journey trying to bend VSCode to my liking and what I learned from it.

devcontainer.json

The most important file to set up VSCode with docker is the devcontainer.json. It tells VSCode which docker image it needs to build and connect to and how to configure VSCode inside the docker container, including which extension to install and how to set them up.

Ignoring such configurations at first resulted in me being able to code inside the container without any of the benefits of a modern IDE (no code competition, highlighting, etc).

After some configuration we will want a file that looks as follows:

// .devcontainer/devcontainer.json
{

	// ...

	// Sets the run context to one level up instead of the .devcontainer folder, i.e, Root folder
	"context": "..",
	// Dockerfile in the root folder
	"dockerFile": "../Dockerfile",
	// Set *default* container specific settings.json values on container create.
	
	// you need to change the following parameters to match your docker container
	"settings": {
		"editor.formatOnSave": true,
		"python.formatting.provider": "black",
		"python.defaultInterpreterPath": "/usr/local/bin/python",
		"python.linting.enabled": true,
		"python.linting.pylintEnabled": true,
		"python.formatting.blackPath": "/home/worker/.local/bin/black",
		"python.linting.pylintPath": "/home/worker/.local/bin/pylint",
		// consisten with python version in dockerfile
		"python.autoComplete.extraPaths": [
			"/home/worker/.local/lib/python3.10/",
			"/home/worker/.local/lib/python3.10/site-packages/",
		]
	},
	
	// Basic extensions for python and path completition
	"extensions": [
		"ms-python.python",
		"ms-python.vscode-pylance",
		"christian-kohler.path-intellisense"
	],
	
	// Mount the code in the /workspace folder inside the container
	"workspaceMount": "source=${localWorkspaceFolder}/,target=/workspace,type=bind",
	"workspaceFolder": "/workspace",
	
	// ...
}

Some important points to highlight:

  • All the python paths need to be configured inside settings. Those paths need to reflect the python path inside the container, and that might vary depending on your specific installation. If a library or extension is not working properly, start by double-checking its path here.

  • Make sure to mount the local workspace in the correct folder. You need to change both, the target folder and the “workspace folder”.

An example project with all the above settings properly configured can be found in this Github repository.

Extra: Connecting via SSH

If your docker container is running in a different host (such as a large company server), the process is almost the same, with the only difference that first you need to ssh into the host and then connect to the remote container.

For machine learning workflows and large-scale simulations, you might need to leave the process running after you disconnect from your ssh session (think of leaving the model training overnight), instead of terminating it as soon as you disconnect from the host.

For such situations, we can configure VSCode to automatically start a Tmux session in the host upon connection. This will have the added benefit that the simulation will keep on running once we disconnect from the host and it will also be waiting for us the next time we connect to it.

To achieve so, add the following lines to your settings.json in your local configuration.

// settings.json
{
// ...

// the following assumes that /usr/bin/tmux is the correct path for tmux
// inside the remote ssh host, and that it is installed

// it attachs to a session named main if it exists or it creates a new one
"terminal.integrated.profiles.linux": {
        "tmux-profile": {
            "path": "/usr/bin/tmux",
            "args": [
                "new-session",
                "-A",
                "-s",
                "main"
            ]
        }
    },
    "terminal.integrated.defaultProfile.linux": "tmux-profile",
		// if your target host is not running linux, change that for the appropiate OS.
// ...
}

Summary

In this blog post, we went over the basics of setting up VSCode for python development inside docker containers. If you have any questions or suggestions, do not hesitate and ping me!

Coming up

After getting used to VIM as my main editor, is hard to code without all the shortcuts. In a future blog post, I will explore how to set up docker to feel like vim.