0
0
mirror of https://github.com/vim/vim.git synced 2025-08-23 19:34:27 -04:00

patch 9.1.0844: if_python: no way to pass local vars to python

Problem:  if_python: no way to pass local vars to python
Solution: Add locals argument to py3eval(), pyeval() and pyxeval()
          (Ben Jackson)

fixes: #8573
closes: #10594

Signed-off-by: Ben Jackson <puremourning@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Ben Jackson 2024-11-06 21:50:05 +01:00 committed by Christian Brabandt
parent fd1a838d36
commit ea19e7856b
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
16 changed files with 291 additions and 30 deletions

View File

@ -1,4 +1,4 @@
*builtin.txt* For Vim version 9.1. Last change: 2024 Nov 01 *builtin.txt* For Vim version 9.1. Last change: 2024 Nov 06
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@ -467,9 +467,9 @@ prop_type_get({name} [, {props}])
prop_type_list([{props}]) List get list of property types prop_type_list([{props}]) List get list of property types
pum_getpos() Dict position and size of pum if visible pum_getpos() Dict position and size of pum if visible
pumvisible() Number whether popup menu is visible pumvisible() Number whether popup menu is visible
py3eval({expr}) any evaluate |python3| expression py3eval({expr}[, {locals}]) any evaluate |python3| expression
pyeval({expr}) any evaluate |Python| expression pyeval({expr}[, {locals}]) any evaluate |Python| expression
pyxeval({expr}) any evaluate |python_x| expression pyxeval({expr}[, {locals}]) any evaluate |python_x| expression
rand([{expr}]) Number get pseudo-random number rand([{expr}]) Number get pseudo-random number
range({expr} [, {max} [, {stride}]]) range({expr} [, {max} [, {stride}]])
List items from {expr} to {max} List items from {expr} to {max}
@ -8127,9 +8127,14 @@ pumvisible() *pumvisible()*
Return type: |Number| Return type: |Number|
py3eval({expr}) *py3eval()* py3eval({expr}[, {locals}]) *py3eval()*
Evaluate Python expression {expr} and return its result Evaluate Python expression {expr} and return its result
converted to Vim data structures. converted to Vim data structures.
If a {locals} |Dictionary| is given, it defines set of local
variables available in the expression. The keys are variable
names and the values are the variable values. |Dictionary| and
|List| values are referenced, and may be updated by the
expression (as if |python-bindeval| was used).
Numbers and strings are returned as they are (strings are Numbers and strings are returned as they are (strings are
copied though, Unicode strings are additionally converted to copied though, Unicode strings are additionally converted to
'encoding'). 'encoding').
@ -8141,15 +8146,17 @@ py3eval({expr}) *py3eval()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetExpr()->py3eval() GetExpr()->py3eval()
'b",".join(l)'->py3eval({'l': ['a', 'b', 'c']})
< <
Return type: any, depending on {expr} Return type: any, depending on {expr}
{only available when compiled with the |+python3| feature} {only available when compiled with the |+python3| feature}
*E858* *E859* *E858* *E859*
pyeval({expr}) *pyeval()* pyeval({expr}[, {locals}]) *pyeval()*
Evaluate Python expression {expr} and return its result Evaluate Python expression {expr} and return its result
converted to Vim data structures. converted to Vim data structures.
For {locals} see |py3eval()|.
Numbers and strings are returned as they are (strings are Numbers and strings are returned as they are (strings are
copied though). copied though).
Lists are represented as Vim |List| type. Lists are represented as Vim |List| type.
@ -8165,9 +8172,10 @@ pyeval({expr}) *pyeval()*
{only available when compiled with the |+python| feature} {only available when compiled with the |+python| feature}
pyxeval({expr}) *pyxeval()* pyxeval({expr}[, {locals}]) *pyxeval()*
Evaluate Python expression {expr} and return its result Evaluate Python expression {expr} and return its result
converted to Vim data structures. converted to Vim data structures.
For {locals} see |py3eval()|.
Uses Python 2 or 3, see |python_x| and 'pyxversion'. Uses Python 2 or 3, see |python_x| and 'pyxversion'.
See also: |pyeval()|, |py3eval()| See also: |pyeval()|, |py3eval()|

View File

