From 283974b358ab5489ba38ec6f3bea1bde521aeb4e Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 2 Mar 2021 13:11:02 +0100 Subject: [PATCH 1/5] Implement ViewableWrapper component --- panel/viewable.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/panel/viewable.py b/panel/viewable.py index ff98bd5c9c..f43b396b7f 100644 --- a/panel/viewable.py +++ b/panel/viewable.py @@ -769,3 +769,34 @@ def server_doc(self, doc=None, title=None, location=True): add_to_doc(model, doc) if location: self._add_location(doc, location, model) return doc + + +class ViewableWrapper(param.Parameterized): + """ + A baseclass for custom components which return a Panel object. By + implementing the __panel__ method users can make a panel component + usable inside Panel without explicitly returning a Panel object. + """ + + def __panel__(self): + """ + Subclasses should return a Panel component to be rendered. + """ + raise NotImplementedError + + def servable(self, title=None, location=True): + return self.__panel__().servable(title, location) + + servable.__doc__ = ServableMixin.servable.__doc__ + + def show(self, title=None, port=0, address=None, websocket_origin=None, + threaded=False, verbose=True, open=True, location=True, **kwargs): + return self.__panel__().show( + title, port, address, websocket_origin, threaded, + verbose, option, location, **kwargs + ) + + show.__doc__ = ServableMixin.show.__doc__ + + def _repr_mimebundle_(self, include=None, exclude=None): + return self.__panel__._repr_mimebundle_(include, exclude) From f5b24aa13d79bc9e8a2d70542f425eb975899a3c Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 2 Mar 2021 13:12:39 +0100 Subject: [PATCH 2/5] Handle objects with __panel__ --- panel/pane/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panel/pane/base.py b/panel/pane/base.py index 42663c8c06..aeb18115b9 100644 --- a/panel/pane/base.py +++ b/panel/pane/base.py @@ -44,6 +44,8 @@ def panel(obj, **kwargs): """ if isinstance(obj, Viewable): return obj + elif hasattr(obj, '__panel__'): + return panel(obj.__panel__()) if kwargs.get('name', False) is None: kwargs.pop('name') pane = PaneBase.get_pane_type(obj, **kwargs)(obj, **kwargs) From 6719a8d7749ab896a53b394af96fbd8883c46095 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 2 Mar 2021 13:13:19 +0100 Subject: [PATCH 3/5] Made Pipeline a ViewableWrapper subclass --- panel/pipeline.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/panel/pipeline.py b/panel/pipeline.py index 348aef863c..3568df904f 100644 --- a/panel/pipeline.py +++ b/panel/pipeline.py @@ -11,6 +11,7 @@ from .widgets import Button, Select from .param import Param from .util import param_reprs +from .viewable import ViewableWrapper class PipelineError(RuntimeError): @@ -102,7 +103,7 @@ def get_breadths(node, graph, depth=0, breadths=None): -class Pipeline(param.Parameterized): +class Pipeline(ViewableWrapper): """ A Pipeline represents a directed graph of stages, which each return a panel object to render. A pipeline therefore represents @@ -222,6 +223,9 @@ def __init__(self, stages=[], graph={}, **params): self.add_stage(name, stage, **kwargs) self.define_graph(graph) + def __panel__(self): + return self.layout + def _validate(self, stage): if any(stage is s for n, (s, kw) in self._stages.items()): raise ValueError('Stage %s is already in pipeline' % stage) @@ -527,9 +531,6 @@ def tap_renderer(plot, element): ) return plot - def _repr_mimebundle_(self, include=None, exclude=None): - return self.layout._repr_mimebundle_(include, exclude) - #---------------------------------------------------------------- # Public API #---------------------------------------------------------------- From bebfa147d0c6ac80040ef14768a2cc545129baa9 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 2 Mar 2021 13:33:44 +0100 Subject: [PATCH 4/5] Renamed to Viewer --- panel/pipeline.py | 4 ++-- panel/viewable.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/panel/pipeline.py b/panel/pipeline.py index 3568df904f..2bde821bfa 100644 --- a/panel/pipeline.py +++ b/panel/pipeline.py @@ -11,7 +11,7 @@ from .widgets import Button, Select from .param import Param from .util import param_reprs -from .viewable import ViewableWrapper +from .viewable import Viewer class PipelineError(RuntimeError): @@ -103,7 +103,7 @@ def get_breadths(node, graph, depth=0, breadths=None): -class Pipeline(ViewableWrapper): +class Pipeline(Viewer): """ A Pipeline represents a directed graph of stages, which each return a panel object to render. A pipeline therefore represents diff --git a/panel/viewable.py b/panel/viewable.py index f43b396b7f..0e01446c5b 100644 --- a/panel/viewable.py +++ b/panel/viewable.py @@ -771,7 +771,7 @@ def server_doc(self, doc=None, title=None, location=True): return doc -class ViewableWrapper(param.Parameterized): +class Viewer(param.Parameterized): """ A baseclass for custom components which return a Panel object. By implementing the __panel__ method users can make a panel component @@ -793,7 +793,7 @@ def show(self, title=None, port=0, address=None, websocket_origin=None, threaded=False, verbose=True, open=True, location=True, **kwargs): return self.__panel__().show( title, port, address, websocket_origin, threaded, - verbose, option, location, **kwargs + verbose, open, location, **kwargs ) show.__doc__ = ServableMixin.show.__doc__ From 448b0cce47e640e7446dbe570ff61b5ecc7f5f04 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 2 Mar 2021 13:37:02 +0100 Subject: [PATCH 5/5] Update docstring --- panel/viewable.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/panel/viewable.py b/panel/viewable.py index 0e01446c5b..2705ebe747 100644 --- a/panel/viewable.py +++ b/panel/viewable.py @@ -773,9 +773,10 @@ def server_doc(self, doc=None, title=None, location=True): class Viewer(param.Parameterized): """ - A baseclass for custom components which return a Panel object. By - implementing the __panel__ method users can make a panel component - usable inside Panel without explicitly returning a Panel object. + A baseclass for custom components that behave like a Panel object. + By implementing __panel__ method an instance of this class will + behave like the returned Panel component when placed in a layout, + render itself in a notebook and provide show and servable methods. """ def __panel__(self):