If you're here just for the section on vscode working with Python on WSL, jump here.
Windows is now a development environment that can compete with Mac and Linux. Windows Subsystems for Linux lets you have an Ubuntu (or other Linux flavor) installation that works near seemlessly inside of Windows. Hyper Terminal running WSL's Bash and Visual Studio Code feel really nice to code in. These are instructions for getting set up and smoothing out most of the remaining rough edges. I've included a section on getting vscode to work well with Python and WSL, but the general pattern should be usable for any unsupported language (as of now, I believe it's only Node.js that has WSL support in vscode).
- Install WSL
- Install Visual Studio Code
- Install and set up Hyper Terminal
- Install and set up a Sublime GUI for editing Linux files
- Install and set up Python to work with vscode and WSL
Requirement: The Windows user can't have spaces in the name. vscode extensions can have issues with WSL if there is a space in the Windows user name.
- Follow the instructions here
- Download the default 64 bit vscode from here and install it.
Hyper is the terminal application for Windows that lives up to modern standards. It's built on Node and is rebindable, extendable, and otherwise customizable. However, WSL has a few extremely annoying defaults that affect all terminals, so we'll to fix those before doing anything else.
- Open up Hyper and type
Ctrl
+,
- Scroll down to shell and change it to
C:\\Windows\\System32\\bash.exe
- Reopen Hyper
- In Hyper, open your bash profile in your Linux user's home directory
nano ~/.bashrc
- Add this to your .bashrc (using
Shift
+Insert
to paste):
# Change ls colours
LS_COLORS="ow=01;36;40" && export LS_COLORS
- Add this to the same file, replacing
[user name]
with your Windows user name:
# For switching to mounted home easily
cd() {
if [[ $@ == "m~" ]]; then
command cd "/mnt/c/Users/[user name]"
else
command cd "$@"
fi
}
Ctl
+o
to save andCtl
+x
to exit- Reload your .bashrc using
source ~/.bashrc
- Create and open .inputrc in your Linux home directory using Nano:
nano ~/.inputrc
- Add this to .inputrc:
# Disable the bell sound on backspace
set bell-style none
- Load the .inputrc using
source ~/.inputrc
- In Hyper, update your list of packages
sudo apt update
- In Hyper, upgrade packages to their newest versions
sudo apt upgrade
It's good to do this every week or two to stay up to date.
- Download the Windows client from here, extract, and install
- Start MobaXTerm
- Go to Settings -> Configuration -> X11 and make sure Clipboard is set to:
disable "copy on select"
- In Hyper terminal do:
wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add -
sudo apt install apt-transport-https
echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list
sudo apt update
sudo apt install libgtk2.0
sudo apt install sublime-text
- Open your .bashrc in nano again using
nano ~/.bashrc
# Use MobaXterm to have a sublime GUI for editing linux files
export DISPLAY=:0
export PATH="$PATH:/mnt/c/Program Files (x86)/Mobatek/MobaXterm"
- Reload your .bashrc with
source ~/.bashrc
-
Install x11-server-utils to get the xset command to see if the server is running
sudo apt install x11-xserver-utils
-
Open your .bashrc in a GUI using sublime
subl ~/.bashrc
-
If you want to have MobaXterm on Windows start whenever you open up a bash shell so that you always have the ability to open Sublime quickly add this to your .bashrc :
# Start MobaXterm on opening terminal if it's not running
if ! xset q &>/dev/null; then
(
command MobaXterm.exe -hideterm &
)&>/dev/null
fi
- If you'd rather manually open MobaXterm when you want to use Sublime, this command will let you do both steps at once. It does take a bit of time for MobaXterm to start after you use it. Add it to your .bashrc :
# A command to open a file in sublime, and start MobaXterm first if it's not running
sublx () {
if ! xset q &>/dev/null; then
echo "Starting MobaXterm..."
(
command MobaXterm.exe -hideterm &
while ! xset q &>/dev/null; do
command sleep 1
done
command subl "$@" &
)&>/dev/null
else
(
command subl "$@" &
)&>/dev/null
fi
}
Both will only start MobaXterm if it isn't already running, and they'll both hide it after it starts up. You can access it directly by clicking on the ^
on your Windows task bar to see applications running in the background.
Note: if you already have a Python that you want to use instead of setting it up through pyenv, point to that Python bash.exe of your bat files.
- Run the following to get the Linux tools for installing new Pythons:
sudo apt install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev
- Install Git
sudo apt install git
- Follow the instructions here to install Pyenv, Pipsi, and Pipenv for your Linux. Make sure to follow the instructions for Ubuntu and write to your .bashrc and not .bash_profile. You must resetart Hyper after installing Pyenv, and you should install the latest stable Python (currently Python 3.6.5).
The one problem remaining with this setup is that vscode and WSL don't play well together yet for anything besides Node. You can't select the version of a language that lives in your Linux installation for vscode running, debugging, linting, code completion, or navigating using workspace symbols. This is a known issue that both the general WSL team and various language plugin teams are aware of and working on.
In the mean time, one solution is to create parallel installations. Linux is the runtime environment, but vscode talks to a Windows install. However, that can cause issues with the debugging, linting, and code completion. To solve this, we can manually set up bat files that translates between the Windows and Linux paths for Python and tell vscode to use that.
- Start vscode from Hyper
code &
- Open the list of extensions
Ctl
+Shift
+x
- Search for and install Python by Microsoft
- Restart vscode
- Go to your Windows user's home directory
cd m~
- Create a new directory for the config file
mkdir .vscode_bats
- Create and open python3.bat using vscode
code .vscode_bats/python3.bat &
- Add this to python3.bat to translate paths between Linux and Windows and point to the python being used by pyenv:
@echo off
set v_params=%*
set v_params=%v_params:\=/%
set v_params=%v_params:c:=/mnt/c%
set v_params=%v_params:"=\"%
bash.exe -c "~/.pyenv/shims/python %v_params%"
- Install pylint
pip install pylint
- And create
code .vscode_bats/pylint.bat &
@echo off
set v_params=%*
set v_params=%v_params:\=/%
set v_params=%v_params:c:=/mnt/c%
set v_params=%v_params:"=\"%
bash.exe -c "~/.pyenv/shims/pylint %v_params%"
- Install exuberant ctags
sudo apt install exuberant-ctags
- And create
code .vscode_bats/ctags.bat &
@echo off
set v_params=%*
set v_params=%v_params:\=/%
set v_params=%v_params:c:=/mnt/c%
set v_params=%v_params:"=\"%
bash.exe -c "ctags %v_params%"
- Open vscode settings using
Ctl
+,
within vscode - Add this between the {} in user settings on the righthand side, replacing
[user name]
with your Windows user name:
"python.pythonPath": "C:\\Users\\[user name]\\vscode_bats\\python3.bat",
"python.linting.pylintPath": "C:\\Users\\[user name]\\vscode_bats\\pylint.bat",
"python.workspaceSymbols.ctagsPath": "c:\\Users\\[user name]\\vscode_bats\\ctags.bat"
- By default linting happens on save, so if you want linting as you type, you can add the setting
"files.autoSave": "afterDelay"
which defaults to
"files.autoSaveDelay": 1000
We now have vscode talking to the Linux python enabled by pyenv, but we're using pipenv to manage Python and packages on a per project basis. To get vscode running with that, I created a bash function which creates and/or sets vscode workspace configuration to use the local pipenv virtual environment in the project folder.
- Install jq
sudo apt install jq
- Install sponge
sudo apt install moreutils
THIS REQUIRES HARD TABS, NOT SPACES. The EOF syntax doesn't like spaces for indentation.
- Open .bashrc
subl .bashrc
- Add:
# Functions to create workspace settings for vscode that tell it to use the local Python virtual environment
code_setup() {
program=$1
cat > .vscode/$program.bat <<- EOF
@echo off
set v_params=%*
set v_params=%v_params:\=/%
set v_params=%v_params:c:=/mnt/c%
set v_params=%v_params:"=\"%
bash.exe -c "$venv_url/bin/$program %v_params%"
EOF
windows_path="$PWD/.vscode/$program.bat"
windows_path=${windows_path/\/mnt\/c\/Users\//C:\/Users\/}
windows_path=${windows_path//\//'\\'}
if [ $program == "pylint" ]; then
program="linting.pylint"
fi
if grep -qF "python.${program}Path" .vscode/settings.json; then
if sed -i.bak "s+\"python.${program}Path\":.*(,)$+\"python.${program}Path\": \"${windows_path}$1\"+" .vscode/settings.json; then
echo "vscode set to use local virtual environment for $program in wokspace settings"
rm .vscode/settings.json.bak
else
echo "Changing workspace settings failed with error: $?"
echo "Reverting to previous vscode workspace settings"
mv -f .vscode/settings.json.bak .vscode/settings.json
fi
else
echo "$(jq ". += {\"python.${program}Path\": \"$windows_path\"}" .vscode/settings.json)" | sponge .vscode/settings.json
echo "adding python.${program}Path to vscode workspace settings"
fi
}
code_pipenv() {
venv_url=$(pipenv --venv)
mkdir -p .vscode
if ! [ -f .vscode/settings.json ]; then
cat > .vscode/settings.json <<- EOF
{
}
EOF
fi
code_setup python
code_setup pylint
}
- Reload your .bashrc using
source ~/.bashrc
- Navigate to the root folder of a python project that uses pipenv or create one:
cd m~
mkdir -p projects/python_vscode_test
cd projects/python_vscode_test
pipenv --python 3.6.5
pipenv install -d pylint
touch test.py
- Run
code_pipenv
in Bash to create or modify vscode workspace settings to use the local virtual environment for Python and Pylint. - Open the folder in vscode
vscode . &
and useCtl
+,
to check that workspace settings are set (righthand side, second tab) - Edit test.py with code completion, navigation, and linting.
code_pipenv
only needs to be run once per project, unless the project is set to use a different virtual environment. In that case, just run it again.
And you're off to the races! Hyper and vscode have a ton of cool features and extensions to explore.
If you use any CSV data, the vscode extensions Excel Viewer and Rainbow CSV are great for viewing it inside the editor.
I wrote the markdown for this using the preview feature of vscode to see the rendered version as I wrote it, and markdownlint for live linting.
hyperterm-paste is really nice if you want to copy code snippets into the termianl without executing them, or for copying multiline snippets.
Inspired by https://github.com/lloydstubber/my-wsl-setup, https://daverupert.com/2017/03/my-bash-on-windows-developer-environment/#hyper, and https://nickjanetakis.com/blog/using-wsl-and-mobaxterm-to-create-a-linux-dev-environment-on-windows#wsl-conemu-and-mobaxterm-to-the-rescue
Thanks for the guide. I have setup vscode and python on wsl. It seems to be working but when I try to navigate to definition of an import, vs code can't open the file as the path it is taking is a wsl path and I guess the path it requires is a windows path. Is there a workaround for this.
Adding the exact error it is
Unable to open 'init.py': File not found (file:///mnt/c/Users/sharat/Documents/projects/testing-python/.venv/lib/python3.6/site-packages/requests/init.py).