29

I would like to detect in a general way from within a Python session whether it is managed by conda.

A few ideas that are not general enough to be useful:

1: Use environment variables

As mentioned in How do I find the name of the conda environment in which my code is running?

import os
is_conda = 'CONDA_PREFIX' in os.system or 'CONDA_DEFAULT_ENV' in os.system

This seems not to work in the root conda environment, where these variables are not always defined. It also has potential false positives if conda happens to be activated while you are using another Python installation.

2: Check the executable path

import sys
is_conda = ('anaconda' in sys.executable) or ('miniconda' in sys.executable)

This will work in the case that users install anaconda/miniconda in the default path. It may fail otherwise. It's also easy to imagine false-positives.

3. Check the version info

As noted in the answers to any way to tell if user's python environment is anaconda, you can check the Python version string in some cases:

import sys
is_conda = ('Continuum Analytics' in sys.version) or ('Anaconda' in sys.version)

This works currently for Python installed from the default channel, but this is quite brittle and may break in the future, particularly with Continuum's company name change. It also probably fails if Python is installed from a third-party source like conda-forge.

4. Check the conda import

try:
    import conda
except:
    is_conda = False
else:
    is_conda = True

This works as long as you're in the root conda environment, but generally fails if you're in another conda env where the conda package is not installed by default.

5: Try conda to see if it works

Suggestion from Atto Allas below:

import subprocess
try:
    retcode = subprocess.call(['conda', 'install', '-y', 'pip'])
except:
    is_conda = False
else:
    is_conda = (retcode == 0)

This works in the simplest cases, but fails in the common case of using multiple kernels in Jupyter, where the conda executable may or may not be connected to the current Python kernel.


Is there any entirely general way to detect from Python whether that Python installation is managed by conda?

jakevdp
  • 77,104
  • 11
  • 125
  • 160
  • 1
    Is there any specific thing you want to check this for? Maybe solving that would be easier... – Atto Allas Dec 02 '17 at 14:04
  • 2
    I want to check from within Python whether I should use pip or conda to install a new package. – jakevdp Dec 02 '17 at 14:05
  • You could check whether `path.join(sys.prefix, "bin", "conda")` or `path.join(sys.prefix, "Scripts", "conda.exe")` exists – isuruf Dec 02 '17 at 16:55
  • This is also needed in, for example, PyInstaller so that it can find DLLs and so on. – strubbly Mar 12 '19 at 11:45
  • I encountered a problem with this solution. A user installed python and conda in same directory, `/usr/local`, and uses python outside conda. In this case `/usr/local` will be detected as a conda environment. – Cruise Liu Jul 13 '21 at 04:27
  • @Cruise Which solution? OP only mentioned imperfect ones. Did you mean to comment on one of the answers? – wjandrea Oct 10 '21 at 19:47

5 Answers5

20
import sys, os
is_conda = os.path.exists(os.path.join(sys.prefix, 'conda-meta'))
Ross Hytnen
  • 214
  • 1
  • 5
  • 1
    Good approach! Though I think ``conda-meta`` is only in the root environment path though, yes? If you change it to ``conda`` and use ``os.path.join`` for windows compatibility, I think this is probably the best answer. – jakevdp Dec 03 '17 at 03:34
  • I think that an approach like this, where one chacks that `sys.prefix` looks like a conda environment is the best way to go. – Zah Dec 03 '17 at 12:54
  • This doesn't work in a virtualenv because conda-meta isn't written to the env. Using sys.base_prefix instead of sys.prefix works. – Stephan Dec 06 '19 at 22:54
4

I think the best approach is a variation on Ross Hynten's answer: in the build process, conda creates a file called {sys.prefix}/conda-meta/history, so checking for its presence should tell you if you're using conda in a reasonably robust manner:

import sys, os
is_conda = os.path.exists(os.path.join(sys.prefix, 'conda-meta', 'history'))

It remains possible to have false-positives with this approach, but seems to me very unlikely unless done deliberately.

jakevdp
  • 77,104
  • 11
  • 125
  • 160
3

Using compile-time flags seems like it'd be reasonably accurate, and hopefully stable going forward.

def is_conda():
    import sysconfig
    return 'conda-bld' in sysconfig.get_config_var("abs_srcdir")

I'm not sure about that specific key "abs_srcdir", but sysconfig.get_config_values() has many items that may work. With my system python it's:

>>> sysconfig.get_config_var("abs_srcdir")
'/Library/Caches/com.apple.xbs/Binaries/python/python-97.50.7~5/TempContent/Objects/2.7/python'

