smhk

Pylint: Use source-roots instead of init-hook to fix E0401 'import-error'

TL;DR: Instead of using sys.path.append(<path>) in init-hook to configure Pylint, use source-roots = "<path>".

Background §

It is common to get the error E0401 “import-error” when setting up Pylint, because Pylint needs to be able to follow your imports to verify they are working.

There is a lot of outdated advice online1 about how to solve this, with countless popular examples2 of using init-hook containing sys.path.append(...) to add your modules to the PATH.

However, all that is now moot!

Use source-roots instead of init-hook §

Today I stumbled across the source-roots option3.

source-roots is a comma separated list of paths4 which can be put in your pyproject.toml as follows:

pyproject.toml
[tool.pylint.main]
source-roots = "my_project/src"

The above option is equivalent to the following init-hook, but avoids the need to stuff Python into your config:

pyproject.toml
[tool.pylint.main]
# OLD METHOD: Do not do this.
init-hook = "import sys; sys.path.append('my_project/src')"

The new source-roots option is much nicer - spread the word! 📢


  1. This note I published five years ago, with an example of how to move a complex Pylint init-hook to an external script, is one such outdated piece of advice. As such, I’ve added a bold warning to mark that note as deprecated, and a link to this note for the new approach. ↩︎

  2. Like this and this↩︎

  3. Going back through the Pylint documentation, it first appeared in v2.17.7. However, the changelog for v2.17.7 lists GitHub issue #8290 which is about adding globbing support to source-roots, which impies the option already existed. If we dig into the Git history, then this commit is where the source-roots option first appeared in doc/user_guide/configuration/all-options.rst, as part of GitHub issue #8153, which was also part of v2.17.7, which was released on 30th September 2023. So this feature has only been around for a little over a year. ↩︎

  4. The paths support globbing, e.g. "path/to/something/*"↩︎