param icon indicating copy to clipboard operation
param copied to clipboard

Use of WidgetBase raises ParamFutureWarning

Open MarcSkovMadsen opened this issue 1 year ago • 3 comments

I'm on panel==1.5.0rc2 and param==2.1.1.

I have a custom CompositeWidget that I noticed started raising a ParamFutureWarning. After some inspection I can see the problem is is caused by the fact that the WidgetBase.value is a Parameter while my CustomWidget.value is a String.

I think this will be cause general problems as WidgetBase is now intended to be mixed into all kinds of custom widgets.

Reproduce

import panel as pn
from panel.widgets.base import WidgetBase
import param

class CustomWidget(pn.viewable.Viewer, WidgetBase):
    value = param.String()

    def __panel__(self):
        return self.param.value

CustomWidget(value="Hello World").servable()
/home/jovyan/repos/mt-pm-reporting/script.py:5: ParamFutureWarning: String parameter 'CustomWidget.value' failed to validate its default value on class creation, this is going to raise an error in the future. The Parameter type changed between class 'CustomWidget' and one of its parent classes (Viewer, WidgetBase) which made it invalid. Please fix the Parameter type.
Validation failed with:
String parameter 'CustomWidget.value' only takes a string value, not value of <class 'NoneType'>.
  value = param.String()

Workaround

Change param.String() to param.String(""). Then the ParamFutureWarning will not be raised.

MarcSkovMadsen avatar Sep 13 '24 04:09 MarcSkovMadsen

This is not a bug, this is a param level warning and it's indicating a real potential issue. One could argue that if no default is set on the baseclass then the overriding class should override the default but we can't do anything about that in Panel, so moving to param.

philippjfr avatar Sep 13 '24 07:09 philippjfr

@jbednar @maximlt pinging you for visibility.

philippjfr avatar Sep 13 '24 07:09 philippjfr

It's also due to allow_None being computed dynamically. It's set to True in the superclass but, in that case, wrongly overridden at the sub-class level

import param

class A(param.Parameterized):
    x = param.Parameter()

class B(A):
    x = param.String()

print(A.x)
print(A.param.x.allow_None)
print(B.x)
print(B.param.x.allow_None)
None
True
None
False

They are a couple of tests that capture this (somewhat buggy) behavior:

https://github.com/holoviz/param/blob/e54dd51d99fa768a8ce08f2414b44d8fe3fab534/tests/testparameterizedobject.py#L1294-L1326

maximlt avatar Sep 13 '24 12:09 maximlt