@ -1,4 +1,4 @@
*if_pyth.txt* For Vim version 9.1. Last change: 2024 May 16 *if_pyth.txt* For Vim version 9.1. Last change: 2024 Nov 06
VIM REFERENCE MANUAL by Paul Moore VIM REFERENCE MANUAL by Paul Moore
@ -201,6 +201,10 @@ vim.eval(str) *python-eval*
[{'cmd': '/^eval_expr(arg, nextcmd)$/', 'static': 0, 'name': ~ [{'cmd': '/^eval_expr(arg, nextcmd)$/', 'static': 0, 'name': ~
'eval_expr', 'kind': 'f', 'filename': './src/eval.c'}] ~ 'eval_expr', 'kind': 'f', 'filename': './src/eval.c'}] ~
NOTE: In vim9script, local variables in def functions are not visible
to to python evaluations. To pass local variables to python evaluations,
use the {locals} dict when calling |py3eval()| and friends.
vim.bindeval(str) *python-bindeval* vim.bindeval(str) *python-bindeval*
Like |python-eval|, but returns special objects described in Like |python-eval|, but returns special objects described in
|python-bindeval-objects|. These python objects let you modify (|List| |python-bindeval-objects|. These python objects let you modify (|List|
@ -741,6 +745,10 @@ To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()|
functions to evaluate Python expressions and pass their values to Vim script. functions to evaluate Python expressions and pass their values to Vim script.
|pyxeval()| is also available. |pyxeval()| is also available.
You can inject local variables into the evaluation using the optional {locals}
dict. This can be particularly useful in vim9script where vim.eval
|python-eval| will not find locals in a def func.
The Python value "None" is converted to v:none. The Python value "None" is converted to v:none.
============================================================================== ==============================================================================

View File

@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2024 Nov 03 *version9.txt* For Vim version 9.1. Last change: 2024 Nov 06
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@ -41606,6 +41606,7 @@ Changed~
- an interactive tutor plugin has been included |vim-tutor-mode|, can be - an interactive tutor plugin has been included |vim-tutor-mode|, can be
started via |:Tutor| started via |:Tutor|
- improve the |vimtutor| and add a second chapter for more advanced tips - improve the |vimtutor| and add a second chapter for more advanced tips
- allow to pass local Vim script variables to python interpreter |py3eval()|
*added-9.2* *added-9.2*
Added ~ Added ~

View File

@ -2487,7 +2487,7 @@ static funcentry_T global_functions[] =
ret_dict_number, f_pum_getpos}, ret_dict_number, f_pum_getpos},
{"pumvisible", 0, 0, 0, NULL, {"pumvisible", 0, 0, 0, NULL,
ret_number_bool, f_pumvisible}, ret_number_bool, f_pumvisible},
{"py3eval", 1, 1, FEARG_1, arg1_string, {"py3eval", 1, 2, FEARG_1, arg2_string_dict,
ret_any, ret_any,
#ifdef FEAT_PYTHON3 #ifdef FEAT_PYTHON3
f_py3eval f_py3eval
@ -2495,7 +2495,7 @@ static funcentry_T global_functions[] =
NULL NULL
#endif #endif
}, },
{"pyeval", 1, 1, FEARG_1, arg1_string, {"pyeval", 1, 2, FEARG_1, arg2_string_dict,
ret_any, ret_any,
#ifdef FEAT_PYTHON #ifdef FEAT_PYTHON
f_pyeval f_pyeval
@ -2503,7 +2503,7 @@ static funcentry_T global_functions[] =
NULL NULL
#endif #endif
}, },
{"pyxeval", 1, 1, FEARG_1, arg1_string, {"pyxeval", 1, 2, FEARG_1, arg2_string_dict,
ret_any, ret_any,
#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
f_pyxeval f_pyxeval
@ -9291,18 +9291,35 @@ f_py3eval(typval_T *argvars, typval_T *rettv)
{ {
char_u *str; char_u *str;
char_u buf[NUMBUFLEN]; char_u buf[NUMBUFLEN];
dict_T *locals;
if (check_restricted() || check_secure()) if (check_restricted() || check_secure())
return; return;
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) if (in_vim9script()
&& (check_for_string_arg(argvars, 0) == FAIL
|| check_for_opt_dict_arg(argvars, 1) == FAIL))
return; return;
if (p_pyx == 0) if (p_pyx == 0)
p_pyx = 3; p_pyx = 3;
if (argvars[1].v_type == VAR_DICT)
{
locals = argvars[1].vval.v_dict;
}
else if (argvars[1].v_type != VAR_UNKNOWN)
{
emsg(_(e_dictionary_required));
return;
}
else
{
locals = NULL;
}
str = tv_get_string_buf(&argvars[0], buf); str = tv_get_string_buf(&argvars[0], buf);
do_py3eval(str, rettv); do_py3eval(str, locals, rettv);
} }
#endif #endif
@ -9315,18 +9332,35 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
{ {
char_u *str; char_u *str;
char_u buf[NUMBUFLEN]; char_u buf[NUMBUFLEN];
dict_T *locals;
if (check_restricted() || check_secure()) if (check_restricted() || check_secure())
return; return;
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) if (in_vim9script() && (
check_for_string_arg(argvars, 0) == FAIL ||
check_for_opt_dict_arg(argvars, 1) == FAIL ) )
return; return;
if (p_pyx == 0) if (p_pyx == 0)
p_pyx = 2; p_pyx = 2;
if (argvars[1].v_type == VAR_DICT)
{
locals = argvars[1].vval.v_dict;
}
else if (argvars[1].v_type != VAR_UNKNOWN)
{
emsg( "Invalid argument: must be dict" );
return;
}
else
{
locals = NULL;
}
str = tv_get_string_buf(&argvars[0], buf); str = tv_get_string_buf(&argvars[0], buf);
do_pyeval(str, rettv); do_pyeval(str, locals, rettv);
} }
#endif #endif
@ -9340,7 +9374,9 @@ f_pyxeval(typval_T *argvars, typval_T *rettv)
if (check_restricted() || check_secure()) if (check_restricted() || check_secure())
return; return;
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) if (in_vim9script()
&& (check_for_string_arg(argvars, 0) == FAIL
|| check_for_opt_dict_arg(argvars, 1) == FAIL))
return; return;
# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)

