Widget refactor backward compat issues

72 views
Skip to first unread message

laundmo

unread,
Sep 22, 2025, 8:39:54 AMSep 22
to py4web
It seems my widget refactor had issues with backwards compatibility, specifically in a way that should have been compatible, and was recently reverted.

I'd like to ask the affected user to please share the widgets they were trying to use, and the errors they got, so i can fix this and add the new widgets system back.

- laund

laundmo

unread,
Sep 22, 2025, 9:23:02 AMSep 22
to py4web
I've resolved one of the issues shared in https://groups.google.com/g/py4web/c/dfAehLbcqtg regarding FormStyle.widgets['fieldname'] = CustomWidget

https://github.com/web2py/py4web/pull/1001

Massimo DiPierro

unread,
Sep 23, 2025, 12:59:35 AMSep 23
to py4web
I am going to review your PR asap, would be great if other users who use custom widgets could also test it with their code.

Massimo DiPierro

unread,
Sep 27, 2025, 12:45:31 AMSep 27
to py4web
To people who use custom widgets. I would very much appreciate if you could try this changes and see if they break your code or not. 

CarlosDB

unread,
Dec 15, 2025, 4:45:44 PM (yesterday) Dec 15
to py4web

I’ve been testing this refactor (https://github.com/web2py/py4web/pull/1001) because the feature that allows widgets to have a read-only version (def make_readonly(self, value)) seems extremely useful.

I haven’t evaluated the widget registration mechanism yet.
However, I’ve run into major issues with my custom widgets, and at the moment it doesn’t seem easy to make them work with this change.

1. Constructor parameters for widget classes

Before:

form_style.widgets['select_field'] = WidgetTomSelect(create=False)

Now:

form_style.widgets['select_field'] = WidgetTomSelect

With the new approach, I can no longer pass parameters to the widget constructor.
This makes it impossible to configure widgets that need runtime options.


2. Using default widgets inside custom widgets

For example, my WidgetTomSelect:

class WidgetTomSelect: def __init__(self, create: bool = False): self.create = create def make(self, field, value, error, title, placeholder="", readonly=False): if not hasattr(field.requires, 'options'): raise ValueError('This field does not support WidgetTomSelect') widget = SelectWidget().make(field, value, error, title, placeholder, readonly) widget['_class'] = (widget.attributes.get('_class', '') + ' tomselect').strip() return widget

With the refactor, it is now impossible to instantiate SelectWidget directly, so this pattern no longer works.


3. OldWidgetCompat instantiation

In:

class OldWidgetCompat(Widget): """Handles custom widgets from the older style, which have a .make(self, field, value, error, title, placeholder="", readonly=False) and don't inherit from Widget""" def __init__(self, old_widget, field, form_style, vars, error=None): super().__init__(field, form_style, vars, error) self.old_widget = old_widget

It seems that old_widget should actually be instantiated:

self.old_widget = old_widget()

Otherwise, old-style widgets that expect instance state cannot work correctly.


4. MakeReadonlyMixin inheritance order

Finally, the standard py4web widgets are now defined like this:

class InputTypeWidget(Widget, MakeReadonlyMixin):

But MakeReadonlyMixin does not seem to have any effect in this order.
Should this instead be:

class InputTypeWidget(MakeReadonlyMixin, Widget):

so that the mixin methods properly override or extend the base behavior?


Overall, I really like the idea behind make_readonly, but at least in my case, migrating existing custom widgets has been quite difficult with the current design.

Thanks for the work on this — I hope this feedback is useful.

Reply all
Reply to author
Forward
0 new messages