Issue #23880: Tkinter's getint() and getdouble() now support Tcl_Obj.

Tkinter's getdouble() now supports any numbers (in particular int).
This commit is contained in:
Serhiy Storchaka 2015-05-06 14:00:04 +03:00
parent 008d88b462
commit 645058d11a
9 changed files with 115 additions and 84 deletions

View file

@ -57,18 +57,18 @@ class CodeContext:
# Calculate the border width and horizontal padding required to # Calculate the border width and horizontal padding required to
# align the context with the text in the main Text widget. # align the context with the text in the main Text widget.
# #
# All values are passed through int(str(<value>)), since some # All values are passed through getint(), since some
# values may be pixel objects, which can't simply be added to ints. # values may be pixel objects, which can't simply be added to ints.
widgets = self.editwin.text, self.editwin.text_frame widgets = self.editwin.text, self.editwin.text_frame
# Calculate the required vertical padding # Calculate the required vertical padding
padx = 0 padx = 0
for widget in widgets: for widget in widgets:
padx += int(str( widget.pack_info()['padx'] )) padx += widget.tk.getint(widget.pack_info()['padx'])
padx += int(str( widget.cget('padx') )) padx += widget.tk.getint(widget.cget('padx'))
# Calculate the required border width # Calculate the required border width
border = 0 border = 0
for widget in widgets: for widget in widgets:
border += int(str( widget.cget('border') )) border += widget.tk.getint(widget.cget('border'))
self.label = tkinter.Label(self.editwin.top, self.label = tkinter.Label(self.editwin.top,
text="\n" * (self.context_depth - 1), text="\n" * (self.context_depth - 1),
anchor=W, justify=LEFT, anchor=W, justify=LEFT,

View file

@ -163,10 +163,10 @@ class TclTest(unittest.TestCase):
self.assertEqual(tcl.getdouble(' 42 '), 42.0) self.assertEqual(tcl.getdouble(' 42 '), 42.0)
self.assertEqual(tcl.getdouble(' 42.5 '), 42.5) self.assertEqual(tcl.getdouble(' 42.5 '), 42.5)
self.assertEqual(tcl.getdouble(42.5), 42.5) self.assertEqual(tcl.getdouble(42.5), 42.5)
self.assertEqual(tcl.getdouble(42), 42.0)
self.assertRaises(TypeError, tcl.getdouble) self.assertRaises(TypeError, tcl.getdouble)
self.assertRaises(TypeError, tcl.getdouble, '42.5', '10') self.assertRaises(TypeError, tcl.getdouble, '42.5', '10')
self.assertRaises(TypeError, tcl.getdouble, b'42.5') self.assertRaises(TypeError, tcl.getdouble, b'42.5')
self.assertRaises(TypeError, tcl.getdouble, 42)
self.assertRaises(TclError, tcl.getdouble, 'a') self.assertRaises(TclError, tcl.getdouble, 'a')
self.assertRaises((TypeError, ValueError, TclError), self.assertRaises((TypeError, ValueError, TclError),
tcl.getdouble, '42.5\0') tcl.getdouble, '42.5\0')

View file

@ -355,7 +355,7 @@ class IntVar(Variable):
def get(self): def get(self):
"""Return the value of the variable as an integer.""" """Return the value of the variable as an integer."""
return getint(self._tk.globalgetvar(self._name)) return self._tk.getint(self._tk.globalgetvar(self._name))
class DoubleVar(Variable): class DoubleVar(Variable):
"""Value holder for float variables.""" """Value holder for float variables."""
@ -374,7 +374,7 @@ class DoubleVar(Variable):
def get(self): def get(self):
"""Return the value of the variable as a float.""" """Return the value of the variable as a float."""
return getdouble(self._tk.globalgetvar(self._name)) return self._tk.getdouble(self._tk.globalgetvar(self._name))
class BooleanVar(Variable): class BooleanVar(Variable):
"""Value holder for boolean variables.""" """Value holder for boolean variables."""
@ -505,14 +505,26 @@ class Misc:
def getvar(self, name='PY_VAR'): def getvar(self, name='PY_VAR'):
"""Return value of Tcl variable NAME.""" """Return value of Tcl variable NAME."""
return self.tk.getvar(name) return self.tk.getvar(name)
getint = int
getdouble = float def getint(self, s):
try:
return self.tk.getint(s)
except TclError as exc:
raise ValueError(str(exc))
def getdouble(self, s):
try:
return self.tk.getdouble(s)
except TclError as exc:
raise ValueError(str(exc))
def getboolean(self, s): def getboolean(self, s):
"""Return a boolean value for Tcl boolean values true and false given as parameter.""" """Return a boolean value for Tcl boolean values true and false given as parameter."""
try: try:
return self.tk.getboolean(s) return self.tk.getboolean(s)
except TclError: except TclError:
raise ValueError("invalid literal for getboolean()") raise ValueError("invalid literal for getboolean()")
def focus_set(self): def focus_set(self):
"""Direct input focus to this widget. """Direct input focus to this widget.
@ -778,7 +790,7 @@ class Misc:
def winfo_atom(self, name, displayof=0): def winfo_atom(self, name, displayof=0):
"""Return integer which represents atom NAME.""" """Return integer which represents atom NAME."""
args = ('winfo', 'atom') + self._displayof(displayof) + (name,) args = ('winfo', 'atom') + self._displayof(displayof) + (name,)
return getint(self.tk.call(args)) return self.tk.getint(self.tk.call(args))
def winfo_atomname(self, id, displayof=0): def winfo_atomname(self, id, displayof=0):
"""Return name of atom with identifier ID.""" """Return name of atom with identifier ID."""
args = ('winfo', 'atomname') \ args = ('winfo', 'atomname') \
@ -786,7 +798,7 @@ class Misc:
return self.tk.call(args) return self.tk.call(args)
def winfo_cells(self): def winfo_cells(self):
"""Return number of cells in the colormap for this widget.""" """Return number of cells in the colormap for this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'cells', self._w)) self.tk.call('winfo', 'cells', self._w))
def winfo_children(self): def winfo_children(self):
"""Return a list of all widgets which are children of this widget.""" """Return a list of all widgets which are children of this widget."""
@ -817,22 +829,22 @@ class Misc:
return self._nametowidget(name) return self._nametowidget(name)
def winfo_depth(self): def winfo_depth(self):
"""Return the number of bits per pixel.""" """Return the number of bits per pixel."""
return getint(self.tk.call('winfo', 'depth', self._w)) return self.tk.getint(self.tk.call('winfo', 'depth', self._w))
def winfo_exists(self): def winfo_exists(self):
"""Return true if this widget exists.""" """Return true if this widget exists."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'exists', self._w)) self.tk.call('winfo', 'exists', self._w))
def winfo_fpixels(self, number): def winfo_fpixels(self, number):
"""Return the number of pixels for the given distance NUMBER """Return the number of pixels for the given distance NUMBER
(e.g. "3c") as float.""" (e.g. "3c") as float."""
return getdouble(self.tk.call( return self.tk.getdouble(self.tk.call(
'winfo', 'fpixels', self._w, number)) 'winfo', 'fpixels', self._w, number))
def winfo_geometry(self): def winfo_geometry(self):
"""Return geometry string for this widget in the form "widthxheight+X+Y".""" """Return geometry string for this widget in the form "widthxheight+X+Y"."""
return self.tk.call('winfo', 'geometry', self._w) return self.tk.call('winfo', 'geometry', self._w)
def winfo_height(self): def winfo_height(self):
"""Return height of this widget.""" """Return height of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'height', self._w)) self.tk.call('winfo', 'height', self._w))
def winfo_id(self): def winfo_id(self):
"""Return identifier ID for this widget.""" """Return identifier ID for this widget."""
@ -844,7 +856,7 @@ class Misc:
return self.tk.splitlist(self.tk.call(args)) return self.tk.splitlist(self.tk.call(args))
def winfo_ismapped(self): def winfo_ismapped(self):
"""Return true if this widget is mapped.""" """Return true if this widget is mapped."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'ismapped', self._w)) self.tk.call('winfo', 'ismapped', self._w))
def winfo_manager(self): def winfo_manager(self):
"""Return the window mananger name for this widget.""" """Return the window mananger name for this widget."""
@ -862,11 +874,11 @@ class Misc:
return self.tk.call(args) return self.tk.call(args)
def winfo_pixels(self, number): def winfo_pixels(self, number):
"""Rounded integer value of winfo_fpixels.""" """Rounded integer value of winfo_fpixels."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'pixels', self._w, number)) self.tk.call('winfo', 'pixels', self._w, number))
def winfo_pointerx(self): def winfo_pointerx(self):
"""Return the x coordinate of the pointer on the root window.""" """Return the x coordinate of the pointer on the root window."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'pointerx', self._w)) self.tk.call('winfo', 'pointerx', self._w))
def winfo_pointerxy(self): def winfo_pointerxy(self):
"""Return a tuple of x and y coordinates of the pointer on the root window.""" """Return a tuple of x and y coordinates of the pointer on the root window."""
@ -874,15 +886,15 @@ class Misc:
self.tk.call('winfo', 'pointerxy', self._w)) self.tk.call('winfo', 'pointerxy', self._w))
def winfo_pointery(self): def winfo_pointery(self):
"""Return the y coordinate of the pointer on the root window.""" """Return the y coordinate of the pointer on the root window."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'pointery', self._w)) self.tk.call('winfo', 'pointery', self._w))
def winfo_reqheight(self): def winfo_reqheight(self):
"""Return requested height of this widget.""" """Return requested height of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'reqheight', self._w)) self.tk.call('winfo', 'reqheight', self._w))
def winfo_reqwidth(self): def winfo_reqwidth(self):
"""Return requested width of this widget.""" """Return requested width of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'reqwidth', self._w)) self.tk.call('winfo', 'reqwidth', self._w))
def winfo_rgb(self, color): def winfo_rgb(self, color):
"""Return tuple of decimal values for red, green, blue for """Return tuple of decimal values for red, green, blue for
@ -892,12 +904,12 @@ class Misc:
def winfo_rootx(self): def winfo_rootx(self):
"""Return x coordinate of upper left corner of this widget on the """Return x coordinate of upper left corner of this widget on the
root window.""" root window."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'rootx', self._w)) self.tk.call('winfo', 'rootx', self._w))
def winfo_rooty(self): def winfo_rooty(self):
"""Return y coordinate of upper left corner of this widget on the """Return y coordinate of upper left corner of this widget on the
root window.""" root window."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'rooty', self._w)) self.tk.call('winfo', 'rooty', self._w))
def winfo_screen(self): def winfo_screen(self):
"""Return the screen name of this widget.""" """Return the screen name of this widget."""
@ -905,27 +917,27 @@ class Misc:
def winfo_screencells(self): def winfo_screencells(self):
"""Return the number of the cells in the colormap of the screen """Return the number of the cells in the colormap of the screen
of this widget.""" of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'screencells', self._w)) self.tk.call('winfo', 'screencells', self._w))
def winfo_screendepth(self): def winfo_screendepth(self):
"""Return the number of bits per pixel of the root window of the """Return the number of bits per pixel of the root window of the
screen of this widget.""" screen of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'screendepth', self._w)) self.tk.call('winfo', 'screendepth', self._w))
def winfo_screenheight(self): def winfo_screenheight(self):
"""Return the number of pixels of the height of the screen of this widget """Return the number of pixels of the height of the screen of this widget
in pixel.""" in pixel."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'screenheight', self._w)) self.tk.call('winfo', 'screenheight', self._w))
def winfo_screenmmheight(self): def winfo_screenmmheight(self):
"""Return the number of pixels of the height of the screen of """Return the number of pixels of the height of the screen of
this widget in mm.""" this widget in mm."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'screenmmheight', self._w)) self.tk.call('winfo', 'screenmmheight', self._w))
def winfo_screenmmwidth(self): def winfo_screenmmwidth(self):
"""Return the number of pixels of the width of the screen of """Return the number of pixels of the width of the screen of
this widget in mm.""" this widget in mm."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'screenmmwidth', self._w)) self.tk.call('winfo', 'screenmmwidth', self._w))
def winfo_screenvisual(self): def winfo_screenvisual(self):
"""Return one of the strings directcolor, grayscale, pseudocolor, """Return one of the strings directcolor, grayscale, pseudocolor,
@ -935,7 +947,7 @@ class Misc:
def winfo_screenwidth(self): def winfo_screenwidth(self):
"""Return the number of pixels of the width of the screen of """Return the number of pixels of the width of the screen of
this widget in pixel.""" this widget in pixel."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'screenwidth', self._w)) self.tk.call('winfo', 'screenwidth', self._w))
def winfo_server(self): def winfo_server(self):
"""Return information of the X-Server of the screen of this widget in """Return information of the X-Server of the screen of this widget in
@ -947,7 +959,7 @@ class Misc:
'winfo', 'toplevel', self._w)) 'winfo', 'toplevel', self._w))
def winfo_viewable(self): def winfo_viewable(self):
"""Return true if the widget and all its higher ancestors are mapped.""" """Return true if the widget and all its higher ancestors are mapped."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'viewable', self._w)) self.tk.call('winfo', 'viewable', self._w))
def winfo_visual(self): def winfo_visual(self):
"""Return one of the strings directcolor, grayscale, pseudocolor, """Return one of the strings directcolor, grayscale, pseudocolor,
@ -979,37 +991,37 @@ class Misc:
"""Return the height of the virtual root window associated with this """Return the height of the virtual root window associated with this
widget in pixels. If there is no virtual root window return the widget in pixels. If there is no virtual root window return the
height of the screen.""" height of the screen."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'vrootheight', self._w)) self.tk.call('winfo', 'vrootheight', self._w))
def winfo_vrootwidth(self): def winfo_vrootwidth(self):
"""Return the width of the virtual root window associated with this """Return the width of the virtual root window associated with this
widget in pixel. If there is no virtual root window return the widget in pixel. If there is no virtual root window return the
width of the screen.""" width of the screen."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'vrootwidth', self._w)) self.tk.call('winfo', 'vrootwidth', self._w))
def winfo_vrootx(self): def winfo_vrootx(self):
"""Return the x offset of the virtual root relative to the root """Return the x offset of the virtual root relative to the root
window of the screen of this widget.""" window of the screen of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'vrootx', self._w)) self.tk.call('winfo', 'vrootx', self._w))
def winfo_vrooty(self): def winfo_vrooty(self):
"""Return the y offset of the virtual root relative to the root """Return the y offset of the virtual root relative to the root
window of the screen of this widget.""" window of the screen of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'vrooty', self._w)) self.tk.call('winfo', 'vrooty', self._w))
def winfo_width(self): def winfo_width(self):
"""Return the width of this widget.""" """Return the width of this widget."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'width', self._w)) self.tk.call('winfo', 'width', self._w))
def winfo_x(self): def winfo_x(self):
"""Return the x coordinate of the upper left corner of this widget """Return the x coordinate of the upper left corner of this widget
in the parent.""" in the parent."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'x', self._w)) self.tk.call('winfo', 'x', self._w))
def winfo_y(self): def winfo_y(self):
"""Return the y coordinate of the upper left corner of this widget """Return the y coordinate of the upper left corner of this widget
in the parent.""" in the parent."""
return getint( return self.tk.getint(
self.tk.call('winfo', 'y', self._w)) self.tk.call('winfo', 'y', self._w))
def update(self): def update(self):
"""Enter event loop until all pending events have been processed by Tcl.""" """Enter event loop until all pending events have been processed by Tcl."""
@ -1126,11 +1138,11 @@ class Misc:
def _getints(self, string): def _getints(self, string):
"""Internal function.""" """Internal function."""
if string: if string:
return tuple(map(getint, self.tk.splitlist(string))) return tuple(map(self.tk.getint, self.tk.splitlist(string)))
def _getdoubles(self, string): def _getdoubles(self, string):
"""Internal function.""" """Internal function."""
if string: if string:
return tuple(map(getdouble, self.tk.splitlist(string))) return tuple(map(self.tk.getdouble, self.tk.splitlist(string)))
def _getboolean(self, string): def _getboolean(self, string):
"""Internal function.""" """Internal function."""
if string: if string:
@ -1229,12 +1241,12 @@ class Misc:
if len(args) != len(self._subst_format): return args if len(args) != len(self._subst_format): return args
getboolean = self.tk.getboolean getboolean = self.tk.getboolean
getint = int getint = self.tk.getint
def getint_event(s): def getint_event(s):
"""Tk changed behavior in 8.4.2, returning "??" rather more often.""" """Tk changed behavior in 8.4.2, returning "??" rather more often."""
try: try:
return int(s) return getint(s)
except ValueError: except (ValueError, TclError):
return s return s
nsign, b, f, h, k, s, t, w, x, y, A, E, K, N, W, T, X, Y, D = args nsign, b, f, h, k, s, t, w, x, y, A, E, K, N, W, T, X, Y, D = args
@ -1278,7 +1290,7 @@ class Misc:
e.y_root = getint_event(Y) e.y_root = getint_event(Y)
try: try:
e.delta = getint(D) e.delta = getint(D)
except ValueError: except (ValueError, TclError):
e.delta = 0 e.delta = 0
return (e,) return (e,)
def _report_exception(self): def _report_exception(self):
@ -1403,10 +1415,10 @@ class Misc:
if not svalue: if not svalue:
return None return None
elif '.' in svalue: elif '.' in svalue:
return getdouble(svalue) return self.tk.getdouble(svalue)
else: else:
return getint(svalue) return self.tk.getint(svalue)
except ValueError: except (ValueError, TclError):
pass pass
return value return value
@ -2284,17 +2296,17 @@ class Canvas(Widget, XView, YView):
def canvasx(self, screenx, gridspacing=None): def canvasx(self, screenx, gridspacing=None):
"""Return the canvas x coordinate of pixel position SCREENX rounded """Return the canvas x coordinate of pixel position SCREENX rounded
to nearest multiple of GRIDSPACING units.""" to nearest multiple of GRIDSPACING units."""
return getdouble(self.tk.call( return self.tk.getdouble(self.tk.call(
self._w, 'canvasx', screenx, gridspacing)) self._w, 'canvasx', screenx, gridspacing))
def canvasy(self, screeny, gridspacing=None): def canvasy(self, screeny, gridspacing=None):
"""Return the canvas y coordinate of pixel position SCREENY rounded """Return the canvas y coordinate of pixel position SCREENY rounded
to nearest multiple of GRIDSPACING units.""" to nearest multiple of GRIDSPACING units."""
return getdouble(self.tk.call( return self.tk.getdouble(self.tk.call(
self._w, 'canvasy', screeny, gridspacing)) self._w, 'canvasy', screeny, gridspacing))
def coords(self, *args): def coords(self, *args):
"""Return a list of coordinates for the item given in ARGS.""" """Return a list of coordinates for the item given in ARGS."""
# XXX Should use _flatten on args # XXX Should use _flatten on args
return [getdouble(x) for x in return [self.tk.getdouble(x) for x in
self.tk.splitlist( self.tk.splitlist(
self.tk.call((self._w, 'coords') + args))] self.tk.call((self._w, 'coords') + args))]
def _create(self, itemType, args, kw): # Args: (val, val, ..., cnf={}) def _create(self, itemType, args, kw): # Args: (val, val, ..., cnf={})
@ -2305,7 +2317,7 @@ class Canvas(Widget, XView, YView):
args = args[:-1] args = args[:-1]
else: else:
cnf = {} cnf = {}
return getint(self.tk.call( return self.tk.getint(self.tk.call(
self._w, 'create', itemType, self._w, 'create', itemType,
*(args + self._options(cnf, kw)))) *(args + self._options(cnf, kw))))
def create_arc(self, *args, **kw): def create_arc(self, *args, **kw):
@ -2389,7 +2401,7 @@ class Canvas(Widget, XView, YView):
self.tk.call((self._w, 'icursor') + args) self.tk.call((self._w, 'icursor') + args)
def index(self, *args): def index(self, *args):
"""Return position of cursor as integer in item specified in ARGS.""" """Return position of cursor as integer in item specified in ARGS."""
return getint(self.tk.call((self._w, 'index') + args)) return self.tk.getint(self.tk.call((self._w, 'index') + args))
def insert(self, *args): def insert(self, *args):
"""Insert TEXT in item TAGORID at position POS. ARGS must """Insert TEXT in item TAGORID at position POS. ARGS must
be TAGORID POS TEXT.""" be TAGORID POS TEXT."""
@ -2515,7 +2527,7 @@ class Entry(Widget, XView):
self.tk.call(self._w, 'icursor', index) self.tk.call(self._w, 'icursor', index)
def index(self, index): def index(self, index):
"""Return position of cursor.""" """Return position of cursor."""
return getint(self.tk.call( return self.tk.getint(self.tk.call(
self._w, 'index', index)) self._w, 'index', index))
def insert(self, index, string): def insert(self, index, string):
"""Insert STRING at INDEX.""" """Insert STRING at INDEX."""
@ -2630,13 +2642,13 @@ class Listbox(Widget, XView, YView):
"""Return index of item identified with INDEX.""" """Return index of item identified with INDEX."""
i = self.tk.call(self._w, 'index', index) i = self.tk.call(self._w, 'index', index)
if i == 'none': return None if i == 'none': return None
return getint(i) return self.tk.getint(i)
def insert(self, index, *elements): def insert(self, index, *elements):
"""Insert ELEMENTS at INDEX.""" """Insert ELEMENTS at INDEX."""
self.tk.call((self._w, 'insert', index) + elements) self.tk.call((self._w, 'insert', index) + elements)
def nearest(self, y): def nearest(self, y):
"""Get index of item which is nearest to y coordinate Y.""" """Get index of item which is nearest to y coordinate Y."""
return getint(self.tk.call( return self.tk.getint(self.tk.call(
self._w, 'nearest', y)) self._w, 'nearest', y))
def scan_mark(self, x, y): def scan_mark(self, x, y):
"""Remember the current X, Y coordinates.""" """Remember the current X, Y coordinates."""
@ -2670,7 +2682,7 @@ class Listbox(Widget, XView, YView):
select_set = selection_set select_set = selection_set
def size(self): def size(self):
"""Return the number of elements in the listbox.""" """Return the number of elements in the listbox."""
return getint(self.tk.call(self._w, 'size')) return self.tk.getint(self.tk.call(self._w, 'size'))
def itemcget(self, index, option): def itemcget(self, index, option):
"""Return the resource value for an ITEM and an OPTION.""" """Return the resource value for an ITEM and an OPTION."""
return self.tk.call( return self.tk.call(
@ -2772,7 +2784,7 @@ class Menu(Widget):
"""Return the index of a menu item identified by INDEX.""" """Return the index of a menu item identified by INDEX."""
i = self.tk.call(self._w, 'index', index) i = self.tk.call(self._w, 'index', index)
if i == 'none': return None if i == 'none': return None
return getint(i) return self.tk.getint(i)
def invoke(self, index): def invoke(self, index):
"""Invoke a menu item identified by INDEX and execute """Invoke a menu item identified by INDEX and execute
the associated command.""" the associated command."""
@ -2789,10 +2801,10 @@ class Menu(Widget):
def xposition(self, index): # new in Tk 8.5 def xposition(self, index): # new in Tk 8.5
"""Return the x-position of the leftmost pixel of the menu item """Return the x-position of the leftmost pixel of the menu item
at INDEX.""" at INDEX."""
return getint(self.tk.call(self._w, 'xposition', index)) return self.tk.getint(self.tk.call(self._w, 'xposition', index))
def yposition(self, index): def yposition(self, index):
"""Return the y-position of the topmost pixel of the menu item at INDEX.""" """Return the y-position of the topmost pixel of the menu item at INDEX."""
return getint(self.tk.call( return self.tk.getint(self.tk.call(
self._w, 'yposition', index)) self._w, 'yposition', index))
class Menubutton(Widget): class Menubutton(Widget):
@ -2848,9 +2860,9 @@ class Scale(Widget):
"""Get the current value as integer or float.""" """Get the current value as integer or float."""
value = self.tk.call(self._w, 'get') value = self.tk.call(self._w, 'get')
try: try:
return getint(value) return self.tk.getint(value)
except ValueError: except (ValueError, TclError):
return getdouble(value) return self.tk.getdouble(value)
def set(self, value): def set(self, value):
"""Set the value to VALUE.""" """Set the value to VALUE."""
self.tk.call(self._w, 'set', value) self.tk.call(self._w, 'set', value)
@ -2888,12 +2900,12 @@ class Scrollbar(Widget):
def delta(self, deltax, deltay): def delta(self, deltax, deltay):
"""Return the fractional change of the scrollbar setting if it """Return the fractional change of the scrollbar setting if it
would be moved by DELTAX or DELTAY pixels.""" would be moved by DELTAX or DELTAY pixels."""
return getdouble( return self.tk.getdouble(
self.tk.call(self._w, 'delta', deltax, deltay)) self.tk.call(self._w, 'delta', deltax, deltay))
def fraction(self, x, y): def fraction(self, x, y):
"""Return the fractional value which corresponds to a slider """Return the fractional value which corresponds to a slider
position of X,Y.""" position of X,Y."""
return getdouble(self.tk.call(self._w, 'fraction', x, y)) return self.tk.getdouble(self.tk.call(self._w, 'fraction', x, y))
def identify(self, x, y): def identify(self, x, y):
"""Return the element under position X,Y as one of """Return the element under position X,Y as one of
"arrow1","slider","arrow2" or "".""" "arrow1","slider","arrow2" or ""."""
@ -3364,14 +3376,14 @@ class Image:
config = configure config = configure
def height(self): def height(self):
"""Return the height of the image.""" """Return the height of the image."""
return getint( return self.tk.getint(
self.tk.call('image', 'height', self.name)) self.tk.call('image', 'height', self.name))
def type(self): def type(self):
"""Return the type of the imgage, e.g. "photo" or "bitmap".""" """Return the type of the imgage, e.g. "photo" or "bitmap"."""
return self.tk.call('image', 'type', self.name) return self.tk.call('image', 'type', self.name)
def width(self): def width(self):
"""Return the width of the image.""" """Return the width of the image."""
return getint( return self.tk.getint(
self.tk.call('image', 'width', self.name)) self.tk.call('image', 'width', self.name))
class PhotoImage(Image): class PhotoImage(Image):

View file

@ -153,7 +153,7 @@ class Font:
args = (text,) args = (text,)
if displayof: if displayof:
args = ('-displayof', displayof, text) args = ('-displayof', displayof, text)
return int(self._call("font", "measure", self.name, *args)) return self._root.tk.getint(self._call("font", "measure", self.name, *args))
def metrics(self, *options, **kw): def metrics(self, *options, **kw):
"""Return font metrics. """Return font metrics.
@ -166,13 +166,13 @@ class Font:
args = ('-displayof', displayof) args = ('-displayof', displayof)
if options: if options:
args = args + self._get(options) args = args + self._get(options)
return int( return self._root.tk.getint(
self._call("font", "metrics", self.name, *args)) self._call("font", "metrics", self.name, *args))
else: else:
res = self._split(self._call("font", "metrics", self.name, *args)) res = self._split(self._call("font", "metrics", self.name, *args))
options = {} options = {}
for i in range(0, len(res), 2): for i in range(0, len(res), 2):
options[res[i][1:]] = int(res[i+1]) options[res[i][1:]] = self._root.tk.getint(res[i+1])
return options return options

View file

@ -325,7 +325,7 @@ class _QueryDialog(Dialog):
class _QueryInteger(_QueryDialog): class _QueryInteger(_QueryDialog):
errormessage = "Not an integer." errormessage = "Not an integer."
def getresult(self): def getresult(self):
return int(self.entry.get()) return self.getint(self.entry.get())
def askinteger(title, prompt, **kw): def askinteger(title, prompt, **kw):
'''get an integer from the user '''get an integer from the user
@ -344,7 +344,7 @@ def askinteger(title, prompt, **kw):
class _QueryFloat(_QueryDialog): class _QueryFloat(_QueryDialog):
errormessage = "Not a floating point value." errormessage = "Not a floating point value."
def getresult(self): def getresult(self):
return float(self.entry.get()) return self.getdouble(self.entry.get())
def askfloat(title, prompt, **kw): def askfloat(title, prompt, **kw):
'''get a float from the user '''get a float from the user

View file

@ -122,10 +122,10 @@ class TestIntVar(TestBase):
def test_invalid_value(self): def test_invalid_value(self):
v = IntVar(self.root, name="name") v = IntVar(self.root, name="name")
self.root.globalsetvar("name", "value") self.root.globalsetvar("name", "value")
with self.assertRaises(ValueError): with self.assertRaises((ValueError, TclError)):
v.get() v.get()
self.root.globalsetvar("name", "345.0") self.root.globalsetvar("name", "345.0")
with self.assertRaises(ValueError): with self.assertRaises((ValueError, TclError)):
v.get() v.get()
@ -152,7 +152,7 @@ class TestDoubleVar(TestBase):
def test_invalid_value(self): def test_invalid_value(self):
v = DoubleVar(self.root, name="name") v = DoubleVar(self.root, name="name")
self.root.globalsetvar("name", "value") self.root.globalsetvar("name", "value")
with self.assertRaises(ValueError): with self.assertRaises((ValueError, TclError)):
v.get() v.get()

View file

@ -70,17 +70,15 @@ class LabeledScaleTest(AbstractTkTest, unittest.TestCase):
# variable initialization/passing # variable initialization/passing
passed_expected = (('0', 0), (0, 0), (10, 10), passed_expected = (('0', 0), (0, 0), (10, 10),
(-1, -1), (sys.maxsize + 1, sys.maxsize + 1)) (-1, -1), (sys.maxsize + 1, sys.maxsize + 1))
if self.wantobjects:
passed_expected += ((2.5, 2),)
for pair in passed_expected: for pair in passed_expected:
x = ttk.LabeledScale(self.root, from_=pair[0]) x = ttk.LabeledScale(self.root, from_=pair[0])
self.assertEqual(x.value, pair[1]) self.assertEqual(x.value, pair[1])
x.destroy() x.destroy()
x = ttk.LabeledScale(self.root, from_='2.5') x = ttk.LabeledScale(self.root, from_='2.5')
self.assertRaises(ValueError, x._variable.get) self.assertRaises((ValueError, tkinter.TclError), x._variable.get)
x.destroy() x.destroy()
x = ttk.LabeledScale(self.root, from_=None) x = ttk.LabeledScale(self.root, from_=None)
self.assertRaises(ValueError, x._variable.get) self.assertRaises((ValueError, tkinter.TclError), x._variable.get)
x.destroy() x.destroy()
# variable should have its default value set to the from_ value # variable should have its default value set to the from_ value
myvar = tkinter.DoubleVar(self.root, value=20) myvar = tkinter.DoubleVar(self.root, value=20)

View file

@ -30,6 +30,9 @@ Core and Builtins
Library Library
------- -------
- Issue #23880: Tkinter's getint() and getdouble() now support Tcl_Obj.
Tkinter's getdouble() now supports any numbers (in particular int).
- Issue #22619: Added negative limit support in the traceback module. - Issue #22619: Added negative limit support in the traceback module.
Based on patch by Dmitry Kazakov. Based on patch by Dmitry Kazakov.

View file

@ -1934,12 +1934,18 @@ _tkinter_tkapp_getint(TkappObject *self, PyObject *arg)
return arg; return arg;
} }
if (!PyArg_Parse(arg, "s:getint", &s)) if (PyTclObject_Check(arg)) {
return NULL; value = ((PyTclObject*)arg)->value;
CHECK_STRING_LENGTH(s); Tcl_IncrRefCount(value);
value = Tcl_NewStringObj(s, -1); }
if (value == NULL) else {
return Tkinter_Error((PyObject *)self); if (!PyArg_Parse(arg, "s:getint", &s))
return NULL;
CHECK_STRING_LENGTH(s);
value = Tcl_NewStringObj(s, -1);
if (value == NULL)
return Tkinter_Error((PyObject *)self);
}
/* Don't use Tcl_GetInt() because it returns ambiguous result for value /* Don't use Tcl_GetInt() because it returns ambiguous result for value
in ranges -2**32..-2**31-1 and 2**31..2**32-1 (on 32-bit platform). in ranges -2**32..-2**31-1 and 2**31..2**32-1 (on 32-bit platform).
@ -1977,12 +1983,24 @@ _tkinter_tkapp_getdouble(TkappObject *self, PyObject *arg)
return arg; return arg;
} }
if (PyNumber_Check(arg)) {
return PyNumber_Float(arg);
}
if (PyTclObject_Check(arg)) {
if (Tcl_GetDoubleFromObj(Tkapp_Interp(self),
((PyTclObject*)arg)->value,
&v) == TCL_ERROR)
return Tkinter_Error((PyObject *)self);
return PyFloat_FromDouble(v);
}
if (!PyArg_Parse(arg, "s:getdouble", &s)) if (!PyArg_Parse(arg, "s:getdouble", &s))
return NULL; return NULL;
CHECK_STRING_LENGTH(s); CHECK_STRING_LENGTH(s);
if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
return Tkinter_Error((PyObject *)self); return Tkinter_Error((PyObject *)self);
return Py_BuildValue("d", v); return PyFloat_FromDouble(v);
} }
/*[clinic input] /*[clinic input]