question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Shebang generation code incorrectly prefers system python over virtualenv python

See original GitHub issue

Operating system: Ubuntu 20.04

Steps to reproduce

  1. 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 have python, python3, python3.8 which all run the same executable /home/user/.pyenv/versions/3.8.0/bin/python3.
  2. Crate a git repository.
  3. Inside the repository, create a virtual environment with python -m venv venv.
  4. Activate the virtual environment with source venv/bin/activate. At this point in my $PATH I have: python and python3 pointing to the virtualenv python, and python3.8 which points to the global one (venv doesn’t create the alias).
  5. Install pre-commit and black with pip install pre-commit black
  6. Add the following python-script hook as hook.py:
#!/usr/bin/env python3
import black
  1. Make the script executable with chmod +x hook.py.
  2. 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
  1. Stage the new files and commit them.
  2. Install the pre-commit script and the hooks with pre-commit install --install-hooks
  3. Add a new file, stage it and commit it.
  4. 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:closed
  • Created 3 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
asottilecommented, Nov 10, 2020

yeah no surprise, this is pyenv doing bad things

0reactions
lg-kialocommented, Nov 10, 2020

Yes, figured that out just now.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Should I put #! (shebang) in Python scripts, and what form ...
It is bad if some tool breaks if you activate a virtualenv in your shell. Luckily, the correct shebang is created automatically in...
Read more >
Interpreter independent isolated/virtual environments
Hi all, I would like to propose adding a way to run isolated/virtual environments completely independently of the interpreter.
Read more >
Why is it better to use "#!/usr/bin/env NAME" instead of "#!/path ...
This answer is not congruent with how Python in particular is commonly used. The Python executable you want to use is rarely /usr/bin/python...
Read more >
Resolve issues between Python and Linux with virtualenv
While Linux OSes favor Python 2, Python 3 is the widely preferred version. Install virtualenv to isolate Python 2 and 3 and prevent...
Read more >
Dead Simple Python: Virtual Environments and pip
A virtual environment, or virtualenv as it is sometimes called, is a sandbox where you can install only the Python packages you need....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found