panel icon indicating copy to clipboard operation
panel copied to clipboard

Combine Existing Components example, EditableRange(Viewer), setting .value not working as expected

Open fohrloop opened this issue 1 year ago • 1 comments

ALL software version info

  • panel 1.4.4
  • param 2.1.0
  • CPython 3.12.2, Ubuntu 22.04

Description of expected behavior and the observed behavior

Following the example in Combine Existing Components. The EditableRange.value does not work as expected.

  • (1) Expecting the value of the EditableRange to be set to the given tuple during initialization. See the test.
  • (2) This one is debatable, but could perhaps also expect that it is possible to set the .value as in other widgets, although the name of the parent class is Viewable (does it mean it is uneditable? Or just that it it's possible to view this inside a Jupyter Notebook or dashboard app?). Nothing in the docs say that it is not editable, and the cross-callbacks (_sync_widgets, _sync_params) might make you think the value it is.

Complete, minimal, self-contained example code that reproduces the issue

This one is copied from the docs (Combine Existing Components).

import panel as pn
import param
from panel.viewable import Viewer

class EditableRange(Viewer):

    value = param.Range(doc="A numeric range.")

    width = param.Integer(default=300)

    def __init__(self, **params):
        self._start_input = pn.widgets.FloatInput()
        self._end_input = pn.widgets.FloatInput(align="end")
        super().__init__(**params)
        self._layout = pn.Row(self._start_input, self._end_input)
        self._sync_widgets()

    def __panel__(self):
        return self._layout

    @param.depends("value", "width", watch=True)
    def _sync_widgets(self):
        self._start_input.name = self.name
        self._start_input.value = self.value[0]
        self._end_input.value = self.value[1]
        self._start_input.width = self.width // 2
        self._end_input.width = self.width // 2

    @param.depends("_start_input.value", "_end_input.value", watch=True)
    def _sync_params(self):
        self.value = (self._start_input.value, self._end_input.value)
  • the unit test:
class TestEditableRange:
    def test_value_change(self):
        er = EditableRange(name="foo", value=(25.0, 75.0))
        assert er.value == (25.0, 75.0)

        er.value = (20.0, 80.0)
        assert er.value == (20.0, 80.0)

Stack traceback and/or browser JavaScript console output

This is what you get from the test:

self = <mypkg.TestEditableRange object at 0x7933b1d8aa80>

    def test_value_change(self):
        er = EditableRange(name="foo", value=(25.0, 75.0))
>       assert er.value == (25.0, 75.0)
E       assert (25.0, 0) == (25.0, 75.0)
E         
E         At index 1 diff: 0 != 75.0
E         Use -v to get more diff

tests/test_example.py:130: AssertionError

Screenshots or screencasts of the bug in action

  • [ ] I may be interested in making a pull request to address this

fohrloop avatar Jun 17 '24 15:06 fohrloop