Skip to content

Fix CI — bokeh 3.9.0#9205

Merged
fjetter merged 4 commits intodask:mainfrom
DimitriPapadopoulos:bokeh_file.html
Mar 17, 2026
Merged

Fix CI — bokeh 3.9.0#9205
fjetter merged 4 commits intodask:mainfrom
DimitriPapadopoulos:bokeh_file.html

Conversation

@DimitriPapadopoulos
Copy link
Contributor

@DimitriPapadopoulos DimitriPapadopoulos commented Mar 16, 2026

Fixes CI by adapting to these changes in bokeh 3.9.0:

  • Tests added / passed
  • Passes pre-commit run --all-files

@DimitriPapadopoulos DimitriPapadopoulos marked this pull request as ready for review March 16, 2026 07:02
@DimitriPapadopoulos DimitriPapadopoulos changed the title Adapt to bokeh 3.9.0 Fix CI for bokeh 3.9.0 Mar 16, 2026
@DimitriPapadopoulos DimitriPapadopoulos changed the title Fix CI for bokeh 3.9.0 Fix CI — bokeh 3.9.0 Mar 16, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 16, 2026

Unit Test Results

See test report for an extended history of previous test failures. This is useful for diagnosing flaky tests.

    31 files  ±    0      31 suites  ±0   10h 43m 23s ⏱️ - 26m 57s
 4 115 tests +    2   4 006 ✅ +    6    106 💤 + 2  3 ❌  -  6 
58 228 runs   - 1 408  55 786 ✅  - 1 333  2 438 💤  - 36  4 ❌  - 39 

For more details on these failures, see this check.

Results for commit 169d913. ± Comparison against base commit a13b06c.

♻️ This comment has been updated with latest results.

@DimitriPapadopoulos
Copy link
Contributor Author

I think it is expected the “not ci1” tests fail.

- numpy >=1.24
- pandas >=2
- bokeh >=3.1.0
- bokeh >=3.9.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't introduce a lower bound to a version that was just released. We should instead implement a fix that supports a range of versions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like something like this?

if bokeh_version >= 3.9:
     ...
else:
    ...

@fjetter
Copy link
Member

fjetter commented Mar 17, 2026

The noci tests fail with a probably related failure.

https://github.com/dask/distributed/actions/runs/23132264071/job/67188011797?pr=9205

FAILED distributed/dashboard/tests/test_scheduler_bokeh.py::test_prefix_bokeh - assert '<script type="text/javascript" src="/foo-bar/static/' in '<!DOCTYPE html>\n<html>\n\n<head>\n    <meta charset="utf-8" />\n    <title>Dask Diagnostic UI</title>\n    <meta name=\'viewport\' content=\'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\' />\n    <link rel="stylesheet" href="statics/css/base.css" />\n    <link rel="shortcut icon" href="statics/images/favicon.ico" />\n    \n    \n    \n    \n    \n    <script src="/foo-bar/static/js/bokeh.min.js?v=2630124d82b67a204b9c9da925d3d456e9ec585bb0cf8f839a1c704dbee3f200b70d237916a9fd429755022dc83ac334505cd7385ebb4453a7b17aa1d3699c35"></script>\n        <script src="/foo-bar/static/js/bokeh-gl.min.js?v=b803cb051212c1e9f0fba71c62739c0cfb38114322d67a2ace60eee732710b6541d80907d9fcf0afb2f962c368f1db1e30b8800652d9510d1b801727f9669eb2"></script>\n        <script src="/foo-bar/static/js/bokeh-widgets.min.js?v=aa4c33f38bd3425dafb970d1ce795ccf91e608a9a6d4db35f85f382954d7a91abf76031394f3af6ecb919a1b5dbbfefa2734c7a543132a8f0c0f24a2f9d3237b"></script>\n        <script src="/foo-bar/static/js/bokeh-tables.min.js?v=62532f6ff926a41c47def08668ee2cec06b351a8e8a5ca01a21fdc78811c3fc5d6b048deaf949f6abc5c6963b7bbf56ea285d6ada0b7a61191449d0d115bf737"></script>\n        <script src... else {\n                attempts++;\n                if (attempts > 100) {\n                  clearInterval(timer);\n                  console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");\n                }\n              }\n            }, 10, root)\n          }\n        })(window);\n      });\n    };\n    if (document.readyState != "loading") fn();\n    else document.addEventListener("DOMContentLoaded", fn);\n  })();\n</script>\n\n\n    </div>\n    <script>\n        /* Add the "active" class to the current navbar li element */\n        var active = document.querySelectorAll("a[href=\'" + location.pathname + "\']");\n        if (active.length > 0) {\n            active[0].closest(\'li\').classList.add(\'active\')\n        }\n\n        /* Toggle between adding and removing the "responsive" class to navbar when the user clicks on the icon */\n        function myFunction() {\n            var x = document.getElementById("myTopnav");\n            if (x.className === "navbar") {\n                x.className += " responsive";\n            } else {\n                x.className = "navbar";\n            }\n        }\n    </script>\n</body>\n\n</html>'
 +  where '<!DOCTYPE html>\n<html>\n\n<head>\n    <meta charset="utf-8" />\n    <title>Dask Diagnostic UI</title>\n    <meta name=\'viewport\' content=\'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\' />\n    <link rel="stylesheet" href="statics/css/base.css" />\n    <link rel="shortcut icon" href="statics/images/favicon.ico" />\n    \n    \n    \n    \n    \n    <script src="/foo-bar/static/js/bokeh.min.js?v=2630124d82b67a204b9c9da925d3d456e9ec585bb0cf8f839a1c704dbee3f200b70d237916a9fd429755022dc83ac334505cd7385ebb4453a7b17aa1d3699c35"></script>\n        <script src="/foo-bar/static/js/bokeh-gl.min.js?v=b803cb051212c1e9f0fba71c62739c0cfb38114322d67a2ace60eee732710b6541d80907d9fcf0afb2f962c368f1db1e30b8800652d9510d1b801727f9669eb2"></script>\n        <script src="/foo-bar/static/js/bokeh-widgets.min.js?v=aa4c33f38bd3425dafb970d1ce795ccf91e608a9a6d4db35f85f382954d7a91abf76031394f3af6ecb919a1b5dbbfefa2734c7a543132a8f0c0f24a2f9d3237b"></script>\n        <script src="/foo-bar/static/js/bokeh-tables.min.js?v=62532f6ff926a41c47def08668ee2cec06b351a8e8a5ca01a21fdc78811c3fc5d6b048deaf949f6abc5c6963b7bbf56ea285d6ada0b7a61191449d0d115bf737"></script>\n        <script src... else {\n                attempts++;\n                if (attempts > 100) {\n                  clearInterval(timer);\n                  console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");\n                }\n              }\n            }, 10, root)\n          }\n        })(window);\n      });\n    };\n    if (document.readyState != "loading") fn();\n    else document.addEventListener("DOMContentLoaded", fn);\n  })();\n</script>\n\n\n    </div>\n    <script>\n        /* Add the "active" class to the current navbar li element */\n        var active = document.querySelectorAll("a[href=\'" + location.pathname + "\']");\n        if (active.length > 0) {\n            active[0].closest(\'li\').classList.add(\'active\')\n        }\n\n        /* Toggle between adding and removing the "responsive" class to navbar when the user clicks on the icon */\n        function myFunction() {\n            var x = document.getElementById("myTopnav");\n            if (x.className === "navbar") {\n                x.className += " responsive";\n            } else {\n                x.className = "navbar";\n            }\n        }\n    </script>\n</body>\n\n</html>' = <built-in method decode of bytes object at 0x55dea3874110>()
 +    where <built-in method decode of bytes object at 0x55dea3874110> = b'<!DOCTYPE html>\n<html>\n\n<head>\n    <meta charset="utf-8" />\n    <title>Dask Diagnostic UI</title>\n    <meta name=\'viewport\' content=\'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\' />\n    <link rel="stylesheet" href="statics/css/base.css" />\n    <link rel="shortcut icon" href="statics/images/favicon.ico" />\n    \n    \n    \n    \n    \n    <script src="/foo-bar/static/js/bokeh.min.js?v=2630124d82b67a204b9c9da925d3d456e9ec585bb0cf8f839a1c704dbee3f200b70d237916a9fd429755022dc83ac334505cd7385ebb4453a7b17aa1d3699c35"></script>\n        <script src="/foo-bar/static/js/bokeh-gl.min.js?v=b803cb051212c1e9f0fba71c62739c0cfb38114322d67a2ace60eee732710b6541d80907d9fcf0afb2f962c368f1db1e30b8800652d9510d1b801727f9669eb2"></script>\n        <script src="/foo-bar/static/js/bokeh-widgets.min.js?v=aa4c33f38bd3425dafb970d1ce795ccf91e608a9a6d4db35f85f382954d7a91abf76031394f3af6ecb919a1b5dbbfefa2734c7a543132a8f0c0f24a2f9d3237b"></script>\n        <script src="/foo-bar/static/js/bokeh-tables.min.js?v=62532f6ff926a41c47def08668ee2cec06b351a8e8a5ca01a21fdc78811c3fc5d6b048deaf949f6abc5c6963b7bbf56ea285d6ada0b7a61191449d0d115bf737"></script>\n        <script sr... else {\n                attempts++;\n                if (attempts > 100) {\n                  clearInterval(timer);\n                  console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");\n                }\n              }\n            }, 10, root)\n          }\n        })(window);\n      });\n    };\n    if (document.readyState != "loading") fn();\n    else document.addEventListener("DOMContentLoaded", fn);\n  })();\n</script>\n\n\n    </div>\n    <script>\n        /* Add the "active" class to the current navbar li element */\n        var active = document.querySelectorAll("a[href=\'" + location.pathname + "\']");\n        if (active.length > 0) {\n            active[0].closest(\'li\').classList.add(\'active\')\n        }\n\n        /* Toggle between adding and removing the "responsive" class to navbar when the user clicks on the icon */\n        function myFunction() {\n            var x = document.getElementById("myTopnav");\n            if (x.className === "navbar") {\n                x.className += " responsive";\n            } else {\n                x.className = "navbar";\n            }\n        }\n    </script>\n</body>\n\n</html>'.decode
 +      where b'<!DOCTYPE html>\n<html>\n\n<head>\n    <meta charset="utf-8" />\n    <title>Dask Diagnostic UI</title>\n    <meta name=\'viewport\' content=\'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\' />\n    <link rel="stylesheet" href="statics/css/base.css" />\n    <link rel="shortcut icon" href="statics/images/favicon.ico" />\n    \n    \n    \n    \n    \n    <script src="/foo-bar/static/js/bokeh.min.js?v=2630124d82b67a204b9c9da925d3d456e9ec585bb0cf8f839a1c704dbee3f200b70d237916a9fd429755022dc83ac334505cd7385ebb4453a7b17aa1d3699c35"></script>\n        <script src="/foo-bar/static/js/bokeh-gl.min.js?v=b803cb051212c1e9f0fba71c62739c0cfb38114322d67a2ace60eee732710b6541d80907d9fcf0afb2f962c368f1db1e30b8800652d9510d1b801727f9669eb2"></script>\n        <script src="/foo-bar/static/js/bokeh-widgets.min.js?v=aa4c33f38bd3425dafb970d1ce795ccf91e608a9a6d4db35f85f382954d7a91abf76031394f3af6ecb919a1b5dbbfefa2734c7a543132a8f0c0f24a2f9d3237b"></script>\n        <script src="/foo-bar/static/js/bokeh-tables.min.js?v=62532f6ff926a41c47def08668ee2cec06b351a8e8a5ca01a21fdc78811c3fc5d6b048deaf949f6abc5c6963b7bbf56ea285d6ada0b7a61191449d0d115bf737"></script>\n        <script sr... else {\n                attempts++;\n                if (attempts > 100) {\n                  clearInterval(timer);\n                  console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");\n                }\n              }\n            }, 10, root)\n          }\n        })(window);\n      });\n    };\n    if (document.readyState != "loading") fn();\n    else document.addEventListener("DOMContentLoaded", fn);\n  })();\n</script>\n\n\n    </div>\n    <script>\n        /* Add the "active" class to the current navbar li element */\n        var active = document.querySelectorAll("a[href=\'" + location.pathname + "\']");\n        if (active.length > 0) {\n            active[0].closest(\'li\').classList.add(\'active\')\n        }\n\n        /* Toggle between adding and removing the "responsive" class to navbar when the user clicks on the icon */\n        function myFunction() {\n            var x = document.getElementById("myTopnav");\n            if (x.className === "navbar") {\n                x.className += " responsive";\n            } else {\n                x.className = "navbar";\n            }\n        }\n    </script>\n</body>\n\n</html>' = HTTPResponse(_body=b'<!DOCTYPE html>\n<html>\n\n<head>\n    <meta charset="utf-8" />\n    <title>Dask Diagnostic UI</title>\n    <meta name=\'viewport\' content=\'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\' />\n    <link rel="stylesheet" href="statics/css/base.css" />\n    <link rel="shortcut icon" href="statics/images/favicon.ico" />\n    \n    \n    \n    \n    \n    <script src="/foo-bar/static/js/bokeh.min.js?v=2630124d82b67a204b9c9da925d3d456e9ec585bb0cf8f839a1c704dbee3f200b70d237916a9fd429755022dc83ac334505cd7385ebb4453a7b17aa1d3699c35"></script>\n        <script src="/foo-bar/static/js/bokeh-gl.min.js?v=b803cb051212c1e9f0fba71c62739c0cfb38114322d67a2ace60eee732710b6541d80907d9fcf0afb2f962c368f1db1e30b8800652d9510d1b801727f9669eb2"></script>\n        <script src="/foo-bar/static/js/bokeh-widgets.min.js?v=aa4c33f38bd3425dafb970d1ce795ccf91e608a9a6d4db35f85f382954d7a91abf76031394f3af6ecb919a1b5dbbfefa2734c7a543132a8f0c0f24a2f9d3237b"></script>\n        <script src="/foo-bar/static/js/bokeh-tables.min.js?v=62532f6ff926a41c47def08668ee2cec06b351a8e8a5ca01a21fdc78811c3fc5d6b048deaf949f6abc5c6963b7bbf56ea285d6ada0b7a61191449d0d115bf737"></script>\...tate != "loading") fn();\n    else document.addEventListener("DOMContentLoaded", fn);\n  })();\n</script>\n\n\n    </div>\n    <script>\n        /* Add the "active" class to the current navbar li element */\n        var active = document.querySelectorAll("a[href=\'" + location.pathname + "\']");\n        if (active.length > 0) {\n            active[0].closest(\'li\').classList.add(\'active\')\n        }\n\n        /* Toggle between adding and removing the "responsive" class to navbar when the user clicks on the icon */\n        function myFunction() {\n            var x = document.getElementById("myTopnav");\n            if (x.className === "navbar") {\n                x.className += " responsive";\n            } else {\n                x.className = "navbar";\n            }\n        }\n    </script>\n</body>\n\n</html>',_error_is_response_code=False,buffer=<_io.BytesIO object at 0x7f9c160b6ca0>,code=200,effective_url='http://localhost:46035/foo-bar/status',error=None,headers=<tornado.httputil.HTTPHeaders object at 0x7f9c160ce6f0>,reason='OK',request=<tornado.httpclient.HTTPRequest object at 0x7f9c0dd39e80>,request_time=0.2169203758239746,start_time=1773645746.063746,time_info={}).body

