util.attributeEditor module¶
A Tk dialog for viewing and editing the attributes of an AttributedObject (see util.attribute): one row per attribute – its value, type and inheritance restrictions – with the values it inherits shown above it. editAttrsBox() returns the edits; applyEditAttrsBox() applies them.
Created on Mar 17, 2025
Code author: Rob Kremer <robkremer@me.com>
- util.attributeEditor.GROUP_SEPARATOR = '/'¶
Attribute names are grouped, like folders, by the parts of their names between these (eg: “gui/label”).
- util.attributeEditor.GROUP_BACKGROUND = 'grey85'¶
The background of a group’s header line (see AttrEditor.makeGroupHeader()).
- util.attributeEditor.TREE_INDENT = 18¶
How far (in pixels) each level of the grouped attribute names is indented.
- util.attributeEditor.isHiddenKey(key: str) bool¶
- Parameters:
key (str) – An attribute’s name.
- Returns:
Whether the editor hides it: if any part of its name (see GROUP_SEPARATOR) starts with “.” – eg: “.openWindows” (hidden itself), “gui/.cache” (likewise, in the gui group), or “.internal/x” (in a hidden group). Such attributes are for the program, not the user, to edit.
- Return type:
bool
- util.attributeEditor.treeOrder(keys: list[str]) list[tuple[str, str, int]]¶
The order to show attributes in, grouped by the parts of their names (see GROUP_SEPARATOR), like a tree of folders: at each level, the names with no more separators first, then each group – its header, and then its own contents, likewise – all sorted (ignoring case). Eg: “a”, “b”, “a/a”, “a/b”, “a/a/a”, “a/a/b”, “b/a” are shown as:
a b a/ (a group) a/a a/b a/a/ (a group) a/a/a a/a/b b/ (a group) b/a
- Parameters:
keys (list[str]) – The attribute names.
- Returns:
(kind, name, depth) for each line: kind is “key” (name is an attribute’s name) or “group” (name is the group’s path, eg: “a/a”).
- Return type:
list[tuple[str, str, int]]
- util.attributeEditor.editAttrsBox(parent: Misc, attrs: AttributedObject, title='Attributes Editor', editKey: str | None = None, disabled: bool = False, displayValues: dict[str, Any] | None = None, hideColumns: Iterable[str] = (), listItemMakers: dict[str, Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]]] | None = None) dict[str, Attribute] | None¶
- Parameters:
parent – The parent widget
attrs – The AttributedObject object to be updated.
title – The title of the dialog window.
displayValues – [Optional] Values to show (and edit) for some keys in place of their stored values – eg: a fuller form of the value, which the caller interprets. A key counts as changed only if its value differs from what was shown.
- Returns:
An dict str->Attribute with any updates
displays an AttrsEditor or a HierarchicalAttrsEditor (depanding on whether attrs is an AttributedObject or a AttributedObject ) and updates the result to attrs .
- Parameters:
editKey (Optional[str])
disabled (bool)
hideColumns (Iterable[str]) – The columns not to show (see AttrEditor.HIDEABLE_COLUMNS).
listItemMakers (Optional[dict[str, ItemMaker]]) – For “list[str]” attributes: what their “Add…” does, by key (see ListEditor).
- util.attributeEditor.applyEditAttrsBox(parent: Misc, attrs: AttributedObject, title='Attributes Editor', editKey: str | None = None, hideColumns: Iterable[str] = (), listItemMakers: dict[str, Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]]] | None = None) None¶
Same as editAttrsBox, but applies the changes.
- Parameters:
parent (tk.Misc)
attrs (AttributedObject)
title (str)
editKey (Optional[str])
hideColumns (Iterable[str]) – The columns not to show (see AttrEditor.HIDEABLE_COLUMNS).
listItemMakers (Optional[dict[str, ItemMaker]]) – As for editAttrsBox().
- util.attributeEditor._updateWith(attrs: AttributedObject, attrChangeList)¶
- Parameters:
attrs (AttributedObject)
attrChangeList
- util.attributeEditor._keyedMessage(key: str, ex: Exception) str¶
An error message that names key exactly once.
- Parameters:
key (str)
ex (Exception)
- Returns:
- Return type:
str
- util.attributeEditor.getEditedAttrsCommandObj(parent: Widget, attrs: AttributedObject, title='Attributes Editor', editKey: str | None = None, disabled: bool = False)¶
- Returns:
An UpdateAttrsCommand object that displays an AttrsEditor or a HierarchicalAttrsEditor (depending on whether attrs is an AttributedObject or a HierarchicalAttributedObject ) with the appropriate do/undo properties.
- Parameters:
parent (tk.Widget)
attrs (AttributedObject)
title (str)
editKey (Optional[str])
disabled (bool)
- util.attributeEditor.clearGrid(widget: Widget, row=None, column=None)¶
- Parameters:
widget (tk.Widget)
row
column
- class util.attributeEditor.ChangeDescr(tkVar: Variable | None, editor: Widget | None, delete: bool, saveMethod: Callable, qual: Restriction | None = None)¶
Bases:
objectThe editor’s record of one attribute’s row: its Tk variable and widget, whether it’s to be deleted, and how to save it.
- tkVar: Variable | None¶
- editor: Widget | None¶
- delete: bool¶
- saveMethod: Callable¶
- typeLabel = None¶
- qual: Restriction | None = None¶
- getValue() Any¶
- Returns:
- Return type:
Any
- setValue(val: Any)¶
- Parameters:
val (Any)
- Returns:
- Return type:
- __init__(tkVar: Variable | None, editor: Widget | None, delete: bool, saveMethod: Callable, qual: Restriction | None = None) None¶
- util.attributeEditor.SYS_ATTRIBUTES = ['name']¶
Used to highlight the ‘system’ labels on the grid
- util.attributeEditor.ItemMaker = typing.Callable[[tkinter.Misc], str | None] | dict[str, typing.Callable[[tkinter.Misc], str | None]]¶
What a list editor’s “Add…” does (see ListEditor): given the editor, the item to add (or None); or several such, by their buttons’ labels (eg: “Add file…”, “Add URL…”).
- class util.attributeEditor.ListEditor(master, items: list[str], newItem: Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]] | None = None)¶
Bases:
FrameAn editor for a list of strings (an attribute of type “list[str]”): the items in order, in a list box, with buttons to add one, remove the selected one, and move it up or down (the order may matter: eg: super-models are searched in order). Double-click an item to edit it.
- MAX_HEIGHT = 6¶
The most items shown at once (the rest scroll).
- __init__(master, items: list[str], newItem: Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]] | None = None)¶
- Parameters:
master
items (list[str]) – The list (not changed: see getList()).
newItem (Optional[ItemMaker]) – What “Add…” does: given this editor (as a parent for any dialog), returns the item to add, or None to add nothing. By default, it asks for a string. Or several ways to add one, by their buttons’ labels (eg: {“Add file…”: …, “Add URL…”: …}): a button each.
- state: str¶
- buttons: dict[str, Button]¶
- _height(n: int) int¶
- getList() list[str]¶
- Returns:
The items, in order.
- Return type:
list[str]
- setList(items: list[str]) None¶
- Parameters:
items (list[str]) – The items to show, in order.
- _selected() int | None¶
- _select(i: int) None¶
- _updateButtons() None¶
- add(maker: Callable[[Misc], str | None] | None = None) None¶
“Add…”: add an item (see newItem) after the selected one, or at the end.
- Parameters:
maker (Optional[Callable[[tk.Misc], Optional[str]]]) – What makes it (one of newItem’s, if it has several); by default, the first.
- remove() None¶
“Remove”: remove the selected item.
- move(step: int) None¶
Move the selected item up (step -1) or down (1).
- Parameters:
step (int) – -1 or 1.
- editSelected() None¶
Edit the selected item’s text (on a double-click).
- config(**conf)¶
“state” (“normal” or “disabled”) applies to the whole editor; colours to the list box; anything else to the frame.
- configure(**conf)¶
“state” (“normal” or “disabled”) applies to the whole editor; colours to the list box; anything else to the frame.
- class util.attributeEditor.ColorEditor(master, var: StringVar, color: str)¶
Bases:
FrameAn editor for a colour value: a swatch that opens the system colour chooser, and a button to make it transparent.
- __init__(master, var: StringVar, color: str)¶
- Parameters:
master
var (tk.StringVar)
color (str)
- setTransparent()¶
- colorChooser()¶
- config(**conf)¶
- Parameters:
conf
- class util.attributeEditor.AttrEditor(parent, attrs: AttributedObject, title='Attribute Editor', disabled=False, displayValues: dict[str, Any] | None = None, hideColumns: Iterable[str] = (), listItemMakers: dict[str, Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]]] | None = None)¶
Bases:
ToplevelImplements a graphical editor for an AttributedObject of the form:
<editor lines> …
[<Message line>]
[<Answer line>]
<Add New Attribute button>
<Cancel button> <Save button>
where <editor lines> look like this:
<stat>
<label>
<value editor>
<type>
<note>
<button> <button>…
<stat>
<label>
<value editor>
<type>
<note>
<button> <button>…
If any attribute’s name has a “/” in it, the lines are grouped by the parts of the names, like folders (see treeOrder()): each group has a header line with a triangle that collapses or expands it, and each attribute is labelled with just the last part of its name, indented under its group.
The <Message line> and <Answer iine> are only visiable when the setMessage() or ask() methods are called.
- collapsedGroups: set[str] = {}¶
The groups collapsed when an editor was last closed: the next one starts with them collapsed too.
- HIDEABLE_COLUMNS: dict[str, str] = {'actions': 'cDel', 'note': 'cNote', 'qualifiers': 'cQuals', 'type': 'cKind'}¶
The columns that can be hidden (see hideColumns), by name: name -> the attribute holding the column’s number. (“qualifiers” – the inheritance restrictions – is only in a HierarchicalAttrEditor.)
- __init__(parent, attrs: AttributedObject, title='Attribute Editor', disabled=False, displayValues: dict[str, Any] | None = None, hideColumns: Iterable[str] = (), listItemMakers: dict[str, Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]]] | None = None)¶
- Parameters:
parent
attrs (AttributedObject)
title (str)
disabled (bool)
displayValues (Optional[dict[str, Any]])
hideColumns (Iterable[str]) – The columns not to show, by name (see HIDEABLE_COLUMNS): eg: (“type”, “qualifiers”, “note”) for settings, whose notes are their documentation – still shown as their names’ tooltips.
listItemMakers (Optional[dict[str, ItemMaker]]) – For “list[str]” attributes: what their “Add…” does, by key – eg: a file chooser (see ListEditor). By default, it asks for a string.
- listItemMakers: dict[str, Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]]]¶
- hideColumns: set[str]¶
The columns not shown (see _applyHiddenColumns()).
- displayValues: dict[str, Any]¶
Values shown for some keys in place of their stored ones (see editAttrsBox()).
- attrs: AttributedObject¶
- vars: dict[str, ChangeDescr]¶
- disabled: bool¶
- rows: int¶
- editKey: str | None¶
- editWidget: Widget | None¶
- noteEdits: dict[str, str]¶
Attributes’ notes as edited (see editNote()), by key: only those that have been.
- treeMode: bool¶
Whether the attributes are shown grouped by the parts of their names (see treeOrder()).
- _labels: dict[str, tuple[str, int]]¶
Each attribute’s label, and its depth in the tree (see makeNewEntry()).
- _groupSpans: dict[str, tuple[int, int]]¶
Each group’s rows in the grid – the first and the one after the last – below its header.
- _groupHeaders: dict[str, Label]¶
The widgets each collapsed group hid (see toggleGroup()), to show again when it’s expanded.
- rEditors: int¶
- rMessage: int¶
- rEnter: int¶
- rButtons1: int¶
- rButtons2: int¶
- rowsPerEntry: int¶
- EntryOffset: int¶
- cStatus: int¶
- cLabel: int¶
- cEdit: int¶
- cKind: int¶
- cNote: int¶
- cDel: int¶
- cspan: int¶
- outerSpan: int¶
- show(editKey: str | None = None)¶
- Parameters:
editKey – [Optional str] If present, set the edit focus to the editKey creating a local attribute if necessary.
- _validateUpdates() list[str]¶
Dry-run the validation setAttr() will apply to each changed attribute.
- Returns:
A message for each change that would be rejected.
- _onReturn(event: Event) str | None¶
<Return>: the default button – “Save Changes” (or “Dismiss”, if nothing can be edited) – except in a multi-line text (where it’s a new line), or while answering a question (see ask(): the answer’s own <Return>).
- Parameters:
event (tk.Event)
- Returns:
“break” if it was dealt with.
- Return type:
str | None
- _placeOverParent() None¶
Put this window over the middle of its parent’s window, so it’s seen where it was asked for – not at the window system’s default place, which may be behind the parent, or on another screen or desktop.
- dismiss()¶
Call this method to destroy the window. It will also release the modal window.
- addNewAttribute()¶
- _addNewAttribute2(event, name: str)¶
- Parameters:
event
name (str)
- _showEntry(key: str) None¶
Scroll the list of attributes to show key’s row, and put the focus in its value: eg: a new attribute, to type its value.
- Parameters:
key (str)
- deleteAttr(key, item, editor, row, button)¶
- Parameters:
key
item
editor
row
button
- typeInconsistent(event, ans, key, row, newType)¶
- Parameters:
event
ans
key
row
newType
- resetKind(kind, key, row, value: Any = NOVALUE)¶
Change key’s type to kind, with value (default: its current one) – which must suit kind (see _convertValue()).
- Parameters:
kind
key
row
value (Any)
- editTypeAnswer(button, event, ans, key, row)¶
- Parameters:
button
event
ans
key
row
- editType(b: Button, parent, key, typ, column, row)¶
- Parameters:
b (tk.Button)
parent
key
typ
column
row
- hasChanged(k: str) bool¶
- Parameters:
k (str)
- Returns:
- Return type:
bool
- save()¶
Stores a key/Attribute dictionary of all attributes that have been modified in the self.updatedKeys dictionary. In the case of deleted Attributes, the key maps to None .
- getEditorForType(parent: Any, key: str, typ: type | str | None, value: Any, keyExt, inhType: str | type | None = None) Any¶
- makeNewEntry(k, v, row, disabled, keyExt, inhType: type | str | None = None)¶
- Parameters:
k
v
row
disabled
keyExt
inhType (type | str | None)
- makeGroupHeader(path: str, depth: int, row: int) Label¶
The header line for a group of attributes (see treeOrder()): a triangle and the group’s name, indented by its depth. Clicking it collapses or expands the group (see toggleGroup()).
- Parameters:
path (str) – The group’s path, eg: “gui/colors”.
depth (int) – How deep the group is in the tree (0 at the top).
row (int) – Its row in the grid.
- Returns:
The header’s text (the triangle and name).
- Return type:
tk.Label
- toggleGroup(path: str, remember: bool = True) None¶
Collapse the group path – hide all the rows below its header, up to the end of the group – or, if it’s collapsed, expand it: show again what it hid. (A collapsed subgroup’s rows were hidden by the subgroup, so they stay hidden until it’s expanded too.)
- Parameters:
path (str) – The group’s path.
remember (bool) – Whether to remember the change for the next editor shown (see collapsedGroups).
- _noteFor(key: str, attr: Attribute, keyExt: str = '') str¶
- Parameters:
key (str) – The attribute’s name.
attr (Attribute) – The attribute shown on the line (its own, or the inherited one).
keyExt (str) – “” for the attribute’s own line; INHERIT_KEY_EXT for its inherited one.
- Returns:
The note to show for the line: as edited, if it has been; else the attribute’s own note, or failing that the one it inherits.
- Return type:
str
- makeNoteButton(key: str, attr: Attribute, row: int, readonly: bool, keyExt: str = '') Button¶
The button in the NOTE column, which shows the note in a pop-up (see editNote()): “note” if there is one, “+” if not. Its tooltip shows the note.
- Parameters:
key (str) – The attribute’s name.
attr (Attribute) – The attribute shown on the line.
row (int) – The line’s row in the grid.
readonly (bool) – Whether the note can only be read (eg: an inherited one).
keyExt (str) – “” for the attribute’s own line; INHERIT_KEY_EXT for its inherited one.
- Returns:
The button.
- Return type:
ttk.Button
- editNote(key: str, attr: Attribute, button: Button, readonly: bool, keyExt: str = '') None¶
Show the attribute’s note in a small pop-up text editor – or, if readonly, viewer. OK keeps the edited note (it’s saved with the other changes: see save()).
- Parameters:
key (str) – The attribute’s name.
attr (Attribute) – The attribute shown on the line.
button (ttk.Button) – The line’s note button (its text is updated).
readonly (bool) – Whether the note can only be read.
keyExt (str) – “” for the attribute’s own line; INHERIT_KEY_EXT for its inherited one.
- makeTitle(col: int, text: str, helpText: str, row: int, **kwargs)¶
- Parameters:
col (int)
text (str)
helpText (str)
row (int)
kwargs
- addTooltip(widget: Widget, helpText: str)¶
- Parameters:
widget (Widget)
helpText (str)
- _applyHiddenColumns() None¶
Take the widgets in the hidden columns (see hideColumns) off the grid – those made since last time too (eg: a new attribute’s row). Only widgets in just that column: not ones spanning it, like the separators and the groups’ header bands.
- makeHeader(row, **kwargs)¶
- Parameters:
row
kwargs
- makeEditor(parent, key, item, column, row, disabled, keyExt, inhType: str | type | None = None)¶
- Parameters:
parent
key
item
column
row
disabled
keyExt
inhType (str | type | None)
- Returns:
- Return type:
- makeButton(parent, key, item, text, command=None, **kwargs)¶
Unlike the other “make*() methods, this one takes a parent that is a frame that will be used as a pack() frame as opposed to the others that take a parent that’s a grid() frame.
- Parameters:
parent
key
item
text
command
kwargs
- Returns:
- Return type:
- makeLabel(parent, key, text, column, row, justify='e', padx: int | tuple[int, int] = 0, **kwargs)¶
- Parameters:
parent
key
text
column
row
justify
padx (int | tuple[int, int]) – Space to the left and right of it (eg: an indent).
kwargs
- Returns:
- Return type:
- makeKind(parent, key, typ: type | str, column, row, command, disabled, keyExt, inhType: str | type | None = None, **kwargs)¶
- setStatus(parent, key, text, column, row, command=None, button=None, **kwargs)¶
- Parameters:
parent
key
text
column
row
command
button
kwargs
- setMessage(text, hideButton=True, **kwargs)¶
- Parameters:
text
hideButton (bool)
kwargs
- clearMessage(*args)¶
- Parameters:
args
- ask(question: str, handler: Callable[[Event, str], Any], default=None, **kwargs)¶
Asks a question and waits for an answer input within the window. The user is expected to fill in the answer and hit <Return> (or <Tab>) to answer. If the focus is shifted to another widget, the question is removed (as if a “cancel” button was pressed.
If the user hits return, self.answer will be called, and the user’s input can be obtained using self.var.get()
- Parameters:
question – The text of the question.
handler – A Callable taking an event argument and a string argument containing the answer
kwargs – A dictionary of legal arguments to ttk.Text() which controls the attributes of the question Text widget.
default
- checkInt(newval)¶
- Parameters:
newval
- Returns:
- Return type:
- checkFloat(newval)¶
- Parameters:
newval
- Returns:
- Return type:
- conf(tkObj, **kwargs)¶
Configure the tk widget tkObj with each of the key/value pairs in kwargs one at a time catching printing any exceptions but otherwise ignoring failures.
- Parameters:
tkObj
kwargs
- class util.attributeEditor.HierarchicalAttrEditor(parent, attrs: AttributedObject, title='Attribute Editor', disabled=False, displayValues: dict[str, Any] | None = None, hideColumns: Iterable[str] = (), listItemMakers: dict[str, Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]]] | None = None)¶
Bases:
AttrEditorAn AttrEditor for an AttributedObject with supertypes: it shows each attribute’s inherited values (greyed, above its own) and its inheritance restrictions, which can be edited too.
- __init__(parent, attrs: AttributedObject, title='Attribute Editor', disabled=False, displayValues: dict[str, Any] | None = None, hideColumns: Iterable[str] = (), listItemMakers: dict[str, Callable[[Misc], str | None] | dict[str, Callable[[Misc], str | None]]] | None = None)¶
- Parameters:
parent
attrs (AttributedObject)
title (str)
disabled (bool)
displayValues (Optional[dict[str, Any]])
hideColumns (Iterable[str]) – As for AttrEditor.
listItemMakers (Optional[dict[str, ItemMaker]]) – As for AttrEditor.
- assertedKeys: set[str]¶
The keys of the inferred attributes whose “assert” button was pressed (see assertAttr()).
- makeNewEntry(k, v, row, disabled, keyExt, inhType: str | type | None = None)¶
- Parameters:
k
v
row
disabled
keyExt
inhType (str | type | None)
- assertAttr(key: str, button: Button) None¶
The “assert” button of an inferred attribute (see Attribute.inferred) was pressed: saving makes it an ordinary (given) attribute, with the same value (see save()).
- Parameters:
key (str) – The attribute’s key.
button (ttk.Button) – The button pressed.
- makeHeader(row, **kwargs)¶
- Parameters:
row
kwargs
- makeQuals(parent, key, quals: Restriction, column, row, disabled, keyExt, **kwargs)¶
- Parameters:
parent
key
quals (Restriction)
column
row
disabled
keyExt
kwargs
- hasChanged(k: str) bool¶
- Parameters:
k (str)
- Returns:
- Return type:
bool
- _effectiveRestriction(k: str, origAttr: Attribute | None) Restriction | None¶
- Returns:
The restriction the qualifier menu started with: the local one, or failing that the inherited one (see makeQuals()).
- Parameters:
k (str)
origAttr (Attribute | None)
- util.attributeEditor._convertValue(typ: str, text: str) Any¶
- Returns:
text (an editor’s value) as a value of the type named typ, or NOVALUE if it can’t be one. Text types take any text; “” isn’t a number or boolean.
- Parameters:
typ (str)
text (str)
- util.attributeEditor._defaultValue(typ: str) Any¶
A reasonable starting value for the type named typ.
- Parameters:
typ (str)
- Returns:
- Return type:
Any