Skip to content

Trigger layout invalidation on widget display #64

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

Merged

Conversation

peytondmurray
Copy link
Contributor

Summary

This PR triggers layout invalidation when the widget is displayed, closing #58. See that issue for a complete discussion and examples.

Changes

  • This change modifies how ipywidgets are displayed by allowing an onDisplay callback to be passed to the WidgetManager.render function which triggers when the view's displayed event is emitted.
  • Back in the IPyWidgetView, the widget manager's render function is passed a callback which invalidates the layout.
  • Also modified the "dev" mode script to avoid minimizing the bundle, making debugging easier.

@peytondmurray
Copy link
Contributor Author

Sounds like while this solves the minimal working example, it doesn't address all use cases. Moving back into draft.

@peytondmurray peytondmurray marked this pull request as draft November 2, 2022 15:12
@philippjfr
Copy link
Contributor

@peytondmurray The changes here still make sense to me! You indicate that this solves the minimal example but not all cases, could you list some other cases that aren't solved by this because so far the issues I've seen primarily focus on the minimal example.

@peytondmurray
Copy link
Contributor Author

To be honest, it's been a long time since I last looked at this. I remember looking at #58 and being able to reproduce the issue with the react widget described there, but I can't remember if there was some other issue that went unresolved. I'll send a message internally to see if I can get any more information.

@peytondmurray peytondmurray reopened this Mar 25, 2025
@peytondmurray peytondmurray force-pushed the trigger-invalidate-on-displayed branch from 5dfa681 to be5d7af Compare March 28, 2025 00:31
@peytondmurray peytondmurray marked this pull request as ready for review March 28, 2025 00:32
@peytondmurray
Copy link
Contributor Author

@philippjfr I've done my best to rebase this onto the latest commit on main - can you double check that everything looks okay?

@philippjfr
Copy link
Contributor

Thanks @peytondmurray and sorry I haven't gotten to this again. I'm happy to take this over so you don't have to fight the CI anymore.

@peytondmurray
Copy link
Contributor Author

Hey, thanks! Not sure what was going on with the CI, but I bumped the versions of what workflows I could and it seems happy now :)

@peytondmurray
Copy link
Contributor Author

@philippjfr I ran these tests locally but was unable to replace the issue in the CI here, though something else came up locally:

_________________________________________________________________________________________________________ test_anywidget[chromium] __________________________________________________________________________________________________________

page = <Page url='http://localhost:5006/'>

    def test_anywidget(page: Page) -> None:
        """Test anywidget button counter example."""
        # Port to run the panel server on.
        port = 5006
    
        # Create an anywidget button and make it a panel object.
        widget = CounterWidget()
        panels = pn.panel(widget)
    
        # Serve the button using panel, the time delay is necessary for panel to start and
        # serve the widget.
        serve(panels=panels, port=port, show=False)
        time.sleep(0.2)
    
        # Go to the page and locate the widget using playwright.
        page.goto(f"http://localhost:{port}")
        button = page.locator(selector=".counter-button")
    
        # Click the button and monitor the results.
        expect(button).to_have_count(0)
>       button.click()

tests/test_anywidget.py:56: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../.pyenv/versions/3.11.11/envs/ipwb/lib/python3.11/site-packages/playwright/sync_api/_generated.py:15507: in click
    self._sync(
../../../.pyenv/versions/3.11.11/envs/ipwb/lib/python3.11/site-packages/playwright/_impl/_locator.py:160: in click
    return await self._frame.click(self._selector, strict=True, **params)
../../../.pyenv/versions/3.11.11/envs/ipwb/lib/python3.11/site-packages/playwright/_impl/_frame.py:488: in click
    await self._channel.send("click", locals_to_params(locals()))
../../../.pyenv/versions/3.11.11/envs/ipwb/lib/python3.11/site-packages/playwright/_impl/_connection.py:61: in send
    return await self._connection.wrap_api_call(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <playwright._impl._connection.Connection object at 0x7161cd569050>, cb = <function Channel.send.<locals>.<lambda> at 0x7161cc184d60>, is_internal = False

    async def wrap_api_call(
        self, cb: Callable[[], Any], is_internal: bool = False
    ) -> Any:
        if self._api_zone.get():
            return await cb()
        task = asyncio.current_task(self._loop)
        st: List[inspect.FrameInfo] = getattr(task, "__pw_stack__", inspect.stack())
        parsed_st = _extract_stack_trace_information_from_stack(st, is_internal)
        self._api_zone.set(parsed_st)
        try:
            return await cb()
        except Exception as error:
>           raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None
E           playwright._impl._errors.TargetClosedError: Locator.click: Target page, context or browser has been closed
E           Call log:
E             - waiting for locator(".counter-button")

../../../.pyenv/versions/3.11.11/envs/ipwb/lib/python3.11/site-packages/playwright/_impl/_connection.py:528: TargetClosedError
----------------------------------------------------------------------------------------------------------- Captured stdout call ------------------------------------------------------------------------------------------------------------
Launching server at http://localhost:5006
------------------------------------------------------------------------------------------------------------- Captured log call -------------------------------------------------------------------------------------------------------------
WARNING  tornado.access:web.py:2348 404 GET /static/extensions/ipywidgets_bokeh/ipywidgets_bokeh.js?v=562368b20a64be95651bb8246b7420f7fce55538dff999aefaa78662a14d0d39 (::1) 2.23ms

I tried running pytest tests/test_anywidget.py::test_anywidget --headed, but the chromium window that popped up was totally unpopulated with anything. Seems worth another look. The same is true on main, though, so I don't think this branch has anything to do with the local failure.

@philippjfr
Copy link
Contributor

Should now be fixed on main, could you rebase?

@peytondmurray peytondmurray force-pushed the trigger-invalidate-on-displayed branch from 6cbe293 to 4f7f55c Compare April 3, 2025 18:55
@peytondmurray
Copy link
Contributor Author

Done, and the test suite is green. Thanks for the support!

@philippjfr philippjfr merged commit 8489a1e into bokeh:main Apr 3, 2025
4 checks passed
@philippjfr
Copy link
Contributor

Thanks so much!

@peytondmurray peytondmurray deleted the trigger-invalidate-on-displayed branch April 3, 2025 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants