Commit 06e66108 authored by Serhiy Storchaka's avatar Serhiy Storchaka

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.
parents 46ba6c85 9a6e201f
...@@ -179,7 +179,8 @@ class TclTest(unittest.TestCase): ...@@ -179,7 +179,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')
......
...@@ -391,6 +391,11 @@ class BooleanVar(Variable): ...@@ -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:
......
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): ...@@ -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()
......
...@@ -573,7 +573,7 @@ class Widget(tkinter.Widget): ...@@ -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): ...@@ -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): ...@@ -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):
......
...@@ -19,6 +19,10 @@ Core and Builtins ...@@ -19,6 +19,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 #10590: xml.sax.parseString() now supports string argument. - Issue #10590: xml.sax.parseString() now supports string argument.
- Issue #23338: Fixed formatting ctypes error messages on Cygwin. - Issue #23338: Fixed formatting ctypes error messages on Cygwin.
......
...@@ -1934,19 +1934,24 @@ Tkapp_GetDouble(PyObject *self, PyObject *args) ...@@ -1934,19 +1934,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)
...@@ -2862,7 +2867,7 @@ static PyMethodDef Tkapp_methods[] = ...@@ -2862,7 +2867,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},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment