Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it easy to use dataclass like models using familiar apis #6912

Open
wants to merge 65 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
cd58f50
improve ipywidgets reference guide
MarcSkovMadsen Jun 5, 2024
e75776a
improve language
MarcSkovMadsen Jun 5, 2024
19c9741
clean notebook
MarcSkovMadsen Jun 5, 2024
428ec92
fix reference links
MarcSkovMadsen Jun 5, 2024
86b5002
explain sizing better
MarcSkovMadsen Jun 5, 2024
71287e4
pre-commit
MarcSkovMadsen Jun 5, 2024
8b41a07
design spec including tests
MarcSkovMadsen Jun 11, 2024
f0a766d
support layout kwargs
MarcSkovMadsen Jun 11, 2024
1da8658
use panel
MarcSkovMadsen Jun 11, 2024
17a39e3
update design spec
MarcSkovMadsen Jun 11, 2024
4907090
implement rx
MarcSkovMadsen Jun 11, 2024
42b2d82
implement first version
MarcSkovMadsen Jun 11, 2024
00b5731
add to_viewer back
MarcSkovMadsen Jun 11, 2024
a8021a5
carve out sync_parameterized
MarcSkovMadsen Jun 11, 2024
1c18076
major refactor of ipywidget
MarcSkovMadsen Jun 12, 2024
09f6a1c
fix remaining todos
MarcSkovMadsen Jun 12, 2024
12583df
skip test if not ipywidgets available
MarcSkovMadsen Jun 13, 2024
883eb7b
carve out and add back in other PR
MarcSkovMadsen Jun 13, 2024
d80a506
Merge branch 'docs/ipywidgets-reference-update' into ipywidget_utility
MarcSkovMadsen Jun 13, 2024
56ed52e
update names and improve docstrings
MarcSkovMadsen Jun 13, 2024
c21c865
use model and names terminology
MarcSkovMadsen Jun 15, 2024
025659b
support wrapping model Classes
MarcSkovMadsen Jun 15, 2024
e649aeb
support WidgetViewer from class
MarcSkovMadsen Jun 15, 2024
83a5f93
add missing test
MarcSkovMadsen Jun 15, 2024
0a83798
make _names an attribute instead of parameter
MarcSkovMadsen Jun 15, 2024
771f986
simplify to model class
MarcSkovMadsen Jun 15, 2024
2f0f175
expose model
MarcSkovMadsen Jun 15, 2024
8471e49
clean up tests
MarcSkovMadsen Jun 15, 2024
36217c9
document. had to move to wrappers module
MarcSkovMadsen Jun 15, 2024
aa0eaa3
rename to observers
MarcSkovMadsen Jun 15, 2024
b1da06b
rename for more generality and alignment with observer pattern
MarcSkovMadsen Jun 15, 2024
7661402
first version of how-to guide
MarcSkovMadsen Jun 15, 2024
b2ad70b
docs review
MarcSkovMadsen Jun 15, 2024
88344a2
add comment
MarcSkovMadsen Jun 15, 2024
d1b5d9e
remove example files
MarcSkovMadsen Jun 15, 2024
56d0740
Merge branch 'main' of https://github.com/holoviz/panel into ipywidge…
MarcSkovMadsen Jun 15, 2024
bcd21a4
review feedback
MarcSkovMadsen Jun 15, 2024
3669877
docs review feedback
MarcSkovMadsen Jun 15, 2024
4a20c94
fix links
MarcSkovMadsen Jun 15, 2024
fdd25bf
refactor to dataclass namespace
MarcSkovMadsen Jun 16, 2024
6e1215d
rename _names to names and _model_names
MarcSkovMadsen Jun 16, 2024
b178ebf
refactor to support Pydantic too
MarcSkovMadsen Jun 16, 2024
289a125
update table
MarcSkovMadsen Jun 16, 2024
6f9c4f5
add ideas for observing pydantic
MarcSkovMadsen Jun 16, 2024
2ae5d19
Various cleanup
philippjfr Jun 17, 2024
a543719
Add pydantic to pixi deps
philippjfr Jun 17, 2024
287d240
Fix indexes
philippjfr Jun 17, 2024
08819f7
Fix index
philippjfr Jun 17, 2024
8baab7c
update names for consistency
MarcSkovMadsen Jun 17, 2024
60f7964
Align docstring
philippjfr Jun 17, 2024
a3c7b4e
Optimize and fix parameter syncing
philippjfr Jun 17, 2024
0fc8092
Rename create_ functions to to_
philippjfr Jun 18, 2024
6d8c2a3
Reorganize dataclass module
philippjfr Jun 18, 2024
11685c8
Convert parameter types
philippjfr Jun 18, 2024
fb2e77d
Merge branch 'main' into ipywidget_utility
philippjfr Jun 21, 2024
1aff765
Serialize datetime objects
philippjfr Jun 22, 2024
3bd2fad
Allow dev version in base_version
philippjfr Jun 22, 2024
bf17799
Merge remote-tracking branch 'origin/main' into ipywidget_utility
MarcSkovMadsen Jul 13, 2024
3cac03e
review feedback
MarcSkovMadsen Jul 14, 2024
ef1521f
fix
MarcSkovMadsen Jul 14, 2024
0a9902a
pydantic parameters + default value
MarcSkovMadsen Jul 14, 2024
11a896d
add missing pydantic parameters
MarcSkovMadsen Jul 15, 2024
f7ee165
fix tuple exception
MarcSkovMadsen Jul 15, 2024
fc76ad4
add ModelForm
MarcSkovMadsen Jul 15, 2024
d364cfe
refactor
MarcSkovMadsen Jul 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions panel/ipywidget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Functionality to enable easily interacting with ipywidgets via familiar APIs like pn.bind,
@pn.depends and pn.rx"""

from typing import TYPE_CHECKING, Iterable

import param

from .viewable import Viewer

if TYPE_CHECKING:
try:
from traitlets import HasTraits
except ModuleNotFoundError:

class HasTraits: # type: ignore
"""Mock class"""

else:

class HasTraits: # type: ignore
"""Mock class"""


def to_viewer(widget: HasTraits, parameters: Iterable | None = None, **kwargs) -> Viewer:
MarcSkovMadsen marked this conversation as resolved.
Show resolved Hide resolved
MarcSkovMadsen marked this conversation as resolved.
Show resolved Hide resolved
"""Returns a Viewer object with parameters synced to the ipywidget widget parameters
MarcSkovMadsen marked this conversation as resolved.
Show resolved Hide resolved

