diff --git a/Lib/lib-tk/Tkinter.py b/Lib/lib-tk/Tkinter.py index 8d21717b467..cb7edf0ed44 100644 --- a/Lib/lib-tk/Tkinter.py +++ b/Lib/lib-tk/Tkinter.py @@ -401,6 +401,10 @@ class BooleanVar(Variable): """ 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)) + def get(self): """Return the value of the variable as a bool.""" return self._tk.getboolean(self._tk.globalgetvar(self._name)) diff --git a/Lib/lib-tk/test/test_tkinter/test_variables.py b/Lib/lib-tk/test/test_tkinter/test_variables.py index c11d8cdf990..5e07528c6d8 100644 --- a/Lib/lib-tk/test/test_tkinter/test_variables.py +++ b/Lib/lib-tk/test/test_tkinter/test_variables.py @@ -1,6 +1,7 @@ import unittest -from Tkinter import Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl, TclError +from Tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl, + TclError) class TestBase(unittest.TestCase): @@ -139,16 +140,57 @@ class TestBooleanVar(TestBase): def test_default(self): v = BooleanVar(self.root) - self.assertEqual(False, v.get()) + self.assertIs(v.get(), False) def test_get(self): v = BooleanVar(self.root, True, "name") - self.assertAlmostEqual(True, v.get()) + self.assertIs(v.get(), True) 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", 42L if self.root.wantobjects() else 1L) + self.assertIs(v.get(), True) + self.root.globalsetvar("name", 0L) + self.assertIs(v.get(), False) + self.root.globalsetvar("name", "on") + self.assertIs(v.get(), True) + self.root.globalsetvar("name", u"0") + self.assertIs(v.get(), False) + self.root.globalsetvar("name", u"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(42L) + self.assertEqual(self.root.globalgetvar("name"), true) + v.set(0L) + self.assertEqual(self.root.globalgetvar("name"), false) + v.set("on") + self.assertEqual(self.root.globalgetvar("name"), true) + v.set(u"0") + self.assertEqual(self.root.globalgetvar("name"), false) + v.set(u"on") + self.assertEqual(self.root.globalgetvar("name"), true) def test_invalid_value_domain(self): + false = 0 if self.root.wantobjects() else "0" 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") with self.assertRaises(TclError): v.get() diff --git a/Lib/lib-tk/ttk.py b/Lib/lib-tk/ttk.py index 58f769895dd..08cb040bd95 100644 --- a/Lib/lib-tk/ttk.py +++ b/Lib/lib-tk/ttk.py @@ -575,7 +575,7 @@ class Widget(Tkinter.Widget): if ret and callback: return callback(*args, **kw) - return bool(ret) + return ret def state(self, statespec=None): @@ -683,7 +683,7 @@ class Entry(Widget, Tkinter.Entry): """Force revalidation, independent of the conditions specified by the validate option. Returns False if validation fails, True 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): @@ -1233,7 +1233,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView): def exists(self, item): """Returns True if the specified item is present in the tree, 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): diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index ff1568b6071..4167588e627 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -182,7 +182,12 @@ class TclTest(unittest.TestCase): tcl = self.interp.tk self.assertIs(tcl.getboolean('on'), True) self.assertIs(tcl.getboolean('1'), True) - self.assertEqual(tcl.getboolean(42), 42) + self.assertIs(tcl.getboolean(u'on'), True) + self.assertIs(tcl.getboolean(u'1'), True) + self.assertIs(tcl.getboolean(42), True) + self.assertIs(tcl.getboolean(0), False) + self.assertIs(tcl.getboolean(42L), True) + self.assertIs(tcl.getboolean(0L), False) self.assertRaises(TypeError, tcl.getboolean) self.assertRaises(TypeError, tcl.getboolean, 'on', '1') self.assertRaises(TypeError, tcl.getboolean, 1.0) diff --git a/Misc/NEWS b/Misc/NEWS index 783bf8821c0..c9febc7b5ec 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,11 @@ Core and Builtins Library ------- +- Issue #15133: _tkinter.tkapp.getboolean() now supports long and Tcl_Obj and + always returns bool. tkinter.BooleanVar now validates input values (accepted + bool, int, long, str, unicode, and Tcl_Obj). tkinter.BooleanVar.get() now + always returns bool. + - Issue #23338: Fixed formatting ctypes error messages on Cygwin. Patch by Makoto Kato. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 840b9dbdab3..bef5c0bbe8f 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -2163,19 +2163,26 @@ Tkapp_GetDouble(PyObject *self, PyObject *args) } static PyObject * -Tkapp_GetBoolean(PyObject *self, PyObject *args) +Tkapp_GetBoolean(PyObject *self, PyObject *arg) { char *s; int v; - if (PyTuple_Size(args) == 1) { - PyObject *o = PyTuple_GetItem(args, 0); - if (PyInt_Check(o)) { - Py_INCREF(o); - return o; - } + if (PyInt_Check(arg)) /* int or bool */ + return PyBool_FromLong(PyInt_AS_LONG(arg)); + + if (PyLong_Check(arg)) + return PyBool_FromLong(Py_SIZE(arg) != 0); + + 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_ParseTuple(args, "s:getboolean", &s)) + + if (!PyArg_Parse(arg, "s:getboolean", &s)) return NULL; CHECK_STRING_LENGTH(s); if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) @@ -3236,7 +3243,7 @@ static PyMethodDef Tkapp_methods[] = {"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS}, {"getint", Tkapp_GetInt, METH_VARARGS}, {"getdouble", Tkapp_GetDouble, METH_VARARGS}, - {"getboolean", Tkapp_GetBoolean, METH_VARARGS}, + {"getboolean", Tkapp_GetBoolean, METH_O}, {"exprstring", Tkapp_ExprString, METH_VARARGS}, {"exprlong", Tkapp_ExprLong, METH_VARARGS}, {"exprdouble", Tkapp_ExprDouble, METH_VARARGS},