View File

@ -328,7 +328,7 @@ static int Vim_PyRun_SimpleString(const char *str)
#define INVALID_TABPAGE_VALUE ((tabpage_T *)(-1)) #define INVALID_TABPAGE_VALUE ((tabpage_T *)(-1))
typedef void (*rangeinitializer)(void *); typedef void (*rangeinitializer)(void *);
typedef void (*runner)(const char *, void * typedef void (*runner)(const char *, dict_T *, void *
#ifdef PY_CAN_RECURSE #ifdef PY_CAN_RECURSE
, PyGILState_STATE * , PyGILState_STATE *
#endif #endif
@ -6032,7 +6032,7 @@ init_range_eval(void *rettv UNUSED)
} }
static void static void
run_cmd(const char *cmd, void *arg UNUSED run_cmd(const char *cmd, dict_T* locals UNUSED, void *arg UNUSED
#ifdef PY_CAN_RECURSE #ifdef PY_CAN_RECURSE
, PyGILState_STATE *pygilstate UNUSED , PyGILState_STATE *pygilstate UNUSED
#endif #endif
@ -6057,7 +6057,7 @@ static const char *code_hdr = "def " DOPY_FUNC "(line, linenr):\n ";
static int code_hdr_len = 30; static int code_hdr_len = 30;
static void static void
run_do(const char *cmd, void *arg UNUSED run_do(const char *cmd, dict_T* locals UNUSED, void *arg UNUSED
#ifdef PY_CAN_RECURSE #ifdef PY_CAN_RECURSE
, PyGILState_STATE *pygilstate , PyGILState_STATE *pygilstate
#endif #endif
@ -6180,7 +6180,7 @@ out:
} }
static void static void
run_eval(const char *cmd, void *arg run_eval(const char *cmd, dict_T *locals, void *arg
#ifdef PY_CAN_RECURSE #ifdef PY_CAN_RECURSE
, PyGILState_STATE *pygilstate UNUSED , PyGILState_STATE *pygilstate UNUSED
#endif #endif
@ -6188,8 +6188,9 @@ run_eval(const char *cmd, void *arg
{ {
PyObject *run_ret; PyObject *run_ret;
typval_T *rettv = (typval_T*)arg; typval_T *rettv = (typval_T*)arg;
PyObject *pylocals = locals ? NEW_DICTIONARY(locals) : globals;
run_ret = PyRun_String((char *)cmd, Py_eval_input, globals, globals); run_ret = PyRun_String((char *)cmd, Py_eval_input, globals, pylocals);
if (run_ret == NULL) if (run_ret == NULL)
{ {
if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit))

View File

@ -1009,7 +1009,7 @@ fail:
* External interface * External interface
*/ */
static void static void
DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg) DoPyCommand(const char *cmd, dict_T* locals, rangeinitializer init_range, runner run, void *arg)
{ {
#ifndef PY_CAN_RECURSE #ifndef PY_CAN_RECURSE
static int recursive = 0; static int recursive = 0;
@ -1058,7 +1058,7 @@ DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg)
Python_RestoreThread(); // enter python Python_RestoreThread(); // enter python
#endif #endif
run((char *) cmd, arg run((char *) cmd, locals, arg
#ifdef PY_CAN_RECURSE #ifdef PY_CAN_RECURSE
, &pygilstate , &pygilstate
#endif #endif
@ -1103,6 +1103,7 @@ ex_python(exarg_T *eap)
p_pyx = 2; p_pyx = 2;
DoPyCommand(script == NULL ? (char *) eap->arg : (char *) script, DoPyCommand(script == NULL ? (char *) eap->arg : (char *) script,
NULL,
init_range_cmd, init_range_cmd,
(runner) run_cmd, (runner) run_cmd,
(void *) eap); (void *) eap);
@ -1154,6 +1155,7 @@ ex_pyfile(exarg_T *eap)
// Execute the file // Execute the file
DoPyCommand(buffer, DoPyCommand(buffer,
NULL,
init_range_cmd, init_range_cmd,
(runner) run_cmd, (runner) run_cmd,
(void *) eap); (void *) eap);
@ -1166,6 +1168,7 @@ ex_pydo(exarg_T *eap)
p_pyx = 2; p_pyx = 2;
DoPyCommand((char *)eap->arg, DoPyCommand((char *)eap->arg,
NULL,
init_range_cmd, init_range_cmd,
(runner)run_do, (runner)run_do,
(void *)eap); (void *)eap);
@ -1521,9 +1524,10 @@ FunctionGetattr(PyObject *self, char *name)
} }
void void
do_pyeval(char_u *str, typval_T *rettv) do_pyeval(char_u *str, dict_T *locals, typval_T *rettv)
{ {
DoPyCommand((char *) str, DoPyCommand((char *) str,
locals,
init_range_eval, init_range_eval,
(runner) run_eval, (runner) run_eval,
(void *) rettv); (void *) rettv);

View File

@ -1436,7 +1436,11 @@ fail:
* External interface * External interface
*/ */
static void static void
DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg) DoPyCommand(const char *cmd,
dict_T* locals,
rangeinitializer init_range,
runner run,
void *arg)
{ {
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
char *saved_locale; char *saved_locale;
@ -1477,7 +1481,7 @@ DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg)
cmdbytes = PyUnicode_AsEncodedString(cmdstr, "utf-8", ERRORS_ENCODE_ARG); cmdbytes = PyUnicode_AsEncodedString(cmdstr, "utf-8", ERRORS_ENCODE_ARG);
Py_XDECREF(cmdstr); Py_XDECREF(cmdstr);
run(PyBytes_AsString(cmdbytes), arg, &pygilstate); run(PyBytes_AsString(cmdbytes), locals, arg, &pygilstate);
Py_XDECREF(cmdbytes); Py_XDECREF(cmdbytes);
PyGILState_Release(pygilstate); PyGILState_Release(pygilstate);
@ -1512,6 +1516,7 @@ ex_py3(exarg_T *eap)
p_pyx = 3; p_pyx = 3;
DoPyCommand(script == NULL ? (char *) eap->arg : (char *) script, DoPyCommand(script == NULL ? (char *) eap->arg : (char *) script,
NULL,
init_range_cmd, init_range_cmd,
(runner) run_cmd, (runner) run_cmd,
(void *) eap); (void *) eap);
@ -1578,6 +1583,7 @@ ex_py3file(exarg_T *eap)
// Execute the file // Execute the file
DoPyCommand(buffer, DoPyCommand(buffer,
NULL,
init_range_cmd, init_range_cmd,
(runner) run_cmd, (runner) run_cmd,
(void *) eap); (void *) eap);
@ -1590,6 +1596,7 @@ ex_py3do(exarg_T *eap)
p_pyx = 3; p_pyx = 3;
DoPyCommand((char *)eap->arg, DoPyCommand((char *)eap->arg,
NULL,
init_range_cmd, init_range_cmd,
(runner)run_do, (runner)run_do,
(void *)eap); (void *)eap);
@ -2137,9 +2144,10 @@ LineToString(const char *str)
} }
void void
do_py3eval(char_u *str, typval_T *rettv) do_py3eval(char_u *str, dict_T *locals, typval_T *rettv)
{ {
DoPyCommand((char *) str, DoPyCommand((char *) str,
locals,
init_range_eval, init_range_eval,
(runner) run_eval, (runner) run_eval,
(void *) rettv); (void *) rettv);

View File

@ -8,6 +8,6 @@ void ex_pydo(exarg_T *eap);
void python_buffer_free(buf_T *buf); void python_buffer_free(buf_T *buf);
void python_window_free(win_T *win); void python_window_free(win_T *win);
void python_tabpage_free(tabpage_T *tab); void python_tabpage_free(tabpage_T *tab);
void do_pyeval(char_u *str, typval_T *rettv); void do_pyeval(char_u *str, dict_T* locals, typval_T *rettv);
int set_ref_in_python(int copyID); int set_ref_in_python(int copyID);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -8,7 +8,7 @@ void ex_py3do(exarg_T *eap);
void python3_buffer_free(buf_T *buf); void python3_buffer_free(buf_T *buf);
void python3_window_free(win_T *win); void python3_window_free(win_T *win);
void python3_tabpage_free(tabpage_T *tab); void python3_tabpage_free(tabpage_T *tab);
void do_py3eval(char_u *str, typval_T *rettv); void do_py3eval(char_u *str, dict_T* locals, typval_T *rettv);
int set_ref_in_python3(int copyID); int set_ref_in_python3(int copyID);
int python3_version(void); int python3_version(void);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -47,6 +47,7 @@ TEST_VIM9 = \
test_vim9_fails \ test_vim9_fails \
test_vim9_func \ test_vim9_func \
test_vim9_import \ test_vim9_import \
test_vim9_python3 \
test_vim9_script \ test_vim9_script \
test_vim9_typealias test_vim9_typealias
@ -61,6 +62,7 @@ TEST_VIM9_RES = \
test_vim9_fails.res \ test_vim9_fails.res \
test_vim9_func.res \ test_vim9_func.res \
test_vim9_import.res \ test_vim9_import.res \
test_vim9_python3.res \
test_vim9_script.res \ test_vim9_script.res \
test_vim9_typealias.res test_vim9_typealias.res

View File

@ -809,6 +809,49 @@ func Test_python_pyeval()
call AssertException(['let v = pyeval("vim")'], 'E859:') call AssertException(['let v = pyeval("vim")'], 'E859:')
endfunc endfunc
" Test for py3eval with locals
func Test_python_pyeval_locals()
let str = 'a string'
let num = 0xbadb33f
let d = {'a': 1, 'b': 2, 'c': str}
let l = [ str, num, d ]
let locals = #{
\ s: str,
\ n: num,
\ d: d,
\ l: l,
\ }
" check basics
call assert_equal('a string', pyeval('s', locals))
call assert_equal(0xbadb33f, pyeval('n', locals))
call assert_equal(d, pyeval('d', locals))
call assert_equal(l, pyeval('l', locals))
py << trim EOF
def __UpdateDict(d, upd):
d.update(upd)
return d
def __ExtendList(l, *args):
l.extend(*args)
return l
EOF
" check assign to dict member works like bindeval
call assert_equal(3, pyeval('__UpdateDict( d, {"c": 3} )["c"]', locals))
call assert_equal(3, d['c'])
" check append lo list
call assert_equal(4, pyeval('len(__ExtendList(l, ["new item"]))', locals))
call assert_equal("new item", l[-1])
" check calling a function
let StrLen = function('strlen')
call assert_equal(3, pyeval('f("abc")', {'f': StrLen}))
endfunc
" Test for vim.bindeval() " Test for vim.bindeval()
func Test_python_vim_bindeval() func Test_python_vim_bindeval()
" Float " Float

View File

@ -1027,6 +1027,52 @@ func Test_python3_pyeval()
call AssertException(['let v = py3eval("vim")'], 'E859:') call AssertException(['let v = py3eval("vim")'], 'E859:')
endfunc endfunc
" Test for py3eval with locals
func Test_python3_pyeval_locals()
let str = 'a string'
let num = 0xbadb33f
let d = {'a': 1, 'b': 2, 'c': str}
let l = [ str, num, d ]
let locals = #{
\ s: str,
\ n: num,
\ d: d,
\ l: l,
\ }
" check basics
call assert_equal('a string', py3eval('s', locals))
call assert_equal(0xbadb33f, py3eval('n', locals))
call assert_equal(d, py3eval('d', locals))
call assert_equal(l, py3eval('l', locals))
call assert_equal('a,b,c', py3eval('b",".join(l)', {'l': ['a', 'b', 'c']}))
call assert_equal('hello', 's'->py3eval({'s': 'hello'}))
call assert_equal('a,b,c', 'b",".join(l)'->py3eval({'l': ['a', 'b', 'c']}))
py3 << trim EOF
def __UpdateDict(d, upd):
d.update(upd)
return d
def __ExtendList(l, *args):
l.extend(*args)
return l
EOF
" check assign to dict member works like bindeval
call assert_equal(3, py3eval('__UpdateDict( d, {"c": 3} )["c"]', locals))
call assert_equal(3, d['c'])
" check append lo list
call assert_equal(4, py3eval('len(__ExtendList(l, ["new item"]))', locals))
call assert_equal("new item", l[-1])
" check calling a function
let StrLen = function('strlen')
call assert_equal(3, py3eval('f("abc")', {'f': StrLen}))
endfunc
" Test for vim.bindeval() " Test for vim.bindeval()
func Test_python3_vim_bindeval() func Test_python3_vim_bindeval()
" Float " Float

View File

@ -38,6 +38,49 @@ func Test_pyxeval()
endfunc endfunc
" Test for pyxeval with locals
func Test_python_pyeval_locals()
let str = 'a string'
let num = 0xbadb33f
let d = {'a': 1, 'b': 2, 'c': str}
let l = [ str, num, d ]
let locals = #{
\ s: str,
\ n: num,
\ d: d,
\ l: l,
\ }
" check basics
call assert_equal('a string', pyxeval('s', locals))
call assert_equal(0xbadb33f, pyxeval('n', locals))
call assert_equal(d, pyxeval('d', locals))
call assert_equal(l, pyxeval('l', locals))
py << trim EOF
def __UpdateDict(d, upd):
d.update(upd)
return d
def __ExtendList(l, *args):
l.extend(*args)
return l
EOF
" check assign to dict member works like bindeval
call assert_equal(3, pyxeval('__UpdateDict( d, {"c": 3} )["c"]', locals))
call assert_equal(3, d['c'])
" check append lo list
call assert_equal(4, pyxeval('len(__ExtendList(l, ["new item"]))', locals))
call assert_equal("new item", l[-1])
" check calling a function
let StrLen = function('strlen')
call assert_equal(3, pyxeval('f("abc")', {'f': StrLen}))
endfunc
func Test_pyxfile() func Test_pyxfile()
" No special comments nor shebangs " No special comments nor shebangs
redir => var redir => var

View File

@ -37,6 +37,48 @@ func Test_pyxeval()
call assert_match(s:py3pattern, split(pyxeval('sys.version'))[0]) call assert_match(s:py3pattern, split(pyxeval('sys.version'))[0])
endfunc endfunc
" Test for pyxeval with locals
func Test_python_pyeval_locals()
let str = 'a string'
let num = 0xbadb33f
let d = {'a': 1, 'b': 2, 'c': str}
let l = [ str, num, d ]
let locals = #{
\ s: str,
\ n: num,
\ d: d,
\ l: l,
\ }
" check basics
call assert_equal('a string', pyxeval('s', locals))
call assert_equal(0xbadb33f, pyxeval('n', locals))
call assert_equal(d, pyxeval('d', locals))
call assert_equal(l, pyxeval('l', locals))
py3 << trim EOF
def __UpdateDict(d, upd):
d.update(upd)
return d
def __ExtendList(l, *args):
l.extend(*args)
return l
EOF
" check assign to dict member works like bindeval
call assert_equal(3, pyxeval('__UpdateDict( d, {"c": 3} )["c"]', locals))
call assert_equal(3, d['c'])
" check append lo list
call assert_equal(4, pyxeval('len(__ExtendList(l, ["new item"]))', locals))
call assert_equal("new item", l[-1])
" check calling a function
let StrLen = function('strlen')
call assert_equal(3, pyxeval('f("abc")', {'f': StrLen}))
endfunc
func Test_pyxfile() func Test_pyxfile()
" No special comments nor shebangs " No special comments nor shebangs

View File

@ -0,0 +1,17 @@
source check.vim
import './vim9.vim' as v9
CheckFeature python3
def Test_python3_py3eval_locals()
var lines =<< trim EOF
var s = 'string'
var d = {'s': s}
assert_equal('string', py3eval('s', {'s': s}))
py3eval('d.update({"s": "new"})', {'d': d})
assert_equal('new', d['s'])
EOF
v9.CheckDefAndScriptSuccess(lines)
enddef
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
844,
/**/ /**/
843, 843,
/**/ /**/