This morning while working on my AoC submission, I wondered what the simplest procedure was for sharing a minimal setup for editing Python in Visual Studio Code using ruff for formatting, linting and import sorting, and doing all of that automatically on save.

It turns out that you can just store the following extensions.json and settings.json in the .vscode sub-directory of your source directory, and all of the above will be done. As a bonus, you can use the ruff.toml example below to customise your ruff setup.

This is an opinionated little setup that will:

  • Suggest installing the oficial ruff formatter and linter extension;
  • Configure some extra mostly docstring-related checks for ruff;
  • Format all files in this project automatically, when you save;
  • Organize Python imports when you save;
  • Activate PyLance, the Python type-checker that comes with the Python extension.

If you are working with others on the same project, and you’re not using devcontainers, you could consider checking these in to git.

extensions.json

This goes in ${workspaceFolder}/.vscode/extensions.json or merge with whatever you have there:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
    // List of extensions which should be recommended for users of this workspace.
    "recommendations": [
        // formatting (replaces black), linting (replaces flake8), sorting imports!
        "charliermarsh.ruff"
    ],
    // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
    "unwantedRecommendations": []
}

settings.json

The following goes in ${workspaceFolder}/.vscode/settings.json, or merge with whatever you have there.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    "editor.formatOnSave": true,
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff"
    },
    "editor.codeActionsOnSave": {
        "source.organizeImports": "explicit"
    },
    "python.analysis.typeCheckingMode": "standard",
    "python.testing.pytestEnabled": true
}

ruff.toml

This goes in ${workspaceFolder}/ruff.toml.

I deviate from the standard 88 characters per line, and I strongly prefer the numpydoc-style docstrings (readability, easy conversion to markdown for openapi.json, numpy familiarity), but you can of course customize to your liking.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
line-length = 120

[lint]
# https://docs.astral.sh/ruff/settings/#select
# default for select is ["E4", "E7", "E9", "F"]
# we add D for docstrings, and N for naming conventions
extend-select = ["D", "N"]

[lint.pydocstyle]
convention = "numpy"