diff --git a/panel/depends.py b/panel/depends.py index 0ae05c2a74..72e8de6940 100644 --- a/panel/depends.py +++ b/panel/depends.py @@ -207,6 +207,7 @@ async def wrapped(*wargs, **wkwargs): def wrapped(*wargs, **wkwargs): combined_args, combined_kwargs = combine_arguments(wargs, wkwargs) return function(*combined_args, **combined_kwargs) + wrapped.__bound_function__ = function return wrapped __all__ = ["bind", "depends"] diff --git a/panel/param.py b/panel/param.py index 64877d385b..84f383e58b 100644 --- a/panel/param.py +++ b/panel/param.py @@ -745,17 +745,16 @@ def _validate_object(self): if not dependencies or not dependencies.get('watch'): return fn_type = 'method' if type(self) is ParamMethod else 'function' - self.param.warning(f"The {fn_type} supplied for Panel to display " - "was declared with `watch=True`, which will " - f"cause the {fn_type} to be called twice for " - "any change in a dependent Parameter. " - "`watch` should be False when Panel is " - "responsible for displaying the result " - f"of the {fn_type} call, while `watch=True` " - f"should be reserved for {fn_type}s that work " - "via side-effects, e.g. by modifying internal " - "state of a class or global state in an " - "application's namespace.") + self.param.warning( + f"The {fn_type} supplied for Panel to display was declared " + f"with `watch=True`, which will cause the {fn_type} to be " + "called twice for any change in a dependent Parameter. " + "`watch` should be False when Panel is responsible for " + f"displaying the result of the {fn_type} call, while " + f"`watch=True` should be reserved for {fn_type}s that work " + "via side-effects, e.g. by modifying internal state of a " + "class or global state in an application's namespace." + ) #---------------------------------------------------------------- # Callback API @@ -878,6 +877,19 @@ class ParamFunction(ParamMethod): def _link_object_params(self): deps = getattr(self.object, '_dinfo', {}) dep_params = list(deps.get('dependencies', [])) + list(deps.get('kw', {}).values()) + if not dep_params: + fn = getattr(self.object, '__bound_function__', self.object) + fn_name = getattr(fn, '__name__', repr(self.object)) + self.param.warning( + f"The function {fn_name!r} does not have any dependencies " + "and will never update. Are you sure you did not intend " + "to depend on or bind a parameter or widget to this function? " + "If not simply call the function before passing it to Panel. " + "Otherwise, when passing a parameter as an argument, " + "ensure you pass at least one parameter and reference the " + "actual parameter object not the current value, i.e. use " + "object.param.parameter not object.parameter." + ) grouped = defaultdict(list) for dep in dep_params: grouped[id(dep.owner)].append(dep)