@@ -1,4 +1,4 @@
name: dask-distributed
name: dask-distributed-310
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that change probably makes sense but I suggest to factor this out into another PR

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DimitriPapadopoulos this way we get full backwards/forwards compat

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for helping out, I wouldn't have guessed {% extends "file.html.jinja" %} can fail silently and fall back on {% extends "file.html" %}.

Looks perfect now.

@fjetter fjetter mentioned this pull request Mar 17, 2026
4 tasks
@@ -1,5 +1,5 @@
{% extends "file.html.jinja" %}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how to have two different extensions based on the version of bokeh. Could you help?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bokeh 3.9 is looking for file.html. We are now including a file.html which just points to the old file.html.jinja. Older versions will simply ignore the new file

I updated the PR in case this is what's causing the confusion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try something like this:

{% if BOKEH_VERSION >= '3.9' %}
    {% extends "file.html.jinja" %}
{% else %}
    {% extends "file.html" %}
{% endif %}

I will need to set BOKEH_VERSION, perhaps somewhere around here:

template = template_environment.get_template("performance_report.html")
save(tabs, filename=fn, template=template)

I'm a bit lost here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it. So it fails silently.

@fjetter fjetter merged commit 595d591 into dask:main Mar 17, 2026
29 of 35 checks passed
@fjetter
Copy link
Member

fjetter commented Mar 17, 2026

test failures appear to be unrelated. Thanks @DimitriPapadopoulos for raising and fixing this!

f'<script type="text/javascript" src="/{prefix}/static/'
in response.body.decode()
)
assert f'src="/{prefix}/static/' in response.body.decode()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps keep the leading space:

Suggested change
assert f'src="/{prefix}/static/' in response.body.decode()
assert f' src="/{prefix}/static/' in response.body.decode()

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