This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author serhiy.storchaka
Recipients Pat Thoyts, patthoyts, serhiy.storchaka, terry.reedy
Date 2020-11-15.12:24:28
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1605443069.84.0.244506553544.issue42328@roundup.psfhosted.org>
In-reply-to
Content
Thank you for your examples Pat. Now it looks clearer to me.

Semantically this data in Tk is a sequence of pairs: states (which can be a single word or several words or empty) and default value.

>>> from tkinter import ttk
>>> style = ttk.Style()
>>> style.theme_use('clam')
>>> style.tk.eval(f'{style._name} map TCombobox -fieldbackground')
'{readonly focus} #4a6984 readonly #dcdad5'
>>> style.tk.eval(f'{style._name} map TNotebook.Tab -background')
'selected #dcdad5 {} #bab5ab'

Internally states represented in Tk as the StateSpec object. When automatically convert to Python it became the Tcl_Obj object with typename 'StateSpec'. Without postprocessing.

>>> style.tk.call(style._name, 'map', 'TCombobox', '-fieldbackground')
(<StateSpec object: 'readonly focus'>, '#4a6984', <StateSpec object: 'readonly'>, '#dcdad5')
>>> style.tk.call(style._name, 'map', 'TNotebook.Tab', '-background')
(<StateSpec object: 'selected'>, '#dcdad5', <StateSpec object: ''>, '#bab5ab')

Style.map() does postprocessing. It converts a sequence (with even items number) to a list of tuples. The last item of a tuple is the default value, and the rest are items of the StateSpec object.

>>> style.map('TCombobox', 'fieldbackground')
[('readonly', 'focus', '#4a6984'), ('readonly', '#dcdad5')]
>>> style.map('TNotebook.Tab', 'background')
[('selected', '#dcdad5'), ('#bab5ab',)]

But when set tkinter.wantobjects = 0 before running this example the result will be different, because StateSpec objects will be automatically represented as strings (it matches the behavior of initial versions of Tkinter):

>>> style.tk.call(style._name, 'map', 'TCombobox', '-fieldbackground')
'{readonly focus} #4a6984 readonly #dcdad5'
>>> style.tk.call(style._name, 'map', 'TNotebook.Tab', '-background')
'selected #dcdad5 {} #bab5ab'
>>> style.map('TCombobox', 'fieldbackground')
[('readonly focus', '#4a6984'), ('readonly', '#dcdad5')]
>>> style.map('TNotebook.Tab', 'background')
[('selected', '#dcdad5'), ('', '#bab5ab')]

The main problem is in representing an empty StateSpec. As every string in Python contains an empty string, {} can represent an empty sequence and a sequence containing single empty string. In Python, it can be no items before default value (like in ('#bab5ab',)) or a single item containing an empty string (like in ('', '#bab5ab')).

The former representation (an empty sequence) is default for the style.map() output, but it is rejected as the style.map() input (see state[0] in _mapdict_values). There are two ways to fix it: either change the output of style.map() (what PR 23241 does) or change the validation of the input. I think that the latter solution can be backported, but the former can be used only in the future Python version.
History
Date User Action Args
2020-11-15 12:24:30serhiy.storchakasetrecipients: + serhiy.storchaka, terry.reedy, Pat Thoyts, patthoyts
2020-11-15 12:24:29serhiy.storchakasetmessageid: <1605443069.84.0.244506553544.issue42328@roundup.psfhosted.org>
2020-11-15 12:24:29serhiy.storchakalinkissue42328 messages
2020-11-15 12:24:28serhiy.storchakacreate