Issue
I have a Python software which includes a configuration file and a manpage. To install these, I have the following line in my setup.py
(as described on href="http://docs.python.org/2/distutils/setupscript.html#installing-additional-files" rel="nofollow">http://docs.python.org/2/distutils/setupscript.html#installing-additional-files):
data_files = [('/etc/foo', ['foo.conf']), ('/usr/share/man/man1', ['foo.1'])]
This works just fine when I want to install the software as root with python setup.py install
, but of course fails in a virtualenv, as the user is not permitted to write to /etc
and /usr/share/man
.
What is the best practice to fix that? Check for VIRTUAL_ENV
in the current environment and just not install those files at all? The software will look for foo.conf
in the local directory, so that should be no problem. The user would miss the manpage, but there is no sane way to install it anyways, as man
won't look for it anywhere near the virtualenv.
Solution
Ultimately it seems that your question is really about how to detect whether the running Python is in a virtualenv. To get to the bottom of this we must understand how virtualenv
actually works.
When you run the activate
script inside a virtualenv, it does two things:
- it updates the
PATH
environment variable to include thebin
directory from the virtualenv, so that when you runpython
the binary from the virtualenv will run. - it sets a variable
VIRTUAL_ENV
so that the activate script itself can keep track of the activation.
It's perfectly acceptable to directly run the python
from the virtualenv, and at runtime python
does not use the VIRTUAL_ENV
variable at all. Instead, it determines the directory containing the running python
binary and uses the parent directory as its "prefix".
You can determine the system's prefix by importing the sys
module and consulting sys.prefix
. However, it would be a bad idea to depend on the value of this when a virtualenv is not activated because this is a build-time setting for Python that can easily be customized, and it will definitely vary between platforms.
However, Python does have one slight runtime difference when it runs from a virtualenv prefix vs. its compiled-in prefix: the sys
package has an additional variable real_prefix
that returns the prefix that is compiled into the Python binary. Therefore one could use this to recognize that Python is running in a non-default location, which is reasonably likely to mean it's running from a virtualenv:
import sys
if getattr(sys, "real_prefix", None) is not None:
print "Maybe in a virtualenv"
else:
print "Probably not in a virtualenv"
However, even this is not an exact science. All this really tells you is that the python binary is not at the location specified at compile time. It does not tell you whether the current user has access to write to /usr/share/man
-- there are some (possibly edge) cases where this won't give you the right answer:
If the user has compiled his own Python from source in his home directory and its compiled prefix is
/home/johnd/local-python
thenreal_prefix
won't be set but the user still has write access to his Pythonlib
directory, and probably not write access to/etc
or/usr/share/man
Likewise, on some systems the administrator may have granted group-write privileges on
/usr/lib/python2.7
to a certain group of app developers so that they can install Python modules, but not have granted them write access to other system files.
So I think in the end the best you can do is a heuristic and it may be better to instead just avoid using absolute paths in data_files
for any module you expect to be used inside a virtualenv. A compromise might be to simply split your module into two distributions, one representing the localizable source files and another representing the system-wide configuration to make it run. The latter can depend on the former so that users can still easily install it, but those using virtualenv
have the option of using the other former directly.
Answered By - Martin Atkins Answer Checked By - Pedro (WPSolving Volunteer)