diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2022-01-28 15:42:19 +0100 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2022-01-29 19:49:37 +0100 |
commit | baec0d3152afeab3007ebb505f3fc274511db434 (patch) | |
tree | 7a6401825cf208ba9aaa21cbe053effd71077a0e | |
parent | b2f77c354a289ac99de4c28425dc39d7d057cf90 (diff) | |
download | rneovim-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.vim | 4 | ||||
-rw-r--r-- | runtime/autoload/health/provider.vim | 19 | ||||
-rw-r--r-- | runtime/autoload/provider/python.vim | 45 | ||||
-rw-r--r-- | runtime/autoload/provider/pythonx.vim | 12 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 1 | ||||
-rw-r--r-- | runtime/doc/if_pyth.txt | 69 | ||||
-rw-r--r-- | runtime/doc/options.txt | 21 | ||||
-rw-r--r-- | runtime/doc/provider.txt | 26 | ||||
-rw-r--r-- | runtime/doc/quickfix.txt | 2 | ||||
-rw-r--r-- | src/nvim/eval.lua | 4 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 25 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 14 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 135 | ||||
-rw-r--r-- | src/nvim/option.c | 10 | ||||
-rw-r--r-- | src/nvim/options.lua | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_python3.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_pyx2.vim | 2 | ||||
-rw-r--r-- | test/functional/ex_cmds/script_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/provider/python3_spec.lua | 43 | ||||
-rw-r--r-- | test/functional/provider/python_spec.lua | 123 |
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) |