From 0930d27fbdb82b9c3732494a0f9d2f50ef2214bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Mon, 21 Oct 2024 11:22:58 +0200 Subject: [PATCH 1/8] ci: Use Microsoft channel for pytest-playwright (#7424) --- pixi.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index d9b80db49c..dec24c81d6 100644 --- a/pixi.toml +++ b/pixi.toml @@ -161,7 +161,7 @@ channels = ["microsoft"] [feature.test-ui.dependencies] playwright = { version = "*", channel = "microsoft" } -pytest-playwright = "*" +pytest-playwright = { version = "*", channel = "microsoft" } pytest-asyncio = "*" jupyter_server = "*" esbuild = "*" From c6505f065346d640f38d95e4e949669112b43ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Mon, 21 Oct 2024 11:55:41 +0200 Subject: [PATCH 2/8] Add reference to patch_tabulator (#7423) * add reference to patch_tabulator * Bump pre-commit --------- Co-authored-by: Philipp Rudiger --- .pre-commit-config.yaml | 4 ++-- panel/compiler.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 32e84421e8..6d1ae3d01c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: exclude: \.min\.js$ - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.9 + rev: v0.7.0 hooks: - id: ruff files: panel/ @@ -47,7 +47,7 @@ repos: - id: oxipng stages: [manual] - repo: https://github.com/pre-commit/mirrors-eslint - rev: v9.12.0 + rev: v9.13.0 hooks: - id: eslint args: ['-c', 'panel/.eslintrc.js', 'panel/*.ts', 'panel/models/**/*.ts', '--fix'] diff --git a/panel/compiler.py b/panel/compiler.py index 108b1b7095..d9152fc9e4 100644 --- a/panel/compiler.py +++ b/panel/compiler.py @@ -349,13 +349,14 @@ def bundle_icons(verbose=False, external=True, download_list=None): shutil.copyfile(icon, dest_dir / os.path.basename(icon)) def patch_tabulator(): - # https://github.com/olifolkerd/tabulator/issues/4421 path = BUNDLE_DIR / 'datatabulator' / 'tabulator-tables@6.3.0' / 'dist' / 'js' / 'tabulator.min.js' text = path.read_text() + # https://github.com/olifolkerd/tabulator/issues/4421 old = '"focus"!==this.options("editTriggerEvent")&&"click"!==this.options("editTriggerEvent")' new = '"click"!==this.options("editTriggerEvent")' assert text.count(old) == 1 text = text.replace(old, new) + # https://github.com/olifolkerd/tabulator/pull/4598 old = '(i=!0,this.subscribed("table-resize")?this.dispatch("table-resize"):this.redraw())' new = '(i=!0,this.redrawing||(this.redrawing=!0,this.subscribed("table-resize")?this.dispatch("table-resize"):this.redraw(),this.redrawing=!1))' assert text.count(old) == 1 From 110117da166b48ddabe4c9285ced301478b8b7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Tue, 22 Oct 2024 08:55:41 +0200 Subject: [PATCH 3/8] enh: Set Bokeh log level to info when importing dask.distributed (#7426) * enh: Set Bokeh log level to info when importing dask.distributed * Update panel/command/serve.py --- panel/command/serve.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/panel/command/serve.py b/panel/command/serve.py index 35e9a6d16a..ae4fe49838 100644 --- a/panel/command/serve.py +++ b/panel/command/serve.py @@ -670,5 +670,10 @@ def invoke(self, args: argparse.Namespace): # Empty layout are valid and the Bokeh warning is silenced as usually # not relevant to Panel users. silence(EMPTY_LAYOUT, True) + # dask.distributed changes the logging level of Bokeh, we will overwrite it + # if the environment variable is not set to the default Bokeh level + # See https://github.com/holoviz/panel/issues/2302 + if "DASK_DISTRIBUTED__LOGGING__BOKEH" not in os.environ: + os.environ["DASK_DISTRIBUTED__LOGGING__BOKEH"] = "info" args.dev = None super().invoke(args) From 03542a6005e1d4eb7dbf58fd8058257bdcbd9b1c Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 23 Oct 2024 06:25:26 -0400 Subject: [PATCH 4/8] Ensure Tabulator table content does not overflow (#7425) --- panel/models/tabulator.ts | 7 +++++++ panel/styles/models/tabulator.less | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 panel/styles/models/tabulator.less diff --git a/panel/models/tabulator.ts b/panel/models/tabulator.ts index 3cc745b2a3..51867a87b4 100644 --- a/panel/models/tabulator.ts +++ b/panel/models/tabulator.ts @@ -2,6 +2,7 @@ import {display, undisplay} from "@bokehjs/core/dom" import {sum} from "@bokehjs/core/util/arrayable" import {isArray, isBoolean, isString, isNumber} from "@bokehjs/core/util/types" import {ModelEvent} from "@bokehjs/core/bokeh_events" +import type {StyleSheetLike} from "@bokehjs/core/dom" import {div} from "@bokehjs/core/dom" import {Enum} from "@bokehjs/core/kinds" import type * as p from "@bokehjs/core/properties" @@ -17,6 +18,8 @@ import {transform_cds_to_records} from "./data" import {HTMLBox, HTMLBoxView} from "./layout" import {schedule_when} from "./util" +import tabulator_css from "styles/models/tabulator.css" + export class TableEditEvent extends ModelEvent { constructor(readonly column: string, readonly row: number, readonly pre: boolean) { super() @@ -547,6 +550,10 @@ export class DataTabulatorView extends HTMLBoxView { this.restore_scroll() } + override stylesheets(): StyleSheetLike[] { + return [...super.stylesheets(), tabulator_css] + } + setCSSClasses(el: HTMLDivElement): void { el.className = "pnx-tabulator tabulator" for (const cls of this.model.theme_classes) { diff --git a/panel/styles/models/tabulator.less b/panel/styles/models/tabulator.less new file mode 100644 index 0000000000..f82ea6ab4a --- /dev/null +++ b/panel/styles/models/tabulator.less @@ -0,0 +1,3 @@ +.tabulator-table { + max-width: 100% +} From 12df5209429ca0a021de45138d67bcdceae754e6 Mon Sep 17 00:00:00 2001 From: Maxime Liquet <35924738+maximlt@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:49:24 +0200 Subject: [PATCH 5/8] Tabulator: ensure markup panes wrap text in row_content (#7431) --- panel/styles/models/tabulator.less | 6 +++++- panel/tests/ui/widgets/test_tabulator.py | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/panel/styles/models/tabulator.less b/panel/styles/models/tabulator.less index f82ea6ab4a..04c5dc6c46 100644 --- a/panel/styles/models/tabulator.less +++ b/panel/styles/models/tabulator.less @@ -1,3 +1,7 @@ .tabulator-table { - max-width: 100% + max-width: 100%; + + .tabulator-row .row-content .bk-panel-models-markup-HTML { + white-space: normal; + } } diff --git a/panel/tests/ui/widgets/test_tabulator.py b/panel/tests/ui/widgets/test_tabulator.py index 8663a597f2..c7643ed344 100644 --- a/panel/tests/ui/widgets/test_tabulator.py +++ b/panel/tests/ui/widgets/test_tabulator.py @@ -23,6 +23,7 @@ from panel.io.state import state from panel.layout.base import Column from panel.models.tabulator import _TABULATOR_THEMES_MAPPING +from panel.pane import Markdown from panel.tests.util import get_ctrl_modifier, serve_component, wait_until from panel.util import BOKEH_GE_3_6 from panel.widgets import Select, Tabulator, TextInput @@ -4079,3 +4080,17 @@ def test_tabulator_header_tooltips(page): page.wait_for_timeout(200) expect(page.locator('.tabulator-tooltip')).to_have_text("Test") + + +def test_tabulator_row_content_markup_wrap(page): + # https://github.com/holoviz/panel/issues/7388 + + df = pd.DataFrame({"col": ["foo"]}) + long_markdown = Markdown("xxxx " * 50) + widget = Tabulator(df, row_content=lambda row: long_markdown, expanded=[0], width=200) + + serve_component(page, widget) + + md = page.locator('.row-content .bk-panel-models-markup-HTML') + + assert md.bounding_box()['height'] >= 130 From 7f850dc3c57a516d4c02656675e884a5b1ddd930 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 23 Oct 2024 12:52:10 +0200 Subject: [PATCH 6/8] Bump panel.js to 1.5.3 --- CHANGELOG.md | 2 ++ doc/about/releases.md | 1 + panel/package-lock.json | 4 ++-- panel/package.json | 2 +- pyproject.toml | 4 ++-- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b25aac1b1..5917acf639 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ This release fixes a number of smaller regressions related to `Tabulator` `row_c - Prevent `Tabulator` from overlapping when `max_height` is set ([#7403](https://github.com/holoviz/panel/pull/7403)) - Do not mutate layout `Children` inplace ([#7417](https://github.com/holoviz/panel/pull/7403)) - Set `Tabulator` null formatter to empty string ([#7421](https://github.com/holoviz/panel/pull/7421)) +- Ensure Tabulator table content does not overflow ([#7425](https://github.com/holoviz/panel/pull/7425)) + ### Compatibility diff --git a/doc/about/releases.md b/doc/about/releases.md index 1972d30591..e7e919821f 100644 --- a/doc/about/releases.md +++ b/doc/about/releases.md @@ -22,6 +22,7 @@ This release fixes a number of smaller regressions related to `Tabulator` `row_c - Prevent `Tabulator` from overlapping when `max_height` is set ([#7403](https://github.com/holoviz/panel/pull/7403)) - Do not mutate layout `Children` inplace ([#7417](https://github.com/holoviz/panel/pull/7403)) - Set `Tabulator` null formatter to empty string ([#7421](https://github.com/holoviz/panel/pull/7421)) +- Ensure Tabulator table content does not overflow ([#7425](https://github.com/holoviz/panel/pull/7425), [#7431](https://github.com/holoviz/panel/pull/7431)) ### Compatibility diff --git a/panel/package-lock.json b/panel/package-lock.json index bfbae0483d..1ef564d22f 100644 --- a/panel/package-lock.json +++ b/panel/package-lock.json @@ -1,12 +1,12 @@ { "name": "@holoviz/panel", - "version": "1.5.3-b.1", + "version": "1.5.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@holoviz/panel", - "version": "1.5.3-b.1", + "version": "1.5.3", "license": "BSD-3-Clause", "dependencies": { "@bokeh/bokehjs": "3.6.0", diff --git a/panel/package.json b/panel/package.json index 248b178691..2d0de61073 100644 --- a/panel/package.json +++ b/panel/package.json @@ -1,6 +1,6 @@ { "name": "@holoviz/panel", - "version": "1.5.3-b.1", + "version": "1.5.3", "description": "The powerful data exploration & web app framework for Python.", "license": "BSD-3-Clause", "repository": { diff --git a/pyproject.toml b/pyproject.toml index 3138f65395..64b76cd384 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,13 +71,13 @@ HoloViz = "https://holoviz.org/" [project.optional-dependencies] recommended = [ 'jupyterlab', - 'holoviews >=1.16.0', + 'holoviews >=1.18.0', 'matplotlib', 'pillow', 'plotly', ] fastapi = [ - 'bokeh-fastapi >= 0.1.0', + 'bokeh-fastapi >= 0.1.2', 'fastapi[standard]', ] dev = [ From 4d4cd6b6f6648535a4bbff7af23489e8e2a179ee Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 23 Oct 2024 08:11:32 -0400 Subject: [PATCH 7/8] Check whether property value has changed after transform (#7432) * Check whether property value has changed after transform * Add test --- panel/reactive.py | 30 +++++++++++++++++++++++------- panel/tests/test_custom.py | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/panel/reactive.py b/panel/reactive.py index 81b0a076ba..6d1e96a780 100644 --- a/panel/reactive.py +++ b/panel/reactive.py @@ -1582,16 +1582,32 @@ def _process_param_change(self, params): def _set_on_model(self, msg: Mapping[str, Any], root: Model, model: Model) -> None: if not msg: return - old = self._changing.get(root.ref['id'], []) - self._changing[root.ref['id']] = [ - attr for attr, value in msg.items() - if not model.lookup(attr).property.matches(getattr(model, attr), value) - ] + prev_changing = self._changing.get(root.ref['id'], []) + changing = [] + transformed = {} + for attr, value in msg.items(): + prop = model.lookup(attr).property + old = getattr(model, attr) + try: + matches = bool(prop.matches(old, value)) + except Exception: + for tp, converter in prop.alternatives: + if tp.is_valid(value): + value = converter(value) + break + try: + matches = bool(prop.matches(old, value)) + except Exception: + matches = False + if not matches: + transformed[attr] = value + changing.append(attr) + self._changing[root.ref['id']] = changing try: - model.update(**msg) + model.update(**transformed) finally: if old: - self._changing[root.ref['id']] = old + self._changing[root.ref['id']] = prev_changing else: del self._changing[root.ref['id']] diff --git a/panel/tests/test_custom.py b/panel/tests/test_custom.py index 45ef95e0ae..97e32a1ea3 100644 --- a/panel/tests/test_custom.py +++ b/panel/tests/test_custom.py @@ -1,3 +1,5 @@ +import numpy as np +import pandas as pd import param from panel.custom import PyComponent, ReactiveESM @@ -44,6 +46,25 @@ def test_py_component_cleanup(document, comm): assert not spy._view__._models +class ESMDataFrame(ReactiveESM): + + df = param.DataFrame() + + +def test_reactive_esm_sync_dataframe(document, comm): + esm_df = ESMDataFrame() + + model = esm_df.get_root(document, comm) + + esm_df.df = pd.DataFrame({"1": [2]}) + + assert isinstance(model.data.df, dict) + assert len(model.data.df) == 2 + expected = {"index": np.array([0]), "1": np.array([2])} + for col, values in model.data.df.items(): + np.testing.assert_array_equal(values, expected.get(col)) + + class ESMWithChildren(ReactiveESM): child = param.ClassSelector(class_=Viewable) From 26c2e7af922392c647dff9ff46cdd4504cd958b9 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 24 Oct 2024 13:21:12 +0200 Subject: [PATCH 8/8] Improve preview error handling (#7434) * improve preview error handling * review feedback --- panel/io/jupyter_server_extension.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panel/io/jupyter_server_extension.py b/panel/io/jupyter_server_extension.py index d11a74e1a7..1c8a7a1f5a 100644 --- a/panel/io/jupyter_server_extension.py +++ b/panel/io/jupyter_server_extension.py @@ -389,6 +389,9 @@ async def open(self, path, *args, **kwargs) -> None: self.session_id = get_session_id(token) if self.session_id not in state._kernels: self.close() + msg = f"Session ID '{self.session_id}' does not correspond to any active kernel." + raise RuntimeError(msg) + kernel_info = state._kernels[self.session_id] self.kernel, self.comm_id, self.kernel_id, _ = kernel_info state._kernels[self.session_id] = kernel_info[:-1] + (True,)