diff -r bdf04552f4df Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py Mon Jul 14 12:20:49 2014 +0300 +++ b/Lib/test/test_tcl.py Mon Jul 14 14:13:17 2014 +0300 @@ -422,19 +422,22 @@ return arg self.interp.createcommand('testfunc', testfunc) self.addCleanup(self.interp.tk.deletecommand, 'testfunc') - def check(value, expected, eq=self.assertEqual): + def check(value, expected, expected2=None, *, eq=self.assertEqual): + if self.wantobjects >= 2 or expected2 is None: + expected2 = expected + nonlocal result + result = None r = self.interp.call('testfunc', value) - self.assertIsInstance(result, str) - eq(result, expected) - self.assertIsInstance(r, str) - eq(r, expected) + self.assertIsInstance(result, type(expected) if self.wantobjects >= 2 else str) + eq(result, expected if self.wantobjects >= 2 else expected2) + self.assertIsInstance(r, type(expected2) if self.wantobjects >= 2 else str) + eq(r, expected2) def float_eq(actual, expected): - expected = float(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', 'string') check('string\xbd', 'string\xbd') check('string\u20ac', 'string\u20ac') @@ -446,18 +449,22 @@ check(b'str\xc0\x80ing', 'str\x00ing') check(b'str\xc0\x80ing\xe2\x82\xac', 'str\x00ing\u20ac') for i in (0, 1, -1, 2**31-1, -2**31): - check(i, str(i)) + check(i, i, repr(i)) for f in (0.0, 1.0, -1.0): - check(f, repr(f)) + check(f, f, repr(f)) for f in (1/3.0, sys.float_info.min, sys.float_info.max, -sys.float_info.min, -sys.float_info.max): check(f, f, eq=float_eq) - check(float('inf'), 'Inf', eq=float_eq) - check(-float('inf'), '-Inf', eq=float_eq) + check(float('inf'), float('inf'), eq=float_eq) + check(-float('inf'), 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((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 bdf04552f4df Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py Mon Jul 14 12:20:49 2014 +0300 +++ b/Lib/tkinter/__init__.py Mon Jul 14 14:13:17 2014 +0300 @@ -41,7 +41,7 @@ import re -wantobjects = 1 +wantobjects = 2 TkVersion = float(_tkinter.TK_VERSION) TclVersion = float(_tkinter.TCL_VERSION) diff -r bdf04552f4df Modules/_tkinter.c --- a/Modules/_tkinter.c Mon Jul 14 12:20:49 2014 +0300 +++ b/Modules/_tkinter.c Mon Jul 14 14:13:17 2014 +0300 @@ -1987,7 +1987,7 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; - PyObject *func, *arg, *res; + PyObject *func, *args, *res; int i, rv; Tcl_Obj *obj_res; @@ -1999,18 +1999,18 @@ func = data->func; /* Create argument list (argv1, ..., argvN) */ - if (!(arg = PyTuple_New(argc - 1))) + 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); + res = PyEval_CallObject(func, args); + Py_DECREF(args); if (res == NULL) return PythonCmd_Error(interp); @@ -2032,6 +2032,59 @@ return rv; } +/* 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 *func, *args, *res; + int i, rv; + Tcl_Obj *obj_res; + + 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 (objv1, ..., objvN) */ + if (!(args = PyTuple_New(objc - 1))) + 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); + } + } + 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); + rv = TCL_OK; + } + + Py_DECREF(res); + + LEAVE_PYTHON + + return rv; +} + static void PythonCmdDelete(ClientData clientData) { @@ -2063,7 +2116,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; @@ -2112,7 +2169,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; @@ -2124,9 +2181,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) { @@ -2617,7 +2681,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;