Skip to content

Commit 9a6e201

Browse files
Issue python#15133: _tkinter.tkapp.getboolean() now supports Tcl_Obj and always
returns bool. tkinter.BooleanVar now validates input values (accepted bool, int, str, and Tcl_Obj). tkinter.BooleanVar.get() now always returns bool.
1 parent c9ba38c commit 9a6e201

6 files changed

Lines changed: 58 additions & 17 deletions

File tree

Lib/test/test_tcl.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ def test_getboolean(self):
181181
tcl = self.interp.tk
182182
self.assertIs(tcl.getboolean('on'), True)
183183
self.assertIs(tcl.getboolean('1'), True)
184-
self.assertEqual(tcl.getboolean(42), 42)
184+
self.assertIs(tcl.getboolean(42), True)
185+
self.assertIs(tcl.getboolean(0), False)
185186
self.assertRaises(TypeError, tcl.getboolean)
186187
self.assertRaises(TypeError, tcl.getboolean, 'on', '1')
187188
self.assertRaises(TypeError, tcl.getboolean, b'on')

Lib/tkinter/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,11 @@ def __init__(self, master=None, value=None, name=None):
391391
"""
392392
Variable.__init__(self, master, value, name)
393393

394+
def set(self, value):
395+
"""Set the variable to VALUE."""
396+
return self._tk.globalsetvar(self._name, self._tk.getboolean(value))
397+
initialize = set
398+
394399
def get(self):
395400
"""Return the value of the variable as a bool."""
396401
try:

Lib/tkinter/test/test_tkinter/test_variables.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22

3-
from tkinter import Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl
3+
from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
4+
TclError)
45

56

67
class Var(Variable):
@@ -159,16 +160,41 @@ class TestBooleanVar(TestBase):
159160

160161
def test_default(self):
161162
v = BooleanVar(self.root)
162-
self.assertEqual(False, v.get())
163+
self.assertIs(v.get(), False)
163164

164165
def test_get(self):
165166
v = BooleanVar(self.root, True, "name")
166-
self.assertAlmostEqual(True, v.get())
167+
self.assertIs(v.get(), True)
167168
self.root.globalsetvar("name", "0")
168-
self.assertAlmostEqual(False, v.get())
169+
self.assertIs(v.get(), False)
170+
self.root.globalsetvar("name", 42 if self.root.wantobjects() else 1)
171+
self.assertIs(v.get(), True)
172+
self.root.globalsetvar("name", 0)
173+
self.assertIs(v.get(), False)
174+
self.root.globalsetvar("name", "on")
175+
self.assertIs(v.get(), True)
176+
177+
def test_set(self):
178+
true = 1 if self.root.wantobjects() else "1"
179+
false = 0 if self.root.wantobjects() else "0"
180+
v = BooleanVar(self.root, name="name")
181+
v.set(True)
182+
self.assertEqual(self.root.globalgetvar("name"), true)
183+
v.set("0")
184+
self.assertEqual(self.root.globalgetvar("name"), false)
185+
v.set(42)
186+
self.assertEqual(self.root.globalgetvar("name"), true)
187+
v.set(0)
188+
self.assertEqual(self.root.globalgetvar("name"), false)
189+
v.set("on")
190+
self.assertEqual(self.root.globalgetvar("name"), true)
169191

170192
def test_invalid_value_domain(self):
193+
false = 0 if self.root.wantobjects() else "0"
171194
v = BooleanVar(self.root, name="name")
195+
with self.assertRaises(TclError):
196+
v.set("value")
197+
self.assertEqual(self.root.globalgetvar("name"), false)
172198
self.root.globalsetvar("name", "value")
173199
with self.assertRaises(ValueError):
174200
v.get()

Lib/tkinter/ttk.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ def instate(self, statespec, callback=None, *args, **kw):
573573
if ret and callback:
574574
return callback(*args, **kw)
575575

576-
return bool(ret)
576+
return ret
577577

578578

579579
def state(self, statespec=None):
@@ -681,7 +681,7 @@ def validate(self):
681681
"""Force revalidation, independent of the conditions specified
682682
by the validate option. Returns False if validation fails, True
683683
if it succeeds. Sets or clears the invalid state accordingly."""
684-
return bool(self.tk.getboolean(self.tk.call(self._w, "validate")))
684+
return self.tk.getboolean(self.tk.call(self._w, "validate"))
685685

686686

687687
class Combobox(Entry):
@@ -1231,7 +1231,7 @@ def detach(self, *items):
12311231
def exists(self, item):
12321232
"""Returns True if the specified item is present in the tree,
12331233
False otherwise."""
1234-
return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item)))
1234+
return self.tk.getboolean(self.tk.call(self._w, "exists", item))
12351235

12361236

12371237
def focus(self, item=None):

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ Core and Builtins
2424
Library
2525
-------
2626

27+
- Issue #15133: _tkinter.tkapp.getboolean() now supports Tcl_Obj and always
28+
returns bool. tkinter.BooleanVar now validates input values (accepted bool,
29+
int, str, and Tcl_Obj). tkinter.BooleanVar.get() now always returns bool.
30+
2731
- Issue #23338: Fixed formatting ctypes error messages on Cygwin.
2832
Patch by Makoto Kato.
2933

Modules/_tkinter.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,19 +1929,24 @@ Tkapp_GetDouble(PyObject *self, PyObject *args)
19291929
}
19301930

19311931
static PyObject *
1932-
Tkapp_GetBoolean(PyObject *self, PyObject *args)
1932+
Tkapp_GetBoolean(PyObject *self, PyObject *arg)
19331933
{
19341934
char *s;
19351935
int v;
19361936

1937-
if (PyTuple_Size(args) == 1) {
1938-
PyObject *o = PyTuple_GetItem(args, 0);
1939-
if (PyLong_Check(o)) {
1940-
Py_INCREF(o);
1941-
return o;
1942-
}
1937+
if (PyLong_Check(arg)) { /* int or bool */
1938+
return PyBool_FromLong(Py_SIZE(arg) != 0);
19431939
}
1944-
if (!PyArg_ParseTuple(args, "s:getboolean", &s))
1940+
1941+
if (PyTclObject_Check(arg)) {
1942+
if (Tcl_GetBooleanFromObj(Tkapp_Interp(self),
1943+
((PyTclObject*)arg)->value,
1944+
&v) == TCL_ERROR)
1945+
return Tkinter_Error(self);
1946+
return PyBool_FromLong(v);
1947+
}
1948+
1949+
if (!PyArg_Parse(arg, "s:getboolean", &s))
19451950
return NULL;
19461951
CHECK_STRING_LENGTH(s);
19471952
if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
@@ -2854,7 +2859,7 @@ static PyMethodDef Tkapp_methods[] =
28542859
{"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS},
28552860
{"getint", Tkapp_GetInt, METH_VARARGS},
28562861
{"getdouble", Tkapp_GetDouble, METH_VARARGS},
2857-
{"getboolean", Tkapp_GetBoolean, METH_VARARGS},
2862+
{"getboolean", Tkapp_GetBoolean, METH_O},
28582863
{"exprstring", Tkapp_ExprString, METH_VARARGS},
28592864
{"exprlong", Tkapp_ExprLong, METH_VARARGS},
28602865
{"exprdouble", Tkapp_ExprDouble, METH_VARARGS},

0 commit comments

Comments
 (0)