Skip to content
Browse files

patch 8.0.0251: not easy to select Python 2 or 3

Problem:    It is not so easy to write a script that works with both Python 2
            and Python 3, even when the Python code works with both.
Solution:   Add 'pyxversion', :pyx, etc. (Marc Weber, Ken Takata)
  • Loading branch information...
brammool committed Jan 28, 2017
1 parent 0c0590d commit f42dd3c3901ea0ba38e67a616aea9953cae81b8d
@@ -122,6 +122,7 @@ SRC_ALL = \
src/testdir/pythonx/topmodule/submodule/subsubmodule/ \
src/testdir/python_after/*.py \
src/testdir/python_before/*.py \
src/testdir/pyxfile/*.py \
src/testdir/bench*.in \
src/testdir/bench*.vim \
src/testdir/samples/*.txt \
@@ -2239,6 +2239,7 @@ printf({fmt}, {expr1}...) String format text
pumvisible() Number whether popup menu is visible
pyeval({expr}) any evaluate |Python| expression
py3eval({expr}) any evaluate |python3| expression
pyxeval({expr}) any evaluate |python_x| expression
range({expr} [, {max} [, {stride}]])
List items from {expr} to {max}
readfile({fname} [, {binary} [, {max}]])
@@ -6163,6 +6164,14 @@ pyeval({expr}) *pyeval()*
non-string keys result in error.
{only available when compiled with the |+python| feature}

pyxeval({expr}) *pyxeval()*
Evaluate Python expression {expr} and return its result
converted to Vim data structures.
Uses Python 2 or 3, see |python_x| and 'pyxversion'.
See also: |pyeval()|, |py3eval()|
{only available when compiled with the |+python| or the
|+python3| feature}

*E726* *E727*
range({expr} [, {max} [, {stride}]]) *range()*
Returns a |List| with Numbers:
@@ -8402,6 +8411,7 @@ printer Compiled with |:hardcopy| support.
profile Compiled with |:profile| support.
python Compiled with Python 2.x interface. |has-python|
python3 Compiled with Python 3.x interface. |has-python|
pythonx Compiled with |python_x| interface. |has-pythonx|
qnx QNX version of Vim.
quickfix Compiled with |quickfix| support.
reltime Compiled with |reltime()| support.
@@ -16,6 +16,7 @@ The Python Interface to Vim *python* *Python*
8. pyeval(), py3eval() Vim functions |python-pyeval|
9. Dynamic loading |python-dynamic|
10. Python 3 |python3|
11. Python X |python_x|

{Vi does not have any of these commands}

@@ -711,6 +712,7 @@ vim.Function object *python-Function*

To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()|
functions to evaluate Python expressions and pass their values to VimL.
|pyxeval()| is also available.

9. Dynamic loading *python-dynamic*
@@ -811,5 +813,69 @@ dynamically, these has() calls will try to load them. If only one can be
loaded at a time, just checking if Python 2 or 3 are available will prevent
the other one from being available.

11. 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 writen. They work exactly
the same as the Python 2 and 3 variants, but select the Python version using
the 'pyxversion' setting.

You should set 'pyxversion' in your |.vimrc| to prefer Python 2 or Python 3
for Python commands. If you change this setting at runtime you may risk that
state of plugins (such as initialization) may be lost.

If you want to use a module, you can put it in the {rtp}/pythonx directory.
See |pythonx-directory|.

*:pyx* *:pythonx*
The `:pyx` and `:pythonx` commands work similar to `:python`. A simple check
if the `:pyx` command is working: >
:pyx print("Hello")

To see what version of Python is being used: >
:pyx import sys
:pyx print(sys.version)
*:pyxfile* *python_x-special-comments*
The `:pyxfile` command works similar to `:pyfile`. However you can add one of
these comments to force Vim using `: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' setting is used.
*W20* *W21*
If Vim does not support the selected Python version a silent message will be
printed. Use `:messages` to read them.

The `:pyxdo` command works similar to `:pydo`.

You can test if pyx* commands are available with: >
if has('pythonx')
echo 'pyx* commands are available. (Python ' . &pyx . ')'

When compiled with only one of |+python| or |+python3|, the has() returns 1.
When compiled with both |+python| and |+python3|, the test depends on the
'pyxversion' setting. If 'pyxversion' is 0, it tests Python 3 first, and if
it is not available then Python 2. If 'pyxversion' is 2 or 3, it tests only
Python 2 or 3 respectively.

Note that for has('pythonx') to work it may try to dynamically load Python 3
or 2. This may have side effects, especially when Vim can only load one of
the two.

If a user prefers Python 2 and want to fallback to Python 3, he needs to set
'pyxversion' explicitly in his |.vimrc|. E.g.: >
if has('python')
set pyx=2
elseif has('python3')
set pyx=3

@@ -1440,6 +1440,10 @@ tag command action ~
|:python| :py[thon] execute Python command
|:pydo| :pyd[o] execute Python command for each line
|:pyfile| :pyf[ile] execute Python script file
|:pyx| :pyx execute |python_x| command
|:pythonx| :pythonx same as :pyx
|:pyxdo| :pyxd[o] execute |python_x| command for each line
|:pyxfile| :pyxf[ile] execute |python_x| script file
|:quit| :q[uit] quit current window (when one window quit Vim)
|:quitall| :quita[ll] quit Vim
|:qall| :qa[ll] quit Vim
@@ -5786,6 +5786,34 @@ A jump table for the options with a short description can be found at |Q_op|.
Specifies the name of the Python 3 shared library. The default is
DYNAMIC_PYTHON3_DLL, which was specified at compile time.
Environment variables are expanded |:set_env|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.

*'pyxversion'* *'pyx'*
'pyxversion' 'pyx' number (default depends on the build)
{not in Vi}
{only available when compiled with the |+python| or
the |+python3| feature}
Specifies the python version used for pyx* functions and commands
|python_x|. The default value is as follows:

Compiled with 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 Vim is compiled with only |+python| or |+python3| setting
'pyxversion' has no effect. The pyx* functions and commands are
always the same as the compiled version.

This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.

@@ -835,6 +835,7 @@ Short explanation of each option: *option-list*
'pumheight' 'ph' maximum height of the popup menu
'pythondll' name of the Python 2 dynamic library
'pythonthreedll' name of the Python 3 dynamic library
'pyxversion' 'pyx' Python version used for pyx* commands
'quoteescape' 'qe' escape characters used in a string
'readonly' 'ro' disallow writing the buffer
'redrawtime' 'rdt' timeout for 'hlsearch' and |:match| highlighting
@@ -923,7 +923,7 @@ if has("folding")
call append("$", "foldmarker\tmarkers used when 'foldmethod' is \"marker\"")
call append("$", "\t(local to window)")
call <SID>OptionL("fmr")
call append("$", "foldnestmax\tmaximum fold depth for when 'foldmethod is \"indent\" or \"syntax\"")
call append("$", "foldnestmax\tmaximum fold depth for when 'foldmethod' is \"indent\" or \"syntax\"")
call append("$", "\t(local to window)")
call <SID>OptionL("fdn")
@@ -1324,6 +1324,10 @@ if exists("&perldll")
call append("$", "perldll\tname of the Perl dynamic library")
call <SID>OptionG("perldll", &perldll)
if has('pythonx')
call append("$", "pyxversion\twhether to use Python 2 or 3")
call append("$", " \tset pyx=" . &wd)
if exists("&pythondll")
call append("$", "pythondll\tname of the Python 2 dynamic library")
call <SID>OptionG("pythondll", &pythondll)
@@ -2151,6 +2151,8 @@ test_arglist \
test_popup \
test_profile \
test_put \
test_pyx2 \
test_pyx3 \
test_quickfix \
test_regexp_latin \
test_regexp_utf8 \
@@ -2754,6 +2756,7 @@ shadow: runtime pixmaps
../../testdir/*.vim \
../../testdir/*.py \
../../testdir/python* \
../../testdir/pyxfile \
../../testdir/sautest \
../../testdir/samples \
../../testdir/test83-tags? \
@@ -289,6 +289,9 @@ static void f_py3eval(typval_T *argvars, typval_T *rettv);
static void f_pyeval(typval_T *argvars, typval_T *rettv);
#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
static void f_pyxeval(typval_T *argvars, typval_T *rettv);
static void f_range(typval_T *argvars, typval_T *rettv);
static void f_readfile(typval_T *argvars, typval_T *rettv);
static void f_reltime(typval_T *argvars, typval_T *rettv);
@@ -715,6 +718,9 @@ static struct fst
{"pyeval", 1, 1, f_pyeval},
#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
{"pyxeval", 1, 1, f_pyxeval},
{"range", 1, 3, f_range},
{"readfile", 1, 3, f_readfile},
@@ -5734,15 +5740,13 @@ f_has(typval_T *argvars, typval_T *rettv)
#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
@@ -5972,17 +5976,30 @@ f_has(typval_T *argvars, typval_T *rettv)
else if (STRICMP(name, "ruby") == 0)
n = ruby_enabled(FALSE);
else if (STRICMP(name, "python") == 0)
n = python_enabled(FALSE);
else if (STRICMP(name, "python3") == 0)
n = python3_enabled(FALSE);
#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
else if (STRICMP(name, "pythonx") == 0)
# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
if (p_pyx == 0)
n = python3_enabled(FALSE) || python_enabled(FALSE);
else if (p_pyx == 3)
n = python3_enabled(FALSE);
else if (p_pyx == 2)
n = python_enabled(FALSE);
# elif defined(DYNAMIC_PYTHON)
n = python_enabled(FALSE);
# elif defined(DYNAMIC_PYTHON3)
n = python3_enabled(FALSE);
# endif
else if (STRICMP(name, "perl") == 0)
@@ -8007,6 +8024,9 @@ f_py3eval(typval_T *argvars, typval_T *rettv)
char_u *str;
char_u buf[NUMBUFLEN];

if (p_pyx == 0)
p_pyx = 3;

str = get_tv_string_buf(&argvars[0], buf);
do_py3eval(str, rettv);
@@ -8022,11 +8042,35 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
char_u *str;
char_u buf[NUMBUFLEN];

if (p_pyx == 0)
p_pyx = 2;

str = get_tv_string_buf(&argvars[0], buf);
do_pyeval(str, rettv);

#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
* "pyxeval()" function
static void
f_pyxeval(typval_T *argvars, typval_T *rettv)
# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
if (p_pyx == 2)
f_pyeval(argvars, rettv);
f_py3eval(argvars, rettv);
# elif defined(FEAT_PYTHON)
f_pyeval(argvars, rettv);
# elif defined(FEAT_PYTHON3)
f_py3eval(argvars, rettv);
# endif

* "range()" function
@@ -1132,6 +1132,18 @@ EX(CMD_python3, "python3", ex_py3,
EX(CMD_py3file, "py3file", ex_py3file,
EX(CMD_pyx, "pyx", ex_pyx,
EX(CMD_pyxdo, "pyxdo", ex_pyxdo,
EX(CMD_pythonx, "pythonx", ex_pyx,
EX(CMD_pyxfile, "pyxfile", ex_pyxfile,
EX(CMD_quit, "quit", ex_quit,

0 comments on commit f42dd3c

Please sign in to comment.
You can’t perform that action at this time.