diff -r f2d1dba10a0e Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py Thu Jun 30 14:03:21 2016 +0300 +++ b/Lib/tkinter/__init__.py Fri Jul 01 00:49:10 2016 +0300 @@ -40,6 +40,7 @@ import re wantobjects = 1 +debug = False+1 TkVersion = float(_tkinter.TK_VERSION) TclVersion = float(_tkinter.TCL_VERSION) @@ -66,7 +67,10 @@ def _stringify(value): else: value = '{%s}' % _join(value) else: - value = str(value) + if isinstance(value, bytes): + value = str(value, 'latin1') + else: + value = str(value) if not value: value = '{}' elif _magic_re.search(value): @@ -2011,6 +2015,7 @@ class Tk(Misc, Wm): baseName = baseName + ext interactive = 0 self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use) + self.debug = debug if useTk: self._loadtk() if not sys.flags.ignore_environment: @@ -2090,6 +2095,22 @@ class Tk(Misc, Wm): "Delegate attribute access to the interpreter object" return getattr(self.tk, attr) + @property + def debug(self): + return self.tk.gettrace() is not None + + @debug.setter + def debug(self, value): + #self.tk.debug(value) + if value: + def trace(cmd): + if isinstance(cmd, tuple): + cmd = _join(cmd) + print(cmd) + self.tk.settrace(trace) + else: + self.tk.settrace(None) + # Ideally, the classes Pack, Place and Grid disappear, the # pack/place/grid methods are defined on the Widget class, and # everybody uses w.pack_whatever(...) instead of Pack.whatever(w, @@ -2261,9 +2282,9 @@ class BaseWidget(Misc): count = master._last_child_ids.get(name, 0) + 1 master._last_child_ids[name] = count if count == 1: - name = '`%s' % (name,) + name = '?%s' % (name,) else: - name = '`%s%d' % (name, count) + name = '?%s%d' % (name, count) self._name = name if master._w=='.': self._w = '.' + name diff -r f2d1dba10a0e Modules/_tkinter.c --- a/Modules/_tkinter.c Thu Jun 30 14:03:21 2016 +0300 +++ b/Modules/_tkinter.c Fri Jul 01 00:49:10 2016 +0300 @@ -291,6 +291,7 @@ typedef struct { int threaded; /* True if tcl_platform[threaded] */ Tcl_ThreadId thread_id; int dispatching; + PyObject *trace; /* We cannot include tclInt.h, as this is internal. So we cache interesting types here. */ const Tcl_ObjType *OldBooleanType; @@ -643,6 +644,7 @@ Tkapp_New(const char *screenName, const TCL_GLOBAL_ONLY) != NULL; v->thread_id = Tcl_GetCurrentThread(); v->dispatching = 0; + v->trace = NULL; #ifndef TCL_THREADS if (v->threaded) { @@ -1563,6 +1574,15 @@ Tkapp_Call(PyObject *selfptr, PyObject * if (!objv) return NULL; + if (self->trace) { + res = PyObject_CallFunction(self->trace, "(O)", args); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL i = Tcl_EvalObjv(self->interp, objc, objv, flags); @@ -1600,6 +1620,15 @@ static PyObject * CHECK_STRING_LENGTH(script); CHECK_TCL_APPARTMENT; + if (self->trace) { + res = PyObject_CallFunction(self->trace, "s", script); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL err = Tcl_Eval(Tkapp_Interp(self), script); ENTER_OVERLAP @@ -1629,6 +1658,15 @@ static PyObject * CHECK_STRING_LENGTH(fileName); CHECK_TCL_APPARTMENT; + if (self->trace) { + res = PyObject_CallFunction(self->trace, "((ss))", "source", fileName); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL err = Tcl_EvalFile(Tkapp_Interp(self), fileName); ENTER_OVERLAP @@ -1658,6 +1696,15 @@ static PyObject * CHECK_STRING_LENGTH(script); CHECK_TCL_APPARTMENT; + if (self->trace) { + res = PyObject_CallFunction(self->trace, "((ssss))", "history", "add", script, "exec"); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL); ENTER_OVERLAP @@ -1860,6 +1907,16 @@ SetVar(PyObject *self, PyObject *args, i newval = AsObj(newValue); if (newval == NULL) return NULL; + + if (((TkappObject *)self)->trace) { + res = PyObject_CallFunction(((TkappObject *)self)->trace, "((ssO))", "set", name1, newValue); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, NULL, newval, flags); @@ -1878,8 +1935,18 @@ SetVar(PyObject *self, PyObject *args, i return NULL; CHECK_STRING_LENGTH(name1); CHECK_STRING_LENGTH(name2); + /* XXX must hold tcl lock already??? */ newval = AsObj(newValue); + if (((TkappObject *)self)->trace) { + res = PyObject_CallFunction(((TkappObject *)self)->trace, "((sssO))", "setarr", name1, name2, newValue); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags); ENTER_OVERLAP @@ -1968,6 +2035,21 @@ UnsetVar(PyObject *self, PyObject *args, CHECK_STRING_LENGTH(name1); CHECK_STRING_LENGTH(name2); + + if (((TkappObject *)self)->trace) { + if (name2) { + res = PyObject_CallFunction(((TkappObject *)self)->trace, "((sss))", "unsetarr", name1, name2); + } + else { + res = PyObject_CallFunction(((TkappObject *)self)->trace, "((ss))", "unset", name1); + } + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags); ENTER_OVERLAP @@ -2141,6 +2223,15 @@ static PyObject * CHECK_STRING_LENGTH(s); CHECK_TCL_APPARTMENT; + if (self->trace) { + res = PyObject_CallFunction(self->trace, "((ss))", "expr", s); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL retval = Tcl_ExprString(Tkapp_Interp(self), s); ENTER_OVERLAP @@ -2171,6 +2262,15 @@ static PyObject * CHECK_STRING_LENGTH(s); CHECK_TCL_APPARTMENT; + if (self->trace) { + res = PyObject_CallFunction(self->trace, "((ss))", "expr", s); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v); ENTER_OVERLAP @@ -2200,6 +2300,16 @@ static PyObject * CHECK_STRING_LENGTH(s); CHECK_TCL_APPARTMENT; + + if (self->trace) { + res = PyObject_CallFunction(self->trace, "((ss))", "expr", s); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0) ENTER_TCL retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v); @@ -2231,6 +2341,16 @@ static PyObject * CHECK_STRING_LENGTH(s); CHECK_TCL_APPARTMENT; + + if (self->trace) { + res = PyObject_CallFunction(self->trace, "((ss))", "expr", s); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + res = NULL; + } + ENTER_TCL retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v); ENTER_OVERLAP @@ -2515,6 +2635,14 @@ static PyObject * return NULL; #endif + if (self->trace) { + PyObject *res = PyObject_CallFunction(self->trace, "((ss()O))", "proc", name, func); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + } + data = PyMem_NEW(PythonCmd_ClientData, 1); if (!data) return PyErr_NoMemory(); @@ -2577,6 +2705,14 @@ static PyObject * CHECK_STRING_LENGTH(name); + if (self->trace) { + PyObject *res = PyObject_CallFunction(self->trace, "((sss))", "rename", name, ""); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + } + #ifdef WITH_THREAD if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { Tcl_Condition cond = NULL; @@ -2709,6 +2845,9 @@ static PyObject * return NULL; } + if (self->trace) { + } + data = NewFHCD(func, file, tfile); if (data == NULL) return NULL; @@ -2740,6 +2879,9 @@ static PyObject * if (tfile < 0) return NULL; + if (self->trace) { + } + DeleteFHCD(tfile); /* Ought to check for null Tcl_File object... */ @@ -2879,6 +3021,9 @@ static PyObject * CHECK_TCL_APPARTMENT; + if (self->trace) { + } + v = Tktt_New(func); if (v) { v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler, @@ -3069,6 +3214,47 @@ Tkapp_WantObjects(PyObject *self, PyObje } /*[clinic input] +_tkinter.tkapp.settrace + + func: object + / + +Set the debug tracing function. +[clinic start generated code]*/ + +static PyObject * +_tkinter_tkapp_settrace(TkappObject *self, PyObject *func) +/*[clinic end generated code: output=847f6ebdf46e84fa input=e4baccb61b74c660]*/ +{ + if (func == Py_None) { + func = NULL; + } + else { + Py_INCREF(func); + } + Py_XSETREF(self->trace, func); + Py_RETURN_NONE; +} + +/*[clinic input] +_tkinter.tkapp.gettrace + +Get the debug tracing function. +[clinic start generated code]*/ + +static PyObject * +_tkinter_tkapp_gettrace_impl(TkappObject *self) +/*[clinic end generated code: output=d4e2ba7d63e77bb5 input=a0cdc58ae62de19b]*/ +{ + PyObject *func = self->trace; + if (!func) { + func = Py_None; + } + Py_INCREF(func); + return func; +} + +/*[clinic input] _tkinter.tkapp.willdispatch [clinic start generated code]*/ @@ -3302,6 +3488,8 @@ static PyMethodDef Tkapp_methods[] = { _TKINTER_TKAPP_WILLDISPATCH_METHODDEF {"wantobjects", Tkapp_WantObjects, METH_VARARGS}, + _TKINTER_TKAPP_SETTRACE_METHODDEF + _TKINTER_TKAPP_GETTRACE_METHODDEF {"call", Tkapp_Call, METH_VARARGS}, _TKINTER_TKAPP_EVAL_METHODDEF _TKINTER_TKAPP_EVALFILE_METHODDEF diff -r f2d1dba10a0e Modules/clinic/_tkinter.c.h --- a/Modules/clinic/_tkinter.c.h Thu Jun 30 14:03:21 2016 +0300 +++ b/Modules/clinic/_tkinter.c.h Fri Jul 01 00:49:10 2016 +0300 @@ -502,6 +502,33 @@ static PyObject * return _tkinter_tkapp_loadtk_impl(self); } +PyDoc_STRVAR(_tkinter_tkapp_settrace__doc__, +"settrace($self, func, /)\n" +"--\n" +"\n" +"Set the debug tracing function."); + +#define _TKINTER_TKAPP_SETTRACE_METHODDEF \ + {"settrace", (PyCFunction)_tkinter_tkapp_settrace, METH_O, _tkinter_tkapp_settrace__doc__}, + +PyDoc_STRVAR(_tkinter_tkapp_gettrace__doc__, +"gettrace($self, /)\n" +"--\n" +"\n" +"Get the debug tracing function."); + +#define _TKINTER_TKAPP_GETTRACE_METHODDEF \ + {"gettrace", (PyCFunction)_tkinter_tkapp_gettrace, METH_NOARGS, _tkinter_tkapp_gettrace__doc__}, + +static PyObject * +_tkinter_tkapp_gettrace_impl(TkappObject *self); + +static PyObject * +_tkinter_tkapp_gettrace(TkappObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _tkinter_tkapp_gettrace_impl(self); +} + PyDoc_STRVAR(_tkinter_tkapp_willdispatch__doc__, "willdispatch($self, /)\n" "--\n" @@ -638,4 +665,4 @@ exit: #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ -/*[clinic end generated code: output=13be3f8313bba3c7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5222d923774dcced input=a9049054013a1b77]*/