diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim index 97498bc42e..526623c86f 100644 --- a/runtime/autoload/health/provider.vim +++ b/runtime/autoload/health/provider.vim @@ -258,10 +258,10 @@ function! s:check_python(version) abort call health#report_start('Python ' . a:version . ' provider (optional)') let pyname = 'python'.(a:version == 2 ? '' : '3') + let python_exe = '' let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : '' let host_prog_var = pyname.'_host_prog' let loaded_var = 'g:loaded_'.pyname.'_provider' - let python_bin = '' let python_multiple = [] if exists(loaded_var) && !exists('*provider#'.pyname.'#Call') @@ -274,38 +274,40 @@ function! s:check_python(version) abort call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var))) endif - let [pyname, pythonx_errs] = provider#pythonx#Detect(a:version) + let [pyname, pythonx_errors] = provider#pythonx#Detect(a:version) + if empty(pyname) - call health#report_warn('No Python interpreter was found with the pynvim ' - \ . 'module. Using the first available for diagnostics.') + call health#report_warn('No Python executable found that could `import neovim`. ' + \ . 'Using the first available executable for diagnostics.') elseif exists('g:'.host_prog_var) - let python_bin = pyname + let python_exe = pyname endif - if !empty(pythonx_errs) - call health#report_error('Python provider error', pythonx_errs) + " No Python executable could `import neovim`. + if !empty(pythonx_errors) + call health#report_error('Python provider error:', pythonx_errors) - elseif !empty(pyname) && empty(python_bin) + elseif !empty(pyname) && empty(python_exe) if !exists('g:'.host_prog_var) call health#report_info(printf('`g:%s` is not set. Searching for ' \ . '%s in the environment.', host_prog_var, pyname)) endif if !empty(pyenv) - let python_bin = s:trim(s:system([pyenv, 'which', pyname], '', 1)) + let python_exe = s:trim(s:system([pyenv, 'which', pyname], '', 1)) - if empty(python_bin) + if empty(python_exe) call health#report_warn(printf('pyenv could not find %s.', pyname)) endif endif - if empty(python_bin) - let python_bin = exepath(pyname) + if empty(python_exe) + let python_exe = exepath(pyname) if exists('$PATH') for path in split($PATH, has('win32') ? ';' : ':') let path_bin = s:normalize_path(path.'/'.pyname) - if path_bin != s:normalize_path(python_bin) + if path_bin != s:normalize_path(python_exe) \ && index(python_multiple, path_bin) == -1 \ && executable(path_bin) call add(python_multiple, path_bin) @@ -319,8 +321,8 @@ function! s:check_python(version) abort \ . 'Set `g:%s` to avoid surprises.', pyname, host_prog_var)) endif - if python_bin =~# '\<shims\>' - call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_bin), [ + if python_exe =~# '\<shims\>' + call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_exe), [ \ '`pyenv` is not in $PATH, your pyenv installation is broken. ' \ .'Set `g:'.host_prog_var.'` to avoid surprises.', \ ]) @@ -329,9 +331,9 @@ function! s:check_python(version) abort endif endif - if !empty(python_bin) && !exists('g:'.host_prog_var) + if !empty(python_exe) && !exists('g:'.host_prog_var) if empty(venv) && !empty(pyenv) - \ && !empty(pyenv_root) && resolve(python_bin) !~# '^'.pyenv_root.'/' + \ && !empty(pyenv_root) && resolve(python_exe) !~# '^'.pyenv_root.'/' call health#report_warn('pyenv is not set up optimally.', [ \ printf('Create a virtualenv specifically ' \ . 'for Neovim using pyenv, and set `g:%s`. This will avoid ' @@ -345,7 +347,7 @@ function! s:check_python(version) abort let venv_root = fnamemodify(venv, ':h') endif - if resolve(python_bin) !~# '^'.venv_root.'/' + if resolve(python_exe) !~# '^'.venv_root.'/' call health#report_warn('Your virtualenv is not set up optimally.', [ \ printf('Create a virtualenv specifically ' \ . 'for Neovim and use `g:%s`. This will avoid ' @@ -356,16 +358,16 @@ function! s:check_python(version) abort endif endif - if empty(python_bin) && !empty(pyname) + if empty(python_exe) && !empty(pyname) " An error message should have already printed. call health#report_error(printf('`%s` was not found.', pyname)) - elseif !empty(python_bin) && !s:check_bin(python_bin) - let python_bin = '' + elseif !empty(python_exe) && !s:check_bin(python_exe) + let python_exe = '' endif " Check if $VIRTUAL_ENV is valid. - if exists('$VIRTUAL_ENV') && !empty(python_bin) - if $VIRTUAL_ENV ==# matchstr(python_bin, '^\V'.$VIRTUAL_ENV) + if exists('$VIRTUAL_ENV') && !empty(python_exe) + if $VIRTUAL_ENV ==# matchstr(python_exe, '^\V'.$VIRTUAL_ENV) call health#report_info('$VIRTUAL_ENV matches executable') else call health#report_warn( @@ -376,7 +378,7 @@ function! s:check_python(version) abort endif " Diagnostic output - call health#report_info('Executable: ' . (empty(python_bin) ? 'Not found' : python_bin)) + call health#report_info('Executable: ' . (empty(python_exe) ? 'Not found' : python_exe)) if len(python_multiple) for path_bin in python_multiple call health#report_info('Other python executable: ' . path_bin) @@ -385,8 +387,8 @@ function! s:check_python(version) abort let pip = 'pip' . (a:version == 2 ? '' : '3') - if !empty(python_bin) - let [pyversion, current, latest, status] = s:version_info(python_bin) + if !empty(python_exe) + let [pyversion, current, latest, status] = s:version_info(python_exe) if a:version != str2nr(pyversion) call health#report_warn('Unexpected Python version.' . \ ' This could lead to confusing error messages.') @@ -398,7 +400,7 @@ function! s:check_python(version) abort call health#report_info('Python version: ' . pyversion) if s:is_bad_response(status) call health#report_info(printf('pynvim version: %s (%s)', current, status)) - let [module_found, _msg] = provider#pythonx#CheckForModule(python_bin, + let [module_found, _msg] = provider#pythonx#CheckForModule(python_exe, \ 'pynvim', a:version) if status !=? '^outdated' && module_found " neovim module was not found, but pynvim was diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim index 05b04e7e2c..06611377b1 100644 --- a/runtime/autoload/provider/pythonx.vim +++ b/runtime/autoload/provider/pythonx.vim @@ -21,37 +21,40 @@ function! provider#pythonx#Require(host) abort return provider#Poll(args, a:host.orig_name, '$NVIM_PYTHON_LOG_FILE') endfunction -function! provider#pythonx#Detect(major_ver) abort - if a:major_ver == 2 - if exists('g:python_host_prog') - return [expand(g:python_host_prog), ''] - else - let progs = ['python2', 'python2.7', 'python2.6', 'python'] - endif - else - if exists('g:python3_host_prog') - return [expand(g:python3_host_prog), ''] - else - let progs = ['python3', 'python3.7', 'python3.6', 'python3.5', - \ 'python3.4', 'python3.3', 'python'] - endif +function! s:get_python_executable_from_host_var(major_version) abort + return expand(get(g:, 'python'.(a:major_version == 3 ? '3' : '').'_host_prog', '')) +endfunction + +function! s:get_python_candidates(major_version) abort + return { + \ 2: ['python2', 'python2.7', 'python2.6', 'python'], + \ 3: ['python3', 'python3.7', 'python3.6', 'python3.5', 'python3.4', 'python3.3', + \ 'python'] + \ }[a:major_version] +endfunction + +" Returns [path_to_python_executable, error_message] +function! provider#pythonx#Detect(major_version) abort + let python_exe = s:get_python_executable_from_host_var(a:major_version) + + if !empty(python_exe) + return [python_exe, ''] endif + let candidates = s:get_python_candidates(a:major_version) let errors = [] - for prog in progs - let [result, err] = provider#pythonx#CheckForModule(prog, 'neovim', a:major_ver) + for exe in candidates + let [result, error] = provider#pythonx#CheckForModule(exe, 'neovim', a:major_version) if result - return [prog, err] + return [exe, error] endif - " Accumulate errors in case we don't find - " any suitable Python interpreter. - call add(errors, err) + " Accumulate errors in case we don't find any suitable Python executable. + call add(errors, error) endfor - " No suitable Python interpreter found. - return ['', 'provider/pythonx: Could not load Python ' . a:major_ver - \ . ":\n" . join(errors, "\n")] + " No suitable Python executable found. + return ['', 'provider/pythonx: Could not load Python '.a:major_version.":\n".join(errors, "\n")] endfunction " Returns array: [prog_exitcode, prog_version]