Custom object property not updating the object AND how to use a gizmo to control custom properties

I have defined a custom property “height” and drawn it in a panel.
I have created a function “set_height_by_vertex_groups” to take the “height” property and update the location of the vertices in the vertex group, using the property’s update attribute or an operator (object.set_height).

Right now it does not work. neither the property in the panel nor operator changes anything.
when i run the function by itself, it works,also The print function in the “height” property’s update function also works.

Please what am I doing wrong?

Also, I will like the operator to be able to set the height and by extension change the vertex positions on the object.

If possible in the long run, it will be nice to have a gizmo that can also set the height property in the viewport (as shown in the screenshot).

sorry for the numerous comments in the code, I tend to forget easily and get confused without the comments.

import bpy

# I want a way to change object dimensions without changing the scale
# bpy.context.object.dimensions works by changing the scale, which requires me to apply the object
# scale ctrl + a (bpy.ops.object.transform_apply(location=False, rotation=False, scale=True).
# Also changing object.dimensions lacks some flexibility for example,
# I would like to be able to either change the dimensions by moving the top of the object, or the 
# bottom, or front or back and not always adjust dimensions "uniformly" with reference to the origin.
# I have created vertex groups for this purpose.
# Ultimately I would like to create properties to drive those vertex groups. changing the properties
# should change the location of vertices in the vertex groups.
# Also I will like to have a gizmo in the viewport that will perform the same function i.e the location of 
# the vertices and the property (height for now) will be updated when the gizmo is translated, and the gizmo
# location will also change if the property is changed from the panel.
# I will prefer not to use armatures, just a gizmo that appears and dissapears depending on whether the object
# is active or not, to avoid cluttering the screen with armatures.



def deselect_all(context):
    """ Deselect all mesh elements in active object """
    # I am using this instead of bpy.ops.mesh.select_all because I want to avoid switching to 
    # edit mode, I intend to make references to vertex indices and I want to ensure they remain the same
    # I wonder if there is a way to restrict an object from entering edit mode even if the tab key is pressed
    for v in context.object.data.vertices:
        v.select = False
    for e in context.object.data.edges:
        e.select = False
    for p in context.object.data.polygons:
        p.select = False
        
def set_height_by_vertex_group(context):
    """ Set object height
    object must have a vertex group named "Top"
    This function changes the z-axis coordinates of all vertices in the "Top" vertex group.
    """
     
    new_height = context.object.location.z + context.object.height 
# I have ensured that the object origin is at the base of the object for now.
# Later I will edit the function to be more flexible use bottom vertex group z location.
# I want it to work independent of object origin location.

#First method, switching modes and using ops    
#    # set active vertex group
#    bpy.context.object.vertex_groups.active_index = bpy.context.object.vertex_groups["Top"].index 
#    bpy.ops.object.mode_set(mode="EDIT")
#    bpy.ops.object.vertex_group_select()
#    bpy.ops.object.mode_set(mode="OBJECT")
#    for v in context.object.data.vertices:
#        if v.select:
#                v.co.z = new_height


# Second Method, no mode switching    
    for v in bpy.context.object.data.vertices: # v = Vertex
        for vge in v.groups: # vge = VertexGroupElement i.e a vertex group to which the vertex 'v' belongs
            if vge.group == bpy.context.object.vertex_groups["Top"].index: # vge.group = index of the vertex group.
                # Also need to update this function to avoid referencing the vertex_group name "Top" directly.
                break # in case the vertex belongs to more than one vertex group to save some time.                                                     
                v.co.z = new_height # set z-axis co-ordinate of v
                
def main(context):
    deselect_all(context)
    set_height_by_vertex_group(context)
    
def update_height(self, context):
    main(context)
    print(f"height changed to: {context.object.height}")
    
class OBJECT_OT_set_height(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.set_height"
    bl_label = "Set Object height"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        main(context)
        return {'FINISHED'}

class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "BOX Properties"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    
    
    def draw(self, context):
        layout = self.layout
        obj = context.object
        row = layout.row()
        row.prop(obj, "name")        
        row = layout.row()
        row.prop(obj, "height")
        

        row = layout.row()
        row.operator("object.set_height")

def register():
    # add object property
    # THIS IS MY CURRENT PROBLEM, CHANGING THIS VALUE IN THE PANEL DOES NOT UPDATE THE OBJECT
    # CALLING THE OPERATOR ALSO DOES NOT UPDATE THE OBJECT
    bpy.types.Object.height = bpy.props.FloatProperty(name="Height", default=2.0, update=update_height)
    bpy.utils.register_class(OBJECT_OT_set_height)
    bpy.utils.register_class(HelloWorldPanel)

def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)
    bpy.utils.unregister_class(SimpleOperator)
    del bpy.types.Object.height

if __name__ == "__main__":
    register()

    for v in bpy.context.object.data.vertices: # v = Vertex
        for vge in v.groups:
            if vge.group == bpy.context.object.vertex_groups["Top"].index:
                break
                v.co.z = new_height

Your v.co.z is unreachable.

Oh oh oh, I see that now, thanks.