Path: blob/main/Sage_base/sage/python/patches/tkinter.patch
242 views
diff -ru Orig/Lib/test/test_tkinter/test_misc.py Python-3.13.1/Lib/test/test_tkinter/test_misc.py1--- Orig/Lib/test/test_tkinter/test_misc.py 2024-12-03 11:59:522+++ Python-3.13.1/Lib/test/test_tkinter/test_misc.py 2024-12-12 12:57:153@@ -66,9 +66,10 @@4f.tk_busy_forget()5self.assertFalse(f.tk_busy_status())6self.assertFalse(f.tk_busy_current())7- with self.assertRaisesRegex(TclError, "can't find busy window"):8+ errmsg = r"can(no|')t find busy window.*"9+ with self.assertRaisesRegex(TclError, errmsg):10f.tk_busy_configure()11- with self.assertRaisesRegex(TclError, "can't find busy window"):12+ with self.assertRaisesRegex(TclError, errmsg):13f.tk_busy_forget()1415@requires_tk(8, 6, 6)16@@ -87,7 +88,8 @@17self.assertEqual(f.tk_busy_configure('cursor')[4], 'heart')1819f.tk_busy_forget()20- with self.assertRaisesRegex(TclError, "can't find busy window"):21+ errmsg = r"can(no|')t find busy window.*"22+ with self.assertRaisesRegex(TclError, errmsg):23f.tk_busy_cget('cursor')2425def test_tk_setPalette(self):26diff -ru Orig/Lib/test/test_tkinter/test_widgets.py Python-3.13.1/Lib/test/test_tkinter/test_widgets.py27--- Orig/Lib/test/test_tkinter/test_widgets.py 2024-12-03 11:59:5228+++ Python-3.13.1/Lib/test/test_tkinter/test_widgets.py 2024-12-12 12:57:1529@@ -7,9 +7,13 @@30from test.test_tkinter.support import (requires_tk, tk_version,31get_tk_patchlevel, widget_eq,32AbstractDefaultRootTest)33+34from test.test_tkinter.widget_tests import (35- add_standard_options,36- AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests)37+ add_configure_tests,38+ AbstractWidgetTest,39+ StandardOptionsTests,40+ IntegerSizeTests,41+ PixelSizeTests)4243requires('gui')4445@@ -20,9 +24,17 @@46def float_round(x):47return float(round(x))4849-50class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):51- _conv_pad_pixels = False52+ if tk_version < (9, 0):53+ _no_round = {'padx', 'pady'}54+ else:55+ _no_round = {'borderwidth', 'height', 'highlightthickness', 'padx',56+ 'pady', 'width'}57+ if tk_version < (9, 0):58+ _clipped = {'highlightthickness'}59+ else:60+ _clipped = {'borderwidth', 'height', 'highlightthickness', 'padx',61+ 'pady', 'width'}6263def test_configure_class(self):64widget = self.create()65@@ -58,7 +70,7 @@66self.assertEqual(widget2['visual'], 'default')676869-@add_standard_options(StandardOptionsTests)70+@add_configure_tests(StandardOptionsTests)71class ToplevelTest(AbstractToplevelTest, unittest.TestCase):72OPTIONS = (73'background', 'backgroundimage', 'borderwidth',74@@ -101,7 +113,7 @@75self.assertEqual(widget2['use'], wid)767778-@add_standard_options(StandardOptionsTests)79+@add_configure_tests(StandardOptionsTests)80class FrameTest(AbstractToplevelTest, unittest.TestCase):81OPTIONS = (82'background', 'backgroundimage', 'borderwidth',83@@ -109,12 +121,17 @@84'highlightbackground', 'highlightcolor', 'highlightthickness',85'padx', 'pady', 'relief', 'takefocus', 'tile', 'visual', 'width',86)87+ if tk_version < (9, 0):88+ _no_round = {'padx', 'pady'}89+ else:90+ _no_round = {'borderwidth', 'height', 'highlightthickness', 'padx',91+ 'pady', 'width'}9293def create(self, **kwargs):94return tkinter.Frame(self.root, **kwargs)959697-@add_standard_options(StandardOptionsTests)98+@add_configure_tests(StandardOptionsTests)99class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):100OPTIONS = (101'background', 'borderwidth',102@@ -124,6 +141,11 @@103'labelanchor', 'labelwidget', 'padx', 'pady', 'relief',104'takefocus', 'text', 'visual', 'width',105)106+ if tk_version < (9, 0):107+ _no_round = {'padx', 'pady'}108+ else:109+ _no_round = {'borderwidth', 'height', 'highlightthickness', 'padx',110+ 'pady', 'width'}111112def create(self, **kwargs):113return tkinter.LabelFrame(self.root, **kwargs)114@@ -141,15 +163,16 @@115self.checkParam(widget, 'labelwidget', label, expected='.foo')116label.destroy()117118-119+# Label, Button, Checkbutton, Radiobutton, MenuButton120class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests):121- _conv_pixels = False122- _clip_highlightthickness = tk_version >= (8, 7)123- _clip_pad = tk_version >= (8, 7)124- _clip_borderwidth = tk_version >= (8, 7)125+ _rounds_pixels = False126+ if tk_version < (9, 0):127+ _clipped = {}128+ else:129+ _clipped = {'borderwidth', 'insertborderwidth', 'highlightthickness',130+ 'padx', 'pady'}131132-133-@add_standard_options(StandardOptionsTests)134+@add_configure_tests(StandardOptionsTests)135class LabelTest(AbstractLabelTest, unittest.TestCase):136OPTIONS = (137'activebackground', 'activeforeground', 'anchor',138@@ -165,7 +188,7 @@139return tkinter.Label(self.root, **kwargs)140141142-@add_standard_options(StandardOptionsTests)143+@add_configure_tests(StandardOptionsTests)144class ButtonTest(AbstractLabelTest, unittest.TestCase):145OPTIONS = (146'activebackground', 'activeforeground', 'anchor',147@@ -186,7 +209,7 @@148self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal')149150151-@add_standard_options(StandardOptionsTests)152+@add_configure_tests(StandardOptionsTests)153class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):154OPTIONS = (155'activebackground', 'activeforeground', 'anchor',156@@ -240,8 +263,7 @@157b2.deselect()158self.assertEqual(v.get(), 0)159160-161-@add_standard_options(StandardOptionsTests)162+@add_configure_tests(StandardOptionsTests)163class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):164OPTIONS = (165'activebackground', 'activeforeground', 'anchor',166@@ -264,7 +286,7 @@167self.checkParams(widget, 'value', 1, 2.3, '', 'any string')168169170-@add_standard_options(StandardOptionsTests)171+@add_configure_tests(StandardOptionsTests)172class MenubuttonTest(AbstractLabelTest, unittest.TestCase):173OPTIONS = (174'activebackground', 'activeforeground', 'anchor',175@@ -277,10 +299,11 @@176'takefocus', 'text', 'textvariable',177'underline', 'width', 'wraplength',178)179- _conv_pixels = round180- _clip_highlightthickness = True181- _clip_pad = True182- _clip_borderwidth = False183+ _rounds_pixels = (tk_version < (9, 0))184+ if tk_version < (9, 0):185+ _clipped = {'highlightthickness', 'padx', 'pady'}186+ else:187+ _clipped ={ 'insertborderwidth', 'highlightthickness', 'padx', 'pady'}188189def create(self, **kwargs):190return tkinter.Menubutton(self.root, **kwargs)191@@ -298,7 +321,10 @@192widget = self.create()193image = tkinter.PhotoImage(master=self.root, name='image1')194self.checkParam(widget, 'image', image, conv=str)195- errmsg = 'image "spam" doesn\'t exist'196+ if tk_version < (9, 0):197+ errmsg = 'image "spam" doesn\'t exist'198+ else:199+ errmsg = 'image "spam" does not exist'200with self.assertRaises(tkinter.TclError) as cm:201widget['image'] = 'spam'202if errmsg is not None:203@@ -328,9 +354,15 @@204with self.assertRaisesRegex(TclError, r"^unknown option -image$"):205tkinter.OptionMenu(self.root, None, 'b', image='')206207-208-@add_standard_options(IntegerSizeTests, StandardOptionsTests)209+@add_configure_tests(IntegerSizeTests, StandardOptionsTests)210class EntryTest(AbstractWidgetTest, unittest.TestCase):211+ _rounds_pixels = (tk_version < (9, 0))212+ if tk_version < (9, 0):213+ _clipped = {'highlightthickness'}214+ else:215+ _clipped = {'highlightthickness', 'borderwidth', 'insertborderwidth',216+ 'selectborderwidth'}217+218OPTIONS = (219'background', 'borderwidth', 'cursor',220'disabledbackground', 'disabledforeground',221@@ -355,16 +387,23 @@222def test_configure_insertborderwidth(self):223widget = self.create(insertwidth=100)224self.checkPixelsParam(widget, 'insertborderwidth',225- 0, 1.3, 2.6, 6, -2, '10p')226+ 0, 1.3, 2.6, 6, '10p')227+ self.checkParam(widget, 'insertborderwidth', -2)228# insertborderwidth is bounded above by a half of insertwidth.229- self.checkParam(widget, 'insertborderwidth', 60, expected=100//2)230+ expected = 100 // 2 if tk_version < (9, 0) else 60231+ self.checkParam(widget, 'insertborderwidth', 60, expected=expected)232233def test_configure_insertwidth(self):234widget = self.create()235self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')236- self.checkParam(widget, 'insertwidth', 0.1, expected=2)237- self.checkParam(widget, 'insertwidth', -2, expected=2)238- self.checkParam(widget, 'insertwidth', 0.9, expected=1)239+ if tk_version < (9, 0):240+ self.checkParam(widget, 'insertwidth', 0.1, expected=2)241+ self.checkParam(widget, 'insertwidth', -2, expected=2)242+ self.checkParam(widget, 'insertwidth', 0.9, expected=1)243+ else:244+ self.checkParam(widget, 'insertwidth', 0.1)245+ self.checkParam(widget, 'insertwidth', -2, expected=0)246+ self.checkParam(widget, 'insertwidth', 0.9)247248def test_configure_invalidcommand(self):249widget = self.create()250@@ -422,7 +461,7 @@251widget.selection_adjust(0)252253254-@add_standard_options(StandardOptionsTests)255+@add_configure_tests(StandardOptionsTests)256class SpinboxTest(EntryTest, unittest.TestCase):257OPTIONS = (258'activebackground', 'background', 'borderwidth',259@@ -559,7 +598,7 @@260self.assertEqual(widget.selection_element(), "buttondown")261262263-@add_standard_options(StandardOptionsTests)264+@add_configure_tests(StandardOptionsTests)265class TextTest(AbstractWidgetTest, unittest.TestCase):266OPTIONS = (267'autoseparators', 'background', 'blockcursor', 'borderwidth',268@@ -574,6 +613,9 @@269'tabs', 'tabstyle', 'takefocus', 'undo', 'width', 'wrap',270'xscrollcommand', 'yscrollcommand',271)272+ _rounds_pixels = (tk_version < (9, 0))273+ _no_round = {'selectborderwidth'}274+ _clipped = {'highlightthickness'}275276def create(self, **kwargs):277return tkinter.Text(self.root, **kwargs)278@@ -602,8 +644,10 @@279def test_configure_height(self):280widget = self.create()281self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c')282- self.checkParam(widget, 'height', -100, expected=1)283- self.checkParam(widget, 'height', 0, expected=1)284+ self.checkParam(widget, 'height', -100,285+ expected=1 if tk_version < (9, 0) else -100)286+ self.checkParam(widget, 'height', 0,287+ expected=1 if tk_version < (9, 0) else 0 )288289def test_configure_maxundo(self):290widget = self.create()291@@ -696,7 +740,7 @@292self.assertRaises(TypeError, widget.bbox, '1.1', 'end')293294295-@add_standard_options(PixelSizeTests, StandardOptionsTests)296+@add_configure_tests(PixelSizeTests, StandardOptionsTests)297class CanvasTest(AbstractWidgetTest, unittest.TestCase):298OPTIONS = (299'background', 'borderwidth',300@@ -710,8 +754,15 @@301'xscrollcommand', 'xscrollincrement',302'yscrollcommand', 'yscrollincrement', 'width',303)304-305- _conv_pixels = round306+ _rounds_pixels = True307+ if tk_version < (9, 0):308+ _noround = {}309+ _clipped = {'highlightthickness'}310+ else:311+ _no_round = {'borderwidth', 'height', 'highlightthickness', 'width',312+ 'xscrollincrement', 'yscrollincrement'}313+ _clipped = {'borderwidth', 'height', 'highlightthickness', 'width',314+ 'xscrollincrement', 'yscrollincrement'}315_stringify = True316317def create(self, **kwargs):318@@ -953,7 +1004,7 @@319self.assertEqual(y2_2 - y1_2, y2_3 - y1_3)320321322-@add_standard_options(IntegerSizeTests, StandardOptionsTests)323+@add_configure_tests(IntegerSizeTests, StandardOptionsTests)324class ListboxTest(AbstractWidgetTest, unittest.TestCase):325OPTIONS = (326'activestyle', 'background', 'borderwidth', 'cursor',327@@ -965,6 +1016,11 @@328'selectmode', 'setgrid', 'state',329'takefocus', 'width', 'xscrollcommand', 'yscrollcommand',330)331+ _rounds_pixels = (tk_version < (9, 0))332+ if tk_version < (9, 0):333+ _clipped = {'highlightthickness'}334+ else:335+ _clipped = { 'borderwidth', 'highlightthickness', 'selectborderwidth'}336337def create(self, **kwargs):338return tkinter.Listbox(self.root, **kwargs)339@@ -1091,7 +1147,7 @@340self.assertRaises(TclError, lb.get, 2.4)341342343-@add_standard_options(PixelSizeTests, StandardOptionsTests)344+@add_configure_tests(PixelSizeTests, StandardOptionsTests)345class ScaleTest(AbstractWidgetTest, unittest.TestCase):346OPTIONS = (347'activebackground', 'background', 'bigincrement', 'borderwidth',348@@ -1102,6 +1158,8 @@349'resolution', 'showvalue', 'sliderlength', 'sliderrelief', 'state',350'takefocus', 'tickinterval', 'to', 'troughcolor', 'variable', 'width',351)352+ _rounds_pixels = (tk_version < (9, 0))353+ _clipped = {'highlightthickness'}354default_orient = 'vertical'355356def create(self, **kwargs):357@@ -1159,7 +1217,7 @@358conv=float_round)359360361-@add_standard_options(PixelSizeTests, StandardOptionsTests)362+@add_configure_tests(PixelSizeTests, StandardOptionsTests)363class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):364OPTIONS = (365'activebackground', 'activerelief',366@@ -1170,7 +1228,14 @@367'repeatdelay', 'repeatinterval',368'takefocus', 'troughcolor', 'width',369)370- _conv_pixels = round371+ _rounds_pixels = True372+ if tk_version >= (9, 0):373+ _no_round = {'borderwidth', 'elementborderwidth', 'highlightthickness',374+ 'width'}375+ if tk_version < (9, 0):376+ _clipped = {'highlightthickness'}377+ else:378+ _clipped = {'borderwidth', 'highlightthickness', 'width'}379_stringify = True380default_orient = 'vertical'381382@@ -1208,7 +1273,7 @@383self.assertRaises(TypeError, sb.set, 0.6, 0.7, 0.8)384385386-@add_standard_options(StandardOptionsTests)387+@add_configure_tests(StandardOptionsTests)388class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):389OPTIONS = (390'background', 'borderwidth', 'cursor',391@@ -1219,6 +1284,15 @@392'sashcursor', 'sashpad', 'sashrelief', 'sashwidth',393'showhandle', 'width',394)395+ _rounds_pixels = True396+ if tk_version < (9, 0):397+ _no_round = {'handlesize', 'height', 'proxyborderwidth', 'sashwidth',398+ 'selectborderwidth', 'width'}399+ else:400+ _no_round = {'borderwidth', 'handlepad', 'handlesize', 'height',401+ 'proxyborderwidth', 'sashpad', 'sashwidth',402+ 'selectborderwidth', 'width'}403+ _clipped = {}404default_orient = 'horizontal'405406def create(self, **kwargs):407@@ -1347,13 +1421,13 @@408409def test_paneconfigure_padx(self):410p, b, c = self.create2()411- self.check_paneconfigure(p, b, 'padx', 1.3, 1)412+ self.check_paneconfigure(p, b, 'padx', 1.3, 1 if tk_version < (9, 0) else 1.3)413self.check_paneconfigure_bad(p, b, 'padx',414EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue'))415416def test_paneconfigure_pady(self):417p, b, c = self.create2()418- self.check_paneconfigure(p, b, 'pady', 1.3, 1)419+ self.check_paneconfigure(p, b, 'pady', 1.3, 1 if tk_version < (9, 0) else 1.3)420self.check_paneconfigure_bad(p, b, 'pady',421EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue'))422423@@ -1379,17 +1453,17 @@424EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue'))425426427-@add_standard_options(StandardOptionsTests)428+@add_configure_tests(StandardOptionsTests)429class MenuTest(AbstractWidgetTest, unittest.TestCase):430OPTIONS = (431'activebackground', 'activeborderwidth', 'activeforeground',432- 'activerelief',433- 'background', 'borderwidth', 'cursor',434+ 'activerelief', 'background', 'borderwidth', 'cursor',435'disabledforeground', 'font', 'foreground',436'postcommand', 'relief', 'selectcolor', 'takefocus',437'tearoff', 'tearoffcommand', 'title', 'type',438)439- _conv_pixels = False440+ _rounds_pixels = False441+ _clipped = {}442443def create(self, **kwargs):444return tkinter.Menu(self.root, **kwargs)445@@ -1458,7 +1532,7 @@446self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2))447448449-@add_standard_options(PixelSizeTests, StandardOptionsTests)450+@add_configure_tests(PixelSizeTests, StandardOptionsTests)451class MessageTest(AbstractWidgetTest, unittest.TestCase):452OPTIONS = (453'anchor', 'aspect', 'background', 'borderwidth',454@@ -1467,11 +1541,12 @@455'justify', 'padx', 'pady', 'relief',456'takefocus', 'text', 'textvariable', 'width',457)458- _conv_pad_pixels = False459- if tk_version >= (8, 7):460- _conv_pixels = False461- _clip_pad = tk_version >= (8, 7)462- _clip_borderwidth = tk_version >= (8, 7)463+ _rounds_pixels = (tk_version < (9, 0))464+ _no_round = {'padx', 'pady'}465+ if tk_version < (9, 0):466+ _clipped = {'highlightthickness'}467+ else:468+ _clipped = {'borderwidth', 'highlightthickness', 'padx', 'pady'}469470def create(self, **kwargs):471return tkinter.Message(self.root, **kwargs)472@@ -1482,16 +1557,14 @@473474def test_configure_padx(self):475widget = self.create()476- self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m',477- conv=self._conv_pad_pixels)478- expected = self._default_pixels if self._clip_pad else -2479+ self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')480+ expected = -2 if tk_version < (9, 0) else self._default_pixels481self.checkParam(widget, 'padx', -2, expected=expected)482483def test_configure_pady(self):484widget = self.create()485- self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m',486- conv=self._conv_pad_pixels)487- expected = self._default_pixels if self._clip_pad else -2488+ self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')489+ expected = -2 if tk_version < (9, 0) else self._default_pixels490self.checkParam(widget, 'pady', -2, expected=expected)491492def test_configure_width(self):493diff -ru Orig/Lib/test/test_tkinter/widget_tests.py Python-3.13.1/Lib/test/test_tkinter/widget_tests.py494--- Orig/Lib/test/test_tkinter/widget_tests.py 2024-12-03 11:59:52495+++ Python-3.13.1/Lib/test/test_tkinter/widget_tests.py 2024-12-12 12:57:15496@@ -6,17 +6,16 @@497pixels_conv, tcl_obj_eq)498import test.support499500-501_sentinel = object()502503+# Options which accept all values allowed by Tk_GetPixels504+# borderwidth = bd505+506class AbstractWidgetTest(AbstractTkTest):507- _default_pixels = '' if tk_version >= (9, 0) else -1 if tk_version >= (8, 7) else ''508- _conv_pixels = round509- _conv_pad_pixels = None510- _stringify = False511- _clip_highlightthickness = True512- _clip_pad = False513- _clip_borderwidth = False514+ _default_pixels = '' # Value for unset pixel options.515+ _rounds_pixels = True # True if some pixel options are rounded.516+ _no_round = {} # Pixel options which are not rounded nonetheless517+ _stringify = False # Whether to convert tuples to strings518_allow_empty_justify = False519520@property521@@ -44,6 +43,9 @@522widget[name] = value523if expected is _sentinel:524expected = value525+ if name in self._clipped:526+ if not isinstance(expected, str):527+ expected = max(expected, 0)528if conv:529expected = conv(expected)530if self._stringify or not self.wantobjects:531@@ -140,14 +142,17 @@532errmsg = 'bad' + errmsg2533self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg)534535- def checkPixelsParam(self, widget, name, *values,536- conv=None, **kwargs):537- if conv is None:538- conv = self._conv_pixels539+ def checkPixelsParam(self, widget, name, *values, conv=None, **kwargs):540+ if not self._rounds_pixels or name in self._no_round:541+ conv = False542+ elif conv != str:543+ conv = round544for value in values:545expected = _sentinel546conv1 = conv547if isinstance(value, str):548+ if not getattr(self, '_converts_pixels', True):549+ conv1 = str550if conv1 and conv1 is not str:551expected = pixels_conv(value) * self.scaling552conv1 = round553@@ -172,8 +177,12 @@554def checkImageParam(self, widget, name):555image = tkinter.PhotoImage(master=self.root, name='image1')556self.checkParam(widget, name, image, conv=str)557+ if tk_version < (9, 0):558+ errmsg = 'image "spam" doesn\'t exist'559+ else:560+ errmsg = 'image "spam" does not exist'561self.checkInvalidParam(widget, name, 'spam',562- errmsg='image "spam" doesn\'t exist')563+ errmsg=errmsg)564widget[name] = ''565566def checkVariableParam(self, widget, name, var):567@@ -215,31 +224,80 @@568print('%s.OPTIONS doesn\'t contain "%s"' %569(self.__class__.__name__, k))570571+class PixelOptionsTests:572+ """Standard options that accept all formats acceptable to Tk_GetPixels.573574-class StandardOptionsTests:575- STANDARD_OPTIONS = (576- 'activebackground', 'activeborderwidth', 'activeforeground', 'anchor',577- 'background', 'bitmap', 'borderwidth', 'compound', 'cursor',578- 'disabledforeground', 'exportselection', 'font', 'foreground',579- 'highlightbackground', 'highlightcolor', 'highlightthickness',580- 'image', 'insertbackground', 'insertborderwidth',581- 'insertofftime', 'insertontime', 'insertwidth',582- 'jump', 'justify', 'orient', 'padx', 'pady', 'relief',583- 'repeatdelay', 'repeatinterval',584- 'selectbackground', 'selectborderwidth', 'selectforeground',585- 'setgrid', 'takefocus', 'text', 'textvariable', 'troughcolor',586- 'underline', 'wraplength', 'xscrollcommand', 'yscrollcommand',587- )588+ In addition to numbers, these options can be set with distances589+ specified as a string consisting of a number followed by a single590+ character giving the unit of distance. The allowed units are:591+ millimeters ('m'), centimeters ('c'), inches ('i') or points ('p').592+ In Tk 9 a cget call for one of these options returns a Tcl_Obj of593+ type "pixels", whose string representation is the distance string594+ passed to configure.595+ """596+ PIXEL_OPTIONS = ('activeborderwidth', 'borderwidth', 'highlightthickness',597+ 'insertborderwidth', 'insertwidth', 'padx', 'pady', 'selectborderwidth')598599- def test_configure_activebackground(self):600- widget = self.create()601- self.checkColorParam(widget, 'activebackground')602-603def test_configure_activeborderwidth(self):604widget = self.create()605self.checkPixelsParam(widget, 'activeborderwidth',6060, 1.3, 2.9, 6, -2, '10p')607608+ def test_configure_borderwidth(self):609+ widget = self.create()610+ self.checkPixelsParam(widget, 'borderwidth',611+ 0, 1.3, 2.6, 6, '10p')612+ self.checkParam(widget, 'borderwidth', -2)613+ if 'bd' in self.OPTIONS:614+ self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, '10p')615+ self.checkParam(widget, 'bd', -2, expected=expected)616+617+ def test_configure_highlightthickness(self):618+ widget = self.create()619+ self.checkPixelsParam(widget, 'highlightthickness',620+ 0, 1.3, 2.6, 6, '10p')621+ self.checkParam(widget, 'highlightthickness', -2)622+623+ def test_configure_insertborderwidth(self):624+ widget = self.create()625+ self.checkPixelsParam(widget, 'insertborderwidth',626+ 0, 1.3, 2.6, 6, '10p')627+ self.checkParam(widget, 'insertborderwidth', -2)628+629+ def test_configure_insertwidth(self):630+ widget = self.create()631+ self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p')632+633+ def test_configure_padx(self):634+ widget = self.create()635+ self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')636+ self.checkParam(widget, 'padx', -2)637+638+ def test_configure_pady(self):639+ widget = self.create()640+ self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')641+ self.checkParam(widget, 'pady', -2)642+643+ def test_configure_selectborderwidth(self):644+ widget = self.create()645+ self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p')646+647+class StandardOptionsTests(PixelOptionsTests):648+649+ STANDARD_OPTIONS = ( 'activebackground', 'activeforeground',650+ 'anchor', 'background', 'bitmap', 'compound', 'cursor',651+ 'disabledforeground', 'exportselection', 'font', 'foreground',652+ 'highlightbackground', 'highlightcolor', 'image',653+ 'insertbackground', 'insertofftime', 'insertontime', 'jump',654+ 'justify', 'orient', 'relief', 'repeatdelay', 'repeatinterval',655+ 'selectbackground', 'selectforeground', 'setgrid', 'takefocus',656+ 'text', 'textvariable', 'troughcolor', 'underline', 'wraplength',657+ 'xscrollcommand', 'yscrollcommand', ) + PixelOptionsTests.PIXEL_OPTIONS658+659+ def test_configure_activebackground(self):660+ widget = self.create()661+ self.checkColorParam(widget, 'activebackground')662+663def test_configure_activeforeground(self):664widget = self.create()665self.checkColorParam(widget, 'activeforeground')666@@ -277,18 +335,6 @@667self.checkInvalidParam(widget, 'bitmap', 'spam',668errmsg='bitmap "spam" not defined')669670- def test_configure_borderwidth(self):671- widget = self.create()672- self.checkPixelsParam(widget, 'borderwidth',673- 0, 1.3, 2.6, 6, '10p')674- expected = 0 if self._clip_borderwidth else -2675- self.checkParam(widget, 'borderwidth', -2, expected=expected,676- conv=self._conv_pixels)677- if 'bd' in self.OPTIONS:678- self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, '10p')679- self.checkParam(widget, 'bd', -2, expected=expected,680- conv=self._conv_pixels)681-682def test_configure_compound(self):683widget = self.create()684self.checkEnumParam(widget, 'compound',685@@ -312,8 +358,8 @@686'-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*')687is_ttk = widget.__class__.__module__ == 'tkinter.ttk'688if not is_ttk:689- self.checkInvalidParam(widget, 'font', '',690- errmsg='font "" doesn\'t exist')691+ errmsg = 'font "" does ?n[o\']t exist'692+ self.checkInvalidParam(widget, 'font', '', errmsg=errmsg)693694def test_configure_foreground(self):695widget = self.create()696@@ -329,14 +375,6 @@697widget = self.create()698self.checkColorParam(widget, 'highlightcolor')699700- def test_configure_highlightthickness(self):701- widget = self.create()702- self.checkPixelsParam(widget, 'highlightthickness',703- 0, 1.3, 2.6, 6, '10p')704- expected = 0 if self._clip_highlightthickness else -2705- self.checkParam(widget, 'highlightthickness', -2, expected=expected,706- conv=self._conv_pixels)707-708def test_configure_image(self):709widget = self.create()710self.checkImageParam(widget, 'image')711@@ -345,11 +383,6 @@712widget = self.create()713self.checkColorParam(widget, 'insertbackground')714715- def test_configure_insertborderwidth(self):716- widget = self.create()717- self.checkPixelsParam(widget, 'insertborderwidth',718- 0, 1.3, 2.6, 6, -2, '10p')719-720def test_configure_insertofftime(self):721widget = self.create()722self.checkIntegerParam(widget, 'insertofftime', 100)723@@ -358,10 +391,6 @@724widget = self.create()725self.checkIntegerParam(widget, 'insertontime', 100)726727- def test_configure_insertwidth(self):728- widget = self.create()729- self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p')730-731def test_configure_jump(self):732widget = self.create()733self.checkBooleanParam(widget, 'jump')734@@ -379,22 +408,6 @@735self.assertEqual(str(widget['orient']), self.default_orient)736self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical')737738- def test_configure_padx(self):739- widget = self.create()740- self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m',741- conv=self._conv_pad_pixels)742- expected = 0 if self._clip_pad else -2743- self.checkParam(widget, 'padx', -2, expected=expected,744- conv=self._conv_pad_pixels)745-746- def test_configure_pady(self):747- widget = self.create()748- self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m',749- conv=self._conv_pad_pixels)750- expected = 0 if self._clip_pad else -2751- self.checkParam(widget, 'pady', -2, expected=expected,752- conv=self._conv_pad_pixels)753-754@requires_tk(8, 7)755def test_configure_placeholder(self):756widget = self.create()757@@ -421,10 +434,6 @@758widget = self.create()759self.checkColorParam(widget, 'selectbackground')760761- def test_configure_selectborderwidth(self):762- widget = self.create()763- self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p')764-765def test_configure_selectforeground(self):766widget = self.create()767self.checkColorParam(widget, 'selectforeground')768@@ -534,6 +543,7 @@769770771class IntegerSizeTests:772+ """ Tests widgets which only accept integral width and height."""773def test_configure_height(self):774widget = self.create()775self.checkIntegerParam(widget, 'height', 100, -100, 0)776@@ -544,6 +554,7 @@777778779class PixelSizeTests:780+ """ Tests widgets which accept screen distances for width and height."""781def test_configure_height(self):782widget = self.create()783self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c')784@@ -553,7 +564,7 @@785self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i')786787788-def add_standard_options(*source_classes):789+def add_configure_tests(*source_classes):790# This decorator adds test_configure_xxx methods from source classes for791# every xxx option in the OPTIONS class attribute if they are not defined792# explicitly.793diff -ru Orig/Lib/test/test_ttk/test_style.py Python-3.13.1/Lib/test/test_ttk/test_style.py794--- Orig/Lib/test/test_ttk/test_style.py 2024-12-03 11:59:52795+++ Python-3.13.1/Lib/test/test_ttk/test_style.py 2024-12-12 12:57:15796@@ -205,7 +205,8 @@797style = self.style798with self.assertRaises(IndexError):799style.element_create('plain.newelem', 'from')800- with self.assertRaisesRegex(TclError, 'theme "spam" doesn\'t exist'):801+ with self.assertRaisesRegex(TclError,802+ 'theme "spam" (does not|doesn\'t) exist'):803style.element_create('plain.newelem', 'from', 'spam')804805def test_element_create_image(self):806diff -ru Orig/Lib/test/test_ttk/test_widgets.py Python-3.13.1/Lib/test/test_ttk/test_widgets.py807--- Orig/Lib/test/test_ttk/test_widgets.py 2024-12-03 11:59:52808+++ Python-3.13.1/Lib/test/test_ttk/test_widgets.py 2024-12-12 13:00:29809@@ -8,7 +8,7 @@810from test.test_tkinter.support import (811AbstractTkTest, requires_tk, tk_version, get_tk_patchlevel,812simulate_mouse_click, AbstractDefaultRootTest)813-from test.test_tkinter.widget_tests import (add_standard_options,814+from test.test_tkinter.widget_tests import (add_configure_tests,815AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests)816817requires('gui')818@@ -125,10 +125,11 @@819820821class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):822- _conv_pixels = False823+ _rounds_pixels = False824+ _clipped = {}825826827-@add_standard_options(StandardTtkOptionsTests)828+@add_configure_tests(StandardTtkOptionsTests)829class FrameTest(AbstractToplevelTest, unittest.TestCase):830OPTIONS = (831'borderwidth', 'class', 'cursor', 'height',832@@ -140,7 +141,7 @@833return ttk.Frame(self.root, **kwargs)834835836-@add_standard_options(StandardTtkOptionsTests)837+@add_configure_tests(StandardTtkOptionsTests)838class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):839OPTIONS = (840'borderwidth', 'class', 'cursor', 'height',841@@ -168,6 +169,8 @@842843class AbstractLabelTest(AbstractWidgetTest):844_allow_empty_justify = True845+ _rounds_pixels = False846+ _clipped = {}847848def checkImageParam(self, widget, name):849image = tkinter.PhotoImage(master=self.root, name='image1')850@@ -179,8 +182,11 @@851expected=('image1', 'active', 'image2'))852self.checkParam(widget, name, 'image1 active image2',853expected=('image1', 'active', 'image2'))854- self.checkInvalidParam(widget, name, 'spam',855- errmsg='image "spam" doesn\'t exist')856+ if tk_version < (9, 0):857+ errmsg = 'image "spam" doesn\'t exist'858+ else:859+ errmsg = 'image "spam" does not exist'860+ self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg)861862def test_configure_compound(self):863values = ('none', 'text', 'image', 'center', 'top', 'bottom', 'left', 'right')864@@ -196,7 +202,7 @@865self.checkParams(widget, 'width', 402, -402, 0)866867868-@add_standard_options(StandardTtkOptionsTests)869+@add_configure_tests(StandardTtkOptionsTests)870class LabelTest(AbstractLabelTest, unittest.TestCase):871OPTIONS = (872'anchor', 'background', 'borderwidth',873@@ -214,7 +220,7 @@874test_configure_justify = StandardOptionsTests.test_configure_justify875876877-@add_standard_options(StandardTtkOptionsTests)878+@add_configure_tests(StandardTtkOptionsTests)879class ButtonTest(AbstractLabelTest, unittest.TestCase):880OPTIONS = (881'class', 'command', 'compound', 'cursor', 'default',882@@ -239,7 +245,7 @@883self.assertTrue(success)884885886-@add_standard_options(StandardTtkOptionsTests)887+@add_configure_tests(StandardTtkOptionsTests)888class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):889OPTIONS = (890'class', 'command', 'compound', 'cursor',891@@ -326,7 +332,7 @@892self.assertEqual(len(set(variables)), len(buttons), variables)893894895-@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests)896+@add_configure_tests(IntegerSizeTests, StandardTtkOptionsTests)897class EntryTest(AbstractWidgetTest, unittest.TestCase):898OPTIONS = (899'background', 'class', 'cursor',900@@ -338,6 +344,8 @@901)902# bpo-27313: macOS Tk/Tcl may or may not report 'Entry.field'.903IDENTIFY_AS = {'Entry.field', 'textarea'}904+ _rounds_pixels = False905+ _clipped = {}906907def setUp(self):908super().setUp()909@@ -371,8 +379,12 @@910self.assertRaises(tkinter.TclError, self.entry.bbox, None)911912def test_identify(self):913+ if (tk_version >= (9, 0) and sys.platform == 'darwin'914+ and isinstance(self.entry, ttk.Combobox)):915+ self.skipTest('Test does not work on macOS Tk 9.')916+ # https://core.tcl-lang.org/tk/tktview/8b49e9cfa6917self.entry.pack()918- self.entry.update()919+ self.root.update()920921self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS)922self.assertEqual(self.entry.identify(-1, -1), "")923@@ -450,7 +462,7 @@924self.assertEqual(self.entry.state(), ())925926927-@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests)928+@add_configure_tests(IntegerSizeTests, StandardTtkOptionsTests)929class ComboboxTest(EntryTest, unittest.TestCase):930OPTIONS = (931'background', 'class', 'cursor', 'exportselection',932@@ -479,11 +491,14 @@933x, y = width - 5, 5934if sys.platform != 'darwin': # there's no down arrow on macOS935self.assertRegex(self.combo.identify(x, y), r'.*downarrow\Z')936- self.combo.event_generate('<ButtonPress-1>', x=x, y=y)937+ self.combo.event_generate('<Button-1>', x=x, y=y)938self.combo.event_generate('<ButtonRelease-1>', x=x, y=y)939- self.combo.update_idletasks()940941def test_virtual_event(self):942+ if (tk_version >= (9, 0) and sys.platform == 'darwin'943+ and isinstance(self.entry, ttk.Combobox)):944+ self.skipTest('Test does not work on macOS Tk 9.')945+ # https://core.tcl-lang.org/tk/tktview/8b49e9cfa6946success = []947948self.combo['values'] = [1]949@@ -501,6 +516,10 @@950self.assertTrue(success)951952def test_configure_postcommand(self):953+ if (tk_version >= (9, 0) and sys.platform == 'darwin'954+ and isinstance(self.entry, ttk.Combobox)):955+ self.skipTest('Test does not work on macOS Tk 9.')956+ # https://core.tcl-lang.org/tk/tktview/8b49e9cfa6957success = []958959self.combo['postcommand'] = lambda: success.append(True)960@@ -576,12 +595,14 @@961combo2.destroy()962963964-@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests)965+@add_configure_tests(IntegerSizeTests, StandardTtkOptionsTests)966class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):967OPTIONS = (968'class', 'cursor', 'height',969'orient', 'style', 'takefocus', 'width',970)971+ _rounds_pixels = False972+ _clipped = {}973974def setUp(self):975super().setUp()976@@ -712,7 +733,7 @@977self.assertIsInstance(self.paned.sashpos(0), int)978979980-@add_standard_options(StandardTtkOptionsTests)981+@add_configure_tests(StandardTtkOptionsTests)982class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):983OPTIONS = (984'class', 'command', 'compound', 'cursor',985@@ -791,13 +812,14 @@986menu.destroy()987988989-@add_standard_options(StandardTtkOptionsTests)990+@add_configure_tests(StandardTtkOptionsTests)991class ScaleTest(AbstractWidgetTest, unittest.TestCase):992OPTIONS = (993'class', 'command', 'cursor', 'from', 'length',994'orient', 'state', 'style', 'takefocus', 'to', 'value', 'variable',995)996- _conv_pixels = False997+ _rounds_pixels = False998+ _clipped = {}999default_orient = 'horizontal'10001001def setUp(self):1002@@ -899,7 +921,7 @@1003self.assertRaises(tkinter.TclError, self.scale.set, None)100410051006-@add_standard_options(StandardTtkOptionsTests)1007+@add_configure_tests(StandardTtkOptionsTests)1008class ProgressbarTest(AbstractWidgetTest, unittest.TestCase):1009OPTIONS = (1010'anchor', 'class', 'cursor', 'font', 'foreground', 'justify',1011@@ -907,7 +929,8 @@1012'mode', 'maximum', 'phase', 'text', 'wraplength',1013'style', 'takefocus', 'value', 'variable',1014)1015- _conv_pixels = False1016+ _rounds_pixels = False1017+ _clipped = {}1018_allow_empty_justify = True1019default_orient = 'horizontal'10201021@@ -952,24 +975,27 @@10221023@unittest.skipIf(sys.platform == 'darwin',1024'ttk.Scrollbar is special on MacOSX')1025-@add_standard_options(StandardTtkOptionsTests)1026+@add_configure_tests(StandardTtkOptionsTests)1027class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):1028OPTIONS = (1029'class', 'command', 'cursor', 'orient', 'style', 'takefocus',1030)1031+ _rounds_pixels = False1032+ _clipped = {}1033default_orient = 'vertical'10341035def create(self, **kwargs):1036return ttk.Scrollbar(self.root, **kwargs)103710381039-@add_standard_options(StandardTtkOptionsTests)1040+@add_configure_tests(StandardTtkOptionsTests)1041class NotebookTest(AbstractWidgetTest, unittest.TestCase):1042OPTIONS = (1043'class', 'cursor', 'height', 'padding', 'style', 'takefocus', 'width',1044)1045- if tk_version >= (8, 7):1046- _conv_pixels = False1047+ _rounds_pixels = (tk_version < (9,0))1048+ _converts_pixels = False1049+ _clipped = {}10501051def setUp(self):1052super().setUp()1053@@ -987,14 +1013,14 @@1054if get_tk_patchlevel(self.root) < (8, 6, 15):1055self.checkIntegerParam(widget, 'height', 402, -402, 0)1056else:1057- self.checkPixelsParam(widget, 'height', '10c', 402, -402, 0, conv=False)1058+ self.checkPixelsParam(widget, 'height', '10c', 402, -402, 0)10591060def test_configure_width(self):1061widget = self.create()1062if get_tk_patchlevel(self.root) < (8, 6, 15):1063self.checkIntegerParam(widget, 'width', 402, -402, 0)1064else:1065- self.checkPixelsParam(widget, 'width', '10c', 402, -402, 0, conv=False)1066+ self.checkPixelsParam(widget, 'width', '10c', 402, -402, 0)10671068def test_tab_identifiers(self):1069self.nb.forget(0)1070@@ -1160,7 +1186,12 @@10711072self.nb.select(0)10731074- focus_identify_as = 'focus' if sys.platform != 'darwin' else ''1075+ if sys.platform == 'darwin':1076+ focus_identify_as = ''1077+ elif sys.platform == 'win32':1078+ focus_identify_as = 'focus'1079+ else:1080+ focus_identify_as = 'focus' if tk_version < (9,0) else 'padding'1081self.assertEqual(self.nb.identify(5, 5), focus_identify_as)1082simulate_mouse_click(self.nb, 5, 5)1083self.nb.focus_force()1084@@ -1193,7 +1224,7 @@1085self.assertEqual(self.nb.select(), str(self.child2))108610871088-@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests)1089+@add_configure_tests(IntegerSizeTests, StandardTtkOptionsTests)1090class SpinboxTest(EntryTest, unittest.TestCase):1091OPTIONS = (1092'background', 'class', 'command', 'cursor', 'exportselection',1093@@ -1370,7 +1401,7 @@1094spin2.destroy()109510961097-@add_standard_options(StandardTtkOptionsTests)1098+@add_configure_tests(StandardTtkOptionsTests)1099class TreeviewTest(AbstractWidgetTest, unittest.TestCase):1100OPTIONS = (1101'class', 'columns', 'cursor', 'displaycolumns',1102@@ -1378,6 +1409,8 @@1103'style', 'takefocus', 'titlecolumns', 'titleitems',1104'xscrollcommand', 'yscrollcommand',1105)1106+ _rounds_pixels = False1107+ _clipped = {}11081109def setUp(self):1110super().setUp()1111@@ -1413,8 +1446,10 @@11121113def test_configure_height(self):1114widget = self.create()1115- self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False)1116- self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=False)1117+ self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c',1118+ conv=False)1119+ self.checkPixelsParam(widget, 'height', 101.2, 102.6, '3c',1120+ conv=False)11211122def test_configure_selectmode(self):1123widget = self.create()1124@@ -1936,24 +1971,28 @@1125self.assertEqual(self.tv.tag_has('tag3'), ())112611271128-@add_standard_options(StandardTtkOptionsTests)1129+@add_configure_tests(StandardTtkOptionsTests)1130class SeparatorTest(AbstractWidgetTest, unittest.TestCase):1131OPTIONS = (1132'class', 'cursor', 'orient', 'style', 'takefocus',1133# 'state'?1134)1135+ _rounds_pixels = False1136+ _clipped = {}1137default_orient = 'horizontal'11381139def create(self, **kwargs):1140return ttk.Separator(self.root, **kwargs)114111421143-@add_standard_options(StandardTtkOptionsTests)1144+@add_configure_tests(StandardTtkOptionsTests)1145class SizegripTest(AbstractWidgetTest, unittest.TestCase):1146OPTIONS = (1147'class', 'cursor', 'style', 'takefocus',1148# 'state'?1149)1150+ _rounds_pixels = False1151+ _clipped = {}11521153def create(self, **kwargs):1154return ttk.Sizegrip(self.root, **kwargs)1155diff -ru Orig/Lib/tkinter/ttk.py Python-3.13.1/Lib/tkinter/ttk.py1156--- Orig/Lib/tkinter/ttk.py 2024-12-03 11:59:521157+++ Python-3.13.1/Lib/tkinter/ttk.py 2024-12-12 12:57:151158@@ -321,6 +321,8 @@1159elif hasattr(val, 'typename'): # some other (single) Tcl object1160val = _convert_stringval(val)11611162+ if isinstance(val, tuple) and len(val) == 0:1163+ return ''1164return val11651166def tclobjs_to_py(adict):1167diff -ru Orig/Modules/_tkinter.c Python-3.13.1/Modules/_tkinter.c1168--- Orig/Modules/_tkinter.c 2024-12-03 11:59:521169+++ Python-3.13.1/Modules/_tkinter.c 2024-12-12 12:57:151170@@ -325,6 +325,7 @@1171const Tcl_ObjType *ListType;1172const Tcl_ObjType *StringType;1173const Tcl_ObjType *UTF32StringType;1174+ const Tcl_ObjType *PixelType;1175} TkappObject;11761177#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)1178@@ -637,6 +638,7 @@1179v->ListType = Tcl_GetObjType("list");1180v->StringType = Tcl_GetObjType("string");1181v->UTF32StringType = Tcl_GetObjType("utf32string");1182+ v->PixelType = Tcl_GetObjType("pixel");11831184/* Delete the 'exit' command, which can screw things up */1185Tcl_DeleteCommand(v->interp, "exit");1186@@ -1236,7 +1238,8 @@1187}11881189if (value->typePtr == tkapp->StringType ||1190- value->typePtr == tkapp->UTF32StringType)1191+ value->typePtr == tkapp->UTF32StringType ||1192+ value->typePtr == tkapp->PixelType)1193{1194return unicodeFromTclObj(tkapp, value);1195}119611971198