And with my conda python it's:

In [17]: sysconfig.get_config_var("abs_srcdir")
Out[17]: '/Users/ilan/minonda/conda-bld/python-3.6_1482520641897/work/Python-3.6.0'

My hope is that compile-time flags are more robust that run-time checks. Runtime things like "is conda in sys.prefix" can be confused by having a Python.org install in a "conda" subdirectory. But the compile-time flags should be OK.

TomAugspurger
  • 28,234
  • 8
  • 86
  • 69
  • This is what I get when creating an environment in `/tmp/test`: ```sysconfig.get_config_vars('abs_srcdir') ['/tmp/test/../work/Python-3.6.3']``` – Zah Dec 02 '17 at 19:32
  • Is that a conda-based environment? – TomAugspurger Dec 02 '17 at 22:51
  • Nice idea! I checked with python installed from conda-forge as well, and ``'conda-bld`` is present there as well. Still a bit worried about failures in corner-cases though... – jakevdp Dec 03 '17 at 03:45
  • @TomAugspurger Yes. That is creates with the latest conda from the defaults channel using `conda create -p /tmp/test python` – Zah Dec 03 '17 at 12:52
0

Maybe this?

from subprocess import check_output, CalledProcessError
import sys


def is_conda_managed():
    try:
        out = check_output(['conda', 'env', 'list']).decode('utf-8')
        lines = (line for line in out.splitlines() if line[:1] != '#')
        roots = set(line.split()[-1] for line in lines if line.strip())
    except CalledProcessError:
        roots = set()

    return sys.prefix in roots
Miki Tebeka
  • 13,428
  • 4
  • 37
  • 49
  • Thanks! One potential issue I see with this is if someone has two copies of conda installed on their system, you might end up in a situation where this returns False when it should return True, because it's looking in the wrong set of conda envs. – jakevdp Dec 03 '17 at 03:47
  • The `conda` it picks up is the one that's going to be used when installing (IMO) – Miki Tebeka Dec 03 '17 at 05:55
  • 1
    Not necessarily: for example, if you're using Jupyter notebook, then the conda package it picks up is the one in the path when ``jupyter notebook`` is started. If there are multiple anaconda/miniconda installations on the machine, the notebook can easily point to a Python kernel associated with another conda installation, and in that case this solution would fail. I've seen this sort of thing many times when helping students trouble-shoot installation issues in Jupyter. – jakevdp Dec 03 '17 at 12:45
0

as i read thru the the ideas and their weaknesses, i am not entirely clear by what you mean by 'managed'.

└─╼ which -a python
/Users/me/anaconda/bin/python
/usr/bin/python
┌─[ ~/myPython]
└─╼ /Users/me/anaconda/bin/python
Python 2.7.13 |Anaconda 2.2.0 (x86_64)| (default, Dec 20 2016, 23:05:08) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.
Please check out: http://continuum.io/thanks and https://anaconda.org
>>> quit()
┌─[ ~/myPython]
└─╼ /usr/bin/python
Python 2.7.10 (default, Feb  7 2017, 00:08:15) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
┌─[ ~/myPython]
└─╼ source activate py36
(py36) ┌─[ ~/myPython]
└─╼ which -a python
/Users/me/anaconda/envs/py36/bin/python
/Users/me/anaconda/bin/python
/usr/bin/python
└─╼ python
Python 3.6.2 |Continuum Analytics, Inc.| (default, Jul 20 2017, 13:14:59) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
(py36) ┌─[ ~/myPython]
└─╼ which -a python
/Users/me/anaconda/envs/py36/bin/python
/Users/me/anaconda/bin/python
/usr/bin/python

are the lines: Python 2.7.10 (default Python 2.7.13 |Anaconda 2.2.0 (x86_64) Python 3.6.2 |Continuum Analytics, Inc.

more or less what you're trying to capture? granted these do not always appear and would be brittle at best. examining the image using the platform might be a step in a useful direction.

In [46]: platform.python_build()
Out[46]: ('default', 'Jul 20 2017 13:14:59')

In [47]: platform.python_compiler()
Out[47]: 'GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)'

In [48]: platform.python_implementation()
Out[48]: 'CPython'

the are alternatives to conda, i expect, so the q would seem to be broader than conda.

(this an answer, only because this is my very first SO post, and i only have a single reputaion)

ShpielMeister
  • 1,417
  • 10
  • 23