diff -r e5f78085499e Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py Mon Aug 18 17:48:15 2014 +0300 +++ b/Lib/test/test_tcl.py Mon Aug 18 17:51:59 2014 +0300 @@ -427,22 +427,29 @@ return arg self.interp.createcommand('testfunc', testfunc) self.addCleanup(self.interp.tk.deletecommand, 'testfunc') - def check(value, expected=None, *, eq=self.assertEqual): - if expected is None: - expected = value + def check(value, arg1=None, arg2=None, *, eq=self.assertEqual): + expected = value + if self.wantobjects >= 2: + if arg2 is not None: + expected = arg2 + expected_type = type(expected) + else: + if arg1 is not None: + expected = arg1 + expected_type = str nonlocal result result = None r = self.interp.call('testfunc', value) - self.assertIsInstance(result, str) + self.assertIsInstance(result, expected_type) eq(result, expected) - self.assertIsInstance(r, str) + self.assertIsInstance(r, expected_type) eq(r, expected) def float_eq(actual, expected): self.assertAlmostEqual(float(actual), expected, delta=abs(expected) * 1e-10) - check(True, '1') - check(False, '0') + check(True, '1', 1) + check(False, '0', 0) check('string') check('string\xbd') check('string\u20ac') @@ -465,9 +472,13 @@ check(float('inf'), eq=float_eq) check(-float('inf'), eq=float_eq) # XXX NaN representation can be not parsable by float() - check((), '') - check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') - check([1, [2,], [3, 4], '5 6', []], '1 2 {3 4} {5 6} {}') + check((), '', '') + check((1, (2,), (3, 4), '5 6', ()), + '1 2 {3 4} {5 6} {}', + (1, (2,), (3, 4), '5 6', '')) + check([1, [2,], [3, 4], '5 6', []], + '1 2 {3 4} {5 6} {}', + (1, (2,), (3, 4), '5 6', '')) def test_splitlist(self): splitlist = self.interp.tk.splitlist diff -r e5f78085499e Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py Mon Aug 18 17:48:15 2014 +0300 +++ b/Lib/tkinter/__init__.py Mon Aug 18 17:51:59 2014 +0300 @@ -41,7 +41,7 @@ import re -wantobjects = 1 +wantobjects = 2 TkVersion = float(_tkinter.TK_VERSION) TclVersion = float(_tkinter.TCL_VERSION) diff -r e5f78085499e Modules/_tkinter.c --- a/Modules/_tkinter.c Mon Aug 18 17:48:15 2014 +0300 +++ b/Modules/_tkinter.c Mon Aug 18 17:51:59 2014 +0300 @@ -1967,6 +1967,32 @@ return TCL_ERROR; } +static int +PythonCmd_Call(Tcl_Interp *interp, PyObject *func, PyObject *args) +{ + Tcl_Obj *obj_res; + PyObject *res = PyEval_CallObject(func, args); + Py_DECREF(args); + + if (res == NULL) + return PythonCmd_Error(interp); + + obj_res = AsObj(res); + if (obj_res == NULL) { + Py_DECREF(res); + return PythonCmd_Error(interp); + } + else { + Tcl_SetObjResult(interp, obj_res); + } + + Py_DECREF(res); + + LEAVE_PYTHON + + return TCL_OK; +} + /* This is the Tcl command that acts as a wrapper for Python * function or method. */ @@ -1974,49 +2000,52 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) { PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; - PyObject *func, *arg, *res; - int i, rv; - Tcl_Obj *obj_res; + PyObject *args; + int i; ENTER_PYTHON - /* TBD: no error checking here since we know, via the - * Tkapp_CreateCommand() that the client data is a two-tuple - */ - func = data->func; - - /* Create argument list (argv1, ..., argvN) */ - if (!(arg = PyTuple_New(argc - 1))) + /* Create argument tuple (argv1, ..., argvN) */ + if (!(args = PyTuple_New(argc - 1))) return PythonCmd_Error(interp); for (i = 0; i < (argc - 1); i++) { PyObject *s = unicodeFromTclString(argv[i + 1]); - if (!s || PyTuple_SetItem(arg, i, s)) { - Py_DECREF(arg); + if (!s || PyTuple_SetItem(args, i, s)) { + Py_DECREF(args); return PythonCmd_Error(interp); } } - res = PyEval_CallObject(func, arg); - Py_DECREF(arg); - - if (res == NULL) + + return PythonCmd_Call(interp, data->func, args); +} + +/* This is the Tcl command that acts as a wrapper for Python + * function or method. + */ +static int +PythonObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; + PyObject *args; + int i; + + ENTER_PYTHON + + /* Create argument tuple (objv1, ..., objvN) */ + if (!(args = PyTuple_New(objc - 1))) return PythonCmd_Error(interp); - obj_res = AsObj(res); - if (obj_res == NULL) { - Py_DECREF(res); - return PythonCmd_Error(interp); + for (i = 0; i < (objc - 1); i++) { + PyObject *s = FromObj(data->self, objv[i + 1]); + if (!s || PyTuple_SetItem(args, i, s)) { + Py_DECREF(args); + return PythonCmd_Error(interp); + } } - else { - Tcl_SetObjResult(interp, obj_res); - rv = TCL_OK; - } - - Py_DECREF(res); - - LEAVE_PYTHON - - return rv; + + return PythonCmd_Call(interp, data->func, args); } static void @@ -2050,7 +2079,11 @@ static int Tkapp_CommandProc(CommandEvent *ev, int flags) { - if (ev->create) + if (ev->create == 2) + *ev->status = Tcl_CreateObjCommand( + ev->interp, ev->name, PythonObjCmd, + ev->data, PythonCmdDelete) == NULL; + else if (ev->create) *ev->status = Tcl_CreateCommand( ev->interp, ev->name, PythonCmd, ev->data, PythonCmdDelete) == NULL; @@ -2099,7 +2132,7 @@ CommandEvent *ev = (CommandEvent*)ckalloc(sizeof(CommandEvent)); ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc; ev->interp = self->interp; - ev->create = 1; + ev->create = ((TkappObject*)self)->wantobjects >= 2 ? 2 : 1; ev->name = cmdName; ev->data = (ClientData)data; ev->status = &err; @@ -2111,9 +2144,16 @@ #endif { ENTER_TCL - err = Tcl_CreateCommand( - Tkapp_Interp(self), cmdName, PythonCmd, - (ClientData)data, PythonCmdDelete) == NULL; + if (((TkappObject*)self)->wantobjects >= 2) { + err = Tcl_CreateObjCommand( + Tkapp_Interp(self), cmdName, PythonObjCmd, + (ClientData)data, PythonCmdDelete) == NULL; + } + else { + err = Tcl_CreateCommand( + Tkapp_Interp(self), cmdName, PythonCmd, + (ClientData)data, PythonCmdDelete) == NULL; + } LEAVE_TCL } if (err) { @@ -2604,7 +2644,7 @@ if (!PyArg_ParseTuple(args, "|i:wantobjects", &wantobjects)) return NULL; if (wantobjects == -1) - return PyBool_FromLong(((TkappObject*)self)->wantobjects); + return PyLong_FromLong(((TkappObject*)self)->wantobjects); ((TkappObject*)self)->wantobjects = wantobjects; Py_RETURN_NONE;