Skip to content

Commit 1fdd378

Browse files
committed
Fix generic stuff
1 parent a9f7fe8 commit 1fdd378

File tree

3 files changed

+42
-35
lines changed

3 files changed

+42
-35
lines changed

tkclasswiz/object_frame/frame_base.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,20 @@ def get_cls_name(cls: Any, args: bool = False) -> str:
101101
the original class when the name cannot be obtained.
102102
If alias exists, alias is returned instead.
103103
"""
104-
if (alias := get_aliased_name(cls)) is not None:
104+
normal_cls = get_origin(cls) or cls
105+
if (alias := get_aliased_name(normal_cls)) is not None:
105106
return alias + f" ({name})"
106-
elif hasattr(cls, "__name__"):
107-
name = cls.__name__
108-
elif hasattr(cls, "_name") and cls._name:
109-
name = cls._name
107+
elif hasattr(normal_cls, "__name__"):
108+
name = normal_cls.__name__
109+
elif hasattr(normal_cls, "_name") and normal_cls._name:
110+
name = normal_cls._name
110111
else:
111-
name = str(cls)
112+
name = str(normal_cls)
112113

113114
if args and (type_args := get_args(cls)):
114115
name = (
115116
name +
116-
f"[{ ', '.join([NewObjectFrameBase.get_cls_name(x) for x in type_args]) }]"
117+
f"[{ ', '.join([NewObjectFrameBase.get_cls_name(x, True) for x in type_args]) }]"
117118
)
118119

119120
return name
@@ -209,21 +210,29 @@ def remove_classes(types: list):
209210
)
210211

211212
origin = get_origin(input_type)
213+
if issubclass_noexcept(origin, Generic):
214+
# Patch for Python versions < 3.10
215+
input_type.__name__ = origin.__name__
216+
212217
# Unpack Union items into a tuple
213-
if origin is Union or issubclass_noexcept(origin, Iterable):
214-
new_types = dict()
218+
if origin is Union or issubclass_noexcept(origin, (Iterable, Generic)):
219+
new_types = []
215220
for type_ in chain.from_iterable([cls.convert_types(r) for r in get_args(input_type)]):
216-
new_types[type_] = 0 # Use dictionary's keys as OrderedSet, with dummy value 0
221+
new_types.append(type_)
217222

218223
new_types = tuple(new_types)
219224
if origin is Union:
220-
return new_types
225+
return new_types # Just expand unions
221226

222-
return (origin[new_types],)
227+
# Process abstract classes and polymorphism
228+
new_origins = []
229+
for origin in cls.convert_types(origin):
230+
if issubclass_noexcept(origin, (Generic, Iterable)):
231+
new_origins.append(origin[new_types])
232+
else:
233+
new_origins.append(origin)
223234

224-
if issubclass_noexcept(origin, Generic):
225-
# Patch for Python versions < 3.10
226-
input_type.__name__ = origin.__name__
235+
return tuple(new_origins)
227236

228237
if input_type.__module__ == "builtins":
229238
# Don't consider built-int types for polymorphism
@@ -259,7 +268,7 @@ def modified(self) -> bool:
259268

260269
def update_window_title(self):
261270
"Set's the window title according to edit context."
262-
self.origin_window.title(f"{'New' if self.old_gui_data is None else 'Edit'} {self.get_cls_name(self.class_)} object")
271+
self.origin_window.title(f"{'New' if self.old_gui_data is None else 'Edit'} {self.get_cls_name(self.class_, True)} object")
263272

264273
def close_frame(self):
265274
if self.allow_save and self.modified:

tkclasswiz/object_frame/frame_iterable.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ def __init__(
6868
allow_save = True
6969
):
7070
dpi_5 = dpi_scaled(5)
71-
7271
super().__init__(class_, return_widget, parent, old_data, check_parameters, allow_save)
7372
self.storage_widget = w = ListBoxScrolled(self.frame_main, height=20)
7473
ListboxTooltip(self.storage_widget, 0)
@@ -127,7 +126,7 @@ def _create_add_menu(self, args: list, menu: tk.Menu):
127126
elif get_origin(arg) is Literal:
128127
insert_items.append(...)
129128
insert_items.extend(get_args(arg))
130-
elif isclass(arg) or isfunction(arg):
129+
else:
131130
menu.add_command(
132131
label=f"New {self.get_cls_name(arg, True)}",
133132
command=partial(self.new_object_frame, arg, widget)
@@ -157,8 +156,8 @@ def to_object(self):
157156
if isinstance(d, str) and str not in self._list_args:
158157
self.check_literals(d, self.filter_literals(self._list_args))
159158

160-
return data
161-
159+
return get_origin(self.class_)(data)
160+
162161
def _edit_selected(self):
163162
selection = self.storage_widget.curselection()
164163
if len(selection) == 1:

tkclasswiz/object_frame/frame_struct.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ def load_template():
139139

140140
self._create_fields(annotations, additional_values, self.frame_main)
141141
if annotations_depr:
142-
ttk.Separator(self.frame_main).pack(fill=tk.X)
143-
ttk.Label(self.frame_main, text="Deprecated").pack(anchor=tk.W)
142+
ttk.Separator(self.frame_main).pack(fill=tk.X, pady=dpi_5)
143+
ttk.Label(self.frame_main, text="Deprecated", font=("TkDefaultFont", 10)).pack(anchor=tk.W)
144144
self._create_fields(annotations_depr, additional_values, self.frame_main)
145145

146146
if old_data is not None: # Edit
@@ -297,12 +297,13 @@ def to_object(self, *, ignore_checks = False) -> ObjectInfo:
297297

298298
map_[attr] = value
299299

300+
class_ = get_origin(self.class_) or self.class_
300301
nickname = self.entry_nick.get() or None
301-
object_ = ObjectInfo(self.class_, map_, nickname) # Abstraction of the underlaying object
302+
object_ = ObjectInfo(class_, map_, nickname) # Abstraction of the underlying object
302303
if (
303304
not ignore_checks and
304305
self.check_parameters and
305-
(inspect.isclass(self.class_) or inspect.isclass(get_origin(self.class_))) # Only check objects
306+
(inspect.isclass(class_)) # Only check objects
306307
):
307308
# Cache the object created for faster
308309
_convert_to_objects_cached(object_) # Tries to create instances to check for errors
@@ -334,20 +335,18 @@ def _edit_selected(self, key: str, combo: ComboBoxObjects):
334335
if isinstance(selection, str):
335336
selection = self.cast_type(selection, self._map[key][1])
336337

337-
if isinstance(selection, list):
338-
types = self.convert_types(get_annotations(self.class_)[key])
339-
for type_ in types:
340-
if get_origin(type_) in {list, tuple, set, Iterable, ABCIterable}:
341-
list_type = type_
342-
break
343-
else:
344-
list_type = None
345-
346-
return self.new_object_frame(list_type, combo, old_data=selection)
347338
if isinstance(selection, ObjectInfo):
348339
return self.new_object_frame(selection.class_, combo, old_data=selection)
349340
else:
350-
return self.new_object_frame(type(selection), combo, old_data=selection)
341+
type_sel = type(selection)
342+
for t in self.convert_types(get_annotations(self.class_)[key]):
343+
if (get_origin(t) or t) == type_sel:
344+
type_ = t
345+
break
346+
else:
347+
type_ = None
348+
349+
return self.new_object_frame(type_, combo, old_data=selection)
351350

352351

353352
class NewObjectFrameStructView(NewObjectFrameStruct):

0 commit comments

Comments
 (0)