I'm maintaining a project that is using Bazel 0.5.4, and it needs to run on an environment where python does not exist. I'd like to point the application to using python3.
This issue is similar to Bazel 0.26.1 use Python3 on py_test, but the version of rules_python mentioned in that ticket is so new that it's not compatible with bazel 0.5.4
GOAL: Issue python commands with /usr/bin/python3, not python
As-is, the application fails when it's unable to find python
bazel build completes without an issue, but bazel test continues to look for python, and fail.
bazel test ... --test_output=all --python_top=//sandbox_app:python-3.8.10
...
/usr/bin/env: 'python': No such file or directory
================================================================================
INFO: Elapsed time: 0.658s, Critical Path: 0.10s
INFO: Build completed, 1 test FAILED, 2 total actions
//sandbox_app:sandbox_test FAILED in 0.1s
This didn't work
The following configuration worked for a similar user, described here:
https://groups.google.com/g/bazel-discuss/c/nVQ48R94S_8
But even after a bazel clean, bazel still continues to invoke python when running the tests.
WORKSPACE
git_repository(
name = "io_bazel_rules_go",
remote = "https://github.com/bazelbuild/rules_go.git",
tag = "0.5.4",
)
BUILD.bazel
package(default_visibility = ["//visibility:public"])
py_test(
name = "sandbox_test",
srcs = ["sandbox_test.py"],
default_python_version = "PY3",
srcs_version = "PY3",
)
py_runtime(
name = "python-3.8.10",
files = [],
interpreter_path = "/usr/bin/python3",
)
Version details:
$ bazel info release
release 0.5.4
It would minimize disruption to the application if this can be done without upgrading bazel.
sandbox_test.py
#!/usr/bin/python3
import unittest
class SandboxTest(unittest.TestCase):
def testRunSandbox(self):
# Valid for Python 3, syntax error for python2
print(print("Hello, Python!"))
if __name__ == '__main__':
unittest.main()
Possibly related issues
https://github.com/bazelbuild/bazel/issues/4815
https://github.com/bazelbuild/bazel/issues/200
Rules spec:
https://bazel.build/reference/be/python
Similar issues:
How do I select the runtime in bazel for Python and pip?
Bazel, python3 and python interpreter options
Getting Bazel to run using Python3 (syntax error)
I, like many python programmers find the command line arguments for python described here very useful. specifically "-i" which keeps the python interpreter running after a program finishes for a stack trace. How can I use these with an exe file compiled with py2exe? Not to be confused with regular argument parsing in an exe file. If you came looking for that, find it here.
My first thought was to try:
pyprogram.exe -i -foo -bar
but that didn't work.
it should be noted that
pyprogram.exe -foo -bar
does in fact work for me.
what I am looking for is the .exe equivalent of
python -i pyprogram.py foo bar
Failing to find an implementation that works for all of the python command line options, what could I do just to make the "-i" argument work? it is the most important to have as an option in my executable.
I did not find anything on the py2exe wiki about passing arguments like -i (to enter interactive mode after execution).
One might be able to discover information about the argument handling in the py2exe source files.
Update: It indeed looks like py2exe does not handle any command line options like the normal interpreter does, instead it just passes them to the script. But it does handle the respective environment variable, which can be used as shown below.
However, as a workaround, you could try to set the PYTHONINSPECT Environment variable:
If this is set to a non-empty string it is equivalent to specifying the -i option.
E.g. run set PYTHONINSPECT=TRUE before running the program.
But, probably even better, this can be done from within the Python script:
This variable can also be modified by Python code using os.environ to force inspect mode on program termination.
Here's a little test script for os.environ (also os.putenv):
import os
one = os.environ
os.putenv("PYTHONINSPECT", "TRUE")
two = os.environ
os.environ["PYTHONINSPECT"] = "TRUE"
three = os.environ
print(one)
print(two)
print(three)
print( set(one.items()) ^ set(two.items()) )
print( set(one.items()) ^ set(three.items()) )
The behaviour is a little weird: there does not seem to be a difference, and it seems to only last until you exit the interactive mode:
G:\>py test.py > test.txt
>>> exit()
G:\>set PYTHONINSPECT
Environment variable PYTHONINSPECT not defined
The contents of test.txt are:
environ({'ALLUSERSPROFILE': 'C:\\ProgramData', ... 'PYTHONINSPECT': 'TRUE'})
environ({'ALLUSERSPROFILE': 'C:\\ProgramData', ... 'PYTHONINSPECT': 'TRUE'})
environ({'ALLUSERSPROFILE': 'C:\\ProgramData', ... 'PYTHONINSPECT': 'TRUE'})
set()
set()
But it seems to work either way (double check the documentation for yourself to ensure you are not corrupting your environment variables), so you could even implement an -i argument for yourself like:
import sys, os
if len(sys.argv) > 1 and sys.argv[1] == '-i':
os.putenv("PYTHONINSPECT", "TRUE")
#os.environ["PYTHONINSPECT"] = "TRUE"
print("interactive")
else:
print("normal")
which runs as follows
G:\>py test.py
normal
G:\>py test.py -i
interactive
>>> quit()
G:\>set PYTHONINSPECT
Environment variable PYTHONINSPECT not defined
Trying with py2exe and Python 3.4.3 (newer versions are apparently not supported and you get an IndexError):
setup.py:
from distutils.core import setup
import py2exe
setup(console=['test.py'])
Get py2exe
G:\>c:\Python34\Scripts\pip.exe install py2exe
You are using pip version 6.0.8, however version 10.0.0b2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting py2exe
Using cached py2exe-0.9.2.2-py33.py34-none-any.whl
Installing collected packages: py2exe
Successfully installed py2exe-0.9.2.2
Run py2exe
G:\>c:\Python34\python.exe setup.py py2exe
running py2exe
3 missing Modules
------------------
? readline imported from cmd, code, pdb
? win32api imported from platform
? win32con imported from platform
Building 'dist\test.exe'.
Building shared code archive 'dist\library.zip'.
Copy c:\windows\system32\python34.dll to dist
Copy c:\Python34\DLLs\_hashlib.pyd to dist\_hashlib.pyd
Copy c:\Python34\DLLs\pyexpat.pyd to dist\pyexpat.pyd
Copy c:\Python34\DLLs\select.pyd to dist\select.pyd
Copy c:\Python34\DLLs\unicodedata.pyd to dist\unicodedata.pyd
Copy c:\Python34\DLLs\_ctypes.pyd to dist\_ctypes.pyd
Copy c:\Python34\DLLs\_socket.pyd to dist\_socket.pyd
Copy c:\Python34\DLLs\_lzma.pyd to dist\_lzma.pyd
Copy c:\Python34\DLLs\_ssl.pyd to dist\_ssl.pyd
Copy c:\Python34\DLLs\_bz2.pyd to dist\_bz2.pyd
Test
G:\>dist\test.exe
normal
G:\>dist\test.exe -i
interactive
>>> sys.exit()
Does not seem to have changed the environment variables permanently:
G:\>set PYTHONINSPECT
Environment variable PYTHONINSPECT not defined
Also works with single exe:
from distutils.core import setup
import py2exe
setup(
options = {'py2exe': {'bundle_files': 1, 'compressed': True}},
console = [{'script': "test.py"}],
zipfile = None,
)
I've got a python module that calls an external binary, built from C source.
The source for that external executable is part of my python module, distributed as a .tar.gz file.
Is there a way of unzipping, then compiling that external executable, and installing it using setuptools/setup.py?
What I'd like to achieve is:
installing that binary into virtual environments
manage compilation/installation of the binary using setup.py install, setup.py build etc.
making the binary part of my python module, so that it can be distributed as a wheel without external dependencies
Solved in the end by modifying setup.py to add additional handlers for commands which did the installation.
An example of a setup.py which does this might be:
import os
from setuptools import setup
from setuptools.command.install import install
import subprocess
def get_virtualenv_path():
"""Used to work out path to install compiled binaries to."""
if hasattr(sys, 'real_prefix'):
return sys.prefix
if hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix:
return sys.prefix
if 'conda' in sys.prefix:
return sys.prefix
return None
def compile_and_install_software():
"""Used the subprocess module to compile/install the C software."""
src_path = './some_c_package/'
# compile the software
cmd = "./configure CFLAGS='-03 -w -fPIC'"
venv = get_virtualenv_path()
if venv:
cmd += ' --prefix=' + os.path.abspath(venv)
subprocess.check_call(cmd, cwd=src_path, shell=True)
# install the software (into the virtualenv bin dir if present)
subprocess.check_call('make install', cwd=src_path, shell=True)
class CustomInstall(install):
"""Custom handler for the 'install' command."""
def run(self):
compile_and_install_software()
super().run()
setup(name='foo',
# ...other settings skipped...
cmdclass={'install': CustomInstall})
Now when python setup.py install is called, the custom CustomInstall class is used, this then compiles and installs software before the normal install steps are run.
You can also do similar for any other steps you're interested in (e.g. build/develop/bdist_egg etc.).
An alternative is to make the compile_and_install_software() function a subclass of setuptools.Command, and create a fully fledged setuptools command for it.
This is more complicated, but lets you do things like specify it as a subcommand of another command (to e.g. avoid executing it twice), and to pass custom options in to it on the command line.
I have a python script that needs dependencies from a virtualenv. I was wondering if there was some way I could add it to my path and have it auto start it's virtualenv, run and then go back to the system's python.
I've try playing around with autoenv and .env but that doesn't seem to do exactly what I'm looking for. I also thought about changing the shabang to point to the virtualenv path but that seems fragile.
There are two ways to do this:
Put the name of the virtual env python into first line of the script. Like this
#!/your/virtual/env/path/bin/python
Add virtual environment directories to the sys.path. Note that you need to import sys library. Like this
import sys
sys.path.append('/path/to/virtual/env/lib')
If you go with the second option you might need to add multiple paths to the sys.path (site etc). The best way to get it is to run your virtual env python interpreter and fish out the sys.path value. Like this:
/your/virtual/env/bin/python
Python blah blah blah
> import sys
> print sys.path
[ 'blah', 'blah' , 'blah' ]
Copy the value of sys.path into the snippet above.
I'm surprised that nobody has mentioned this yet, but this is why there is a file called activate_this.py in the virtualenv's bin directory. You can pass that to execfile() to alter the module search path for the currently running interpreter.
# doing execfile() on this file will alter the current interpreter's
# environment so you can import libraries in the virtualenv
activate_this_file = "/path/to/virtualenv/bin/activate_this.py"
execfile(activate_this_file, dict(__file__=activate_this_file))
You can put this file at the top of your script to force the script to always run in that virtualenv. Unlike the modifying hashbang, you can use relative path with by doing:
script_directory = os.path.dirname(os.path.abspath(__file__))
activate_this_file = os.path.join(script_directory, '../../relative/path/to/env/bin/activate_this.py')
From the virtualenv documentation:
If you directly run a script or the python interpreter from the
virtualenv’s bin/ directory (e.g. path/to/env/bin/pip or
/path/to/env/bin/python script.py) there’s no need for activation.
So if you just call the python executable in your virtualenv, your virtualenv will be 'active'. So you can create a script like this:
#!/bin/bash
PATH_TO_MY_VENV=/opt/django/ev_scraper/venv/bin
$PATH_TO_MY_VENV/python -c 'import sys; print(sys.version_info)'
python -c 'import sys; print(sys.version_info)'
When I run this script on my system, the two calls to python print what you see below. (Python 3.2.3 is in my virtualenv, and 2.7.3 is my system Python.)
sys.version_info(major=3, minor=2, micro=3, releaselevel='final', serial=0)
sys.version_info(major=2, minor=7, micro=3, releaselevel='final', serial=0)
So any libraries you have installed in your virtualenv will be available when you call $PATH_TO_MY_VENV/python. Calls to your regular system python will of course be unaware of whatever is in the virtualenv.
I think the best answer here is to create a simple script and install it inside your virtualenv. Then you can either directly use the script, or create a symlink, or whatever.
Here's an example:
$ mkdir my-tool
$ cd my-tool
$ mkdir scripts
$ touch setup.py
$ mkdir scripts
$ touch scripts/crunchy-frog
$ chmod +x scripts/crunchy-frog
crunchy-frog
#!/usr/bin/env python
print("Constable Parrot ate one of those!")
setup.py
from setuptools import setup
setup(name="my-cool-tool",
scripts=['scripts/crunchy-frog'],
)
Now:
$ source /path/to/my/env/bin/activate
(env) $ python setup.py develop
(env) $ deactivate
$ cd ~
$ ln -s /path/to/my/env/bin/crunchy-frog crunchy-frog
$ ./crunchy-frog
Constable Parrot ate one of those!
When you install your script (via setup.py install or setup.py develop) then it will replace the first line of the scripts with a shebang line for the env python (which you can verify with $ head /path/to/my/env/bin/crunchy-frog). So whenever you run that particular script, it will use that specific Python env.
Does this help?
import site
site.addsitedir('/path/to/virtualenv/lib/python2.7/site-packages/')
I had this problem before and I made a simple script to look for a virtualenv folder recursively just importing and calling a function:
script_autoenv.py
# -*- coding:utf-8 -*-
import os, site
def locate_env(path, env_name):
"""search for a env directory name in each directory in the path"""
if os.path.isdir(path + "/env"):
env_26_path = '%s/%s/lib/python2.6/site-packages/' % (path, env_name)
env_27_path = '%s/%s/lib/python2.7/site-packages/' % (path, env_name)
if os.path.isdir(env_26_path):
site.addsitedir(env_26_path)
print "Virtualenv 2.6 founding"
elif os.path.isdir(env_27_path):
site.addsitedir(env_27_path)
print "Virtualenv 2.7 founding"
else:
new_path, old_dir = os.path.split(path)
if old_dir:
locate_env(new_path, env_name)
else:
print "No envs found"
You just need to specify the script directory and the env name folder and the script do the rest:
test.py
# -*- coding:utf-8 -*-
import os
import script_autoenv
script_autoenv.locate_env(os.path.realpath(__file__), 'env')
import django
print django.VERSION
I hope it's works for you
The answer may be pipenv (https://pipenv.readthedocs.io/en/latest/).
It will allow you to do something like:
pipenv run python main.py
to run main.py in the python environment with the specified libraries.
You can give it a try here https://rootnroll.com/d/pipenv/
...Maybe is not exactly what you are looking for, but it may be worth taking a look before reinventing it.
Is it possible to determine if the current script is running inside a virtualenv environment?
The most reliable way to check for this is to check whether sys.prefix == sys.base_prefix. If they are equal, you are not in a virtual environment; if they are unequal, you are. Inside a virtual environment, sys.prefix points to the virtual environment, and sys.base_prefix is the prefix of the system Python the virtualenv was created from.
The above always works for Python 3 stdlib venv and for recent virtualenv (since version 20). Older versions of virtualenv used sys.real_prefix instead of sys.base_prefix (and sys.real_prefix did not exist outside a virtual environment), and in Python 3.3 and earlier sys.base_prefix did not ever exist. So a fully robust check that handles all of these cases could look like this:
import sys
def get_base_prefix_compat():
"""Get base/real prefix, or sys.prefix if there is none."""
return getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
def in_virtualenv():
return get_base_prefix_compat() != sys.prefix
If you only care about supported Python versions and latest virtualenv, you can replace get_base_prefix_compat() with simply sys.base_prefix.
Using the VIRTUAL_ENV environment variable is not reliable. It is set by the virtualenv activate shell script, but a virtualenv can be used without activation by directly running an executable from the virtualenv's bin/ (or Scripts) directory, in which case $VIRTUAL_ENV will not be set. Or a non-virtualenv Python binary can be executed directly while a virtualenv is activated in the shell, in which case $VIRTUAL_ENV may be set in a Python process that is not actually running in that virtualenv.
Try using pip -V (notice capital V)
If you are running the virtual env. it'll show the path to the env.'s location.
This is an improvement of the accepted answer by Carl Meyer. It works with virtualenv for Python 3 and 2 and also for the venv module in Python 3:
import sys
def is_venv():
return (hasattr(sys, 'real_prefix') or
(hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))
The check for sys.real_prefix covers virtualenv, the equality of non-empty sys.base_prefix with sys.prefix covers venv.
Consider a script that uses the function like this:
if is_venv():
print('inside virtualenv or venv')
else:
print('outside virtualenv or venv')
And the following invocation:
$ python2 test.py
outside virtualenv or venv
$ python3 test.py
outside virtualenv or venv
$ python2 -m virtualenv virtualenv2
...
$ . virtualenv2/bin/activate
(virtualenv2) $ python test.py
inside virtualenv or venv
(virtualenv2) $ deactivate
$ python3 -m virtualenv virtualenv3
...
$ . virtualenv3/bin/activate
(virtualenv3) $ python test.py
inside virtualenv or venv
(virtualenv3) $ deactivate
$ python3 -m venv venv3
$ . venv3/bin/activate
(venv3) $ python test.py
inside virtualenv or venv
(venv3) $ deactivate
Check the $VIRTUAL_ENV environment variable.
The $VIRTUAL_ENV environment variable contains the virtual environment's directory when in an active virtual environment.
>>> import os
>>> os.environ['VIRTUAL_ENV']
'/some/path/project/venv'
Once you run deactivate / leave the virtual environment, the $VIRTUAL_ENV variable will be cleared/empty. Python will raise a KeyError because the environment variable was unset.
>>> import os
>>> os.environ['VIRTUAL_ENV']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/os.py", line 678, in __getitem__
raise KeyError(key) from None
KeyError: 'VIRTUAL_ENV'
These same environment variable checks can of course also be done outside of the Python script, in the shell.
There are multiple good answers here, and some less robust ones.
Here's an overview.
How not to do it
Do not rely on on the location of Python or the site-packages folder.
If these are set to non-standard locations, that does not mean
you're actually in a virtual environment. Users can have more than one
Python version installed, and those are not always where you expect them to be.
Avoid looking at:
sys.executable
sys.prefix
pip -V
which python
Also, do not check for the presence of venv, .venv or envs in any of these paths.
This will break for environments with a more unique location. For example,
Pipenv uses hash values as the name for its environments.
VIRTUAL_ENV environment variable
Both virtualenv and venv set the environment variable $VIRTUAL_ENV when activating an environment.
See PEP 405.
You can read out this variable in shell scripts, or use this Python code to determine if it's set.
import os
running_in_virtualenv = "VIRTUAL_ENV" in os.environ
# alternative ways to write this, also supporting the case where
# the variable is set but contains an empty string to indicate
# 'not in a virtual environment':
running_in_virtualenv = bool(os.environ.get("VIRTUAL_ENV"))
running_in_virtualenv = bool(os.getenv("VIRTUAL_ENV"))
The problem is, this only works when the environment is activated by the activate shell script.
You can start the environment's scripts without activating the environment, so if that is a concern, you have to use a different method.
sys.base_prefix
virtualenv, venv and pyvenv point sys.prefix to the Python installed inside of the virtualenv as you would expect.
At the same time, the original value of sys.prefix is also made available as sys.base_prefix.
We can use that to detect if we're in a virtualenv.
import sys
# note: Python versions before 3.3 don't have sys.base_prefix
# if you're not in virtual environment
running_in_virtualenv = sys.prefix != sys.base_prefix
Fallback: sys.real_prefix
Now watch out, virtualenv before version 20 did not set sys.base_prefix but it set sys.real_prefix instead.
So to be safe, check both as suggested in hroncok's answer:
import sys
real_prefix = getattr(sys, "real_prefix", None)
base_prefix = getattr(sys, "base_prefix", sys.prefix)
running_in_virtualenv = (base_prefix or real_prefix) != sys.prefix
Anaconda
If you're using Anaconda virtual environments, check
Victoria Stuart's answer.
According to the virtualenv pep at http://www.python.org/dev/peps/pep-0405/#specification you can just use sys.prefix instead os.environ['VIRTUAL_ENV'].
the sys.real_prefix does not exist in my virtualenv and same with sys.base_prefix.
To check whether your inside Virtualenv:
import os
if os.getenv('VIRTUAL_ENV'):
print('Using Virtualenv')
else:
print('Not using Virtualenv')
You can also get more data on your environment:
import sys
import os
print(f'Python Executable: {sys.executable}')
print(f'Python Version: {sys.version}')
print(f'Virtualenv: {os.getenv("VIRTUAL_ENV")}')
You can do which python and see if its pointing to the one in virtual env.
Updated Nov 2019 (appended).
I routinely use several Anaconda-installed virtual environments (venv). This code snippet/examples enables you to determine whether or not you are in a venv (or your system environment), and to also require a specific venv for your script.
Add to Python script (code snippet):
# ----------------------------------------------------------------------------
# Want script to run in Python 3.5 (has required installed OpenCV, imutils, ... packages):
import os
# First, see if we are in a conda venv { py27: Python 2.7 | py35: Python 3.5 | tf: TensorFlow | thee : Theano }
try:
os.environ["CONDA_DEFAULT_ENV"]
except KeyError:
print("\tPlease set the py35 { p3 | Python 3.5 } environment!\n")
exit()
# If we are in a conda venv, require the p3 venv:
if os.environ['CONDA_DEFAULT_ENV'] != "py35":
print("\tPlease set the py35 { p3 | Python 3.5 } environment!\n")
exit()
# See also:
# Python: Determine if running inside virtualenv
# http://stackoverflow.com/questions/1871549/python-determine-if-running-inside-virtualenv
# [ ... SNIP! ... ]
Example:
$ p2
[Anaconda Python 2.7 venv (source activate py27)]
(py27) $ python webcam_.py
Please set the py35 { p3 | Python 3.5 } environment!
(py27) $ p3
[Anaconda Python 3.5 venv (source activate py35)]
(py35) $ python webcam.py -n50
current env: py35
processing (live): found 2 faces and 4 eyes in this frame
threaded OpenCV implementation
num_frames: 50
webcam -- approx. FPS: 18.59
Found 2 faces and 4 eyes!
(py35) $
Update 1 -- use in bash scripts:
You can also use this approach in bash scripts (e.g., those that must run in a specific virtual environment). Example (added to bash script):
if [ $CONDA_DEFAULT_ENV ] ## << note the spaces (important in BASH)!
then
printf 'venv: operating in tf-env, proceed ...'
else
printf 'Note: must run this script in tf-env venv'
exit
fi
Update 2 [Nov 2019]
For simplicity, I like Matt's answer (https://stackoverflow.com/a/51245168/1904943).
Since my original post I've moved on from Anaconda venv (and Python itself has evolved viz-a-viz virtual environments).
Reexamining this issue, here is some updated Python code that you can insert to test that you are operating in a specific Python virtual environment (venv).
import os, re
try:
if re.search('py37', os.environ['VIRTUAL_ENV']):
pass
except KeyError:
print("\n\tPlease set the Python3 venv [alias: p3]!\n")
exit()
Here is some explanatory code.
[victoria#victoria ~]$ date; python --version
Thu 14 Nov 2019 11:27:02 AM PST
Python 3.8.0
[victoria#victoria ~]$ python
Python 3.8.0 (default, Oct 23 2019, 18:51:26)
[GCC 9.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, re
>>> re.search('py37', os.environ['VIRTUAL_ENV'])
<re.Match object; span=(20, 24), match='py37'>
>>> try:
... if re.search('py37', os.environ['VIRTUAL_ENV']):
... print('\n\tOperating in Python3 venv, please proceed! :-)')
... except KeyError:
... print("\n\tPlease set the Python3 venv [alias: p3]!\n")
...
Please set the Python3 venv [alias: p3]!
>>> [Ctrl-d]
now exiting EditableBufferInteractiveConsole...
[victoria#victoria ~]$ p3
[Python 3.7 venv (source activate py37)]
(py37) [victoria#victoria ~]$ python --version
Python 3.8.0
(py37) [victoria#victoria ~]$ env | grep -i virtual
VIRTUAL_ENV=/home/victoria/venv/py37
(py37) [victoria#victoria ~]$ python
Python 3.8.0 (default, Oct 23 2019, 18:51:26)
[GCC 9.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, re
>>> try:
... if re.search('py37', os.environ['VIRTUAL_ENV']):
... print('\n\tOperating in Python3 venv, please proceed! :-)')
... except KeyError:
... print("\n\tPlease set the Python3 venv [alias: p3]!\n")
...
Operating in Python3 venv, please proceed! :-)
>>>
Easiest way is to just run: which python, if you are in a virtualenv it will point to its python instead of the global one
(edited) I found that way, what do you think of it ? (it also returns the venv base path and works even for readthedocs where checking the env variable does not):
import os
import sys
from distutils.sysconfig import get_config_vars
def get_venv_basedir():
"""Returns the base directory of the virtualenv, useful to read configuration and plugins"""
exec_prefix = get_config_vars()['exec_prefix']
if hasattr(sys, 'real_prefix') is False or exec_prefix.startswith(sys.real_prefix):
raise EnvironmentError('You must be in a virtual environment')
return os.path.abspath(get_config_vars()['exec_prefix'] + '/../')
In windows OS you see something like this:
C:\Users\yourusername\virtualEnvName\Scripts>activate
(virtualEnvName) C:\Users\yourusername\virtualEnvName\Scripts>
Parentheses mean that you are actually in the virtual environment called "virtualEnvName".
There are a lot of great methods posted here already, but just adding one more:
import site
site.getsitepackages()
tells you where pip installed the packages.
If you are using Anaconda here is the solution. This command lists all the discoverable environments
conda info --envs
I typically use a bash wrapper script to start my application and was running into the problem of imports not working because of pip packages not being installed outside the virtual environment.
Using the solution provided by Matt Harasymczuk, here are the few lines of bash script to check the virtual environment has been activated before starting the application.
#!/bin/bash
# check the virtual environment is active
if [ -z "$VIRTUAL_ENV" ]
then
echo "[ERROR] Virtual environment not activated"
exit 1
fi
# start the application
python3 # amend with application name and other details
# end of file
You can look for the 'signature' of whatever venv method you're trying to support. In my case I want to support:
python -m venv venv_dir
or
virtualenv venv_dir
So I can write:
import sys
from pathlib import Path
IS_VENV_ENVIRONMENT = (Path(sys.prefix) / "pyvenv.cfg").exists()
See: https://docs.python.org/3/library/venv.html
"Running this command creates the target directory (creating any parent directories that don’t exist already) and places a pyvenv.cfg file in it"
NB: virtualenv also creates the same file but I couldn't see any docs about that, I only noticed by experiment.
It's not bullet-proof but for UNIX environments simple test like
if run("which python3").find("venv") == -1:
# something when not executed from venv
works great for me. It's simpler then testing existing of some attribute and, anyway, you should name your venv directory venv.
A potential solution is:
os.access(sys.executable, os.W_OK)
In my case I really just wanted to detect if I could install items with pip as is. While it might not be the right solution for all cases, consider simply checking if you have write permissions for the location of the Python executable.
Note: this works in all versions of Python, but also returns True if you run the system Python with sudo. Here's a potential use case:
import os, sys
can_install_pip_packages = os.access(sys.executable, os.W_OK)
if can_install_pip_packages:
import pip
pip.main(['install', 'mypackage'])