diff --git a/doc/conf.py b/doc/conf.py index cbdfa33cb7..6e0d2bac55 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -2,6 +2,8 @@ import os import pathlib +from typing import Any + import param param.parameterized.docstring_signature = False @@ -71,8 +73,8 @@ "icon": "fa-brands fa-discord", }, ], - "pygment_light_style": "material", - "pygment_dark_style": "material", + "pygments_light_style": "material", + "pygments_dark_style": "material", "header_links_before_dropdown": 5, 'secondary_sidebar_items': [ "github-stars-button", @@ -82,15 +84,27 @@ "announcement": announcement_text, } -extensions += [ - 'sphinx.ext.napoleon', - 'nbsite.gallery', + +extensions = [ + 'myst_parser', + 'sphinx_design', + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.linkcode', 'sphinx_copybutton', + 'sphinxext.rediraffe', + 'nbsite.gallery', 'nbsite.pyodide', 'nbsite.analytics', ] napoleon_numpy_docstring = True +autodoc_mock_imports = ["panel.pane.vtk"] + myst_enable_extensions = ["colon_fence", "deflist"] gallery_endpoint = 'panel-gallery-dev' if is_dev else 'panel-gallery' @@ -137,12 +151,13 @@ 'PanelCallbackHandler': 'LangChain CallbackHandler', }, 'as_pyodide': True, - 'normalize_titles': False + 'normalize_titles': False, } }, 'thumbnail_url': 'https://assets.holoviz.org/panel/thumbnails', 'deployment_url': gallery_url, 'jupyterlite_url': jlite_url, + 'only_use_existing': True, } if panel.__version__ != version and (PANEL_ROOT / 'dist' / 'wheels').is_dir(): @@ -257,6 +272,37 @@ def update_versions(app, docname, source): source[0] = source[0].replace(old, new) +def setup_mystnb(app): + from myst_nb.core.config import NbParserConfig + from myst_nb.sphinx_ import ( + HideCodeCellNode, HideInputCells, SelectMimeType, + ) + from myst_nb.sphinx_ext import create_mystnb_config + + _UNSET = "--unset--" + for name, default, field in NbParserConfig().as_triple(): + if not field.metadata.get("sphinx_exclude"): + # TODO add types? + app.add_config_value(f"nb_{name}", default, "env", Any) # type: ignore[arg-type] + if "legacy_name" in field.metadata: + app.add_config_value( + f"{field.metadata['legacy_name']}", + _UNSET, + "env", + Any, # type: ignore[arg-type] + ) + app.add_config_value("nb_render_priority", _UNSET, "env", Any) # type: ignore[arg-type] + create_mystnb_config(app) + + # add post-transform for selecting mime type from a bundle + app.add_post_transform(SelectMimeType) + + # setup collapsible content + app.add_post_transform(HideInputCells) + HideCodeCellNode.add_to_app(app) + + + def setup(app) -> None: try: from nbsite.paramdoc import param_formatter, param_skip @@ -265,6 +311,8 @@ def setup(app) -> None: except ImportError: print('no param_formatter (no param?)') + app.connect('builder-inited', setup_mystnb) + app.connect('source-read', update_versions) nbbuild.setup(app) app.add_config_value('grid_item_link_domain', '', 'html') diff --git a/doc/explanation/comms.md b/doc/explanation/architecture/comms.md similarity index 99% rename from doc/explanation/comms.md rename to doc/explanation/architecture/comms.md index 5ceec84758..2a909566d6 100644 --- a/doc/explanation/comms.md +++ b/doc/explanation/architecture/comms.md @@ -1,4 +1,4 @@ -# Panel + Juypter, Servers, etc. +# Communication Channels Panel lets you write Python code that corresponds to Javascript/HTML objects in a web browser, which requires some means of communication between the two languages. How this communication is achieved depends on the context in which Panel is used, i.e., whether it is being run in a notebook like Classic Jupyter, in JupyterLab, as a standalone web server, etc. Usually it all Just Works™, but in case it doesn't, or if you want to understand the details or limitations of a particular configuration, this page will explain which technologies are used in which contexts to achieve the required channels of communication. diff --git a/doc/explanation/linking.md b/doc/explanation/architecture/index.md similarity index 71% rename from doc/explanation/linking.md rename to doc/explanation/architecture/index.md index 20e7f4c882..ece47654e3 100644 --- a/doc/explanation/linking.md +++ b/doc/explanation/architecture/index.md @@ -1,14 +1,14 @@ .. raw:: html - + setValue(newValue) } /> - ) - } - """ + ) + } + """ class DiscreteSlider(MaterialComponent): @@ -88,7 +88,7 @@ class DiscreteSlider(MaterialComponent): aria-label="Restricted values" defaultValue={value} marks={marks} - onChange={(e) => setValue(e.target.value)} + onChange={(e) => setValue(e.target.value)} step={null} valueLabelDisplay="auto" /> @@ -103,7 +103,7 @@ slider = DiscreteSlider() pn.Row( pn.Column(button.controls(['disabled', 'label', 'variant']), button), - pn.Column(rating.controls(['value']), rating), - pn.Column(slider.controls(['value']), slider), + pn.Column(rating.controls(['value']), rating), + pn.Column(slider.controls(['value']), slider), ).servable() ``` diff --git a/doc/how_to/custom_components/python/create_custom_widget.md b/doc/how_to/custom_components/python/create_custom_widget.md index 7bdfdb21ed..514ebf8292 100644 --- a/doc/how_to/custom_components/python/create_custom_widget.md +++ b/doc/how_to/custom_components/python/create_custom_widget.md @@ -45,12 +45,12 @@ class FeatureInput(WidgetBase, PyComponent): super().__init__(**params) - selected_features_widget = pn.widgets.MultiChoice.from_param( + self._selected_features_widget = pn.widgets.MultiChoice.from_param( self.param.selected_features, sizing_mode="stretch_width" ) def __panel__(self): - return pn.Column(selected_features_widget, self._selected_widgets) + return pn.Column(self._selected_features_widget, self._selected_widgets) @param.depends("features", watch=True, on_init=True) def _reset_selected_features(self): diff --git a/examples/gallery/penguin_crossfilter.ipynb b/examples/gallery/penguin_crossfilter.ipynb index 1db7b2263a..e5f7aa736f 100644 --- a/examples/gallery/penguin_crossfilter.ipynb +++ b/examples/gallery/penguin_crossfilter.ipynb @@ -75,7 +75,7 @@ "penguins = pd.read_csv('https://datasets.holoviz.org/penguins/v1/penguins.csv')\n", "penguins = penguins[~penguins.sex.isnull()].reset_index().sort_values('species')\n", "\n", - "penguins" + "penguins.head()" ] }, { diff --git a/panel/_templates/pyodide_handler.js b/panel/_templates/pyodide_handler.js index 6bb454666c..f8774bb129 100644 --- a/panel/_templates/pyodide_handler.js +++ b/panel/_templates/pyodide_handler.js @@ -69,6 +69,9 @@ pyodideWorker.onmessage = async (event) => { render_items[0]['roots'] = roots render_items[0]['root_ids'] = root_ids + // Clear pre-rendered contents + Bokeh.index.roots.map((v) => v.remove()) + // Embed content const [views] = await Bokeh.embed.embed_items(docs_json, render_items) diff --git a/panel/dist/css/chat_message.css b/panel/dist/css/chat_message.css index 06ea28cbf7..80fe23976e 100644 --- a/panel/dist/css/chat_message.css +++ b/panel/dist/css/chat_message.css @@ -149,6 +149,7 @@ .divider { margin-right: 0px; + margin-top: 2px; opacity: 0.2; } diff --git a/panel/io/convert.py b/panel/io/convert.py index ebe2412efc..3a909c2184 100644 --- a/panel/io/convert.py +++ b/panel/io/convert.py @@ -2,7 +2,6 @@ import base64 import concurrent.futures -import dataclasses import json import os import pathlib @@ -12,7 +11,6 @@ import bokeh -from bokeh.application.application import SessionContext from bokeh.application.handlers.code import CodeHandler from bokeh.core.json_encoder import serialize_json from bokeh.core.templates import FILE, MACROS, get_env @@ -25,6 +23,7 @@ from .. import __version__, config from ..util import base_version, escape from .application import Application, build_single_handler_application +from .document import MockSessionContext from .loading import LOADING_INDICATOR_CSS_CLASS from .mime_render import find_requirements from .resources import ( @@ -121,32 +120,6 @@ """ -@dataclasses.dataclass -class Request: - headers : dict - cookies : dict - arguments : dict - - -class MockSessionContext(SessionContext): - - def __init__(self, *args, document=None, **kwargs): - self._document = document - super().__init__(*args, server_context=None, session_id=None, **kwargs) - - def with_locked_document(self, *args): - return - - @property - def destroyed(self) -> bool: - return False - - @property - def request(self): - return Request(headers={}, cookies={}, arguments={}) - - - def make_index(files, title=None, manifest=True): if manifest: manifest = 'site.webmanifest' diff --git a/panel/io/document.py b/panel/io/document.py index dd0d8b629a..ea03602e23 100644 --- a/panel/io/document.py +++ b/panel/io/document.py @@ -75,6 +75,10 @@ def __init__(self, *args, document=None, **kwargs): def with_locked_document(self, *args): return + @property + def session(self): + return None + @property def destroyed(self) -> bool: return False diff --git a/panel/io/ipywidget.py b/panel/io/ipywidget.py index 24be606f25..7cf01502c3 100644 --- a/panel/io/ipywidget.py +++ b/panel/io/ipywidget.py @@ -90,8 +90,8 @@ def _on_widget_constructed(widget, doc=None): if widget._model_id is not None: args['comm_id'] = widget._model_id try: + _IPyComm.kernel = kernel widget.comm = _IPyComm(**args) - widget.comm.kernel = kernel except Exception as e: if 'PANEL_IPYWIDGET' not in os.environ: raise e diff --git a/pixi.toml b/pixi.toml index 94e55f7c1e..2b514e150a 100644 --- a/pixi.toml +++ b/pixi.toml @@ -177,16 +177,18 @@ test-type = 'mypy panel' [feature.doc.activation.env] MOZ_HEADLESS = "1" PANEL_IPYWIDGET = "1" +OBJC_DISABLE_INITIALIZE_FORK_SAFETY = "YES" [feature.doc.dependencies] lxml = "*" -nbsite = ">=0.8.4" +nbsite = ">=0.8.6rc1" selenium = "*" [feature.doc.tasks] _docs-refmanual = 'python ./doc/generate_modules.py panel -d ./doc/api -n panel -e tests' _docs-convert-gallery = 'python scripts/gallery/convert_gallery.py' -_docs-generate = 'nbsite build --what=html --output=builtdocs --org holoviz --project-name panel' +_docs-generate = 'nbsite build --what=html --output=builtdocs --org holoviz --project-name panel --disable-parallel' +_docs-generate-parallel = 'nbsite build --what=html --output=builtdocs --org holoviz --project-name panel' _docs-copy-panel-dist = 'cp -r ./panel/dist ./builtdocs/panel_dist' _docs-pyodide = 'panel convert examples/gallery/*.ipynb doc/how_to/*/examples/*.md --to pyodide-worker --out ./builtdocs/pyodide/ --pwa --index --requirements doc/pyodide_dependencies.json --exclude examples/gallery/vtk*.ipynb' docs-server = 'python -m http.server 5500 --directory ./builtdocs' @@ -200,6 +202,15 @@ depends_on = [ '_docs-pyodide', ] +[feature.doc.tasks.docs-build-parallel] +depends_on = [ + '_docs-refmanual', + '_docs-convert-gallery', + '_docs-generate-parallel', + '_docs-copy-panel-dist', + '_docs-pyodide', +] + # ============================================= # ================== BUILD ==================== # =============================================