If you want to walk up from the current module/file that was handed to pylint
looking for the root of the module, this will do it.
[MASTER]
init-hook=sys.path += [os.path.abspath(os.path.join(os.path.sep, *sys.argv[-1].split(os.sep)[:i])) for i, _ in enumerate(sys.argv[-1].split(os.sep)) if os.path.isdir(os.path.abspath(os.path.join(os.path.sep, *sys.argv[-1].split(os.sep)[:i], '.git')))][::-1]
If you have a python module ~/code/mymodule/
, with a top-level directory layout like this
~/code/mymodule/
├── .pylintrc
├── mymodule/
│ └── src.py
└── tests/
└── test_src.py
Then this will add ~/code/mymodule/
to your python path and allow for pylint to run in your IDE, even if you're importing mymodule.src
in tests/test_src.py
.
You could swap out a check for a .pylintrc
instead but a git directory is usually what you want when it comes to the root of a python module.
Before you ask
The answers using import sys, os; sys.path.append(...)
are missing something that justifies the format of my answer. I don't normally write code that way, but in this case you're stuck dealing with the limitations of the pylintrc config parser and evaluator. It literally runs exec
in the context of the init_hook callback so any attempt to import pathlib
, use multi-line statements, store something into variables, etc., won't work.
A less disgusting form of my code might look like this:
import os
import sys
def look_for_git_dirs(filename):
has_git_dir = []
filename_parts = filename.split(os.sep)
for i, _ in enumerate(filename_parts):
filename_part = os.path.abspath(os.path.join(os.path.sep, *filename_parts[:i]))
if os.path.isdir(os.path.join(filename_part, '.git')):
has_git_dir.append(filename_part)
return has_git_dir[::-1]
# don't use .append() in case there's < 1 or > 1 matches found
sys.path += look_for_git_dirs(sys.argv[-1])
I wish I could have used pathlib.Path(filename).parents
it would have made things much easier.