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.
This commit is contained in:
Björn Linse 2022-01-28 15:42:19 +01:00
parent b2f77c354a
commit baec0d3152
20 changed files with 110 additions and 450 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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.

View File

@ -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,21 +52,11 @@ 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: >
@ -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

View File

@ -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

View File

@ -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},

View File

@ -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);

View File

@ -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',

View File

@ -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)
{

View File

@ -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

View File

@ -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',

View File

@ -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

View File

@ -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\+'

View File

@ -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)

View File

@ -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)

View File

@ -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)