Issue #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.
This commit is contained in:
Serhiy Storchaka 2015-04-04 12:43:01 +03:00
parent c9ba38c21c
commit 9a6e201f7d
6 changed files with 58 additions and 17 deletions

View file

@ -181,7 +181,8 @@ class TclTest(unittest.TestCase):
tcl = self.interp.tk tcl = self.interp.tk
self.assertIs(tcl.getboolean('on'), True) self.assertIs(tcl.getboolean('on'), True)
self.assertIs(tcl.getboolean('1'), True) self.assertIs(tcl.getboolean('1'), True)
self.assertEqual(tcl.getboolean(42), 42) self.assertIs(tcl.getboolean(42), True)
self.assertIs(tcl.getboolean(0), False)
self.assertRaises(TypeError, tcl.getboolean) self.assertRaises(TypeError, tcl.getboolean)
self.assertRaises(TypeError, tcl.getboolean, 'on', '1') self.assertRaises(TypeError, tcl.getboolean, 'on', '1')
self.assertRaises(TypeError, tcl.getboolean, b'on') self.assertRaises(TypeError, tcl.getboolean, b'on')

View file

@ -391,6 +391,11 @@ class BooleanVar(Variable):
""" """
Variable.__init__(self, master, value, name) Variable.__init__(self, master, value, name)
def set(self, value):
"""Set the variable to VALUE."""
return self._tk.globalsetvar(self._name, self._tk.getboolean(value))
initialize = set
def get(self): def get(self):
"""Return the value of the variable as a bool.""" """Return the value of the variable as a bool."""
try: try:

View file

@ -1,6 +1,7 @@
import unittest import unittest
from tkinter import Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
TclError)
class Var(Variable): class Var(Variable):
@ -159,16 +160,41 @@ class TestBooleanVar(TestBase):
def test_default(self): def test_default(self):
v = BooleanVar(self.root) v = BooleanVar(self.root)
self.assertEqual(False, v.get()) self.assertIs(v.get(), False)
def test_get(self): def test_get(self):
v = BooleanVar(self.root, True, "name") v = BooleanVar(self.root, True, "name")
self.assertAlmostEqual(True, v.get()) self.assertIs(v.get(), True)
self.root.globalsetvar("name", "0") self.root.globalsetvar("name", "0")
self.assertAlmostEqual(False, v.get()) self.assertIs(v.get(), False)
self.root.globalsetvar("name", 42 if self.root.wantobjects() else 1)
self.assertIs(v.get(), True)
self.root.globalsetvar("name", 0)
self.assertIs(v.get(), False)
self.root.globalsetvar("name", "on")
self.assertIs(v.get(), True)
def test_set(self):
true = 1 if self.root.wantobjects() else "1"
false = 0 if self.root.wantobjects() else "0"
v = BooleanVar(self.root, name="name")
v.set(True)
self.assertEqual(self.root.globalgetvar("name"), true)
v.set("0")
self.assertEqual(self.root.globalgetvar("name"), false)
v.set(42)
self.assertEqual(self.root.globalgetvar("name"), true)
v.set(0)
self.assertEqual(self.root.globalgetvar("name"), false)
v.set("on")
self.assertEqual(self.root.globalgetvar("name"), true)
def test_invalid_value_domain(self): def test_invalid_value_domain(self):
false = 0 if self.root.wantobjects() else "0"
v = BooleanVar(self.root, name="name") v = BooleanVar(self.root, name="name")
with self.assertRaises(TclError):
v.set("value")
self.assertEqual(self.root.globalgetvar("name"), false)
self.root.globalsetvar("name", "value") self.root.globalsetvar("name", "value")
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
v.get() v.get()

View file

@ -573,7 +573,7 @@ class Widget(tkinter.Widget):
if ret and callback: if ret and callback:
return callback(*args, **kw) return callback(*args, **kw)
return bool(ret) return ret
def state(self, statespec=None): def state(self, statespec=None):
@ -681,7 +681,7 @@ class Entry(Widget, tkinter.Entry):
"""Force revalidation, independent of the conditions specified """Force revalidation, independent of the conditions specified
by the validate option. Returns False if validation fails, True by the validate option. Returns False if validation fails, True
if it succeeds. Sets or clears the invalid state accordingly.""" if it succeeds. Sets or clears the invalid state accordingly."""
return bool(self.tk.getboolean(self.tk.call(self._w, "validate"))) return self.tk.getboolean(self.tk.call(self._w, "validate"))
class Combobox(Entry): class Combobox(Entry):
@ -1231,7 +1231,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
def exists(self, item): def exists(self, item):
"""Returns True if the specified item is present in the tree, """Returns True if the specified item is present in the tree,
False otherwise.""" False otherwise."""
return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item))) return self.tk.getboolean(self.tk.call(self._w, "exists", item))
def focus(self, item=None): def focus(self, item=None):

View file

@ -24,6 +24,10 @@ Core and Builtins
Library Library
------- -------
- Issue #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.
- Issue #23338: Fixed formatting ctypes error messages on Cygwin. - Issue #23338: Fixed formatting ctypes error messages on Cygwin.
Patch by Makoto Kato. Patch by Makoto Kato.

View file

@ -1929,19 +1929,24 @@ Tkapp_GetDouble(PyObject *self, PyObject *args)
} }
static PyObject * static PyObject *
Tkapp_GetBoolean(PyObject *self, PyObject *args) Tkapp_GetBoolean(PyObject *self, PyObject *arg)
{ {
char *s; char *s;
int v; int v;
if (PyTuple_Size(args) == 1) { if (PyLong_Check(arg)) { /* int or bool */
PyObject *o = PyTuple_GetItem(args, 0); return PyBool_FromLong(Py_SIZE(arg) != 0);
if (PyLong_Check(o)) {
Py_INCREF(o);
return o;
}
} }
if (!PyArg_ParseTuple(args, "s:getboolean", &s))
if (PyTclObject_Check(arg)) {
if (Tcl_GetBooleanFromObj(Tkapp_Interp(self),
((PyTclObject*)arg)->value,
&v) == TCL_ERROR)
return Tkinter_Error(self);
return PyBool_FromLong(v);
}
if (!PyArg_Parse(arg, "s:getboolean", &s))
return NULL; return NULL;
CHECK_STRING_LENGTH(s); CHECK_STRING_LENGTH(s);
if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
@ -2854,7 +2859,7 @@ static PyMethodDef Tkapp_methods[] =
{"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS}, {"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS},
{"getint", Tkapp_GetInt, METH_VARARGS}, {"getint", Tkapp_GetInt, METH_VARARGS},
{"getdouble", Tkapp_GetDouble, METH_VARARGS}, {"getdouble", Tkapp_GetDouble, METH_VARARGS},
{"getboolean", Tkapp_GetBoolean, METH_VARARGS}, {"getboolean", Tkapp_GetBoolean, METH_O},
{"exprstring", Tkapp_ExprString, METH_VARARGS}, {"exprstring", Tkapp_ExprString, METH_VARARGS},
{"exprlong", Tkapp_ExprLong, METH_VARARGS}, {"exprlong", Tkapp_ExprLong, METH_VARARGS},
{"exprdouble", Tkapp_ExprDouble, METH_VARARGS}, {"exprdouble", Tkapp_ExprDouble, METH_VARARGS},