Shebang generation code incorrectly prefers system python over virtualenv python
See original GitHub issueOperating system: Ubuntu 20.04
Steps to reproduce
- Install Python 3.8.0 using
pyenv
and set the global Python version to 3.8.0 (pyenv global 3.8.0
). After this, in my$PATH
I havepython
,python3
,python3.8
which all run the same executable/home/user/.pyenv/versions/3.8.0/bin/python3
. - Crate a git repository.
- Inside the repository, create a virtual environment with
python -m venv venv
. - Activate the virtual environment with
source venv/bin/activate
. At this point in my$PATH
I have:python
andpython3
pointing to the virtualenv python, andpython3.8
which points to the global one (venv
doesn’t create the alias). - Install
pre-commit
andblack
withpip install pre-commit black
- Add the following python-script hook as
hook.py
:
#!/usr/bin/env python3
import black
- Make the script executable with
chmod +x hook.py
. - Add the following
.pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: my-hook
name: my hook
language: script
entry: hook.py
always_run: true
verbose: true
- Stage the new files and commit them.
- Install the
pre-commit
script and the hooks withpre-commit install --install-hooks
- Add a new file, stage it and commit it.
- Bug: the hook fails due to
ModuleNotFoundError
my hook..................................................................Failed
- hook id: my-hook
- duration: 0.02s
- exit code: 1
Traceback (most recent call last):
File "/home/user/test/hook.py", line 2, in <module>
import black
ModuleNotFoundError: No module named 'black
So, what is happening here?
Running ./hook.py
works as expected. Same for python hook.py
and simply running pre-commit
.
The problem, I think, is in the shebang generation code: https://github.com/pre-commit/pre-commit/blob/8f32c5b929ca99e4d396d27b993017f821f6670a/pre_commit/commands/install_uninstall.py#L56-L73
The code looks first for python3.8
in my $PATH
, and it finds the global one which doesn’t have the module black
installed, and uses it. This is confirmed by looking at .git/hooks/pre-commit
, which has the shebang #!/usr/bin/env python3.8
.
This means that git runs the hook using system python, which is not what I’d like.
But still it doesn’t explain why pre-commit
is running my hook.py
using the system python. Looking at .git/hooks/pre-commit
I find INSTALL_PYTHON = '/home/user/test/venv/bin/python'
, which means in turn that CMD
contains the virtualenv python.
I verified this by raising an exception before os.execvp(CMD[0], CMD)
and CMD
is the following
['/home/user/test/venv/bin/python', '-mpre_commit', 'hook-impl', '--config=.pre-commit-config.yaml', '--hook-type=pre-commit', '--hook-dir', '/home/user/test/.git/hooks', '--']
Moreover, running
/home/user/test/venv/bin/python -mpre_commit hook-impl --config=.pre-commit-config.yaml --hook-type=pre-commit --hook-dir /home/user/test/.git/hooks --
works just fine.
So my assumption is that the shebang in .git/hooks/pre-commit
which points to the system python is influencing anyway which interpreter gets chosen to execute the python script hooks.
In fact, changing the shebang in .git/hooks/pre-commit
to #!/usr/bin/env python3
, which resolves to the virtualenv python, makes everything work as expected. The problem is, of course, that every time the hooks are reinstalled the shebang is reset to the system python.
I would appreciate your feedback about the issue.
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (4 by maintainers)
Top GitHub Comments
yeah no surprise, this is pyenv doing bad things
Yes, figured that out just now.