forked from VimPlug/jedi
Find Python environments on Windows using the registry
This commit is contained in:
50
appveyor.yml
50
appveyor.yml
@@ -2,83 +2,83 @@ environment:
|
|||||||
matrix:
|
matrix:
|
||||||
- TOXENV: py27
|
- TOXENV: py27
|
||||||
PYTHON_PATH: C:\Python27
|
PYTHON_PATH: C:\Python27
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python27\python.exe
|
JEDI_TEST_ENVIRONMENT: 27
|
||||||
- TOXENV: py27
|
- TOXENV: py27
|
||||||
PYTHON_PATH: C:\Python27
|
PYTHON_PATH: C:\Python27
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python33\python.exe
|
JEDI_TEST_ENVIRONMENT: 33
|
||||||
- TOXENV: py27
|
- TOXENV: py27
|
||||||
PYTHON_PATH: C:\Python27
|
PYTHON_PATH: C:\Python27
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python34\python.exe
|
JEDI_TEST_ENVIRONMENT: 34
|
||||||
- TOXENV: py27
|
- TOXENV: py27
|
||||||
PYTHON_PATH: C:\Python27
|
PYTHON_PATH: C:\Python27
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python35\python.exe
|
JEDI_TEST_ENVIRONMENT: 35
|
||||||
- TOXENV: py27
|
- TOXENV: py27
|
||||||
PYTHON_PATH: C:\Python27
|
PYTHON_PATH: C:\Python27
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python36\python.exe
|
JEDI_TEST_ENVIRONMENT: 36
|
||||||
|
|
||||||
- TOXENV: py33
|
- TOXENV: py33
|
||||||
PYTHON_PATH: C:\Python33
|
PYTHON_PATH: C:\Python33
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python27\python.exe
|
JEDI_TEST_ENVIRONMENT: 27
|
||||||
- TOXENV: py33
|
- TOXENV: py33
|
||||||
PYTHON_PATH: C:\Python33
|
PYTHON_PATH: C:\Python33
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python33\python.exe
|
JEDI_TEST_ENVIRONMENT: 33
|
||||||
- TOXENV: py33
|
- TOXENV: py33
|
||||||
PYTHON_PATH: C:\Python33
|
PYTHON_PATH: C:\Python33
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python34\python.exe
|
JEDI_TEST_ENVIRONMENT: 34
|
||||||
- TOXENV: py33
|
- TOXENV: py33
|
||||||
PYTHON_PATH: C:\Python33
|
PYTHON_PATH: C:\Python33
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python35\python.exe
|
JEDI_TEST_ENVIRONMENT: 35
|
||||||
- TOXENV: py33
|
- TOXENV: py33
|
||||||
PYTHON_PATH: C:\Python33
|
PYTHON_PATH: C:\Python33
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python36\python.exe
|
JEDI_TEST_ENVIRONMENT: 36
|
||||||
|
|
||||||
- TOXENV: py34
|
- TOXENV: py34
|
||||||
PYTHON_PATH: C:\Python34
|
PYTHON_PATH: C:\Python34
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python27\python.exe
|
JEDI_TEST_ENVIRONMENT: 27
|
||||||
- TOXENV: py34
|
- TOXENV: py34
|
||||||
PYTHON_PATH: C:\Python34
|
PYTHON_PATH: C:\Python34
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python33\python.exe
|
JEDI_TEST_ENVIRONMENT: 33
|
||||||
- TOXENV: py34
|
- TOXENV: py34
|
||||||
PYTHON_PATH: C:\Python34
|
PYTHON_PATH: C:\Python34
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python34\python.exe
|
JEDI_TEST_ENVIRONMENT: 34
|
||||||
- TOXENV: py34
|
- TOXENV: py34
|
||||||
PYTHON_PATH: C:\Python34
|
PYTHON_PATH: C:\Python34
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python35\python.exe
|
JEDI_TEST_ENVIRONMENT: 35
|
||||||
- TOXENV: py34
|
- TOXENV: py34
|
||||||
PYTHON_PATH: C:\Python34
|
PYTHON_PATH: C:\Python34
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python36\python.exe
|
JEDI_TEST_ENVIRONMENT: 36
|
||||||
|
|
||||||
- TOXENV: py35
|
- TOXENV: py35
|
||||||
PYTHON_PATH: C:\Python35
|
PYTHON_PATH: C:\Python35
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python27\python.exe
|
JEDI_TEST_ENVIRONMENT: 27
|
||||||
- TOXENV: py35
|
- TOXENV: py35
|
||||||
PYTHON_PATH: C:\Python35
|
PYTHON_PATH: C:\Python35
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python33\python.exe
|
JEDI_TEST_ENVIRONMENT: 33
|
||||||
- TOXENV: py35
|
- TOXENV: py35
|
||||||
PYTHON_PATH: C:\Python35
|
PYTHON_PATH: C:\Python35
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python34\python.exe
|
JEDI_TEST_ENVIRONMENT: 34
|
||||||
- TOXENV: py35
|
- TOXENV: py35
|
||||||
PYTHON_PATH: C:\Python35
|
PYTHON_PATH: C:\Python35
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python35\python.exe
|
JEDI_TEST_ENVIRONMENT: 35
|
||||||
- TOXENV: py35
|
- TOXENV: py35
|
||||||
PYTHON_PATH: C:\Python35
|
PYTHON_PATH: C:\Python35
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python36\python.exe
|
JEDI_TEST_ENVIRONMENT: 36
|
||||||
|
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON_PATH: C:\Python36
|
PYTHON_PATH: C:\Python36
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python27\python.exe
|
JEDI_TEST_ENVIRONMENT: 27
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON_PATH: C:\Python36
|
PYTHON_PATH: C:\Python36
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python33\python.exe
|
JEDI_TEST_ENVIRONMENT: 33
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON_PATH: C:\Python36
|
PYTHON_PATH: C:\Python36
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python34\python.exe
|
JEDI_TEST_ENVIRONMENT: 34
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON_PATH: C:\Python36
|
PYTHON_PATH: C:\Python36
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python35\python.exe
|
JEDI_TEST_ENVIRONMENT: 35
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON_PATH: C:\Python36
|
PYTHON_PATH: C:\Python36
|
||||||
JEDI_TEST_ENVIRONMENT_EXECUTABLE: C:\Python36\python.exe
|
JEDI_TEST_ENVIRONMENT: 36
|
||||||
install:
|
install:
|
||||||
- set PATH=%PYTHON_PATH%;%PYTHON_PATH%\Scripts;%PATH%
|
- set PATH=%PYTHON_PATH%;%PYTHON_PATH%\Scripts;%PATH%
|
||||||
- pip install --disable-pip-version-check --user --upgrade pip
|
- pip install --disable-pip-version-check --user --upgrade pip
|
||||||
|
|||||||
@@ -87,10 +87,6 @@ def clean_jedi_cache(request):
|
|||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def environment(request):
|
def environment(request):
|
||||||
python = os.environ.get('JEDI_TEST_ENVIRONMENT_EXECUTABLE')
|
|
||||||
if python:
|
|
||||||
return get_python_environment(python)
|
|
||||||
|
|
||||||
version = request.config.option.env
|
version = request.config.option.env
|
||||||
if version is None:
|
if version is None:
|
||||||
version = os.environ.get('JEDI_TEST_ENVIRONMENT', str(py_version))
|
version = os.environ.get('JEDI_TEST_ENVIRONMENT', str(py_version))
|
||||||
|
|||||||
@@ -163,12 +163,41 @@ def find_python_environments():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_python_environment(python_name):
|
# TODO: the logic to find the Python prefix is much more complicated than that.
|
||||||
exe = find_executable(python_name)
|
# See Modules/getpath.c for UNIX and PC/getpathp.c for Windows in CPython's
|
||||||
if exe is None:
|
# source code. A solution would be to deduce it by running the Python
|
||||||
raise InvalidPythonEnvironment("This executable doesn't exist.")
|
# interpreter and printing the value of sys.prefix.
|
||||||
path = os.path.dirname(os.path.dirname(exe))
|
def _get_python_prefix(executable):
|
||||||
return Environment(path, exe)
|
if os.name != 'nt':
|
||||||
|
return os.path.dirname(os.path.dirname(executable))
|
||||||
|
landmark = os.path.join('Lib', 'os.py')
|
||||||
|
prefix = os.path.dirname(executable)
|
||||||
|
while prefix:
|
||||||
|
if os.path.join(prefix, landmark):
|
||||||
|
return prefix
|
||||||
|
prefix = os.path.dirname(prefix)
|
||||||
|
raise InvalidPythonEnvironment(
|
||||||
|
"Cannot find prefix of executable %s." % executable)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: this function should probably return a list of environments since
|
||||||
|
# multiple Python installations can be found on a system for the same version.
|
||||||
|
def get_python_environment(python):
|
||||||
|
"""
|
||||||
|
Return the first Python environment found for a given path or for a string
|
||||||
|
of the form 'pythonX.Y' where X and Y are the major and minor versions of
|
||||||
|
Python.
|
||||||
|
"""
|
||||||
|
exe = find_executable(python)
|
||||||
|
if exe:
|
||||||
|
return Environment(_get_python_prefix(exe), exe)
|
||||||
|
if os.name == 'nt':
|
||||||
|
match = re.search('python(\d+\.\d+)$', python)
|
||||||
|
if match:
|
||||||
|
version = match.group(1)
|
||||||
|
for prefix, exe in _get_executables_from_windows_registry(version):
|
||||||
|
return Environment(prefix, exe)
|
||||||
|
raise InvalidPythonEnvironment("Cannot find executable %s." % python)
|
||||||
|
|
||||||
|
|
||||||
def create_environment(path):
|
def create_environment(path):
|
||||||
@@ -206,6 +235,33 @@ def _get_executable_path(path, safe=True):
|
|||||||
return python
|
return python
|
||||||
|
|
||||||
|
|
||||||
|
def _get_executables_from_windows_registry(version):
|
||||||
|
# The winreg module is named _winreg on Python 2.
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
except ImportError:
|
||||||
|
import _winreg as winreg
|
||||||
|
|
||||||
|
# TODO: support Python Anaconda.
|
||||||
|
sub_keys = [
|
||||||
|
r'SOFTWARE\Python\PythonCore\{version}\InstallPath',
|
||||||
|
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath',
|
||||||
|
r'SOFTWARE\Python\PythonCore\{version}-32\InstallPath',
|
||||||
|
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}-32\InstallPath'
|
||||||
|
]
|
||||||
|
for root_key in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]:
|
||||||
|
for sub_key in sub_keys:
|
||||||
|
sub_key = sub_key.format(version=version)
|
||||||
|
try:
|
||||||
|
with winreg.OpenKey(root_key, sub_key) as key:
|
||||||
|
prefix = winreg.QueryValueEx(key, '')[0]
|
||||||
|
exe = os.path.join(prefix, 'python.exe')
|
||||||
|
if os.path.isfile(exe):
|
||||||
|
yield prefix, exe
|
||||||
|
except WindowsError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _is_safe(executable_path):
|
def _is_safe(executable_path):
|
||||||
real_path = os.path.realpath(executable_path)
|
real_path = os.path.realpath(executable_path)
|
||||||
if _is_admin():
|
if _is_admin():
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import pytest
|
|||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
from jedi._compatibility import py_version
|
from jedi._compatibility import py_version
|
||||||
from jedi.api.environment import Environment, get_default_environment, \
|
from jedi.api.environment import get_default_environment, \
|
||||||
InvalidPythonEnvironment, find_python_environments
|
get_python_environment, InvalidPythonEnvironment, find_python_environments
|
||||||
|
|
||||||
|
|
||||||
def test_sys_path():
|
def test_sys_path():
|
||||||
@@ -24,24 +24,21 @@ def test_find_python_environments():
|
|||||||
assert parser_version[:2] == env.version_info[:2]
|
assert parser_version[:2] == env.version_info[:2]
|
||||||
|
|
||||||
|
|
||||||
# Cannot deduce the environment from Python executable name on Windows.
|
|
||||||
@pytest.mark.skipif("os.name == 'nt'")
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'version',
|
'version',
|
||||||
['2.7', '3.3', '3.4', '3.5', '3.6', '3.7']
|
['2.7', '3.3', '3.4', '3.5', '3.6', '3.7']
|
||||||
)
|
)
|
||||||
def test_versions(version):
|
def test_versions(version):
|
||||||
executable = 'python' + version
|
|
||||||
try:
|
try:
|
||||||
env = Environment('some path', executable)
|
env = get_python_environment('python' + version)
|
||||||
except InvalidPythonEnvironment:
|
except InvalidPythonEnvironment:
|
||||||
if int(version.replace('.', '')) == py_version:
|
if int(version.replace('.', '')) == py_version:
|
||||||
# At least the current version has to work
|
# At least the current version has to work
|
||||||
raise
|
raise
|
||||||
return
|
pytest.skip()
|
||||||
|
|
||||||
sys_path = env.get_sys_path()
|
assert version == str(env.version_info[0]) + '.' + str(env.version_info[1])
|
||||||
assert any(executable in p for p in sys_path)
|
assert env.get_sys_path()
|
||||||
|
|
||||||
|
|
||||||
def test_load_module(evaluator):
|
def test_load_module(evaluator):
|
||||||
|
|||||||
Reference in New Issue
Block a user