Serhiy Storchaka added the comment:

> The patch appears to change it to 2 in tkinter/__init__.py.

This is for development only. You can apply the patch and test how new mode 
affects IDLE or other applications.

> One thing slightly puzzles me: the current PythonCmd is used in a call to
> Tcl_CreateCommand.  (Since the latter is not in _tkinter, I presume it is
> 'imported' in one of the includes.)  The new PythonObjCmd is passed to
> Tcl_CreateObjCommand. Does that already exist, just waiting for us to add
> PythonObjCmd?

All Tcl_* functions are Tcl C API functions. Old functions work with strings 
(char *). Modern functions (have "Obj" in a name) work with specialized Tcl 
objects (Tcl_Obj *).

> I near as I can tell, the only differences between PythonCmd and
> PythonOjbCmd are /argv/objv/ and the following.
> 
>       PyObject *s = unicodeFromTclString(argv[i + 1]);
>       PyObject *s = FromObj(data->self, objv[i + 1]);
> 
> I think I would make the name substitution either in both or neither.  It
> would be nice to reuse the rest of the code.

I'm not sure that I understand all you mean, but in updated patch the common 
code are extracted to separate function.

----------
Added file: http://bugs.python.org/file36406/tkinter_obj_cmd_2.patch

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue22214>
_______________________________________
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;
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to