Tranquilizer endpoint inside class

Hi all,

I need:

  1. A means to set parameters so that a dashboard can be launched to specific target data from elsewhere. Elsewhere probably being a Flask app, but not necessarily.
  2. Separate users (different LAN IPs) to have separate values for various parameters in their respective sessions and they can adjust some of them.
  3. Some parameters may be considered fixed in stage (1) and adjustable in stage (2)

Currently looking at trying to put a tranquilize API endpoint inside a class so separate app instances will serve each user and they’ll be self-contained.

MRP below.

from panel.viewable import ServableMixin
from tranquilizer import tranquilize

import panel as pn
import param

main.py
# -----------------------------------------------------------------------------
class TestViewerApp(pn.viewable.Viewer):

    value_input: str = param.String(label="Input")
    value_output: str = param.String(label="Output")

    intermediary: str = param.String()

    # -------------------------------------------------------------------------
    def __init__(
        self,
        **params,
    ):
        super().__init__(**params)

        self._input_widget = pn.widgets.TextInput.from_param(
            self.param.value_input,
            placeholder="Enter Some text ...",
        )
        self._output_widget = pn.widgets.StaticText.from_param(
            self.param.value_output,
            )

        self._layout = pn.Column(self._input_widget,
                                 self._output_widget)

    # -------------------------------------------------------------------------
    def __panel__(self):
        return self._layout

    # -------------------------------------------------------------------------
    def create_template(self):
        return pn.template.BootstrapTemplate(main=[self._layout])

    # -------------------------------------------------------------------------
    @pn.depends("value_input", watch=True, on_init=True)
    def _update_output(self) -> None:
        inpt = self.value_input
        if not inpt:
            self.value_output="Enter Some text ..."
        else:
            self.value_output = f"Input: {inpt!r}"

    # -------------------------------------------------------------------------
    @tranquilize(method="get")
    def update_input(self, value_input):
        self.value_input = value_input
        print(f"Updating value for input to : {value_input}")


# -----------------------------------------------------------------------------
def session_test_app() -> ServableMixin:
    """A simple test app to check if the platform client is running."""
    return TestViewerApp().create_template()


# %% Main
print(f"test_panel.py {__name__=!r}")
if __name__ == "__main__":
    # Run with `python test_panel.py`
    pn.serve(
        {"session_test": session_test_app},
    )
else:
    # Run with `panel serve test_panel.py`
    session_test_app().servable()

Running with

panel serve main.py --address=“0.0.0.0” --allow-websocket-origins=127.0.0.1:5006 --allow-websocket-origins=X.X.X.X:5006 --rest-provider tranquilizer

Is leading to a 404 when trying to hit

localhost:5006/rest/update_input?value_input=sfsdgsfd

Will dig around tranquiliser source to see what I can do (as its likely the problem is there) - but putting this here in case anyone else has had similar and may have an alternative route to resolution.

[Particularly with regards other approaches to the use case]

Thank you for reading this far!

I’ve ended up taking a different pathway outside tranquilizer and using the url access/manipulate section of docs.

Example code is now:

from panel.viewable import ServableMixin

import panel as pn
import param


# -----------------------------------------------------------------------------
class TestViewerApp(pn.viewable.Viewer):
    """!
    A class for creating a test app to demonstrate independent sessions and
    user ability to manipulate via URL

    """

    value_input: str = param.String(label="Input")
    value_output: str = param.String(label="Output")

    slider_val: int = param.Integer(label="Input")

    # -------------------------------------------------------------------------
    def __init__(self,
                 **params,
                 ):
        """!
        **Instantiate the class**

        @param [in] params [dict] Holds the class vars for use in super()

        """
        super().__init__(**params)

        self._input_widget = pn.widgets.TextInput.from_param(
            self.param.value_input,
            placeholder="Enter Some text ...",
        )
        self._output_widget = pn.widgets.StaticText.from_param(
            self.param.value_output,
            )

        self.slider_input_widget = pn.widgets.IntSlider(
            name='Slider A',
            start=0,
            end=10,
            value=self.param.slider_val,
            )

        self.slider_output_widget = pn.widgets.StaticText.from_param(
            self.param.slider_val,
            )

        self.slider_input_widget.link(
            self.slider_output_widget,
            callbacks={"value": self._update_output_slider2,
                       },
            )

        self._layout = pn.Column(self._input_widget,
                                 self._output_widget,
                                 self.slider_input_widget,
                                 self.slider_output_widget,
                                 )

        self.state = pn.state

    # -------------------------------------------------------------------------
    def create_template(self):
        """!
        **Cretae the template for viewing**
        """
        return pn.template.BootstrapTemplate(main=[self._layout])

    # -------------------------------------------------------------------------
    @pn.depends("value_input", watch=True, on_init=True)
    def _update_output_value(self) -> None:
        input_ = self.value_input
        if not input_:
            self.value_output = "Enter Some text ..."
        else:
            self.value_output = f"Input: {input_!r}"

    # -------------------------------------------------------------------------
    def _update_output_slider2(self, target, event):
        target.value = int(event.new)
        self.slider_val = int(event.new)


# -----------------------------------------------------------------------------
def session_test_app() -> ServableMixin:
    """Test app to check if the platform client is running."""
    app = TestViewerApp()

    template_ = app.create_template()

    if app.state.location:
        app.state.location.sync(app._input_widget,
                                {"value": "value_input"})
        app.state.location.sync(app.slider_input_widget,
                                {"value": "slider_input"})

    return template_


# %% Main
print(f"test_panel.py {__name__=!r}")
if __name__ == "__main__":
    # Run with `python test_panel.py`
    pn.serve(
        {"session_test": session_test_app},
        address="0.0.0.0",
        port=5006,
        allow_websocket_origin=["localhost:5006",
                                "127.0.0.1:5006",
                                "10.15.44.86:5006",
                                ],
        show=False,
    )
else:
    # Run with `panel serve test_panel.py`
    session_test_app().servable()
1 Like