Home Unify Python Linting. Syncing Ruff between PyCharm and Neovim
Post
Cancel

Unify Python Linting. Syncing Ruff between PyCharm and Neovim

Configure PyCharm and Neovim to ensure your develpment environment is consistent and your code style matches, regardless of which editor your choose.

Why?

A linter is a tool used in software development to analyze source code for errors, bugs, and stylistic issues. It helps improve code quality by flagging problems before the code is executed. Linters are essential for maintaining coding standards and ensuring that code is clean and maintainable.

When we program in python, although IDEs claim to follow PEP8, the reality is that PEP8 is a style guide, not a single software configuration.

Since I usually use PyCharm and Neovim as python IDEs, I, sometimes, encounter minor formatting style differences. These small differences slightly break the consistency between files/files projects and end up costing me some time to fix.

Ruff

PyCharm saves its configuration in the .idea/ folder or in its global settings. Neovim looks for standard configuration files in the project root. For consistency between linters, ideally both should read the same source of truth.

Ruff is currently the de facto standard because it replaces almost a dozen tools (flake8, isort, pydocstyle, etc.) and is faster because it’s written in Rust.

The plan is to keep Pyright for type analysis (where it excels) and add Ruff for linting and automatic formatting.

First off, let’s install Ruff:

pipx install ruff

Now, we uninstall python-lsp-server

pipx uninstall python-lsp-server

Create a common python standard

As we mentioned before, to ensure both IDEs behave the same, they should read the same font. To force both IDEs to follow the same rules, we need to configure our Ruff settings.

Configuring ruff

Ruff follows a specific hierarchy to resolve settings. It searches for a configuration file in the current directory and continues up the parent directories until it finds one.

Global Configuration (User-wide)

To apply rules to every Python project on your machine (as a fallback when no project-specific file exists), use the following directory: ~/.config/ruff/ with one of the following filenames:

  • settings.toml (Recommended)
  • ruff.toml
  • .ruff.toml

My settings.toml:

Do not use the [tool.ruff] header. Write properties directly at the root of the file.

Project Configuration

To apply rules to a specific project, place the file in the project’s root directory:

  • pyproject.toml (must use [tool.ruff] header and sections)
  • ruff.toml or .ruff.toml (direct properties, no headers)

My pyproject.toml:

Folder-Specific Configuration (Nested)

To override or extend rules for a specific subdirectory (e.g., allowing assert only in /tests or changing line lengths in /scripts), place a file inside that folder.

  • ruff.toml or .ruff.toml

Configure Neovim

Instead of pylsp (which is heavier), the ideal solution is to use the new Ruff server.

Let’s add the following sections to our init.vim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
local lspconfig = require('lspconfig')

lspconfig.ruff.setup({
  on_attach = function(client, bufnr)
    client.server_capabilities.hoverProvider = false
  end,
})

lspconfig.pyright.setup({
  settings = {
    pyright = {
      disableOrganizeImports = true,
    },
    python = {
      analysis = {
        ignore = { '*' },
      },
    },
  },
})

Configure PyCharm

Starting in 2025.3, JetBrains included Ruff as a “Core” tool (native) through the Python LSP plugin (enabled by default).

To configure Ruff: Go to Settings (Ctrl+Alt+S) > Python > Tools > Ruff:

  • Select the Enablecheckbox to start configuring Ruff settings.

  • Interpreter mode: PyCharm searches for a Ruff executable installed in your interpreter. To install the Ruff package for the selected interpreter, click Install Ruff.

  • Path mode: PyCharm searches for a Ruff executable in $PATH. If the executable is not found, you can specify the path by clicking the Browse... icon.

  • Select which Ruff options should be enabled.

JetBrains doc:

Thanks for reading! :)

This post is licensed under CC BY 4.0 by the author.