Parameter validation#

Validation is the process of checking whether everything is defined as intended. TkClassWizard defines 2 different types of built-in validation and additionally allows custom user defined validation.

Built-in validation#

Data type validation#

When you click on “Save” inside the object definition window or try to edit a value, the system will attempt to convert the entered value to one of the appropriate annotated data types if it is not already of correct type. For example if number is manually entered directly into a Combobox, it may try to convert the entered string into an actual int type, that is if int is one of the annotated types. Casting will only be done into built-in Python data types and not any user defined classes. If casting fails (either no built-in types available or casting actually failed), an exception will be displayed through a popup, as shown in the following image.

../_images/new_define_frame_string_cast_error.png

Literals validation#

Validation is also done for string literals. The system will check if any of the parameters are a string literal and if the entered content matches any of the literal values. For example if we have a class defined like the below code block, then the parameter job_type will be validated. If the value entered for job_type does not match the ones inside the Literal brackets, an exception will be displayed on screen.

class Person:
    def __init__(self, name: str, job_type: Literal["Science", "Technology", "Engineering", "Math"]):
        ...
../_images/new_define_frame_struct_literal_error.png

User-defined validation#

Note

When using the Template feature (described in Defining structured data (objects)), user-defined validation is not executed.

It is also possible for users to define their own custom validation. This can be done quite easily with the use of Python exceptions. Every time the data is saved, the object definition window tries to create a Python object and then caches that object to prevent recursive creations. This allows users to check all of the parameters with their own Python code and then raise an appropriate exception when an irregularity appears.

If we take our example from First steps, we can add user defined validation like displayed below.

 1import tkinter as tk
 2import tkinter.ttk as ttk
 3import tkclasswiz as wiz
 4
 5# Normal Python classes with annotations (type hints)
 6class Wheel:
 7    def __init__(self, diameter: float):
 8        self.diameter = diameter
 9
10class Car:
11    def __init__(self, name: str, speed: float, wheels: list[Wheel]):
12        self.name = name
13        self.speed = speed
14        self.wheels = wheels
15
16        if speed > 50_000:
17            raise ValueError("Car can go up to 50 000 km / h")
18
19        if len(wheels) != 4:
20            raise ValueError("The car must have 4 wheels!")
21
22
23# Tkinter main window
24root = tk.Tk("Test")
25
26# Modified tkinter Combobox that will store actual objects instead of strings
27combo = wiz.ComboBoxObjects(root)
28combo.pack(fill=tk.X, padx=5)
29
30def make_car(old = None):
31    """
32    Function for opening a window either in new definition mode (old = None) or
33    edit mode (old != None)
34    """
35    assert old is None or isinstance(old, wiz.ObjectInfo)
36
37    window = wiz.ObjectEditWindow()  # The object definition window / wizard
38    window.open_object_edit_frame(Car, combo, old_data=old)  # Open the actual frame
39
40def print_defined():
41    data = combo.get()
42    data = wiz.convert_to_objects(data)  # Convert any abstract ObjectInfo objects into actual Python objects
43    print(f"Object: {data}; Type: {type(data)}",)  # Print the object and it's datatype
44
45
46# Main GUI structure
47ttk.Button(text="Define Car", command=make_car).pack()
48ttk.Button(text="Edit Car", command=lambda: make_car(combo.get())).pack()
49ttk.Button(text="Print defined", command=print_defined).pack()
50root.mainloop()

This is how our exceptions look when we try to define a car which’s speed is above 50 000 km/h and which’s wheel count is not four:

../_images/new_define_frame_struct_user_valid_speed.png ../_images/new_define_frame_struct_user_valid_wheels.png