to :c:func:`PyUnstable_Code_GetFirstFree`.
(Contributed by Bogdan Romanyuk in :gh:`115781`.)
+* Callbacks registered in the :mod:`tkinter` module now take arguments as
+ various Python objects (``int``, ``float``, ``bytes``, ``tuple``),
+ not just ``str``.
+ To restore the previous behavior set :mod:`!tkinter` module global
+ :data:`!wantobject` to ``1`` before creating the
+ :class:`!Tk` object or call the :meth:`!wantobject`
+ method of the :class:`!Tk` object with argument ``1``.
+ Calling it with argument ``2`` restores the current default behavior.
+ (Contributed by Serhiy Storchaka in :gh:`66410`.)
+
Build Changes
=============
to *args to accomplish that. For an example, see colorizer.py.
'''
+ operation = str(operation) # can be a Tcl_Obj
m = self._operations.get(operation)
try:
if m:
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, expected1=None, expected2=None, *, eq=self.assertEqual):
+ expected = value
+ if self.wantobjects >= 2:
+ if expected2 is not None:
+ expected = expected2
+ expected_type = type(expected)
+ else:
+ if expected1 is not None:
+ expected = expected1
+ 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')
check('string\U0001f4bb')
if sys.platform != 'win32':
- check('<\udce2\udc82\udcac>', '<\u20ac>')
- check('<\udced\udca0\udcbd\udced\udcb2\udcbb>', '<\U0001f4bb>')
+ check('<\udce2\udc82\udcac>', '<\u20ac>', '<\u20ac>')
+ check('<\udced\udca0\udcbd\udced\udcb2\udcbb>', '<\U0001f4bb>', '<\U0001f4bb>')
check('')
check(b'string', 'string')
check(b'string\xe2\x82\xac', 'string\xe2\x82\xac')
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
from tkinter.constants import *
import re
-wantobjects = 1
+wantobjects = 2
_debug = False # set to True to print executed Tcl/Tk commands
TkVersion = float(_tkinter.TK_VERSION)
try:
e.type = EventType(T)
except ValueError:
- e.type = T
+ try:
+ e.type = EventType(str(T)) # can be int
+ except ValueError:
+ e.type = T
try:
e.widget = self._nametowidget(W)
except KeyError:
--- /dev/null
+Callbacks registered in the :mod:`tkinter` module now take arguments as
+various Python objects (``int``, ``float``, ``bytes``, ``tuple``), not just
+``str``. To restore the previous behavior set :mod:`!tkinter` module global
+:data:`~tkinter.wantobject` to ``1`` before creating the
+:class:`~tkinter.Tk` object or call the :meth:`~tkinter.Tk.wantobject`
+method of the :class:`!Tk` object with argument ``1``. Calling it with
+argument ``2`` restores the current default behavior.
/* Client data struct */
typedef struct {
- PyObject *self;
+ TkappObject *self;
PyObject *func;
} PythonCmd_ClientData;
PyObject *args, *res;
int i;
Tcl_Obj *obj_res;
+ int objargs = data->self->wantobjects >= 2;
ENTER_PYTHON
return PythonCmd_Error(interp);
for (i = 0; i < (objc - 1); i++) {
- PyObject *s = unicodeFromTclObj(objv[i + 1]);
+ PyObject *s = objargs ? FromObj(data->self, objv[i + 1])
+ : unicodeFromTclObj(objv[i + 1]);
if (!s) {
Py_DECREF(args);
return PythonCmd_Error(interp);
data = PyMem_NEW(PythonCmd_ClientData, 1);
if (!data)
return PyErr_NoMemory();
- data->self = Py_NewRef(self);
+ Py_INCREF(self);
+ data->self = self;
data->func = Py_NewRef(func);
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
Tcl_Condition cond = NULL;
{
int wantobjects = -1;
- if (!PyArg_ParseTuple(args, "|p:wantobjects", &wantobjects))
+ 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;
baseName: str = ""
className: str = "Tk"
interactive: bool = False
- wantobjects: bool = False
+ wantobjects: int = 0
wantTk: bool = True
if false, then Tk_Init() doesn't get called
sync: bool = False
const char *baseName, const char *className,
int interactive, int wantobjects, int wantTk, int sync,
const char *use)
-/*[clinic end generated code: output=e3315607648e6bb4 input=09afef9adea70a19]*/
+/*[clinic end generated code: output=e3315607648e6bb4 input=7e382ba431bed537]*/
{
/* XXX baseName is not used anymore;
* try getting rid of it. */
PyDoc_STRVAR(_tkinter_create__doc__,
"create($module, screenName=None, baseName=\'\', className=\'Tk\',\n"
-" interactive=False, wantobjects=False, wantTk=True, sync=False,\n"
+" interactive=False, wantobjects=0, wantTk=True, sync=False,\n"
" use=None, /)\n"
"--\n"
"\n"
if (nargs < 5) {
goto skip_optional;
}
- wantobjects = PyObject_IsTrue(args[4]);
- if (wantobjects < 0) {
+ wantobjects = PyLong_AsInt(args[4]);
+ if (wantobjects == -1 && PyErr_Occurred()) {
goto exit;
}
if (nargs < 6) {
#ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF
#define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF
#endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */
-/*[clinic end generated code: output=86a515890d48a2ce input=a9049054013a1b77]*/
+/*[clinic end generated code: output=d90c1a9850c63249 input=a9049054013a1b77]*/