Skip to content

Import Error on Linux #711

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
cookiestuf opened this issue Dec 24, 2017 · 14 comments
Open

Import Error on Linux #711

cookiestuf opened this issue Dec 24, 2017 · 14 comments

Comments

@cookiestuf
Copy link

cookiestuf commented Dec 24, 2017

gitpython version: 2.1.8
git version: 1.8.3.1
python version: 2.7.5

I'm using REL7. This is not an issue in REL6 (not sure if I should post here or somewhere else...)

To reproduce on REL7:

  • create repo in your home dir with 700 permissions
  • cd $repo
  • sudo -u $someotheruser python -c "import git"
    here, someotheruser is not able to read $repo

I get this error: `Traceback (most recent call last):

  File "<string>", line 1, in <module>
  File "/usr/lib64/python2.7/site-packages/git/__init__.py", line 82, in <module>
    refresh()
  File "/usr/lib64/python2.7/site-packages/git/__init__.py", line 73, in refresh
    if not Git.refresh(path=path):
  File "/usr/lib64/python2.7/site-packages/git/cmd.py", line 293, in refresh
    raise ImportError(err)
ImportError: Bad git executable.
The git executable must be specified in one of the following ways:
    - be included in your $PATH
    - be set via $GIT_PYTHON_GIT_EXECUTABLE
    - explicitly set via git.refresh()

All git commands will error until this is rectified.

This initial warning can be silenced or aggravated in the future by setting the
$GIT_PYTHON_REFRESH environment variable. Use one of the following values:
    - quiet|q|silence|s|none|n|0: for no warning or exception
    - warn|w|warning|1: for a printed warning
    - error|e|raise|r|2: for a raised exception

Example:
    export GIT_PYTHON_REFRESH=quiet
@Byron
Copy link
Member

Byron commented Dec 24, 2017

Thanks for the detailed descriptions, which I am sure would help to reproduce it.

It appears this issue is not entirely complete, the example seems to be truncated - is this intended?
Also I am wondering what the desired behavior would be.
Thanks for the clarification.

@cookiestuf
Copy link
Author

Yes, I only mean to import git. The issue is that I am unable to import git in that specific situation (import git from an unreadable directory). The desired behavior is no error when trying to import git.

@Byron
Copy link
Member

Byron commented Dec 25, 2017

Thank you! I wonder why git does not appear to be in the PATH in that case, which is the source of the trouble.
When looking at the sudo ... invocation, I wonder what would happen if you would also specify the -i flag, like so: sudo -i -u $someotheruser python -c "import git". That should source some additional configuration files and hopefully set the PATH accordingly.

The way I see it right now, GitPython clearly communicates what the problem is, and allows the issue to be alleviated by following the instructions. Changing the defaults to be silent would certainly just delay the inevitable.
However, maybe there is a better way to deal with this, even though I am wondering what the value added would be.

@tomkcook
Copy link

This happens because explicitly passing a directory to which the user does not have permission as the cwd to POpen causes a PermissionError to be thrown. Compare:

$ mkdir temp
$ chmod go-rwx temp
$ pwd
/home/me/temp
$ sudo -u another_user python3 'import subprocess; subprocess.call(["pwd"], cwd=None)'
/home/me/temp
$ sudo -u another_user python3 'import subprocess; subprocess.call(["pwd"], cwd=".")'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.5/subprocess.py", line 557, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/lib/python3.5/subprocess.py", line 947, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.5/subprocess.py", line 1551, in _execute_child
    raise child_exception_type(errno_num, err_msg)
PermissionError: [Errno 13] Permission denied

I think you could fix this by changing cmd.py:691 to cwd = self._working_dir but haven't had a chance to test it.

@ianwestcott
Copy link

I have encountered the same problem under Ubuntu 14.04.

Git version: 1.9.1
GitPython version: 2.1.8
Python version: 2.7.6

In my case, I am attempting to invoke GitPython as another user, but from within my own home directory. To illustrate:

# confirm current user and path
$ whoami
ianw
$ pwd
/home/ianw
# confirm path is set when running commands as other user
$ sudo -u ubuntu echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
# confirm other user has git in path
$ sudo -u ubuntu which git
/usr/bin/git
# attempt to import GitPython as other user
$ sudo -u ubuntu python -c "import git"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/git/__init__.py", line 82, in <module>
    refresh()
  File "/usr/local/lib/python2.7/dist-packages/git/__init__.py", line 73, in refresh
    if not Git.refresh(path=path):
  File "/usr/local/lib/python2.7/dist-packages/git/cmd.py", line 293, in refresh
    raise ImportError(err)
ImportError: Bad git executable.
The git executable must be specified in one of the following ways:
    - be included in your $PATH
    - be set via $GIT_PYTHON_GIT_EXECUTABLE
    - explicitly set via git.refresh()

All git commands will error until this is rectified.

This initial warning can be silenced or aggravated in the future by setting the
$GIT_PYTHON_REFRESH environment variable. Use one of the following values:
    - quiet|q|silence|s|none|n|0: for no warning or exception
    - warn|w|warning|1: for a printed warning
    - error|e|raise|r|2: for a raised exception

Example:
    export GIT_PYTHON_REFRESH=quiet

I concur with @tomkcook's analysis that Popen() is throwing PermissionError because it can't read cwd, not because it can't find git. Thus, the error message shown above is inaccurate. To wit:

  1. On initialization of the module, the refresh() function is called with no arguments, meaning path defaults to None.
  2. That means that the Git.refresh() classmethod is also called with path set to None.
  3. Which, in turn, means that the Git class is instantiated with working_dir set to None, so its self._working_dir attribute is None as well.
  4. So when Git.refresh() attempts to invoke the "git version" command as a sanity test, it means execute() has no value for self._working_dir, so it falls back to using os.getcwd().
  5. Thus, in the case where cwd is a path that the user cannot access, the call to Popen() fails with the ambiguous PermissionError.

Aside from the error message being inaccurate, I question whether GitPython actually needs to use the current working directory in this context. If there's a need to preserve defaulting to the current working directory, perhaps it's worth confirming that it can be accessed (e.g. with os.access()) before passing it to Popen()?

@Byron
Copy link
Member

Byron commented Mar 17, 2018

@yarikoptic I totally agree, testing before failing is certainly a viable fix for the issue. Maybe it's even possible to handle the CWD differently, even though I would be afraid of subtle breakage if that behaviour would indeed change.
My recommendation is to check with os.access() and do the right thing™️ depending on the outcome.

@yarikoptic
Copy link
Contributor

Thanks for thinking about me @Byron, but did you mean ianwestcott ? or should I analyze the situation as well and provide feedback?

@Byron
Copy link
Member

Byron commented Mar 18, 2018

Indeed, I meant to reply to @ianwestcott, thanks for pointing it out 🥇 !

@JonZeolla
Copy link

JonZeolla commented Jul 11, 2018

Nice digging @ianwestcott - I'm having this same issue, but in another scenario where I have a puppet agent running what is effectively a GitPython wrapper, and notably doesn't have an interactive shell which tickles the Popen() PermissionError discussed above. In order to resolve it, I had to specify a cwd to my exec, but just poking my head in here to suggest perhaps an upstream fix/better error message.

@Byron
Copy link
Member

Byron commented Jul 15, 2018

Somehow I vaguely remember that a PR landed to fix this kind of issue. Maybe it's worth trying again with the latest release v2.1.11 .

@bhoward-rpx
Copy link

I'm still encountering this problem with GitPython 2.1.11 (with Python 2.7.6 on Ubuntu 14.04.1), when trying to invoke a script via sudo (e.g. sudo -Hu scriptuser /home/scriptuser/bin/script.py foo).

Initially very confused because the script's path definitely included the dir with the git executable.

Thanks to @ianwestcott 's deep dive, I was able to solve the problem by sticking these two lines at the very beginning of the script:

import os
os.chdir('/tmp')

@tomkcook
Copy link

@ianwestcott Given your analysis, why not do as I suggested and pass self._working_dir instead of os.getcwd()? In this case _working_dir will be None and this avoids the PermissionError.

@kartikeyangupta
Copy link

[root@a25d0d47c918 app]# python3

[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import git

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/git/__init__.py", line 83, in <module>
    refresh()
  File "/usr/local/lib/python3.6/site-packages/git/__init__.py", line 73, in refresh
    if not Git.refresh(path=path):
  File "/usr/local/lib/python3.6/site-packages/git/cmd.py", line 278, in refresh
    raise ImportError(err)
ImportError: Bad git executable.
The git executable must be specified in one of the following ways:
    - be included in your $PATH
    - be set via $GIT_PYTHON_GIT_EXECUTABLE
    - explicitly set via git.refresh()

All git commands will error until this is rectified.

This initial warning can be silenced or aggravated in the future by setting the
$GIT_PYTHON_REFRESH environment variable. Use one of the following values:
    - quiet|q|silence|s|none|n|0: for no warning or exception
    - warn|w|warning|1: for a printed warning
    - error|e|raise|r|2: for a raised exception

Example:
    export GIT_PYTHON_REFRESH=quiet


During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/git/__init__.py", line 85, in <module>
    raise ImportError('Failed to initialize: {0}'.format(exc))
ImportError: Failed to initialize: Bad git executable.
The git executable must be specified in one of the following ways:
    - be included in your $PATH
    - be set via $GIT_PYTHON_GIT_EXECUTABLE
    - explicitly set via git.refresh()

All git commands will error until this is rectified.

This initial warning can be silenced or aggravated in the future by setting the
$GIT_PYTHON_REFRESH environment variable. Use one of the following values:
    - quiet|q|silence|s|none|n|0: for no warning or exception
    - warn|w|warning|1: for a printed warning
    - error|e|raise|r|2: for a raised exception

Example:
    export GIT_PYTHON_REFRESH=quiet

I have to write export GIT_PYTHON_REFRESH=quiet after every reboot , I am trying this in docker:centos 7 , any way i can fix this permanently in centos 7.

@kartikeyangupta
Copy link

[root@a25d0d47c918 app]# python3

[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import git

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/git/__init__.py", line 83, in <module>
    refresh()
  File "/usr/local/lib/python3.6/site-packages/git/__init__.py", line 73, in refresh
    if not Git.refresh(path=path):
  File "/usr/local/lib/python3.6/site-packages/git/cmd.py", line 278, in refresh
    raise ImportError(err)
ImportError: Bad git executable.
The git executable must be specified in one of the following ways:
    - be included in your $PATH
    - be set via $GIT_PYTHON_GIT_EXECUTABLE
    - explicitly set via git.refresh()

All git commands will error until this is rectified.

This initial warning can be silenced or aggravated in the future by setting the
$GIT_PYTHON_REFRESH environment variable. Use one of the following values:
    - quiet|q|silence|s|none|n|0: for no warning or exception
    - warn|w|warning|1: for a printed warning
    - error|e|raise|r|2: for a raised exception

Example:
    export GIT_PYTHON_REFRESH=quiet


During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/git/__init__.py", line 85, in <module>
    raise ImportError('Failed to initialize: {0}'.format(exc))
ImportError: Failed to initialize: Bad git executable.
The git executable must be specified in one of the following ways:
    - be included in your $PATH
    - be set via $GIT_PYTHON_GIT_EXECUTABLE
    - explicitly set via git.refresh()

All git commands will error until this is rectified.

This initial warning can be silenced or aggravated in the future by setting the
$GIT_PYTHON_REFRESH environment variable. Use one of the following values:
    - quiet|q|silence|s|none|n|0: for no warning or exception
    - warn|w|warning|1: for a printed warning
    - error|e|raise|r|2: for a raised exception

Example:
    export GIT_PYTHON_REFRESH=quiet

I have to write export GIT_PYTHON_REFRESH=quiet after every reboot , I am trying this in docker:centos 7 , any way i can fix this permanently in centos 7.

Actually I had not installed git in the os therefore it was throwing this warning. Check if you all have installed git in your os.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

8 participants