AttributeError when attempting to add PyComponent to column in FastListTemplate main/modal
ALL software version info
Software Version Info
Python == 3.11.11 (but it also happens on lesser versions, such as 3.10 -- not sure for higher versions))
panel==1.6.0 (but it also happens on lesser versions)
bokeh==3.6.3
param==2.2.0
Description of expected behavior and the observed behavior
In my full project, I am attempting to add a custom PyComponent to a column which I have in the modal of a FastListTemplate. When I append my component and then open the modal, I get the error shown below, and the modal doesn't open (as expected since an error occurred). If I open the modal first and then append, I get the error, and my component shows correctly with some style errors (not sure if that is reproduced in the example below).
I was able to semi-work around this issue by directly inheriting from pn.reactive.Reactive, which implements _process_param_change. Then, I started getting other errors which may be seen by adding in Reactive to the FeatureInput inheritance below. (I already imported it at the top of the example.)
The example I provide below is the minimal example I could get to reproduce the issue.
The expected behavior is to be able to append a PyComponent to these columns and have it work with no errors.
Complete, minimal, self-contained example code that reproduces the issue
This is the FeatureInput example from the PyComponent example page, except I changed it to display in a FastListTemplate main or modal.
Remember to test adding Reactive to the inheritance of FeatureInput as well.
import panel as pn
import param
from panel.widgets.base import WidgetBase
from panel.custom import PyComponent
from panel.reactive import Reactive
class FeatureInput(WidgetBase, PyComponent):
"""
The `FeatureInput` enables a user to select from a list of features and set their values.
"""
value = param.Dict(
doc="The names of the features selected and their set values", allow_None=False
)
features = param.Dict(
doc="The names of the available features and their default values"
)
selected_features = param.ListSelector(
doc="The list of selected features"
)
_selected_widgets = param.ClassSelector(
class_=pn.Column, doc="The widgets used to edit the selected features"
)
def __init__(self, **params):
params["value"] = params.get("value", {})
params["features"] = params.get("features", {})
params["selected_features"] = params.get("selected_features", [])
params["_selected_widgets"] = self.param._selected_widgets.class_()
super().__init__(**params)
self._selected_features_widget = pn.widgets.MultiChoice.from_param(
self.param.selected_features, sizing_mode="stretch_width"
)
def __panel__(self):
return pn.Column(self._selected_features_widget, self._selected_widgets)
@param.depends("features", watch=True, on_init=True)
def _reset_selected_features(self):
selected_features = []
for feature in self.selected_features.copy():
if feature in self.features.copy():
selected_features.append(feature)
self.param.selected_features.objects = list(self.features)
self.selected_features = selected_features
@param.depends("selected_features", watch=True, on_init=True)
def _handle_selected_features_change(self):
org_value = self.value
self._update_selected_widgets(org_value)
self._update_value()
def _update_value(self, *args): # pylint: disable=unused-argument
new_value = {}
for widget in self._selected_widgets:
new_value[widget.name] = widget.value
self.value = new_value
def _update_selected_widgets(self, org_value):
new_widgets = {}
for feature in self.selected_features:
value = org_value.get(feature, self.features[feature])
widget = self._new_widget(feature, value)
new_widgets[feature] = widget
self._selected_widgets[:] = list(new_widgets.values())
def _new_widget(self, feature, value):
widget = pn.widgets.FloatInput(
name=feature, value=value, sizing_mode="stretch_width"
)
pn.bind(self._update_value, widget, watch=True)
return widget
features = {
"Blade Length (m)": 73.5,
"Cut-in Wind Speed (m/s)": 3.5,
"Cut-out Wind Speed (m/s)": 25,
"Grid Connection Capacity (MW)": 5,
"Hub Height (m)": 100,
"Rated Wind Speed (m/s)": 12,
"Rotor Diameter (m)": 150,
"Turbine Efficiency (%)": 45,
"Water Depth (m)": 30,
"Wind Speed (m/s)": 10,
}
_selected_features = ["Wind Speed (m/s)", "Rotor Diameter (m)"]
_widget = FeatureInput(
features=features,
selected_features=_selected_features,
width=500,
)
##### My code starts here #####
main_column = pn.Column()
modal_column = pn.Column()
flt = pn.template.FastListTemplate(
main=[main_column],
modal=[modal_column]
)
def add_to_main(_):
main_column.append(pn.FlexBox(
pn.Column(
"## Widget",
_widget,
),
pn.Column(
"## Value",
pn.pane.JSON(_widget.param.value, width=500, height=200),
),
))
def add_to_modal(_):
modal_column.append(
pn.FlexBox(
pn.Column(
"## Widget",
_widget,
),
pn.Column(
"## Value",
pn.pane.JSON(_widget.param.value, width=500, height=200),
),
)
)
def add_then_open(_):
modal_column.append(
pn.FlexBox(
pn.Column(
"## Widget",
_widget,
),
pn.Column(
"## Value",
pn.pane.JSON(_widget.param.value, width=500, height=200),
),
)
)
flt.open_modal()
def open_then_add(_):
flt.open_modal()
modal_column.append(
pn.FlexBox(
pn.Column(
"## Widget",
_widget,
),
pn.Column(
"## Value",
pn.pane.JSON(_widget.param.value, width=500, height=200),
),
)
)
main_column.append(pn.widgets.Button(
name='add to main', on_click=add_to_main))
main_column.append(pn.widgets.Button(
name='add to modal', on_click=add_to_modal))
main_column.append(pn.widgets.Button(
name="add to modal, then open modal", on_click=add_then_open))
main_column.append(pn.widgets.Button(
name="open modal, then add to modal", on_click=open_then_add))
flt.servable()
Stack traceback and/or browser JavaScript console output
Errors without inheriting from Reactive:
AttributeError: 'FeatureInput' object has no attribute '_process_param_change'
2025-02-06 19:21:37,267 WebSocket connection closed: code=1001, reason=None
2025-02-06 19:21:37,826 WebSocket connection opened
2025-02-06 19:21:37,826 ServerConnection created
2025-02-06 19:21:39,019 error handling message
message: Message 'PATCH-DOC' content: {'events': [{'kind': 'MessageSent', 'msg_type': 'bokeh_event', 'msg_data': {'type': 'event', 'name': 'button_click', 'values': {'type': 'map', 'entries': [['model', {'id': 'p1289'}]]}}}]}
error: AttributeError("'FeatureInput' object has no attribute '_process_param_change'")
Traceback (most recent call last):
File "/code/venv/lib/python3.11/site-packages/bokeh/server/protocol_handler.py", line 94, in handle
work = await handler(message, connection)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/bokeh/server/session.py", line 94, in _needs_document_lock_wrapper
result = func(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/bokeh/server/session.py", line 286, in _handle_patch
message.apply_to_document(self.document, self)
File "/code/venv/lib/python3.11/site-packages/bokeh/protocol/messages/patch_doc.py", line 104, in apply_to_document
invoke_with_curdoc(doc, lambda: doc.apply_json_patch(self.payload, setter=setter))
File "/code/venv/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 453, in invoke_with_curdoc
return f()
^^^
File "/code/venv/lib/python3.11/site-packages/bokeh/protocol/messages/patch_doc.py", line 104, in <lambda>
invoke_with_curdoc(doc, lambda: doc.apply_json_patch(self.payload, setter=setter))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/bokeh/document/document.py", line 391, in apply_json_patch
DocumentPatchedEvent.handle_event(self, event, setter)
File "/code/venv/lib/python3.11/site-packages/bokeh/document/events.py", line 244, in handle_event
event_cls._handle_event(doc, event)
File "/code/venv/lib/python3.11/site-packages/bokeh/document/events.py", line 279, in _handle_event
cb(event.msg_data)
File "/code/venv/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 400, in trigger_event
model._trigger_event(event)
File "/code/venv/lib/python3.11/site-packages/bokeh/util/callback_manager.py", line 111, in _trigger_event
self.document.callbacks.notify_event(cast(Model, self), event, invoke)
File "/code/venv/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 262, in notify_event
invoke_with_curdoc(doc, callback_invoker)
File "/code/venv/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 453, in invoke_with_curdoc
return f()
^^^
File "/code/venv/lib/python3.11/site-packages/bokeh/util/callback_manager.py", line 107, in invoke
cast(EventCallbackWithEvent, callback)(event)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 580, in _server_event
self._comm_event(doc, event)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 567, in _comm_event
state._handle_exception(e)
File "/code/venv/lib/python3.11/site-packages/panel/io/state.py", line 484, in _handle_exception
raise exception
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 565, in _comm_event
self._process_bokeh_event(doc, event)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 502, in _process_bokeh_event
self._process_event(event)
File "/code/venv/lib/python3.11/site-packages/panel/widgets/button.py", line 241, in _process_event
self.clicks += 1
^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 515, in _f
instance_param.__set__(obj, val)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 517, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameters.py", line 541, in __set__
super().__set__(obj,val)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 517, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 1564, in __set__
obj.param._call_watcher(watcher, event)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2604, in _call_watcher
self_._execute_watcher(watcher, (event,))
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/workspaces/dexter-ui/test.py", line 125, in add_to_modal
modal_column.append(
File "/code/venv/lib/python3.11/site-packages/panel/layout/base.py", line 474, in append
self.objects = new_objects
^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 515, in _f
instance_param.__set__(obj, val)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 517, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/panel/viewable.py", line 1184, in __set__
super().__set__(obj, self._transform_value(val))
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 517, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 1564, in __set__
obj.param._call_watcher(watcher, event)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2604, in _call_watcher
self_._execute_watcher(watcher, (event,))
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 451, in _param_change
applied &= self._apply_update(named_events, properties, model, ref)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 339, in _apply_update
self._update_model(events, msg, root, model, doc, comm)
File "/code/venv/lib/python3.11/site-packages/panel/layout/base.py", line 135, in _update_model
state._views[ref][0]._preprocess(root, self, old_children)
File "/code/venv/lib/python3.11/site-packages/panel/viewable.py", line 619, in _preprocess
hook(self, root, changed, old_models)
File "/code/venv/lib/python3.11/site-packages/panel/theme/base.py", line 150, in _apply_hooks
self._reapply(changed, root, old_models, isolated=False, cache=cache, document=root.document)
File "/code/venv/lib/python3.11/site-packages/panel/theme/base.py", line 138, in _reapply
self._apply_modifiers(o, ref, self.theme, isolated, cache, document)
File "/code/venv/lib/python3.11/site-packages/panel/theme/base.py", line 253, in _apply_modifiers
cls._apply_params(viewable, mref, modifiers, document)
File "/code/venv/lib/python3.11/site-packages/panel/theme/base.py", line 273, in _apply_params
props = viewable._process_param_change(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'FeatureInput' object has no attribute '_process_param_change'
Errors when inheriting from Reactive and trying to add something in the UI:
2025-02-06 19:52:36,522 WebSocket connection closed: code=1001, reason=None
2025-02-06 19:52:37,391 WebSocket connection opened
2025-02-06 19:52:37,392 ServerConnection created
2025-02-06 19:52:42,574 ERROR: panel.reactive - Callback failed for object named 'Selected features' changing property {'value': ['Rotor Diameter (m)', 'Wind Speed (m/s)', 'Blade Length (m)']}
Traceback (most recent call last):
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 470, in _process_events
self.param.update(**self_params)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/code/venv/lib/python3.11/site-packages/panel/param.py", line 526, in link_widget
self.object.param.update(**{p_name: change.new})
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 767, in _sync_caller
return function()
^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/depends.py", line 85, in _depends
return func(*args, **kw)
^^^^^^^^^^^^^^^^^
File "/workspaces/dexter-ui/test.py", line 61, in _handle_selected_features_change
self._update_value()
File "/workspaces/dexter-ui/test.py", line 69, in _update_value
self.value = new_value
^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 515, in _f
instance_param.__set__(obj, val)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 517, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 1564, in __set__
obj.param._call_watcher(watcher, event)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2604, in _call_watcher
self_._execute_watcher(watcher, (event,))
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 451, in _param_change
applied &= self._apply_update(named_events, properties, model, ref)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 339, in _apply_update
self._update_model(events, msg, root, model, doc, comm)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 711, in _update_model
super()._update_model(events, msg, root, model, doc, comm)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 371, in _update_model
model_val = getattr(model, attr)
^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/bokeh/core/has_props.py", line 369, in __getattr__
self._raise_attribute_error_with_matches(name, properties)
File "/code/venv/lib/python3.11/site-packages/bokeh/core/has_props.py", line 377, in _raise_attribute_error_with_matches
raise AttributeError(f"unexpected attribute {name!r} to {self.__class__.__name__}, {text} attributes are {nice_join(matches)}")
AttributeError: unexpected attribute 'value' to Column, possible attributes are align, aspect_ratio, auto_scroll_limit, children, context_menu, css_classes, css_variables, disabled, elements, flow_mode, height, height_policy, js_event_callbacks, js_property_callbacks, margin, max_height, max_width, min_height, min_width, name, resizable, scroll_button_threshold, scroll_index, scroll_position, sizing_mode, spacing, styles, stylesheets, subscribed_events, syncable, tags, view_latest, visible, width or width_policy
2025-02-06 19:52:42,578 Exception in callback functools.partial(<bound method IOLoop._discard_future_result of <tornado.platform.asyncio.AsyncIOMainLoop object at 0x774f97e62390>>, <Task finished name='Task-1212' coro=<ServerSession.with_document_locked() done, defined at /code/venv/lib/python3.11/site-packages/bokeh/server/session.py:77> exception=AttributeError("unexpected attribute 'value' to Column, possible attributes are align, aspect_ratio, auto_scroll_limit, children, context_menu, css_classes, css_variables, disabled, elements, flow_mode, height, height_policy, js_event_callbacks, js_property_callbacks, margin, max_height, max_width, min_height, min_width, name, resizable, scroll_button_threshold, scroll_index, scroll_position, sizing_mode, spacing, styles, stylesheets, subscribed_events, syncable, tags, view_latest, visible, width or width_policy")>)
Traceback (most recent call last):
File "/code/venv/lib/python3.11/site-packages/tornado/ioloop.py", line 750, in _run_callback
ret = callback()
^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/tornado/ioloop.py", line 774, in _discard_future_result
future.result()
File "/code/venv/lib/python3.11/site-packages/bokeh/server/session.py", line 98, in _needs_document_lock_wrapper
result = await result
^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 517, in _change_coroutine
state._handle_exception(e)
File "/code/venv/lib/python3.11/site-packages/panel/io/state.py", line 484, in _handle_exception
raise exception
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 515, in _change_coroutine
self._change_event(doc)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 533, in _change_event
self._process_events(events)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 470, in _process_events
self.param.update(**self_params)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/code/venv/lib/python3.11/site-packages/panel/param.py", line 526, in link_widget
self.object.param.update(**{p_name: change.new})
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 767, in _sync_caller
return function()
^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/depends.py", line 85, in _depends
return func(*args, **kw)
^^^^^^^^^^^^^^^^^
File "/workspaces/dexter-ui/test.py", line 61, in _handle_selected_features_change
self._update_value()
File "/workspaces/dexter-ui/test.py", line 69, in _update_value
self.value = new_value
^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 515, in _f
instance_param.__set__(obj, val)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 517, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 1564, in __set__
obj.param._call_watcher(watcher, event)
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2604, in _call_watcher
self_._execute_watcher(watcher, (event,))
File "/code/venv/lib/python3.11/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 451, in _param_change
applied &= self._apply_update(named_events, properties, model, ref)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 339, in _apply_update
self._update_model(events, msg, root, model, doc, comm)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 711, in _update_model
super()._update_model(events, msg, root, model, doc, comm)
File "/code/venv/lib/python3.11/site-packages/panel/reactive.py", line 371, in _update_model
model_val = getattr(model, attr)
^^^^^^^^^^^^^^^^^^^^
File "/code/venv/lib/python3.11/site-packages/bokeh/core/has_props.py", line 369, in __getattr__
self._raise_attribute_error_with_matches(name, properties)
File "/code/venv/lib/python3.11/site-packages/bokeh/core/has_props.py", line 377, in _raise_attribute_error_with_matches
raise AttributeError(f"unexpected attribute {name!r} to {self.__class__.__name__}, {text} attributes are {nice_join(matches)}")
AttributeError: unexpected attribute 'value' to Column, possible attributes are align, aspect_ratio, auto_scroll_limit, children, context_menu, css_classes, css_variables, disabled, elements, flow_mode, height, height_policy, js_event_callbacks, js_property_callbacks, margin, max_height, max_width, min_height, min_width, name, resizable, scroll_button_threshold, scroll_index, scroll_position, sizing_mode, spacing, styles, stylesheets, subscribed_events, syncable, tags, view_latest, visible, width or width_policy
2025-02-06 19:52:42,620 Dropping a patch because it contains a previously known reference (id='p1637'). Most of the time this is harmless and usually a result of updating a model on one side of a communications channel while it was being removed on the other end.
2025-02-06 19:52:42,621 Dropping a patch because it contains a previously known reference (id='p1638'). Most of the time this is harmless and usually a result of updating a model on one side of a communications channel while it was being removed on the other end.
I'm also running into this. I've made a basic extension to date picker with some buttons below to input presets. It works in a very simple test app but fails as described when adding to BootstrapTemplate, which all my apps use.
Is there any work around?
@ta264 did you try to have your component also inherit from pn.reactive.Reactive? That worked for me as a temporary fix — you’ll still get errors, but everything works fine as far as I can tell.
I haven’t updated to 1.7.0 yet, so not sure if that will affect the fix.
@ta264 did you try to have your component also inherit from
pn.reactive.Reactive? That worked for me as a temporary fix — you’ll still get errors, but everything works fine as far as I can tell.
Thanks, I did try this and got errors just like the ones you posted. But unfortunately my component also didn't seem to work
@ta264 Sorry, I don't have any other workarounds. Could you post the errors you're getting with and without inheriting from pn.reactive.Reactive plus some of your code if possible? It might be helpful in finding a workaround or helping the devs fix the bug.
I think I have got a related issue ~and can provide a workaround~ (edit: now I also get other errors with the workaround).
Software Version Info
Python == 3.13.3
panel == 1.7.1
bokeh == 3.7.3
param == 2.2.0
Description of expected behavior and the observed behavior
The following script raises the error about missing _process_param_change in MyCustomWidget whenever a tab is switched, resulting in some weird behavior:
- The content of
MyCustomWidgetis shown, but when switching back to the first tab, nothing is shown. - When the order of the tabs is switched, or
active=1is set on theTabswidget, no error occurs and everything renders as expected.
Complete, minimal, self-contained example code that reproduces the issue
import panel as pn
from panel.custom import PyComponent
from panel.widgets.base import WidgetBase
pn.extension()
class MyCustomWidget(WidgetBase, PyComponent):
def __panel__(self) -> pn.Column:
return pn.Column("I am the custom widget.")
template = pn.template.BootstrapTemplate(
title="Panel Test App",
main=[
pn.Tabs(
("Test 1", "Hello world!"),
("Test 2", MyCustomWidget()),
dynamic=True,
)
],
)
template.servable()
Stack traceback
Stack traceback
2025-05-30 15:35:01,835 ERROR: panel.reactive - Callback failed for object named 'Tabs00717' changing property {'active': 1}
Traceback (most recent call last):
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 470, in _process_events
self.param.update(**self_params)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/layout/tabs.py", line 139, in _update_active
self.param.trigger('objects')
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2556, in trigger
self_.update(dict(params, **triggers))
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 456, in _param_change
self._apply_update(named_events, properties, model, ref)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 345, in _apply_update
self._update_model(events, msg, root, model, doc, comm)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/layout/base.py", line 264, in _update_model
state._views[ref][0]._preprocess(root, self, old_children)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/viewable.py", line 631, in _preprocess
hook(self, root, changed, old_models)
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 156, in _apply_hooks
self._reapply(changed, root, old_models, isolated=False, cache=cache, document=root.document)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 142, in _reapply
self._apply_modifiers(o, ref, self.theme, isolated, cache, document)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 260, in _apply_modifiers
cls._apply_params(viewable, mref, modifiers, document)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 280, in _apply_params
props = viewable._process_param_change(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'MyCustomWidget' object has no attribute '_process_param_change'
2025-05-30 15:35:01,841 Exception in callback functools.partial(<bound method IOLoop._discard_future_result of <tornado.platform.asyncio.AsyncIOMainLoop object at 0x72a595926900>>, <Task finished name='Task-699' coro=<ServerSession.with_document_locked() done, defined at *****/panel-test/.venv/lib/python3.13/site-packages/bokeh/server/session.py:77> exception=AttributeError("'MyCustomWidget' object has no attribute '_process_param_change'")>)
Traceback (most recent call last):
File "*****/panel-test/.venv/lib/python3.13/site-packages/tornado/ioloop.py", line 758, in _run_callback
ret = callback()
File "*****/panel-test/.venv/lib/python3.13/site-packages/tornado/ioloop.py", line 782, in _discard_future_result
future.result()
~~~~~~~~~~~~~^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/bokeh/server/session.py", line 98, in _needs_document_lock_wrapper
result = await result
^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 519, in _change_coroutine
state._handle_exception(e)
~~~~~~~~~~~~~~~~~~~~~~~^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/io/state.py", line 488, in _handle_exception
raise exception
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 517, in _change_coroutine
self._change_event(doc)
~~~~~~~~~~~~~~~~~~^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 535, in _change_event
self._process_events(events)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 489, in _process_events
raise e
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 470, in _process_events
self.param.update(**self_params)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/layout/tabs.py", line 139, in _update_active
self.param.trigger('objects')
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2556, in trigger
self_.update(dict(params, **triggers))
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2406, in update
restore = dict(self_._update(arg, **kwargs))
~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2439, in _update
self_._batch_call_watchers()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2624, in _batch_call_watchers
self_._execute_watcher(watcher, events)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/param/parameterized.py", line 2586, in _execute_watcher
watcher.fn(*args, **kwargs)
~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 456, in _param_change
self._apply_update(named_events, properties, model, ref)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/reactive.py", line 345, in _apply_update
self._update_model(events, msg, root, model, doc, comm)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/layout/base.py", line 264, in _update_model
state._views[ref][0]._preprocess(root, self, old_children)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/viewable.py", line 631, in _preprocess
hook(self, root, changed, old_models)
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 156, in _apply_hooks
self._reapply(changed, root, old_models, isolated=False, cache=cache, document=root.document)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 142, in _reapply
self._apply_modifiers(o, ref, self.theme, isolated, cache, document)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 260, in _apply_modifiers
cls._apply_params(viewable, mref, modifiers, document)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*****/panel-test/.venv/lib/python3.13/site-packages/panel/theme/base.py", line 280, in _apply_params
props = viewable._process_param_change(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'MyCustomWidget' object has no attribute '_process_param_change'
Workaround for simple example
Inherit panel.reactive.Syncable. It implements _process_param_change and I observed no other issues with this example, but in more complex cases it produces other errors and makes components unusable.
import panel as pn
from panel.custom import PyComponent
from panel.reactive import Syncable
from panel.widgets.base import WidgetBase
pn.extension()
class MyCustomWidget(WidgetBase, PyComponent, Syncable):
def __panel__(self) -> pn.Column:
return pn.Column("I am the custom widget.")
template = pn.template.BootstrapTemplate(
title="Panel Test App",
main=[
pn.Tabs(
("Test 1", "Hello world!"),
("Test 2", MyCustomWidget()),
dynamic=True,
)
],
)
template.servable()
I'm running into related issues. It does seem like the workarounds mentioned here can get it to run, but not without other issues and bugs. Without a template it seems to work as the example shows, but i really don't want to give up the templating.
Specifically with the Syncable workaround, it seems to introduce attribute errors when updating a parameter attribute of my custom widget. It seems to be trying to assign that attribute to the element returned in __panel__.
Fixed by https://github.com/holoviz/panel/pull/7975. Will try to get a new release out tomorrow.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.