Skip to content

Commit

Permalink
Add utilities to get info from Python environments
Browse files Browse the repository at this point in the history
Most of these functions were added to Spyder first but we need to have
them here now.
  • Loading branch information
ccordoba12 committed Aug 13, 2024
1 parent c0c785c commit 0eee303
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 0 deletions.
75 changes: 75 additions & 0 deletions spyder_kernels/utils/pythonenv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2009- Spyder Kernels Contributors
#
# Licensed under the terms of the MIT License
# (see spyder_kernels/__init__.py for details)
# -----------------------------------------------------------------------------

"""Utilities to get information about Python environments."""

# Standard library imports
import os
from pathlib import Path


def add_quotes(path):
"""Return quotes if needed for spaces on path."""
quotes = '"' if ' ' in path and '"' not in path else ''
return '{quotes}{path}{quotes}'.format(quotes=quotes, path=path)


def get_conda_env_path(pyexec, quote=False):
"""
Return the full path to the conda environment from a given python
executable.
If `quote` is True, then quotes are added if spaces are found in the path.
"""
pyexec = pyexec.replace('\\', '/')
if os.name == 'nt':
conda_env = os.path.dirname(pyexec)
else:
conda_env = os.path.dirname(os.path.dirname(pyexec))

if quote:
conda_env = add_quotes(conda_env)

return conda_env


def is_conda_env(prefix=None, pyexec=None):
"""Check if prefix or python executable are in a conda environment."""
if pyexec is not None:
pyexec = pyexec.replace('\\', '/')

if (prefix is None and pyexec is None) or (prefix and pyexec):
raise ValueError('Only `prefix` or `pyexec` should be provided!')

if pyexec and prefix is None:
prefix = get_conda_env_path(pyexec).replace('\\', '/')

return os.path.exists(os.path.join(prefix, 'conda-meta'))


def is_pyenv_env(pyexec):
"""Check if a python executable is a Pyenv environment."""
path = Path(pyexec)
return "pyenv" in path.parts[:-1]


def get_env_dir(interpreter, only_dir=False):
"""Get the environment directory from the interpreter executable."""
path = Path(interpreter)

if os.name == 'nt':
# This is enough for Conda and Pyenv envs
env_dir = path.parent

# This is necessary for envs created with `python -m venv`
if env_dir.parts[-1].lower() == "scripts":
env_dir = path.parents[1]
else:
env_dir = path.parents[1]

return env_dir.parts[-1] if only_dir else str(env_dir)
66 changes: 66 additions & 0 deletions spyder_kernels/utils/tests/test_pythonenv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2009- Spyder Kernels Contributors
#
# Licensed under the terms of the MIT License
# (see spyder_kernels/__init__.py for details)
# -----------------------------------------------------------------------------

"""
Tests for utilities in the pythonenv module
"""

# Standard library imports
import os

# Third-party imports
import pytest

# Local imports
from spyder_kernels.utils.pythonenv import (
add_quotes,
get_conda_env_path,
get_env_dir,
)


if os.name == 'nt':
TEST_PYEXEC = 'c:/miniconda/envs/foobar/python.exe'
else:
TEST_PYEXEC = '/miniconda/envs/foobar/bin/python'


def test_add_quotes():
output = add_quotes('/some path/with spaces')
assert output == '"/some path/with spaces"'

output = add_quotes('/some-path/with-no-spaces')
assert output == '/some-path/with-no-spaces'


def test_get_conda_env_path():
output = get_conda_env_path(TEST_PYEXEC)
if os.name == 'nt':
assert output == 'c:/miniconda/envs/foobar'
else:
assert output == '/miniconda/envs/foobar'


def test_get_env_dir():
output_dir = get_env_dir(TEST_PYEXEC, only_dir=False)
if os.name == "nt":
assert output_dir == 'c:\\miniconda\\envs\\foobar'
else:
assert output_dir == '/miniconda/envs/foobar'

output = get_env_dir(TEST_PYEXEC, only_dir=True)
assert output == "foobar"

if os.name == "nt":
venv_pyexec = 'C:\\Miniconda3\\envs\\foobar\\Scripts\\python.exe'
output = get_env_dir(venv_pyexec, only_dir=True)
assert output == "foobar"


if __name__ == "__main__":
pytest.main()

0 comments on commit 0eee303

Please sign in to comment.