Args:
widget (HasTraits): The ipywidget to create the Viewer from.
parameters (Iterable | None): The parameters to add to the Viewer and to sync.
If no parameters are specified all parameters on the widget will be added
and synced.
kwargs: Any kwargs provided will be forwarded to the IPyWidget pane used to display the
widget.
"""
raise NotImplementedError()


def to_rx(
MarcSkovMadsen marked this conversation as resolved.
Show resolved Hide resolved
widget: HasTraits, parameters: Iterable | None = None
) -> tuple[param.rx, ...]:
"""Returns a tuple of `rx` parameters. Each one synced to a parameter of the ipywidget widget.

Args:
widget (HasTraits): The ipywidget to create the `rx` parameters from.
parameters (Iterable): The parameters to create `rx` parameters from and to sync.
If no parameters are specified all parameters on the widget will be added
and synced.
"""
raise NotImplementedError()
135 changes: 135 additions & 0 deletions panel/tests/test_ipywidget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"""We test that we can work with Ipywidgets and AnyWidgets via Parameters or Reactive values
instead of Traitlets observer pattern.

The purpose is to enable Panel users to easily use Ipywidgets using familiar APIs.
"""

import param

from traitlets import (
Float, HasTraits, Int, Unicode,
)

import panel as pn

from panel.ipywidget import to_rx, to_viewer


class ExampleTraitlets(HasTraits):
name = Unicode("Default Name").tag(description="A string trait")
age = Int(0).tag(description="An integer trait")
height = Float(0.0).tag(description="A float trait")


def test_to_viewer():
widget = ExampleTraitlets(name="A", age=1, height=1.1)

viewer = to_viewer(widget)

Check failure on line 27 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:ubuntu-latest

test_to_viewer NotImplementedError

Check failure on line 27 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / core:test-core:ubuntu-latest

test_to_viewer NotImplementedError

Check failure on line 27 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:ubuntu-latest

test_to_viewer NotImplementedError

Check failure on line 27 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:macos-latest

test_to_viewer NotImplementedError

Check failure on line 27 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:macos-latest

test_to_viewer NotImplementedError

assert isinstance(viewer, pn.viewable.Viewer)
assert {"name", "age", "height"} == set(viewer.param.params)

assert viewer.name == widget.name
assert viewer.age == widget.age
assert viewer.height == widget.height

# widget synced to widget
widget.name = "B"
widget.age = 2
widget.height = 2.2
assert viewer.name == widget.name
assert viewer.age == widget.age
assert viewer.height == widget.height

# widget synced to viewer
viewer.name = "C"
viewer.age = 3
viewer.height = 3.3
assert viewer.name == widget.name
assert viewer.age == widget.age
assert viewer.height == widget.height

component = viewer.__panel__()
assert isinstance(component, pn.pane.IPyWidget)
assert component.object == widget


def test_to_viewer_parameter_list():
widget = ExampleTraitlets(name="A", age=1, height=1.1)

viewer = to_viewer(widget, parameters=["name", "age"])

Check failure on line 60 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:ubuntu-latest

test_to_viewer_parameter_list NotImplementedError

Check failure on line 60 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / core:test-core:ubuntu-latest

test_to_viewer_parameter_list NotImplementedError

Check failure on line 60 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:ubuntu-latest

test_to_viewer_parameter_list NotImplementedError

Check failure on line 60 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:macos-latest

test_to_viewer_parameter_list NotImplementedError

Check failure on line 60 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:macos-latest

test_to_viewer_parameter_list NotImplementedError

assert isinstance(viewer, pn.viewable.Viewer)
assert {"name", "age"} == set(viewer.param.params)

assert viewer.name == widget.name
assert viewer.age == widget.age

# widget synced to widget
widget.name = "B"
widget.age = 2
assert viewer.name == widget.name
assert viewer.age == widget.age

# widget synced to viewer
viewer.name = "C"
viewer.age = 3
assert viewer.name == widget.name
assert viewer.age == widget.age

def test_to_viewer_kwargs():
widget = ExampleTraitlets(name="A", age=1, height=1.1)

viewer = to_viewer(widget, parameters=["name", "age"], sizing_mode="stretch_width")

Check failure on line 83 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:ubuntu-latest

test_to_viewer_kwargs NotImplementedError

Check failure on line 83 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / core:test-core:ubuntu-latest

test_to_viewer_kwargs NotImplementedError

Check failure on line 83 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:ubuntu-latest

test_to_viewer_kwargs NotImplementedError

Check failure on line 83 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:macos-latest

test_to_viewer_kwargs NotImplementedError

Check failure on line 83 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:macos-latest

test_to_viewer_kwargs NotImplementedError
assert viewer.__panel__().sizing_mode=="stretch_width"

def test_to_rx():
widget = ExampleTraitlets(name="A", age=1, height=1.1)

name, age, height = to_rx(widget)

Check failure on line 89 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:ubuntu-latest

test_to_rx NotImplementedError

Check failure on line 89 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / core:test-core:ubuntu-latest

test_to_rx NotImplementedError

Check failure on line 89 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:ubuntu-latest

test_to_rx NotImplementedError

Check failure on line 89 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:macos-latest

test_to_rx NotImplementedError

Check failure on line 89 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:macos-latest

test_to_rx NotImplementedError
assert isinstance(name, param.rx)
assert isinstance(age, param.rx)
assert isinstance(height, param.rx)

assert name.rx.value == widget.name
assert age.rx.value == widget.age
assert height.rx.value == widget.height

# widget synced to reactive
widget.name = "B"
widget.age = 2
widget.height = 2.2
assert name.rx.value == widget.name
assert age.rx.value == widget.age
assert height.rx.value == widget.height

# reactive synced to viewer
name.rx.value = "C"
age.rx.value = 3
height.rx.value = 3.3
assert name.rx.value == widget.name
assert age.rx.value == widget.age
assert height.rx.value == widget.height


def test_to_rx_parameter_list():
widget = ExampleTraitlets(name="A", age=1, height=1.1)

name, age = to_rx(widget, parameters=["name", "age"])

Check failure on line 118 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:ubuntu-latest

test_to_rx_parameter_list NotImplementedError

Check failure on line 118 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / core:test-core:ubuntu-latest

test_to_rx_parameter_list NotImplementedError

Check failure on line 118 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:ubuntu-latest

test_to_rx_parameter_list NotImplementedError

Check failure on line 118 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-310:macos-latest

test_to_rx_parameter_list NotImplementedError

Check failure on line 118 in panel/tests/test_ipywidget.py

View workflow job for this annotation

GitHub Actions / unit:test-312:macos-latest

test_to_rx_parameter_list NotImplementedError
assert isinstance(name, param.rx)
assert isinstance(age, param.rx)

assert name.rx.value == widget.name
assert age.rx.value == widget.age

# widget synced to reactive
widget.name = "B"
widget.age = 2
assert name.rx.value == widget.name
assert age.rx.value == widget.age

# reactive synced to viewer
name.rx.value = "C"
age.rx.value = 3
assert name.rx.value == widget.name
assert age.rx.value == widget.age
Loading