2015-03-20 15:55:39 -07:00
|
|
|
" The Python provider helper
|
|
|
|
if exists('s:loaded_pythonx_provider')
|
|
|
|
finish
|
|
|
|
endif
|
|
|
|
|
|
|
|
let s:loaded_pythonx_provider = 1
|
|
|
|
|
2016-03-01 13:06:36 -07:00
|
|
|
function! provider#pythonx#Require(host) abort
|
|
|
|
let ver = (a:host.orig_name ==# 'python') ? 2 : 3
|
|
|
|
|
|
|
|
" Python host arguments
|
2016-05-12 13:25:15 -07:00
|
|
|
let prog = (ver == '2' ? provider#python#Prog() : provider#python3#Prog())
|
2019-10-27 14:27:22 -07:00
|
|
|
let args = [prog, '-c', 'import sys; sys.path = list(filter(lambda x: x != "", sys.path)); import neovim; neovim.start_host()']
|
|
|
|
|
2016-03-01 13:06:36 -07:00
|
|
|
|
|
|
|
" Collect registered Python plugins into args
|
|
|
|
let python_plugins = remote#host#PluginsForHost(a:host.name)
|
|
|
|
for plugin in python_plugins
|
|
|
|
call add(args, plugin.path)
|
|
|
|
endfor
|
|
|
|
|
2018-02-16 11:53:02 -07:00
|
|
|
return provider#Poll(args, a:host.orig_name, '$NVIM_PYTHON_LOG_FILE')
|
2016-03-01 13:06:36 -07:00
|
|
|
endfunction
|
|
|
|
|
2019-01-06 09:19:57 -07:00
|
|
|
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'],
|
2020-05-20 04:57:46 -07:00
|
|
|
\ 3: ['python3', 'python3.9', 'python3.8', 'python3.7', 'python3.6', 'python3.5',
|
2019-11-17 06:23:17 -07:00
|
|
|
\ 'python3.4', 'python3.3', 'python']
|
2019-01-06 09:19:57 -07:00
|
|
|
\ }[a:major_version]
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Returns [path_to_python_executable, error_message]
|
|
|
|
function! provider#pythonx#Detect(major_version) abort
|
2019-01-07 06:46:58 -07:00
|
|
|
return provider#pythonx#DetectByModule('neovim', a:major_version)
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Returns [path_to_python_executable, error_message]
|
|
|
|
function! provider#pythonx#DetectByModule(module, major_version) abort
|
2019-01-06 09:19:57 -07:00
|
|
|
let python_exe = s:get_python_executable_from_host_var(a:major_version)
|
|
|
|
|
|
|
|
if !empty(python_exe)
|
provider#pythonx: resolve/expand exe from host var (#11047)
This reverts part of ade88fe4c [1].
This is required for `let g:python3_host_prog = 'python'` etc, where it
should get picked up from PATH.
Without this it would show:
```
- INFO: pyenv: Path: /home/user/.pyenv/libexec/pyenv
- INFO: pyenv: Root: /home/user/.pyenv
- INFO: Using: g:python3_host_prog = "python"
- ERROR: "python" was not found.
- INFO: Executable: Not found
- ERROR: Detected pip upgrade failure: Python executable can import "pynvim" but not "neovim": python
- ADVICE:
- Use that Python version to reinstall "pynvim" and optionally "neovim".
pip3 uninstall pynvim neovim
pip3 install pynvim
pip3 install neovim # only if needed by third-party software
```
Note that it additionally causes a weird error
("Detected pip upgrade failure"), due to `s:check_bin` emptying
`python_exe` (because the non-absolute file not being readable), and
`provider#pythonx#DetectByModule('pynvim', a:version)` from 75593e6fce
then just getting the value from the host var again (without actual
checks).
This is implicitly fixed via this patch now (because it is skipped), but
could need some improvement in this regard probably.
With this patch it resolves it (for a virtualenv where pynvim is not
made available intentionally):
```
- INFO: pyenv: Path: /home/daniel/.pyenv/libexec/pyenv
- INFO: pyenv: Root: /home/daniel/.pyenv
- INFO: Using: g:python3_host_prog = "python"
- WARNING: $VIRTUAL_ENV exists but appears to be inactive. This could lead to unexpected results.
- ADVICE:
- If you are using Zsh, see: http://vi.stackexchange.com/a/7654
- INFO: Executable: /home/daniel/.pyenv/shims/tmp-system-deoplete.nvim-f205aF/python
- ERROR: Command error (job=11, exit code 1): `'/home/daniel/.pyenv/shims/tmp-system-deoplete.nvim-f205aF/python' -c 'import sys; sys.path.remove(""); import neovim; print(neovim.__file__)'` (in '/home/daniel/.dotfiles/vim/plugged/deoplete.nvim')
Output: Traceback (most recent call last): File "<string>", line 1, in <module>ModuleNotFoundError: No module named 'neovim'
Stderr: Traceback (most recent call last): File "<string>", line 1, in <module>ModuleNotFoundError: No module named 'neovim'
- INFO: Python version: 3.7.4
- INFO: pynvim version: unable to load neovim Python module
- ERROR: pynvim is not installed.
Error: unable to load neovim Python module
- ADVICE:
- Run in shell: pip3 install pynvim
```
Note: this appears to display the error twice via "Output:" and
"Stderr:".
1: https://github.com/neovim/neovim/pull/8784
2019-09-30 03:52:04 -07:00
|
|
|
return [exepath(expand(python_exe)), '']
|
2015-03-20 15:55:39 -07:00
|
|
|
endif
|
|
|
|
|
2019-01-06 09:19:57 -07:00
|
|
|
let candidates = s:get_python_candidates(a:major_version)
|
2015-05-24 10:05:09 -07:00
|
|
|
let errors = []
|
2016-12-09 07:08:18 -07:00
|
|
|
|
2019-01-06 09:19:57 -07:00
|
|
|
for exe in candidates
|
2019-01-07 06:46:58 -07:00
|
|
|
let [result, error] = provider#pythonx#CheckForModule(exe, a:module, a:major_version)
|
2015-05-24 10:05:09 -07:00
|
|
|
if result
|
2019-01-06 09:19:57 -07:00
|
|
|
return [exe, error]
|
2015-03-20 15:55:39 -07:00
|
|
|
endif
|
2019-01-06 09:19:57 -07:00
|
|
|
" Accumulate errors in case we don't find any suitable Python executable.
|
|
|
|
call add(errors, error)
|
2015-03-20 15:55:39 -07:00
|
|
|
endfor
|
|
|
|
|
2019-01-06 09:19:57 -07:00
|
|
|
" No suitable Python executable found.
|
|
|
|
return ['', 'provider/pythonx: Could not load Python '.a:major_version.":\n".join(errors, "\n")]
|
2015-03-20 15:55:39 -07:00
|
|
|
endfunction
|
|
|
|
|
2018-11-20 01:57:43 -07:00
|
|
|
" Returns array: [prog_exitcode, prog_version]
|
|
|
|
function! s:import_module(prog, module) abort
|
2018-11-18 07:46:55 -07:00
|
|
|
let prog_version = system([a:prog, '-c' , printf(
|
|
|
|
\ 'import sys; ' .
|
2019-10-27 14:27:22 -07:00
|
|
|
\ 'sys.path = list(filter(lambda x: x != "", sys.path)); ' .
|
2018-11-18 07:46:55 -07:00
|
|
|
\ 'sys.stdout.write(str(sys.version_info[0]) + "." + str(sys.version_info[1])); ' .
|
|
|
|
\ 'import pkgutil; ' .
|
|
|
|
\ 'exit(2*int(pkgutil.get_loader("%s") is None))',
|
2018-11-20 01:57:43 -07:00
|
|
|
\ a:module)])
|
2018-11-18 07:46:55 -07:00
|
|
|
return [v:shell_error, prog_version]
|
|
|
|
endfunction
|
|
|
|
|
2018-11-20 01:57:43 -07:00
|
|
|
" Returns array: [was_success, error_message]
|
|
|
|
function! provider#pythonx#CheckForModule(prog, module, major_version) abort
|
2015-06-05 02:16:52 -07:00
|
|
|
let prog_path = exepath(a:prog)
|
2016-05-28 08:16:24 -07:00
|
|
|
if prog_path ==# ''
|
2015-06-05 02:16:52 -07:00
|
|
|
return [0, a:prog . ' not found in search path or not executable.']
|
2015-03-20 15:55:39 -07:00
|
|
|
endif
|
|
|
|
|
2018-11-18 07:46:55 -07:00
|
|
|
let min_version = (a:major_version == 2) ? '2.6' : '3.3'
|
2015-09-16 14:38:34 -07:00
|
|
|
|
2019-01-01 12:19:42 -07:00
|
|
|
" Try to load module, and output Python version.
|
2018-11-18 07:46:55 -07:00
|
|
|
" Exit codes:
|
2019-01-01 12:19:42 -07:00
|
|
|
" 0 module can be loaded.
|
|
|
|
" 2 module cannot be loaded.
|
2016-05-28 08:07:27 -07:00
|
|
|
" Otherwise something else went wrong (e.g. 1 or 127).
|
2019-01-01 12:19:42 -07:00
|
|
|
let [prog_exitcode, prog_version] = s:import_module(a:prog, a:module)
|
2015-09-16 14:38:34 -07:00
|
|
|
|
2018-11-18 07:46:55 -07:00
|
|
|
if prog_exitcode == 2 || prog_exitcode == 0
|
2016-05-28 08:07:27 -07:00
|
|
|
" Check version only for expected return codes.
|
2018-11-18 07:46:55 -07:00
|
|
|
if prog_version !~ '^' . a:major_version
|
|
|
|
return [0, prog_path . ' is Python ' . prog_version . ' and cannot provide Python '
|
|
|
|
\ . a:major_version . '.']
|
|
|
|
elseif prog_version =~ '^' . a:major_version && prog_version < min_version
|
|
|
|
return [0, prog_path . ' is Python ' . prog_version . ' and cannot provide Python >= '
|
2015-09-16 14:38:34 -07:00
|
|
|
\ . min_version . '.']
|
|
|
|
endif
|
2015-06-04 09:43:12 -07:00
|
|
|
endif
|
|
|
|
|
2018-11-18 07:46:55 -07:00
|
|
|
if prog_exitcode == 2
|
2019-01-01 12:19:42 -07:00
|
|
|
return [0, prog_path.' does not have the "' . a:module . '" module. :help provider-python']
|
2018-11-18 07:46:55 -07:00
|
|
|
elseif prog_exitcode == 127
|
2016-05-28 08:07:27 -07:00
|
|
|
" This can happen with pyenv's shims.
|
2018-11-18 07:46:55 -07:00
|
|
|
return [0, prog_path . ' does not exist: ' . prog_version]
|
|
|
|
elseif prog_exitcode
|
2016-05-28 08:07:27 -07:00
|
|
|
return [0, 'Checking ' . prog_path . ' caused an unknown error. '
|
2018-11-18 07:46:55 -07:00
|
|
|
\ . '(' . prog_exitcode . ', output: ' . prog_version . ')'
|
2017-04-17 16:57:19 -07:00
|
|
|
\ . ' Report this at https://github.com/neovim/neovim']
|
2015-05-02 11:56:09 -07:00
|
|
|
endif
|
2015-03-20 15:55:39 -07:00
|
|
|
|
2015-09-16 14:38:34 -07:00
|
|
|
return [1, '']
|
2015-06-04 09:43:12 -07:00
|
|
|
endfunction
|