aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2022-01-28 15:42:19 +0100
committerBjörn Linse <bjorn.linse@gmail.com>2022-01-29 19:49:37 +0100
commitbaec0d3152afeab3007ebb505f3fc274511db434 (patch)
tree7a6401825cf208ba9aaa21cbe053effd71077a0e
parentb2f77c354a289ac99de4c28425dc39d7d057cf90 (diff)
downloadrneovim-baec0d3152afeab3007ebb505f3fc274511db434.tar.gz
rneovim-baec0d3152afeab3007ebb505f3fc274511db434.tar.bz2
rneovim-baec0d3152afeab3007ebb505f3fc274511db434.zip
feat(provider)!: remove support for python2 and python3.[3-5]
These versions of python has reached End-of-life. getting rid of python2 support removes a lot of logic to support two incompatible python versions in the same version.
-rw-r--r--runtime/autoload/health/nvim.vim4
-rw-r--r--runtime/autoload/health/provider.vim19
-rw-r--r--runtime/autoload/provider/python.vim45
-rw-r--r--runtime/autoload/provider/pythonx.vim12
-rw-r--r--runtime/doc/eval.txt1
-rw-r--r--runtime/doc/if_pyth.txt69
-rw-r--r--runtime/doc/options.txt21
-rw-r--r--runtime/doc/provider.txt26
-rw-r--r--runtime/doc/quickfix.txt2
-rw-r--r--src/nvim/eval.lua4
-rw-r--r--src/nvim/eval/funcs.c25
-rw-r--r--src/nvim/ex_cmds.lua14
-rw-r--r--src/nvim/ex_cmds2.c135
-rw-r--r--src/nvim/option.c10
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/testdir/test_python3.vim1
-rw-r--r--src/nvim/testdir/test_pyx2.vim2
-rw-r--r--test/functional/ex_cmds/script_spec.lua2
-rw-r--r--test/functional/provider/python3_spec.lua43
-rw-r--r--test/functional/provider/python_spec.lua123
20 files changed, 110 insertions, 450 deletions
diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim
index 0bb343e198..ef680097d5 100644
--- a/runtime/autoload/health/nvim.vim
+++ b/runtime/autoload/health/nvim.vim
@@ -104,8 +104,8 @@ function! s:check_rplugin_manifest() abort
if !has_key(existing_rplugins, script)
let msg = printf('"%s" is not registered.', fnamemodify(path, ':t'))
if python_version ==# 'pythonx'
- if !has('python2') && !has('python3')
- let msg .= ' (python2 and python3 not available)'
+ if !has('python3')
+ let msg .= ' (python3 not available)'
endif
elseif !has(python_version)
let msg .= printf(' (%s not available)', python_version)
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index e6523aa215..8f0dbbab39 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -282,10 +282,10 @@ function! s:disabled_via_loaded_var(provider) abort
return 0
endfunction
-function! s:check_python(version) abort
- call health#report_start('Python ' . a:version . ' provider (optional)')
+function! s:check_python() abort
+ call health#report_start('Python 3 provider (optional)')
- let pyname = 'python'.(a:version == 2 ? '' : '3')
+ let pyname = 'python3'
let python_exe = ''
let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
let host_prog_var = pyname.'_host_prog'
@@ -301,7 +301,7 @@ 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_errors] = provider#pythonx#Detect(a:version)
+ let [pyname, pythonx_errors] = provider#pythonx#Detect(3)
if empty(pyname)
call health#report_warn('No Python executable found that can `import neovim`. '
@@ -405,7 +405,7 @@ function! s:check_python(version) abort
" can import 'pynvim'. If so, that Python failed to import 'neovim' as
" well, which is most probably due to a failed pip upgrade:
" https://github.com/neovim/neovim/wiki/Following-HEAD#20181118
- let [pynvim_exe, errors] = provider#pythonx#DetectByModule('pynvim', a:version)
+ let [pynvim_exe, errors] = provider#pythonx#DetectByModule('pynvim', 3)
if !empty(pynvim_exe)
call health#report_error(
\ 'Detected pip upgrade failure: Python executable can import "pynvim" but '
@@ -416,14 +416,14 @@ function! s:check_python(version) abort
\ . pynvim_exe ." -m pip install neovim # only if needed by third-party software")
endif
else
- let [pyversion, current, latest, status] = s:version_info(python_exe)
+ let [majorpyversion, current, latest, status] = s:version_info(python_exe)
- if a:version != str2nr(pyversion)
+ if 3 != str2nr(majorpyversion)
call health#report_warn('Unexpected Python version.' .
\ ' This could lead to confusing error messages.')
endif
- call health#report_info('Python version: ' . pyversion)
+ call health#report_info('Python version: ' . majorpyversion)
if s:is_bad_response(status)
call health#report_info(printf('pynvim version: %s (%s)', current, status))
@@ -751,8 +751,7 @@ endfunction
function! health#provider#check() abort
call s:check_clipboard()
- call s:check_python(2)
- call s:check_python(3)
+ call s:check_python()
call s:check_virtualenv()
call s:check_ruby()
call s:check_node()
diff --git a/runtime/autoload/provider/python.vim b/runtime/autoload/provider/python.vim
deleted file mode 100644
index 8a1d162784..0000000000
--- a/runtime/autoload/provider/python.vim
+++ /dev/null
@@ -1,45 +0,0 @@
-" The Python provider uses a Python host to emulate an environment for running
-" python-vim plugins. :help provider
-"
-" Associating the plugin with the Python host is the first step because plugins
-" will be passed as command-line arguments
-
-if exists('g:loaded_python_provider')
- finish
-endif
-let [s:prog, s:err] = provider#pythonx#Detect(2)
-let g:loaded_python_provider = empty(s:prog) ? 1 : 2
-
-function! provider#python#Prog() abort
- return s:prog
-endfunction
-
-function! provider#python#Error() abort
- return s:err
-endfunction
-
-" The Python provider plugin will run in a separate instance of the Python
-" host.
-call remote#host#RegisterClone('legacy-python-provider', 'python')
-call remote#host#RegisterPlugin('legacy-python-provider', 'script_host.py', [])
-
-function! provider#python#Call(method, args) abort
- if s:err != ''
- return
- endif
- if !exists('s:host')
- let s:rpcrequest = function('rpcrequest')
-
- " Ensure that we can load the Python host before bootstrapping
- try
- let s:host = remote#host#Require('legacy-python-provider')
- catch
- let s:err = v:exception
- echohl WarningMsg
- echomsg v:exception
- echohl None
- return
- endtry
- endif
- return call(s:rpcrequest, insert(insert(a:args, 'python_'.a:method), s:host))
-endfunction
diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim
index 0eeb35cba8..5b299b322c 100644
--- a/runtime/autoload/provider/pythonx.vim
+++ b/runtime/autoload/provider/pythonx.vim
@@ -6,10 +6,8 @@ endif
let s:loaded_pythonx_provider = 1
function! provider#pythonx#Require(host) abort
- let ver = (a:host.orig_name ==# 'python') ? 2 : 3
-
" Python host arguments
- let prog = (ver == '2' ? provider#python#Prog() : provider#python3#Prog())
+ let prog = provider#python3#Prog()
let args = [prog, '-c', 'import sys; sys.path = list(filter(lambda x: x != "", sys.path)); import neovim; neovim.start_host()']
@@ -23,14 +21,12 @@ function! provider#pythonx#Require(host) abort
endfunction
function! s:get_python_executable_from_host_var(major_version) abort
- return expand(get(g:, 'python'.(a:major_version == 3 ? '3' : '').'_host_prog', ''), v:true)
+ return expand(get(g:, 'python'.(a:major_version == 3 ? '3' : execute("throw 'unsupported'")).'_host_prog', ''), v:true)
endfunction
function! s:get_python_candidates(major_version) abort
return {
- \ 2: ['python2', 'python2.7', 'python2.6', 'python'],
- \ 3: ['python3', 'python3.10', 'python3.9', 'python3.8', 'python3.7',
- \ 'python3.6', 'python']
+ \ 3: ['python3', 'python3.10', 'python3.9', 'python3.8', 'python3.7', 'python']
\ }[a:major_version]
endfunction
@@ -82,7 +78,7 @@ function! provider#pythonx#CheckForModule(prog, module, major_version) abort
return [0, a:prog . ' not found in search path or not executable.']
endif
- let min_version = (a:major_version == 2) ? '2.6' : '3.3'
+ let min_version = '3.7'
" Try to load module, and output Python version.
" Exit codes:
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 4a307c0d13..800604b506 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5806,7 +5806,6 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
this is not present).
mac MacOS system.
nvim This is Nvim.
- python2 Legacy Vim |python2| interface. |has-python|
python3 Legacy Vim |python3| interface. |has-python|
pythonx Legacy Vim |python_x| interface. |has-pythonx|
ttyin input is a terminal (tty)
diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt
index fea47de220..afdf039aa8 100644
--- a/runtime/doc/if_pyth.txt
+++ b/runtime/doc/if_pyth.txt
@@ -1,10 +1,10 @@
*if_pyth.txt* Nvim
- VIM REFERENCE MANUAL by Paul Moore
+ NVIM REFERENCE MANUAL
-The Python Interface to Vim *if_pyth* *python* *Python*
+The Python Interface to NVim *if_pyth* *python* *Python*
See |provider-python| for more information.
@@ -134,7 +134,7 @@ Instead, put the Python command in a function and call that function:
Note that "EOF" must be at the start of the line.
==============================================================================
-The vim module *python-vim* *python2*
+The vim module *python-vim*
Python code gets all of its access to vim (with one exception - see
|python-output| below) via the "vim" module. The vim module implements two
@@ -322,14 +322,13 @@ Output from Python *python-output*
supported, and may cause the program to crash. This should probably be
fixed.
- *python2-directory* *python3-directory* *pythonx-directory*
+ *python3-directory* *pythonx-directory*
Python 'runtimepath' handling *python-special-path*
In python vim.VIM_SPECIAL_PATH special directory is used as a replacement for
the list of paths found in 'runtimepath': with this directory in sys.path and
vim.path_hooks in sys.path_hooks python will try to load module from
-{rtp}/python2 (or python3) and {rtp}/pythonx (for both python versions) for
-each {rtp} found in 'runtimepath'.
+{rtp}/python3 and {rtp}/pythonx for each {rtp} found in 'runtimepath'.
Implementation is similar to the following, but written in C: >
@@ -401,8 +400,8 @@ vim._get_paths *python-_get_paths*
hook. You should not rely on this method being present in future
versions, but can use it for debugging.
- It returns a list of {rtp}/python2 (or {rtp}/python3) and
- {rtp}/pythonx directories for each {rtp} in 'runtimepath'.
+ It returns a list of {rtp}/python3 and {rtp}/pythonx
+ directories for each {rtp} in 'runtimepath'.
==============================================================================
Buffer objects *python-buffer*
@@ -590,6 +589,11 @@ functions to evaluate Python expressions and pass their values to Vim script.
==============================================================================
Python 3 *python3*
+As Python 3 is the only supported version in Nvim, "python" is synonymous
+with "python3" in the current version. However, code that aims to support older
+versions of Neovim, as well as Vim, should prefer to use "python3"
+variants explicitly if Python 3 is required.
+
*:py3* *:python3*
:[range]py3 {stmt}
:[range]py3 << [endmarker]
@@ -619,31 +623,26 @@ Raising SystemExit exception in python isn't endorsed way to quit vim, use: >
:py vim.command("qall!")
<
*has-python*
-You can test what Python version is available with: >
- if has('python')
- echo 'there is Python 2.x'
+You can test if Python is available with: >
+ if has('pythonx')
+ echo 'there is Python'
endif
if has('python3')
echo 'there is Python 3.x'
endif
+Python 2 is no longer supported. Thus `has('python')` always returns
+zero for backwards compatibility reasons.
+
==============================================================================
Python X *python_x* *pythonx*
-Because most python code can be written so that it works with Python 2.6+ and
-Python 3, the pyx* functions and commands have been written. They work the
-same as the Python 2 and 3 variants, but select the Python version using the
-'pyxversion' setting.
-
-Set 'pyxversion' in your |vimrc| to prefer Python 2 or Python 3 for Python
-commands. Changing this setting at runtime risks losing the state of plugins
-(such as initialization).
-
-If you want to use a module, you can put it in the {rtp}/pythonx directory.
-See |pythonx-directory|.
+The "pythonx" and "pyx" prefixes were introduced for python code which
+works with Python 2.6+ and Python 3. As Nvim only supports Python 3,
+all these commands are now synonymous to their "python3" equivalents.
*:pyx* *:pythonx*
-`:pyx` and `:pythonx` work similar to `:python`. To check if `:pyx` works: >
+`:pyx` and `:pythonx` work the same as `:python3`. To check if `:pyx` works: >
:pyx print("Hello")
To see what version of Python is being used: >
@@ -651,34 +650,16 @@ To see what version of Python is being used: >
:pyx print(sys.version)
<
*:pyxfile* *python_x-special-comments*
-`:pyxfile` works similar to `:pyfile`. But you can add a "shebang" comment to
-force Vim to use `:pyfile` or `:py3file`: >
- #!/any string/python2 " Shebang. Must be the first line of the file.
- #!/any string/python3 " Shebang. Must be the first line of the file.
- # requires python 2.x " Maximum lines depend on 'modelines'.
- # requires python 3.x " Maximum lines depend on 'modelines'.
-Unlike normal modelines, the bottom of the file is not checked.
-If none of them are found, the 'pyxversion' option is used.
- *W20* *W21*
-If Vim does not support the selected Python version a silent message will be
-printed. Use `:messages` to read them.
+`:pyxfile` works the same as `:py3file`.
*:pyxdo*
-`:pyxdo` works similar to `:pydo`.
+`:pyxdo` works the same as `:py3do`.
*has-pythonx*
-To check if pyx* functions and commands are available: >
+To check if `pyx*` functions and commands are available: >
if has('pythonx')
echo 'pyx* commands are available. (Python ' . &pyx . ')'
endif
-If you prefer Python 2 and want to fallback to Python 3, set 'pyxversion'
-explicitly in your |.vimrc|. Example: >
- if has('python')
- set pyx=2
- elseif has('python3')
- set pyx=3
- endif
-
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 13a19d8991..5e7d709584 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4637,26 +4637,11 @@ A jump table for the options with a short description can be found at |Q_op|.
nudged to fit on the screen.
*'pyxversion'* *'pyx'*
-'pyxversion' 'pyx' number (default depends on the build)
+'pyxversion' 'pyx' number (default 3)
global
Specifies the python version used for pyx* functions and commands
- |python_x|. The default value is as follows:
-
- |provider| installed Default ~
- |+python| and |+python3| 0
- only |+python| 2
- only |+python3| 3
-
- Available values are 0, 2 and 3.
- If 'pyxversion' is 0, it is set to 2 or 3 after the first execution of
- any python2/3 commands or functions. E.g. `:py` sets to 2, and `:py3`
- sets to 3. `:pyx` sets it to 3 if Python 3 is available, otherwise sets
- to 2 if Python 2 is available.
- See also: |has-pythonx|
-
- If only |+python| or |+python3| are available,
- 'pyxversion' has no effect. The pyx* functions and commands are
- always the same as the installed version.
+ |python_x|. As only Python 3 is supported, this always has the value
+ `3`. Setting any other value is an error.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index b785010699..9fd35f19c5 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -20,11 +20,12 @@ Run the |:checkhealth| command, and review the sections below.
==============================================================================
Python integration *provider-python*
-Nvim supports Python |remote-plugin|s and the Vim legacy |python2| and
-|python3| interfaces (which are implemented as remote-plugins).
+Nvim supports Python |remote-plugin|s and the Vim legacy |python3| and
+|pythonx| interfaces (which are implemented as remote-plugins).
Note: Only the Vim 7.3 legacy interface is supported, not later features such
-as |python-bindeval| (Vim 7.4); use the Nvim API instead.
+as |python-bindeval| (Vim 7.4); use the Nvim API instead. Python 2 is not
+supported.
PYTHON QUICKSTART ~
@@ -38,11 +39,6 @@ For Python 3 plugins:
2. Install the module (try "python" if "python3" is missing): >
python3 -m pip install --user --upgrade pynvim
-For Python 2 plugins:
-1. Make sure Python 2.7 is available in your $PATH.
-2. Install the module (try "python" if "python2" is missing): >
- python2 -m pip install --user --upgrade pynvim
-
The pip `--upgrade` flag ensures that you get the latest version even if
a previous version was already installed.
@@ -56,22 +52,12 @@ If you run into problems, uninstall _both_ then install "pynvim" again: >
PYTHON PROVIDER CONFIGURATION ~
- *g:python_host_prog*
-Command to start Python 2 (executable, not directory). Setting this makes
-startup faster. Useful for working with virtualenvs. Must be set before any
-check for has("python2"). >
- let g:python_host_prog = '/path/to/python'
-<
*g:python3_host_prog*
Command to start Python 3 (executable, not directory). Setting this makes
startup faster. Useful for working with virtualenvs. Must be set before any
check for has("python3"). >
let g:python3_host_prog = '/path/to/python3'
<
- *g:loaded_python_provider*
-To disable Python 2 support: >
- let g:loaded_python_provider = 0
-<
*g:loaded_python3_provider*
To disable Python 3 support: >
let g:loaded_python3_provider = 0
@@ -81,8 +67,8 @@ PYTHON VIRTUALENVS ~
*python-virtualenv*
If you plan to use per-project virtualenvs often, you should assign one
virtualenv for Neovim and hard-code the interpreter path via
-|g:python3_host_prog| (or |g:python_host_prog|) so that the "pynvim" package
-is not required for each virtualenv.
+|g:python3_host_prog| so that the "pynvim" package is not required
+for each virtualenv.
Example using pyenv: >
pyenv install 3.4.4
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 873fbd8971..bb4d807413 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1446,7 +1446,7 @@ error message (line numbers are not part of the actual output):
4 Traceback (most recent call last):
5 File "unittests/dbfacadeTest.py", line 89, in testFoo
6 self.assertEquals(34, dtid)
- 7 File "/usr/lib/python2.2/unittest.py", line 286, in
+ 7 File "/usr/lib/python3.8/unittest.py", line 286, in
8 failUnlessEqual
9 raise self.failureException, \
10 AssertionError: 34 != 33
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 0b460fe887..18967b80f2 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -270,8 +270,8 @@ return {
pum_getpos={},
pumvisible={},
py3eval={args=1, base=1},
- pyeval={args=1, base=1},
- pyxeval={args=1, base=1},
+ pyeval={args=1, base=1, func="f_py3eval"},
+ pyxeval={args=1, base=1, func="f_py3eval"},
perleval={args=1, base=1},
range={args={1, 3}, base=1},
readdir={args={1, 2}, base=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index ae383dc981..29619f62e9 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -6982,36 +6982,13 @@ static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/*
- * "pyeval()" function
- */
-static void f_pyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- script_host_eval("python", argvars, rettv);
-}
-
-/*
- * "py3eval()" function
- */
+/// "py3eval()" and "pyxeval()" functions (always python3)
static void f_py3eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
script_host_eval("python3", argvars, rettv);
}
-// "pyxeval()" function
-static void f_pyxeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- init_pyxversion();
- if (p_pyx == 2) {
- f_pyeval(argvars, rettv, NULL);
- } else {
- f_py3eval(argvars, rettv, NULL);
- }
-}
-
-///
/// "perleval()" function
-///
static void f_perleval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
script_host_eval("perl", argvars, rettv);
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index c391cf96aa..c2d40c8bb7 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -2097,19 +2097,19 @@ module.cmds = {
command='python',
flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
addr_type='ADDR_LINES',
- func='ex_python',
+ func='ex_python3',
},
{
command='pydo',
flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
addr_type='ADDR_LINES',
- func='ex_pydo',
+ func='ex_pydo3',
},
{
command='pyfile',
flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
addr_type='ADDR_LINES',
- func='ex_pyfile',
+ func='ex_py3file',
},
{
command='py3',
@@ -2139,25 +2139,25 @@ module.cmds = {
command='pyx',
flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
addr_type='ADDR_LINES',
- func='ex_pyx',
+ func='ex_python3',
},
{
command='pyxdo',
flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
addr_type='ADDR_LINES',
- func='ex_pyxdo',
+ func='ex_pydo3',
},
{
command='pythonx',
flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
addr_type='ADDR_LINES',
- func='ex_pyx',
+ func='ex_python3',
},
{
command='pyxfile',
flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
addr_type='ADDR_LINES',
- func='ex_pyxfile',
+ func='ex_py3file',
},
{
command='quit',
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 846789233f..e5cec0e060 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -135,21 +135,6 @@ void ex_profile(exarg_T *eap)
}
}
-void ex_python(exarg_T *eap)
-{
- script_host_execute("python", eap);
-}
-
-void ex_pyfile(exarg_T *eap)
-{
- script_host_execute_file("python", eap);
-}
-
-void ex_pydo(exarg_T *eap)
-{
- script_host_do_range("python", eap);
-}
-
void ex_ruby(exarg_T *eap)
{
script_host_execute("ruby", eap);
@@ -1660,126 +1645,6 @@ void ex_options(exarg_T *eap)
cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
}
-// Detect Python 3 or 2, and initialize 'pyxversion'.
-void init_pyxversion(void)
-{
- if (p_pyx == 0) {
- if (eval_has_provider("python3")) {
- p_pyx = 3;
- } else if (eval_has_provider("python")) {
- p_pyx = 2;
- }
- }
-}
-
-// Does a file contain one of the following strings at the beginning of any
-// line?
-// "#!(any string)python2" => returns 2
-// "#!(any string)python3" => returns 3
-// "# requires python 2.x" => returns 2
-// "# requires python 3.x" => returns 3
-// otherwise return 0.
-static int requires_py_version(char_u *filename)
-{
- FILE *file;
- int requires_py_version = 0;
- int i, lines;
-
- lines = (int)p_mls;
- if (lines < 0) {
- lines = 5;
- }
-
- file = os_fopen((char *)filename, "r");
- if (file != NULL) {
- for (i = 0; i < lines; i++) {
- if (vim_fgets(IObuff, IOSIZE, file)) {
- break;
- }
- if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!') {
- // Check shebang.
- if (strstr((char *)IObuff + 2, "python2") != NULL) {
- requires_py_version = 2;
- break;
- }
- if (strstr((char *)IObuff + 2, "python3") != NULL) {
- requires_py_version = 3;
- break;
- }
- }
- IObuff[21] = '\0';
- if (STRCMP("# requires python 2.x", IObuff) == 0) {
- requires_py_version = 2;
- break;
- }
- if (STRCMP("# requires python 3.x", IObuff) == 0) {
- requires_py_version = 3;
- break;
- }
- }
- fclose(file);
- }
- return requires_py_version;
-}
-
-
-// Source a python file using the requested python version.
-static void source_pyx_file(exarg_T *eap, char_u *fname)
-{
- exarg_T ex;
- long int v = requires_py_version(fname);
-
- init_pyxversion();
- if (v == 0) {
- // user didn't choose a preference, 'pyx' is used
- v = p_pyx;
- }
-
- // now source, if required python version is not supported show
- // unobtrusive message.
- if (eap == NULL) {
- memset(&ex, 0, sizeof(ex));
- } else {
- ex = *eap;
- }
- ex.arg = fname;
- ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
-
- if (v == 2) {
- ex_pyfile(&ex);
- } else {
- ex_py3file(&ex);
- }
-}
-
-// ":pyxfile {fname}"
-void ex_pyxfile(exarg_T *eap)
-{
- source_pyx_file(eap, eap->arg);
-}
-
-// ":pyx"
-void ex_pyx(exarg_T *eap)
-{
- init_pyxversion();
- if (p_pyx == 2) {
- ex_python(eap);
- } else {
- ex_python3(eap);
- }
-}
-
-// ":pyxdo"
-void ex_pyxdo(exarg_T *eap)
-{
- init_pyxversion();
- if (p_pyx == 2) {
- ex_pydo(eap);
- } else {
- ex_pydo3(eap);
- }
-}
-
/// ":source [{fname}]"
void ex_source(exarg_T *eap)
{
diff --git a/src/nvim/option.c b/src/nvim/option.c
index a4a6423ac7..2fb1966cda 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -4349,6 +4349,12 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
} else if (value > 10000) {
errmsg = e_invarg;
}
+ } else if (pp == &p_pyx) {
+ if (value == 0) {
+ value = 3;
+ } else if (value != 3) {
+ errmsg = e_invarg;
+ }
} else if (pp == &p_re) {
if (value < 0 || value > 2) {
errmsg = e_invarg;
@@ -4523,10 +4529,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
if (pum_drawn()) {
pum_redraw();
}
- } else if (pp == &p_pyx) {
- if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) {
- errmsg = e_invarg;
- }
} else if (pp == &p_ul || pp == &curbuf->b_p_ul) {
// sync undo before 'undolevels' changes
// use the old value, otherwise u_sync() may not work properly
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index aea2179a61..e665ffd346 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1846,7 +1846,7 @@ return {
type='number', scope={'global'},
secure=true,
varname='p_pyx',
- defaults={if_true=0}
+ defaults={if_true=3}
},
{
full_name='quickfixtextfunc', abbreviation='qftf',
diff --git a/src/nvim/testdir/test_python3.vim b/src/nvim/testdir/test_python3.vim
index 54da3d2eba..f6a1942e24 100644
--- a/src/nvim/testdir/test_python3.vim
+++ b/src/nvim/testdir/test_python3.vim
@@ -69,6 +69,7 @@ func Test_vim_function()
endfunc
func Test_skipped_python3_command_does_not_affect_pyxversion()
+ throw 'skipped: Nvim hardcodes pyxversion=3'
set pyxversion=0
if 0
python3 import vim
diff --git a/src/nvim/testdir/test_pyx2.vim b/src/nvim/testdir/test_pyx2.vim
index b6ed80f842..6a8ebf3da0 100644
--- a/src/nvim/testdir/test_pyx2.vim
+++ b/src/nvim/testdir/test_pyx2.vim
@@ -1,9 +1,9 @@
" Test for pyx* commands and functions with Python 2.
-set pyx=2
if !has('python')
finish
endif
+set pyx=2
let s:py2pattern = '^2\.[0-7]\.\d\+'
let s:py3pattern = '^3\.\d\+\.\d\+'
diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua
index 0a772c559b..f249b9ba7c 100644
--- a/test/functional/ex_cmds/script_spec.lua
+++ b/test/functional/ex_cmds/script_spec.lua
@@ -62,10 +62,10 @@ describe('script_get-based command', function()
-- Provider-based scripts
test_garbage_exec('ruby', not missing_provider('ruby'))
- test_garbage_exec('python', not missing_provider('python'))
test_garbage_exec('python3', not missing_provider('python3'))
-- Missing scripts
+ test_garbage_exec('python', false)
test_garbage_exec('tcl', false)
test_garbage_exec('mzscheme', false)
test_garbage_exec('perl', false)
diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua
index d100db8de2..603f4d91b9 100644
--- a/test/functional/provider/python3_spec.lua
+++ b/test/functional/provider/python3_spec.lua
@@ -8,6 +8,7 @@ local source = helpers.source
local missing_provider = helpers.missing_provider
local matches = helpers.matches
local pcall_err = helpers.pcall_err
+local funcs = helpers.funcs
do
clear()
@@ -93,16 +94,40 @@ describe('python3 provider', function()
ghi]])
end)
- it('py3eval', function()
- eq({1, 2, {['key'] = 'val'}}, eval([[py3eval('[1, 2, {"key": "val"}]')]]))
+ describe('py3eval()', function()
+ it('works', function()
+ eq({1, 2, {['key'] = 'val'}}, funcs.py3eval('[1, 2, {"key": "val"}]'))
+ end)
+
+ it('errors out when given non-string', function()
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(10)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:_null_dict)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:_null_list)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(0.0)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(function("tr"))'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:true)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:false)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:null)'))
+ end)
+
+ it('accepts NULL string', function()
+ matches('.*SyntaxError.*', pcall_err(eval, 'py3eval($XXX_NONEXISTENT_VAR_XXX)'))
+ end)
end)
it('pyxeval #10758', function()
- eq(0, eval([[&pyxversion]]))
+ eq(3, eval([[&pyxversion]]))
eq(3, eval([[pyxeval('sys.version_info[:3][0]')]]))
eq(3, eval([[&pyxversion]]))
end)
+ it("setting 'pyxversion'", function()
+ command 'set pyxversion=3' -- no error
+ eq('Vim(set):E474: Invalid argument: pyxversion=2', pcall_err(command, 'set pyxversion=2'))
+ command 'set pyxversion=0' -- allowed, but equivalent to pyxversion=3
+ eq(3, eval'&pyxversion')
+ end)
+
it('RPC call to expand("<afile>") during BufDelete #5245 #5617', function()
helpers.add_builddir_to_rtp()
source([=[
@@ -120,3 +145,15 @@ describe('python3 provider', function()
assert_alive()
end)
end)
+
+describe('python2 feature test', function()
+ -- python2 is not supported, so correct behaviour is to return 0
+ it('works', function()
+ eq(0, funcs.has('python2'))
+ eq(0, funcs.has('python'))
+ eq(0, funcs.has('python_compiled'))
+ eq(0, funcs.has('python_dynamic'))
+ eq(0, funcs.has('python_dynamic_'))
+ eq(0, funcs.has('python_'))
+ end)
+end)
diff --git a/test/functional/provider/python_spec.lua b/test/functional/provider/python_spec.lua
deleted file mode 100644
index d60d8d1001..0000000000
--- a/test/functional/provider/python_spec.lua
+++ /dev/null
@@ -1,123 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local eq = helpers.eq
-local neq = helpers.neq
-local feed = helpers.feed
-local clear = helpers.clear
-local funcs = helpers.funcs
-local meths = helpers.meths
-local insert = helpers.insert
-local expect = helpers.expect
-local command = helpers.command
-local exc_exec = helpers.exc_exec
-local write_file = helpers.write_file
-local curbufmeths = helpers.curbufmeths
-local missing_provider = helpers.missing_provider
-local matches = helpers.matches
-local pcall_err = helpers.pcall_err
-
-do
- clear()
- local reason = missing_provider('python')
- if reason then
- it(':python reports E319 if provider is missing', function()
- local expected = [[Vim%(py.*%):E319: No "python" provider found.*]]
- matches(expected, pcall_err(command, 'py print("foo")'))
- matches(expected, pcall_err(command, 'pyfile foo'))
- end)
- pending(string.format('Python 2 (or the pynvim module) is broken/missing (%s)', reason), function() end)
- return
- end
-end
-
-before_each(function()
- clear()
- command('python import vim')
-end)
-
-describe('python feature test', function()
- it('works', function()
- eq(1, funcs.has('python'))
- eq(1, funcs.has('python_compiled'))
- eq(1, funcs.has('python_dynamic'))
- eq(0, funcs.has('python_dynamic_'))
- eq(0, funcs.has('python_'))
- end)
-end)
-
-describe(':python command', function()
- it('works with a line', function()
- command('python vim.vars["set_by_python"] = [100, 0]')
- eq({100, 0}, meths.get_var('set_by_python'))
- end)
-
- -- TODO(ZyX-I): works with << EOF
- -- TODO(ZyX-I): works with execute 'python' line1."\n".line2."\n"…
-
- it('supports nesting', function()
- command([[python vim.command('python vim.command("python vim.command(\'let set_by_nested_python = 555\')")')]])
- eq(555, meths.get_var('set_by_nested_python'))
- end)
-
- it('supports range', function()
- insert([[
- line1
- line2
- line3
- line4]])
- feed('ggjvj:python vim.vars["range"] = vim.current.range[:]<CR>')
- eq({'line2', 'line3'}, meths.get_var('range'))
- end)
-end)
-
-describe(':pyfile command', function()
- it('works', function()
- local fname = 'pyfile.py'
- write_file(fname, 'vim.command("let set_by_pyfile = 123")')
- command('pyfile pyfile.py')
- eq(123, meths.get_var('set_by_pyfile'))
- os.remove(fname)
- end)
-end)
-
-describe(':pydo command', function()
- it('works', function()
- -- :pydo 42 returns None for all lines,
- -- the buffer should not be changed
- command('normal :pydo 42')
- eq(false, curbufmeths.get_option('modified'))
- -- insert some text
- insert('abc\ndef\nghi')
- expect([[
- abc
- def
- ghi]])
- -- go to top and select and replace the first two lines
- feed('ggvj:pydo return str(linenr)<CR>')
- expect([[
- 1
- 2
- ghi]])
- end)
-end)
-
-describe('pyeval()', function()
- it('works', function()
- eq({1, 2, {['key'] = 'val'}}, funcs.pyeval('[1, 2, {"key": "val"}]'))
- end)
-
- it('errors out when given non-string', function()
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(10)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:_null_dict)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:_null_list)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(0.0)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(function("tr"))'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:true)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:false)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:null)'))
- end)
-
- it('accepts NULL string', function()
- neq(0, exc_exec('call pyeval($XXX_NONEXISTENT_VAR_XXX)'))
- end)
-end)