From bed2372f19eae5968e11c45f8036fd1efa762eb0 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 12 Sep 2026 21:43:10 +0200 Subject: [PATCH 01/17] Serve the Reflex chart data plane as a channel on the app websocket, dropping socket.io --- CLAUDE.md | 9 +- docs/app/pyproject.toml | 13 +- docs/app/uv.lock | 146 +--- examples/reflex/README.md | 2 +- news/505.breaking.md | 8 + news/505.feature.md | 9 + pyproject.toml | 35 +- python/reflex_xy/__init__.py | 12 +- python/reflex_xy/app.py | 65 +- python/reflex_xy/assets/XYChart.jsx | 127 ++- .../reflex_xy/{namespace.py => data_plane.py} | 240 ++++-- python/reflex_xy/registry.py | 12 +- python/reflex_xy/state_bridge.py | 4 +- python/xy/interaction.py | 2 +- scripts/reflex_ws_smoke.py | 6 +- scripts/verify_sdist.py | 2 +- scripts/verify_wheel.py | 2 +- spec/README.md | 4 +- spec/api/chart-roadmap.md | 2 +- .../reflex-component-api-implementation.md | 6 +- spec/design/reflex-component-api-options.md | 2 +- spec/design/reflex-integration.md | 201 +++-- spec/design/renderer-architecture.md | 2 +- spec/design/view-state.md | 2 +- spec/design/wire-protocol.md | 12 +- tests/reflex_adapter/test_assets.py | 80 +- tests/reflex_adapter/test_channel_browser.py | 169 ++++ ...ocket_data_plane.py => test_data_plane.py} | 793 +++++++++--------- .../test_page_plan_registration.py | 9 +- tests/test_dependencies.py | 13 +- tests/test_tailwind_root_customization.py | 2 +- uv.lock | 639 ++++++-------- 32 files changed, 1402 insertions(+), 1228 deletions(-) create mode 100644 news/505.breaking.md create mode 100644 news/505.feature.md rename python/reflex_xy/{namespace.py => data_plane.py} (76%) create mode 100644 tests/reflex_adapter/test_channel_browser.py rename tests/reflex_adapter/{test_socket_data_plane.py => test_data_plane.py} (72%) diff --git a/CLAUDE.md b/CLAUDE.md index dd21739f2..98320e545 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,10 +67,11 @@ control. `tests/pyplot/corpus/` + `spec/matplotlib/compat.md`. - `python/reflex_xy/` — the bundled Reflex integration (import namespace `reflex_xy`; design: `spec/design/reflex-integration.md`). Chart - data rides the app's own websocket as a second socket.io namespace; - figures live in a per-process registry rebuilt from Reflex state on miss. - The source ships in every `xy` artifact; the `xy[reflex]` extra selects the - supported Reflex floor while plain `xy` keeps no Reflex runtime dependency. + data rides the app's own websocket as a dedicated Reflex channel (`/_xy`, + `data_plane.py`); figures live in a per-process registry rebuilt from Reflex + state on miss. The source ships in every `xy` artifact; the `xy[reflex]` + extra selects the supported Reflex while plain `xy` keeps no Reflex runtime + dependency. The core `python/xy` package must never import Reflex. The render client is linked out of that package at app compile (no second copy to drift). Tests: `tests/reflex_adapter/` (skip unless Reflex is installed). diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index b5d21c1b2..adb1f7a8f 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -3,13 +3,18 @@ name = "xy-docs-app" version = "0.1.0" description = "Documentation site for XY." requires-python = ">=3.11" +# TEMPORARY: these four normally track reflex-dev/reflex@main, but `xy[reflex]` +# requires the unreleased channel transport (reflex-dev/reflex#6932) and uv +# refuses two URLs for one package. They therefore point at the same branch the +# root pyproject does — all from one repo, so the framework is never half +# branch and half main. Restore `@main` when channels land there. dependencies = [ "numpy", "pillow", - "reflex @ git+https://github.com/reflex-dev/reflex@main", - "reflex-components-internal @ git+https://github.com/reflex-dev/reflex@main#subdirectory=packages/reflex-components-internal", - "reflex-docgen @ git+https://github.com/reflex-dev/reflex@main#subdirectory=packages/reflex-docgen", - "reflex-site-shared @ git+https://github.com/reflex-dev/reflex@main#subdirectory=packages/reflex-site-shared", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional", + "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional#subdirectory=packages/reflex-components-internal", + "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional#subdirectory=packages/reflex-docgen", + "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional#subdirectory=packages/reflex-site-shared", "xy[reflex]", ] diff --git a/docs/app/uv.lock b/docs/app/uv.lock index 53b08dd30..16bf81cf8 100644 --- a/docs/app/uv.lock +++ b/docs/app/uv.lock @@ -51,15 +51,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, ] -[[package]] -name = "bidict" -version = "0.23.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093, upload-time = "2024-02-18T19:09:05.748Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764, upload-time = "2024-02-18T19:09:04.156Z" }, -] - [[package]] name = "certifi" version = "2026.7.22" @@ -994,18 +985,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/71/45/689603d04b3bb8d7faa00f25c24acef993aab7813b3dbbfc472a459ab0b5/python_discovery-1.5.2-py3-none-any.whl", hash = "sha256:3e338c2d0f15dfaeea57493f4c2c6caebe0e998ea815c30ae8bf8ee21f1112d3", size = 38350, upload-time = "2026-08-12T14:05:25.113Z" }, ] -[[package]] -name = "python-engineio" -version = "4.13.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "simple-websocket" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/d8/65cc479ab697a2e7fdee83a9bd8a06b61ec68bf763a58a302cf161bf38bb/python_engineio-4.13.5.tar.gz", hash = "sha256:b5764d62243e3ffbc4c76dda3d7897c329dc52294c80c27105f9faa054e76897", size = 80035, upload-time = "2026-08-12T22:52:23.78Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/01/f804208061b504894546fddc479f6075e0f00dfe88cb1703dafaa8c3c67e/python_engineio-4.13.5-py3-none-any.whl", hash = "sha256:05c9f4951d242ad33d613b4245299562e5f64e4199f00e5390f9888505831704", size = 59963, upload-time = "2026-08-12T22:52:22.5Z" }, -] - [[package]] name = "python-multipart" version = "0.0.32" @@ -1015,19 +994,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, ] -[[package]] -name = "python-socketio" -version = "5.16.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bidict" }, - { name = "python-engineio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/5e/87d6b547c87c6d64f4a05f5bfaf6f42e9b786561216434290fdaa83f8667/python_socketio-5.16.4.tar.gz", hash = "sha256:f7fa4a43cc8e687930b5c6e44d6e2efc2071eca4bef49b8bb3dc0827f7f92235", size = 128140, upload-time = "2026-08-06T23:11:21.346Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/d9/463feca73ec119a135d90c9f40c0172b4758150b5ed442f0ca1e8fed807a/python_socketio-5.16.4-py3-none-any.whl", hash = "sha256:0eb9c7687e7fbf59e60d714fd62afba77dfaf8ef8a06a0bff05a86c351accc2f", size = 82098, upload-time = "2026-08-06T23:11:19.851Z" }, -] - [[package]] name = "pyyaml" version = "6.0.3" @@ -1097,8 +1063,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.9.8.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1106,7 +1072,6 @@ dependencies = [ { name = "packaging" }, { name = "psutil", marker = "sys_platform == 'win32'" }, { name = "python-multipart" }, - { name = "python-socketio" }, { name = "redis" }, { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1130,8 +1095,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.9.8.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-base&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1141,8 +1106,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.9.3.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-code&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1152,8 +1117,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.9.8.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-core&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1165,8 +1130,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.9.1.post307.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-dataeditor&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1174,32 +1139,32 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.9.1.post307.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-gridjs&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-internal" -version = "0.0.23.post105.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-internal&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex" }, ] [[package]] name = "reflex-components-lucide" -version = "1.0.3.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-lucide&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.9.3.post175.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-markdown&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1209,16 +1174,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.9.3.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-moment&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.9.4.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-plotly&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1226,8 +1191,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.9.7.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-radix&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1236,8 +1201,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.9.1.post307.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-react-player&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1245,16 +1210,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.9.2.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-recharts&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.9.1.post307.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-sonner&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1262,8 +1227,8 @@ dependencies = [ [[package]] name = "reflex-docgen" -version = "0.9.4.post23.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-docgen&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "griffelib" }, { name = "mistletoe" }, @@ -1274,8 +1239,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.1.68.post31.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-hosting-cli&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -1286,13 +1251,13 @@ dependencies = [ [[package]] name = "reflex-integrations-docs" -version = "0.0.0.post3313.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Fintegrations-docs&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } [[package]] name = "reflex-site-shared" -version = "0.0.41.post53.dev0+ed9acd35" -source = { git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-site-shared&rev=main#ed9acd35df9708cef819337904854cf4f13abd22" } +version = "0.0.3.post248.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "email-validator" }, { name = "httpx" }, @@ -1380,18 +1345,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d6/92/477780b98169e0dc3d37fac015f3f9ef3ced1dfcd2ec3a44686c8e07f8d8/ruff_format-0.5.4-cp38-abi3-win_arm64.whl", hash = "sha256:b0dfb4ef7c7f0da7b17c018dc48103907375f06c7b9e3dac3bc396722a725a65", size = 1988587, upload-time = "2026-08-10T18:06:51.397Z" }, ] -[[package]] -name = "simple-websocket" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wsproto" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300, upload-time = "2024-10-10T22:39:31.412Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842, upload-time = "2024-10-10T22:39:29.645Z" }, -] - [[package]] name = "stack-data" version = "0.6.3" @@ -1661,18 +1614,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, ] -[[package]] -name = "wsproto" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/79/12135bdf8b9c9367b8701c2c19a14c913c120b882d50b014ca0d38083c2c/wsproto-1.3.2.tar.gz", hash = "sha256:b86885dcf294e15204919950f666e06ffc6c7c114ca900b060d6e16293528294", size = 50116, upload-time = "2025-11-20T18:18:01.871Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl", hash = "sha256:61eea322cdf56e8cc904bd3ad7573359a242ba65688716b0710a5eb12beab584", size = 24405, upload-time = "2025-11-20T18:18:00.454Z" }, -] - [[package]] name = "xy" source = { editable = "../../" } @@ -1691,7 +1632,7 @@ reflex = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", specifier = ">=0.9.6" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional" }, ] provides-extras = ["reflex"] @@ -1708,6 +1649,7 @@ dev = [ { name = "starlette", specifier = ">=0.36" }, { name = "ty" }, { name = "uvicorn", specifier = ">=0.23" }, + { name = "websockets", specifier = ">=12" }, ] [[package]] @@ -1738,10 +1680,10 @@ dev = [ requires-dist = [ { name = "numpy" }, { name = "pillow" }, - { name = "reflex", git = "https://github.com/reflex-dev/reflex?rev=main" }, - { name = "reflex-components-internal", git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-components-internal&rev=main" }, - { name = "reflex-docgen", git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-docgen&rev=main" }, - { name = "reflex-site-shared", git = "https://github.com/reflex-dev/reflex?subdirectory=packages%2Freflex-site-shared&rev=main" }, + { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional" }, + { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=make-sio-optional" }, + { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=make-sio-optional" }, + { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=make-sio-optional" }, { name = "xy", extras = ["reflex"], editable = "../../" }, ] diff --git a/examples/reflex/README.md b/examples/reflex/README.md index 226553b34..4d625523b 100644 --- a/examples/reflex/README.md +++ b/examples/reflex/README.md @@ -5,7 +5,7 @@ One page walks through the ways to link chart data into a Reflex app, and each section carries a **Code** accordion showing its source via `inspect.getsource`. -Chart data rides the app's own websocket as a second socket.io namespace of +Chart data rides the app's own websocket as a dedicated Reflex channel of binary columns; Reflex state holds only a tiny handle per chart. Charts use the data-bound component API — structure declared in the page, compiled to a validated plan at `reflex run`, columns supplied by `@reflex_xy.data` — diff --git a/news/505.breaking.md b/news/505.breaking.md new file mode 100644 index 000000000..3947b91a1 --- /dev/null +++ b/news/505.breaking.md @@ -0,0 +1,8 @@ +The Reflex integration's chart data plane no longer uses socket.io. `/_xy` is +now a Reflex channel on the app's own event websocket, which means `xy[reflex]` +requires a Reflex that ships the channel transport and an app on the default +`transport="websocket"`; `transport="socketio"` and `transport="polling"` apps +can no longer serve charts. `reflex_xy.XYNamespace` and `reflex_xy.XY_NAMESPACE` +are replaced by `reflex_xy.XYChannel` and `reflex_xy.XY_PLANE`, and +`reflex_xy.namespace` by `reflex_xy.data_plane`. Application code that only +uses `XYPlugin`/`setup()` and the chart components is unaffected. diff --git a/news/505.feature.md b/news/505.feature.md new file mode 100644 index 000000000..1d7e32dca --- /dev/null +++ b/news/505.feature.md @@ -0,0 +1,9 @@ +The Reflex integration's chart data plane rides the app's own websocket as a +Reflex channel, with no socket.io anywhere. Binary columns now arrive beside +the message as frame attachments — aligned typed-array views over the received +frame rather than copies — and the per-message attachment budget rises from +socket.io-parser's hard limit of 10 to the channel frame's 64, so far more +figures ship their columns split instead of paying for a joined blob. The chart +component opens no connection of its own and mirrors none of Reflex's socket +options: it asks Reflex for the `/_xy` channel and rides whatever the app +already has. diff --git a/pyproject.toml b/pyproject.toml index 352fdb86b..14dae9655 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,8 +18,22 @@ dependencies = [ # The adapter source ships in every xy wheel so the framework integration and # render client can never drift. The extra only selects the supported Reflex # floor; importing plain `xy` remains framework-free. +# +# TEMPORARY, and deliberately unmergeable: the data plane is a Reflex *channel* +# (spec/design/reflex-integration.md §2), which no released Reflex ships yet — +# it exists only on reflex-dev/reflex#6932. There is no socket.io fallback any +# more, so a version specifier here would be a lie in either direction: +# `>=0.9.6` admits versions where every chart stays blank, and a guessed +# `>=0.10` names a release that does not exist. The git requirement is the +# honest statement of what this integration needs, it keeps `uv sync` working +# for contributors, and uv resolves the rest of that repo's workspace +# (reflex-base, the component packages) from the same branch, so the framework +# is never half branch and half release. `docs/app/pyproject.toml` points its +# own Reflex requirements at the same branch for the same reason. Replace all +# of it with the real floor the moment channels are released (see the Status +# note in the design doc). reflex = [ - "reflex>=0.9.6", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional", ] [project.urls] @@ -45,10 +59,15 @@ dev = [ # drilldown pan-alignment browser test importorskips it, so it lives in dev # where CI exercises that test. "starlette>=0.36", - # tests/reflex_adapter exercises the real socket data plane when the - # `reflex` extra is installed in the main CI job. + # tests/reflex_adapter exercises the real websocket data plane when the + # `reflex` extra is installed in the main CI job: uvicorn serves the app, + # aiohttp is the client. Bare uvicorn has no websocket protocol of its own + # and answers an upgrade request with 404, so the implementation is an + # explicit dev dependency rather than something inherited from a transport + # package. "aiohttp>=3.14.3", "uvicorn>=0.23", + "websockets>=12", # Parses .binder/environment.yml in tests/test_binder_config.py so the # Binder contract is asserted on structure, not string transcription. "pyyaml>=6", @@ -71,6 +90,16 @@ codspeed = [ [tool.hatch.version] source = "uv-dynamic-versioning" +# TEMPORARY, and paired with the git requirement in the `reflex` extra. Direct +# references are refused by default because PyPI refuses them on upload — which +# is the point here: while the channel transport is unreleased there is no +# version specifier that honestly describes what `xy[reflex]` needs, and a +# release built from this tree *should* fail rather than ship a floor that +# installs a Reflex where every chart stays blank. Remove both when channels +# are released. +[tool.hatch.metadata] +allow-direct-references = true + [tool.uv-dynamic-versioning] vcs = "git" style = "pep440" diff --git a/python/reflex_xy/__init__.py b/python/reflex_xy/__init__.py index befa9d395..ec1082bc6 100644 --- a/python/reflex_xy/__init__.py +++ b/python/reflex_xy/__init__.py @@ -2,7 +2,7 @@ The integration in one paragraph (full design: spec/design/reflex-integration.md in the xy repo): chart data rides -the app's *existing* websocket as a second socket.io namespace — binary +the app's *existing* websocket as a dedicated Reflex channel — binary columns, no JSON numbers, no extra endpoints to proxy. Figures and columns live in a per-process registry keyed by tokens; Reflex state holds only small typed handles. State methods are both the definition and the @@ -106,8 +106,8 @@ def index() -> rx.Component: "SelectEndEvent": ".events", "SelectionPayload": ".events", "ViewChangeEvent": ".events", - "XY_NAMESPACE": ".namespace", - "XYNamespace": ".namespace", + "XY_PLANE": ".data_plane", + "XYChannel": ".data_plane", "FigureRegistry": ".registry", "registry": ".registry", "resolve_selection": ".selections", @@ -179,7 +179,7 @@ def index() -> rx.Component: ) __all__ = [ - "XY_NAMESPACE", + "XY_PLANE", "AsyncDataVar", "AsyncFigureVar", "CanonicalRowIdGroup", @@ -197,7 +197,7 @@ def index() -> rx.Component: "SelectEndEvent", "SelectionPayload", "ViewChangeEvent", - "XYNamespace", + "XYChannel", "XYPlugin", "animation", "append", @@ -455,6 +455,7 @@ def release(token: "str | FigureHandle") -> None: ) from .app import XYPlugin, append, clear_selection, reset_view, select, set_view, setup + from .data_plane import XY_PLANE, XYChannel from .data_vars import AsyncDataVar, DataVar, data from .events import ( CanonicalRowIdGroup, @@ -492,7 +493,6 @@ def release(token: "str | FigureHandle") -> None: violin_chart, ) from .handles import DataHandle, FigureHandle - from .namespace import XY_NAMESPACE, XYNamespace from .registry import FigureRegistry, registry from .selections import resolve_selection from .vars import AsyncFigureVar, FigureVar, figure diff --git a/python/reflex_xy/app.py b/python/reflex_xy/app.py index 2fd276d86..16bbcb5c0 100644 --- a/python/reflex_xy/app.py +++ b/python/reflex_xy/app.py @@ -10,9 +10,9 @@ `setup` is idempotent; using both costs nothing. -What setup does: registers the `/_xy` socket.io namespace on the app's -existing AsyncServer (same physical websocket as the app plane — see -namespace.py), wires publish fan-out, and adds a lifespan task that +What setup does: registers the `/_xy` channel on the app's existing event +websocket (data_plane.py — the same physical connection as the app plane), +wires publish fan-out, and adds a lifespan task that registers this worker's chart plans (`_ensure_page_plans`, fail-closed), captures the event loop (for thread-safe broadcasts from sync handlers), and runs the registry TTL sweep. @@ -29,8 +29,8 @@ from reflex.plugins import Plugin +from .data_plane import XYChannel from .handles import FigureHandle, token_of -from .namespace import XYNamespace from .registry import _figure_of, registry from .state_bridge import make_rebuild_hook from .tokens import BUILDER_ATTR, PROBE_ATTR @@ -48,24 +48,27 @@ "setup", ] -_namespace: Optional[XYNamespace] = None +_channel: Optional[XYChannel] = None +# The app the current channel is attached to. Idempotency is per app, not +# per process: a hot reload (and AppHarness) re-imports the app module, and +# the new App gets its own websocket that must be attached to. +_setup_app: Any = None -def setup(app: Any) -> XYNamespace: - """Attach the xy data plane to a Reflex app (idempotent).""" - global _namespace - if _namespace is not None: - return _namespace - sio = getattr(app, "sio", None) - if sio is None: - msg = ( - "reflex_xy.setup(app) needs the app's socket server; it exists " - "only when state is enabled (rx.App(enable_state=True), the default)." - ) - raise RuntimeError(msg) - namespace = XYNamespace(registry, rebuild=make_rebuild_hook(app)) - sio.register_namespace(namespace) - wire(namespace) +def setup(app: Any) -> XYChannel: + """Attach the xy data plane to a Reflex app (idempotent). + + The plane is a Reflex channel on the app's own event websocket. Reflex's + `register_channel` refuses an app that cannot carry one — state disabled, + or a non-WebSocket transport — so a misconfiguration fails here at startup + rather than as a blank chart in the browser. + """ + global _channel, _setup_app + if _channel is not None and _setup_app is app: + return _channel + channel = XYChannel(registry, rebuild=make_rebuild_hook(app)) + app.register_channel(channel) + wire(channel) def _lifespan() -> Coroutine[Any, Any, None]: # Deliberately a *sync* function returning the sweep coroutine, not an @@ -80,8 +83,9 @@ def _lifespan() -> Coroutine[Any, Any, None]: return _xy_lifespan() app.register_lifespan_task(_lifespan) - _namespace = namespace - return namespace + _channel = channel + _setup_app = app + return channel def _ensure_page_plans(app: Any) -> None: @@ -129,11 +133,11 @@ def _ensure_page_plans(app: Any) -> None: raise RuntimeError(msg) -def wire(namespace: XYNamespace) -> None: - """Point the registry's fan-out seams at a namespace (setup and tests).""" - registry.on_publish(namespace.broadcast_payload) - registry.on_push(namespace.broadcast_message) - registry.on_error(namespace.broadcast_error) +def wire(channel: XYChannel) -> None: + """Point the registry's fan-out seams at the data plane (setup and tests).""" + registry.on_publish(channel.broadcast_payload) + registry.on_push(channel.broadcast_message) + registry.on_error(channel.broadcast_error) async def _xy_lifespan() -> None: @@ -331,6 +335,7 @@ def clear_selection(token: "str | FigureHandle") -> None: def reset_setup_for_tests() -> None: - """Forget the wired namespace (test isolation only).""" - global _namespace - _namespace = None + """Forget the wired data plane (test isolation only).""" + global _channel, _setup_app + _channel = None + _setup_app = None diff --git a/python/reflex_xy/assets/XYChart.jsx b/python/reflex_xy/assets/XYChart.jsx index 9bab7c54c..7aebe4bad 100644 --- a/python/reflex_xy/assets/XYChart.jsx +++ b/python/reflex_xy/assets/XYChart.jsx @@ -6,18 +6,18 @@ // `plan` digest + `data` ({token} DataHandle), composed client-side as // `xyp1||` once the data handle hydrates. // -// Live — this component does NOT open its own connection. -// socket.io multiplexing reuses the app's engine.io websocket when the -// manager options match, so `xySocket()` below constructs its `/_xy` -// namespace socket with exactly the options Reflex's own `connect()` uses -// (`$/utils/state`). Whichever side runs first creates the shared manager; -// the other rides it. One TCP connection carries app state and chart data — -// same lifecycle, same auth surface, same proxy config. +// Live — this component does NOT open its own connection. `getChannel("/_xy")` +// multiplexes the data plane onto the app's own event websocket as a Reflex +// channel (data_plane.py), so one TCP connection carries app state and chart +// data: same lifecycle, same auth surface, same proxy config. Columns arrive +// beside the metadata as frame attachments — aligned typed-array views over the +// received frame, never copies and never JSON numbers. // -// Live data protocol (namespace.py): +// Live data protocol (data_plane.py); `buffers` is the handler's second +// argument, not a field of the envelope: // out: sub {fig, px, mid} | unsub {fig, mid} | msg {fig, v?, mid, m} -// in: payload {fig, version, spec, buffers, mid?} — direct replies carry mid -// msg {fig, version?, mid?, message, buffers} — replies carry our mid +// in: payload {fig, version, spec, mid?} — direct replies carry mid +// msg {fig, version?, mid?, message} — replies carry our mid // err {fig, error, resync?} // A subscribe/reconnect starts a version epoch: no msg is applied until its // authoritative payload arrives. Replies and room-wide pushes carry the @@ -40,10 +40,7 @@ import { // emotion's jsx() (a guaranteed app dependency) honors it without relying // on any jsxImportSource configuration in the app's build. import { jsx } from "@emotion/react"; -import io from "socket.io-client"; -import env from "$/env.json"; -import reflexEnvironment from "$/reflex.json"; -import { getBackendURL, getToken } from "$/utils/state"; +import { getChannel } from "$/utils/state"; import { ChartView, decodeFrame, renderStandalone } from "./xy_client.js"; // Opt-in console tracing: localStorage.setItem("xy_debug", "1") @@ -59,31 +56,23 @@ const dbg = (...args) => ); dbg("XYChart module loaded"); -let sharedSocket = null; +let sharedPlane = null; // fig token -> number of mounted charts using it (unsub only at zero, since // room membership is per-connection, not per-mount). const subCounts = new Map(); -function xySocket() { - if (sharedSocket) return sharedSocket; - const endpoint = getBackendURL(env.EVENT); - const nsUrl = new URL(endpoint.href); - // The URI pathname selects the socket.io *namespace*; the engine.io mount - // path stays the app's (`endpoint.pathname`), which is what keys the - // manager cache — same key as Reflex's socket, hence one physical ws. - nsUrl.pathname = "/_xy"; - nsUrl.search = ""; - sharedSocket = io(nsUrl.href, { - path: endpoint.pathname, - transports: [env.TRANSPORT], - protocols: [reflexEnvironment.version], - autoUnref: false, - query: { token: getToken() }, - reconnection: false, // the app plane owns manager reconnects - }); - sharedSocket.on("connect", () => dbg("xy namespace connected")); - sharedSocket.on("connect_error", (e) => dbg("xy connect_error", String(e))); - return sharedSocket; +// The data plane's channel name, matching XY_PLANE in data_plane.py. +const XY_PLANE = "/_xy"; + +/** + * The shared xy data plane: one Reflex channel on the app's own websocket. + * @returns The data plane handle: connected, emit(), on(), off(). + */ +function xyDataPlane() { + if (sharedPlane) return sharedPlane; + sharedPlane = getChannel(XY_PLANE); + sharedPlane.on("error", (error) => dbg("xy channel error", error)); + return sharedPlane; } let nextMountId = 1; @@ -429,12 +418,12 @@ export function XYChart(props) { }; }, [src]); - // Live mode: subscribe on the shared websocket. + // Live mode: subscribe on the shared data plane. useEffect(() => { const el = elRef.current; dbg("effect run", { token: liveToken && liveToken.slice(0, 24), hasEl: !!el }); if (!liveToken || src || !el) return undefined; - const socket = xySocket(); + const plane = xyDataPlane(); const mid = `m${nextMountId++}`; let view = null; let destroyed = false; @@ -484,16 +473,16 @@ export function XYChart(props) { // A reconnect can land on a fresh worker whose rebuilt figure starts at // version 1. Versions are monotonic only within this subscription epoch. resetEpoch(); - socket.emit("sub", { fig: liveToken, px: el.clientWidth || null, mid }); + plane.emit("sub", { fig: liveToken, px: el.clientWidth || null, mid }); }; const emitMessage = (m) => { - // socket.io flushes its sendBuffer before firing `connect`; never queue - // an old-epoch request while the namespace is disconnected. - if (awaitingPayload || !socket.connected) return; + // Both transports buffer sends made while disconnected; never queue an + // old-epoch request that would arrive after a reconnect. + if (awaitingPayload || !plane.connected) return; const envelope = { fig: liveToken, mid, m }; if (payloadVersion !== null) envelope.v = payloadVersion; - socket.emit("msg", envelope); + plane.emit("msg", envelope); }; const withSelectionSeq = (m) => ({ @@ -577,7 +566,7 @@ export function XYChart(props) { // preceding epoch arm a new trailing timer after resetEpoch cleared it. if ( awaitingPayload - || !socket.connected + || !plane.connected || !cbRef.current.onViewChange || m.source === "linked" || m.source === "republish" @@ -599,7 +588,7 @@ export function XYChart(props) { dispatchView(m); return; } - if (awaitingPayload || !socket.connected) return; + if (awaitingPayload || !plane.connected) return; if (m.type === "select" || m.type === "select_polygon" || m.type === "select_clear") { m = withSelectionSeq(m); pendingSelectionSeqs.add(m.seq); @@ -637,7 +626,9 @@ export function XYChart(props) { }; const toSpans = (spec, buffers) => { - const spans = (buffers || []).map((b) => new Uint8Array(b)); + const spans = (buffers || []).map( + (b) => (b instanceof Uint8Array ? b : new Uint8Array(b)), + ); return spec.buffer_layout === "split" ? spans : spans[0]; }; @@ -684,13 +675,13 @@ export function XYChart(props) { invalidateSelectionReplies(); }; - const deferStatePush = (data, message) => { + const deferStatePush = (data, message, buffers) => { // Programmatic view/selection pushes are not part of the authoritative // figure payload. Preserve only generation-stamped room events; replies // and appends remain unsafe to defer across payload mounts. const generation = statePushGeneration(data, message); if (generation !== null) { - pendingStatePushes.push({ generation, message, buffers: data.buffers || [] }); + pendingStatePushes.push({ generation, message, buffers }); return true; } return false; @@ -711,7 +702,7 @@ export function XYChart(props) { generation === payloadGeneration && selectionPushReplacesSelection(message) ); - const onPayload = (data) => { + const onPayload = (data, buffers) => { if (destroyed || !data || data.fig !== liveToken) return; // Direct subscription replies are mount-addressed; room-wide rebuild // broadcasts intentionally omit mid and remain visible to every mount. @@ -776,7 +767,7 @@ export function XYChart(props) { : selectionRequest(selectionToRestore); payloadVersion = nextPayloadVersion; const spec = withHoverFlag(eventSpec(data.spec, cbRef.current)); - const nextBuffers = toSpans(data.spec, data.buffers); + const nextBuffers = toSpans(data.spec, buffers); const chromeChanged = Boolean(view && !sameMountedChromeSpec(view.spec, spec)); if (!chromeChanged && view?.updatePayload?.(spec, nextBuffers)) { // updatePayload re-homes the viewport and rebuilds trace state, so pin @@ -820,14 +811,14 @@ export function XYChart(props) { replayPendingStatePushes(nextPayloadVersion); }; - const onMsg = (data) => { + const onMsg = (data, buffers) => { if (destroyed || !data || data.fig !== liveToken) return; // Replies are mount-addressed; pushes (append) carry no mid. if (data.mid !== undefined && data.mid !== null && data.mid !== mid) return; const message = data.message; if (!message) return; if (awaitingPayload) { - if (!deferStatePush(data, message)) discardPendingReply(message); + if (!deferStatePush(data, message, buffers)) discardPendingReply(message); return; } const wireVersion = Number.isInteger(data.version) ? data.version : null; @@ -841,7 +832,7 @@ export function XYChart(props) { // or a replacement payload. Keep it until that generation mounts; // unlike a reply, it remains authoritative room state. if (selectionPushReplacesSelection(message)) invalidateSelectionReplies(); - deferStatePush(data, message); + deferStatePush(data, message, buffers); return; } if (wireVersion !== null && payloadVersion !== null) { @@ -854,7 +845,7 @@ export function XYChart(props) { // A forward gap means at least one append was not applied (for // example, an oversized binary push). Re-prime from a full payload // instead of rejecting every subsequent append forever. - if (isAppendPush && wireVersion > expected && socket.connected) subscribe(); + if (isAppendPush && wireVersion > expected && plane.connected) subscribe(); return; } } @@ -922,17 +913,17 @@ export function XYChart(props) { // The append establishes the generation whose state writes may have // reached this mount first. Apply the data delta before replaying // those writes so row-backed selections see the new trace lengths. - dispatchToView(clientMessage, data.buffers || []); + dispatchToView(clientMessage, buffers); replayPendingStatePushes(wireVersion); return; } - dispatchToView(clientMessage, data.buffers || []); + dispatchToView(clientMessage, buffers); }; const onErr = (data) => { if (destroyed || !data || data.fig !== liveToken) return; console.warn(`xy: ${data.error} (fig ${data.fig})`); - if (data.resync === true && socket.connected && errResyncs < 5) { + if (data.resync === true && plane.connected && errResyncs < 5) { errResyncs += 1; subscribe(); } @@ -942,10 +933,10 @@ export function XYChart(props) { resetEpoch(); }; - socket.on("payload", onPayload); - socket.on("msg", onMsg); - socket.on("err", onErr); - socket.on("disconnect", onDisconnect); + plane.on("payload", onPayload); + plane.on("msg", onMsg); + plane.on("err", onErr); + plane.on("disconnect", onDisconnect); // Resubscribe on every (re)connect: after the app plane reconnects the // shared manager, rooms are gone and — on another backend node — the // figure itself may need a state-driven rebuild. `sub` triggers both. @@ -956,9 +947,9 @@ export function XYChart(props) { errResyncs = 0; subscribe(); }; - socket.on("connect", onConnect); + plane.on("connect", onConnect); subCounts.set(liveToken, (subCounts.get(liveToken) || 0) + 1); - if (socket.connected) subscribe(); + if (plane.connected) subscribe(); const rememberClick = (event) => { if (!cbRef.current.onPointClick) return; @@ -983,15 +974,15 @@ export function XYChart(props) { destroyed = true; if (tracksClickInput) el.removeEventListener("click", rememberClick, true); resetEpoch(); - socket.off("payload", onPayload); - socket.off("msg", onMsg); - socket.off("err", onErr); - socket.off("disconnect", onDisconnect); - socket.off("connect", onConnect); + plane.off("payload", onPayload); + plane.off("msg", onMsg); + plane.off("err", onErr); + plane.off("disconnect", onDisconnect); + plane.off("connect", onConnect); const remaining = (subCounts.get(liveToken) || 1) - 1; if (remaining <= 0) { subCounts.delete(liveToken); - if (socket.connected) socket.emit("unsub", { fig: liveToken, mid }); + if (plane.connected) plane.emit("unsub", { fig: liveToken, mid }); } else { subCounts.set(liveToken, remaining); } diff --git a/python/reflex_xy/namespace.py b/python/reflex_xy/data_plane.py similarity index 76% rename from python/reflex_xy/namespace.py rename to python/reflex_xy/data_plane.py index 8a2732432..889ca0b46 100644 --- a/python/reflex_xy/namespace.py +++ b/python/reflex_xy/data_plane.py @@ -1,28 +1,29 @@ -"""The xy data plane as a second socket.io namespace on Reflex's server. +"""The xy data plane as a Reflex channel on the app's websocket. Transport decision (spec/design/reflex-integration.md): instead of new HTTP -endpoints, the data plane multiplexes onto the app's existing engine.io -websocket as its own namespace (`/_xy`). socket.io multiplexing means the -browser keeps ONE physical connection for app state and chart data; this -namespace inherits the connection's lifecycle, origin checks, and query -token — anything the app plane gains (auth on connect, proxy config, TLS) -the data plane gets for free, because it *is* the same connection. - -Wire shape: metadata is one small JSON object per event; every data column -rides as a native socket.io binary attachment (`bytes` values below), which -the browser receives as `ArrayBuffer`s in-place. No JSON numbers for data, -no base64 (§29) — and no custom length-prefix framing needed, because the -socket.io protocol already delimits attachments. +endpoints or a second connection, the data plane multiplexes onto the app's +existing event websocket as its own *channel* (`/_xy`). The browser keeps ONE +physical connection for app state and chart data; this channel inherits the +connection's lifecycle, origin checks, and resolved client token — anything the +app plane gains (auth on connect, proxy config, TLS) the data plane gets for +free, because it *is* the same connection. + +Wire shape: metadata is one small JSON object per message, and every data +column rides *beside* it as a binary frame attachment. Reflex pads every +attachment to an 8-byte boundary, so the browser reads each column as an +aligned typed-array view over the received frame. No JSON numbers for data, no +base64 (§29) — and no custom length-prefix framing needed, because a channel +frame already delimits its attachments. Events, client -> server: sub {fig, px?, mid?} subscribe; joins the figure room, replies `payload` unsub {fig} leave the figure room msg {fig, v?, mid?, m} one channel.handle_message dispatch, reply `msg` -Events, server -> client: - payload {fig, version, spec, buffers, mid?} first paint / full refresh - msg {fig, version?, mid?, message, buffers} reply or room-wide push - err {fig, error, resync?} failure; resync requests a new `sub` +Events, server -> client (metadata; the columns are the frame's attachments): + payload {fig, version, spec, mid?} first paint / full refresh + msg {fig, version?, mid?, message} reply or room-wide push + err {fig, error, resync?} failure; resync requests a new `sub` Each successful `sub` begins an authoritative client comparison epoch. Replies and room-wide pushes carry the FigureEntry version whose data produced them. @@ -37,12 +38,12 @@ from __future__ import annotations import asyncio -import urllib.parse from collections.abc import Awaitable, Callable, Sequence from dataclasses import dataclass from typing import TYPE_CHECKING, Any, Optional -from socketio import AsyncNamespace +import reflex as rx +from reflex.channels import MAX_MESSAGE_BUFFERS from xy.channel import handle_message @@ -53,25 +54,25 @@ if TYPE_CHECKING: from xy._figure import Figure -__all__ = ["XY_NAMESPACE", "XYNamespace"] +__all__ = ["XY_PLANE", "XYChannel"] -#: socket.io namespace for the chart data plane. A namespace name is part of -#: the socket.io protocol, not a URL: it needs no route, no mount, and no +#: Channel name for the chart data plane. A channel name is part of Reflex's +#: websocket protocol, not a URL: it needs no route, no mount, and no #: reverse-proxy entry beyond what the app's websocket already has. -XY_NAMESPACE = "/_xy" +XY_PLANE = "/_xy" # One payload/message is screen-bounded by construction (§29); these caps are # the transport's fail-closed backstop, not a tuning knob. _MAX_PX_HINT = 8192 _MIN_PX_HINT = 16 -# socket.io-parser's Decoder ships with `maxAttachments: 10`; a binary packet -# with more attachments makes the BROWSER close the whole shared websocket as -# a parse error — which the app plane then re-opens, re-subscribing every -# chart into an infinite reconnect loop. Figures stay under the limit or fall -# back to the joined single-blob payload (`buffer_layout` != "split", which -# the client's `toSpans` already handles). -_MAX_WIRE_ATTACHMENTS = 10 +# A channel frame declares its attachment count in the header, and Reflex +# refuses to encode or decode more than `MAX_MESSAGE_BUFFERS` of them on either +# side. Taking the framework's constant rather than a local copy means the two +# cannot drift into emitting a frame the client will reject. Figures stay under +# the limit or fall back to the joined single-blob payload +# (`buffer_layout` != "split", which the client's `toSpans` already handles). +_MAX_WIRE_ATTACHMENTS = MAX_MESSAGE_BUFFERS def _build_wire_payload( @@ -83,7 +84,7 @@ def _build_wire_payload( return spec, raw # Rebuild joined rather than concatenating `raw`: the split spec addresses # columns by `buf` index and carries `buffer_layout: "split"`, which the - # client rejects for a one-buffer packet. Running the emitters twice is + # client rejects for a one-buffer frame. Running the emitters twice is # safe — they only assign shipped_sel/drill state, and the caller holds # the figure lock across both builds. spec, blob = figure.build_payload(px) @@ -163,29 +164,36 @@ def _plain(value: Any) -> Any: def _buffer_bytes( buffers: Optional[Sequence[bytes | bytearray | memoryview]], -) -> list[bytes | bytearray]: - """socket.io attaches `bytes`/`bytearray` only; memoryviews must convert. +) -> list[bytes]: + """Frame attachments are `bytes`; anything else converts. This is the single wire copy of each column (the join copy the split payload layout avoids does not come back — each column converts alone). + The emitters hand over `memoryview`s, so in practice this is exactly one + copy per column and never two. """ - return [b if isinstance(b, (bytes, bytearray)) else bytes(b) for b in (buffers or [])] + return [b if isinstance(b, bytes) else bytes(b) for b in (buffers or [])] -class XYNamespace(AsyncNamespace): - """Serve registry figures to browser clients over the shared socket.""" +class XYChannel(rx.channels.Channel): + """Serve registry figures to browser clients over the app's websocket.""" + + name = XY_PLANE + + # Clients send JSON only; every column travels server -> client. + accepts_binary = False def __init__( self, registry: FigureRegistry, *, - namespace: str = XY_NAMESPACE, rebuild: Optional[RebuildHook] = None, ) -> None: - super().__init__(namespace) + super().__init__() self.registry = registry self._rebuild = rebuild - # Socket.IO may dispatch events for one SID concurrently. Serialize + self._sessions_by_sid: dict[str, rx.channels.ChannelSession] = {} + # Reflex may dispatch messages for one session concurrently. Serialize # subscribe/unsubscribe for one mount token so a slow rebuild cannot # re-add membership after a later unsubscribe. Locks are reference- # counted so hostile/abandoned token strings do not create a second @@ -202,27 +210,43 @@ def __init__( # -- connection lifecycle ------------------------------------------------ - async def on_connect(self, sid: str, environ: dict) -> None: - """Record the Reflex client token presented by this connection. + async def on_open(self, session: rx.channels.ChannelSession) -> None: + """Record the session and the Reflex client token it carries. - The engine.io connection is shared with Reflex's `/_event` namespace, - so the same `?token=` query string reaches us. Reflex treats this as a - bearer session identifier (its TokenManager links rather than - authenticates it); engine-level origin/auth policy is inherited from - the shared connection. + The websocket is shared with Reflex's own event plane, so Reflex has + already resolved the connection's `?token=`. It treats that as a bearer + session identifier (its TokenManager links rather than authenticates + it); connection-level origin/auth policy is inherited from the shared + connection. """ - query = urllib.parse.parse_qs(environ.get("QUERY_STRING", "")) - token_list = query.get("token", []) - await self.save_session(sid, {"client_token": token_list[0] if token_list else None}) + self._sessions_by_sid[session.sid] = session + session.data["client_token"] = session.client_token - async def on_disconnect(self, sid: str) -> None: - """Rooms are cleaned up by socket.io; figures outlive the socket. + async def on_close(self, session: rx.channels.ChannelSession) -> None: + """Release the session; figures outlive the socket. Deliberate: a dropped connection (reload, laptop lid, transient network) must not destroy server-side figures — the client resubscribes with the same tokens on reconnect. """ - self.registry.disconnect(sid) + self._sessions_by_sid.pop(session.sid, None) + self.registry.disconnect(session.sid) + + async def on_message( + self, + session: rx.channels.ChannelSession, + event: str, + data: Any, + buffers: list[bytes], + ) -> None: + """Dispatch one inbound message to the data plane handlers.""" + handler = { + "sub": self.on_sub, + "unsub": self.on_unsub, + "msg": self.on_msg, + }.get(event) + if handler is not None: + await handler(session.sid, data) # -- subscription ---------------------------------------------------------- @@ -239,7 +263,7 @@ async def on_sub(self, sid: str, data: Any) -> None: ) if token is None or entry is None or not self._is_connected(sid): return - await self.enter_room(sid, self._room(token)) + self._enter_room(sid, self._room(token)) if not self._is_connected(sid): return # Mirror membership only after the await-heavy join/rebuild @@ -293,15 +317,10 @@ async def _send_payload( "fig": token, "version": entry.version, "spec": spec, - "buffers": _buffer_bytes(raw), } if mid is not None: envelope["mid"] = mid - await self.emit( - "payload", - envelope, - to=sid, - ) + await self._send("payload", envelope, _buffer_bytes(raw), to=sid) async def on_unsub(self, sid: str, data: Any) -> None: token = self._token_of(data) @@ -311,7 +330,7 @@ async def on_unsub(self, sid: str, data: Any) -> None: try: async with lock: try: - await self.leave_room(sid, self._room(token)) + self._leave_room(sid, self._room(token)) finally: self.registry.unsubscribe(token, sid) finally: @@ -354,25 +373,25 @@ async def on_msg(self, sid: str, data: Any) -> None: message, buffers = reply wire_buffers = _buffer_bytes(buffers) if len(wire_buffers) > _MAX_WIRE_ATTACHMENTS: - # Never exceed the browser parser's attachment limit: one oversized - # packet closes the shared websocket for the whole app. Channel - # replies are bounded by construction, so this is a contract check. - await self.emit( - "err", {"fig": token, "error": "reply exceeds wire attachment limit"}, to=sid + # Never exceed the frame's attachment limit: Reflex refuses to + # encode it, so the reply would be lost rather than answered. + # Channel replies are bounded by construction, so this is a + # contract check. + await self._send( + "err", {"fig": token, "error": "reply exceeds wire attachment limit"}, [], to=sid ) return envelope: dict[str, Any] = { "fig": token, "version": operation_version, "message": _plain(message), - "buffers": wire_buffers, } # Replies are mount-addressed: several charts on one page share one # socket, so the client tags requests with a mount id and we echo it. mid = self._mid_of(data) if mid is not None: envelope["mid"] = mid - await self.emit("msg", envelope, to=sid) + await self._send("msg", envelope, wire_buffers, to=sid) # -- server-side pushes (append/refresh fan-out) --------------------------- @@ -386,29 +405,29 @@ async def broadcast_message( """Push one channel message to every subscriber of a figure.""" wire_buffers = _buffer_bytes(buffers) if len(wire_buffers) > _MAX_WIRE_ATTACHMENTS: - # This packet goes to a room: one oversized push would close every - # subscriber's shared websocket at once (see _MAX_WIRE_ATTACHMENTS). - # Fail loud instead of emitting it. Append pushes also ask clients - # to resubscribe because the figure advanced; view-state pushes - # carry a generation stamp but do not mutate the figure payload. - await self.emit( + # This frame goes to a room: an unencodable push would silently + # drop the update for every subscriber at once. Fail loud instead. + # Append pushes also ask clients to resubscribe because the figure + # advanced; view-state pushes carry a generation stamp but do not + # mutate the figure payload. + await self._send( "err", { "fig": token, "error": "push exceeds wire attachment limit", "resync": message.get("type") == "append" and version is not None, }, + [], room=self._room(token), ) return - envelope = { + envelope: dict[str, Any] = { "fig": token, "message": _plain(message), - "buffers": wire_buffers, } if version is not None: envelope["version"] = version - await self.emit("msg", envelope, room=self._room(token)) + await self._send("msg", envelope, wire_buffers, room=self._room(token)) async def broadcast_payload(self, token: str, entry: FigureEntry) -> None: """Push a full refreshed payload (figure rebuilt) to subscribers.""" @@ -416,17 +435,59 @@ async def broadcast_payload(self, token: str, entry: FigureEntry) -> None: spec, raw = await asyncio.to_thread(_build_entry_payload, entry) if not self.registry.is_current(token, entry): return - await self.emit( + await self._send( "payload", { "fig": token, "version": entry.version, "spec": spec, - "buffers": _buffer_bytes(raw), }, + _buffer_bytes(raw), room=self._room(token), ) + # -- transport seams ------------------------------------------------------- + + async def _send( + self, + event: str, + data: dict[str, Any], + buffers: list[bytes], + *, + to: Optional[str] = None, + room: Optional[str] = None, + ) -> None: + """Send one envelope, with its columns as the frame's attachments.""" + if to is not None: + session = self._sessions_by_sid.get(to) + if session is not None: + await session.send(event, data, buffers) + elif room is not None: + await self.send_to_room(room, event, data, buffers) + + def _enter_room(self, sid: str, room: str) -> None: + """Join a fan-out room (never suspends — see ``on_sub``'s liveness + checks, which bracket this call).""" + session = self._sessions_by_sid.get(sid) + if session is not None: + session.join(room) + + def _leave_room(self, sid: str, room: str) -> None: + """Leave a fan-out room.""" + session = self._sessions_by_sid.get(sid) + if session is not None: + session.leave(room) + + def _session_data(self, sid: str) -> dict[str, Any]: + """Read the per-connection store.""" + held = self._sessions_by_sid.get(sid) + return held.data if held is not None else {} + + def _is_connected(self, sid: str) -> bool: + """Whether the channel session is still open.""" + session = self._sessions_by_sid.get(sid) + return session is not None and session.open + # -- internals --------------------------------------------------------------- @staticmethod @@ -460,12 +521,6 @@ def _mid_of(data: Any) -> Optional[str]: return None return mid - def _is_connected(self, sid: str) -> bool: - """Whether Socket.IO still owns ``sid`` in this namespace.""" - server = getattr(self, "server", None) - manager = getattr(server, "manager", None) - return manager is not None and manager.is_connected(sid, self.namespace) - def _retain_subscription_lock(self, key: tuple[str, str]) -> asyncio.Lock: lock = self._subscription_locks.setdefault(key, asyncio.Lock()) self._subscription_lock_users[key] = self._subscription_lock_users.get(key, 0) + 1 @@ -544,7 +599,7 @@ async def _run_rebuild_attempt( try: await self.broadcast_payload(token, entry) - except Exception: # noqa: BLE001 - payload build/emit is a protocol boundary + except Exception: # noqa: BLE001 - payload build/send is a protocol boundary # A failed generation must not poison later cache hits. Remove # only the generation this attempt inserted; if a normal # replacement won meanwhile, preserve and return that entry. @@ -581,11 +636,12 @@ async def _entry_for( if token is None: return None, None, False identity = _token_identity(token) - if identity.affinity_client is not None: - session = await self.get_session(sid) - if session.get("client_token") != identity.affinity_client: - await self._err(sid, token, "figure belongs to another session") - return token, None, False + if ( + identity.affinity_client is not None + and self._session_data(sid).get("client_token") != identity.affinity_client + ): + await self._err(sid, token, "figure belongs to another session") + return token, None, False entry, rebuild_guarded = self.registry.get_with_rebuild_guard(token) attempt = self._rebuild_attempts.get(token) # A normal publish invalidates the old attempt's guard atomically with @@ -626,7 +682,7 @@ async def _err( envelope: dict[str, Any] = {"fig": token, "error": error} if resync: envelope["resync"] = True - await self.emit("err", envelope, to=sid) + await self._send("err", envelope, [], to=sid) async def broadcast_error(self, token: str, error: str, resync: bool = False) -> None: """Room-wide err frame for server-side failures with no request to @@ -634,4 +690,4 @@ async def broadcast_error(self, token: str, error: str, resync: bool = False) -> envelope: dict[str, Any] = {"fig": token, "error": error} if resync: envelope["resync"] = True - await self.emit("err", envelope, room=self._room(token)) + await self._send("err", envelope, [], room=self._room(token)) diff --git a/python/reflex_xy/registry.py b/python/reflex_xy/registry.py index 375b9e556..37f379d2d 100644 --- a/python/reflex_xy/registry.py +++ b/python/reflex_xy/registry.py @@ -69,7 +69,7 @@ class FigureEntry: # parallelize (the kernels release the GIL on the Rust side). lock: asyncio.Lock = field(default_factory=asyncio.Lock) # The unwired/headless path cannot use the asyncio lock. This lock also - # makes synchronous message construction atomic with namespace payload/ + # makes synchronous message construction atomic with data-plane payload/ # interaction kernels and append mutation/version bump. Code needing both # locks always takes ``lock`` then ``sync_lock``; sync callers take only # this lock. It remains entry-local, so unrelated figures proceed. @@ -125,7 +125,7 @@ def __init__(self, ttl_seconds: float = DEFAULT_TTL_SECONDS) -> None: # and the data-token -> {plan digest} index that lets a column # republish rebuild + broadcast every mounted dependent figure. The # index is bounded by mounted plans: entries are added when a - # composite figure binds (namespace sub) and dropped by + # composite figure binds (data-plane sub) and dropped by # _unbind_plan_if_unmounted_locked on every transition that can end # the mount — unsubscribe, disconnect, release, failed-rebuild # cleanup, TTL sweep, and a republish that finds it unmounted. @@ -138,7 +138,7 @@ def __init__(self, ttl_seconds: float = DEFAULT_TTL_SECONDS) -> None: # tokens with no subscribers leave no unbounded tombstones behind. self._evicted_versions: dict[str, int] = {} # Only rebuildable subscriptions need registry lifecycle state; - # socket.io owns rooms for both token families. The inverse indexes + # the channel owns rooms for both token families. The inverse indexes # make subscribe/unsubscribe/disconnect idempotent and bounded by live # connections. self._rebuildable_subscribers: dict[str, set[str]] = {} @@ -160,7 +160,7 @@ def __init__(self, ttl_seconds: float = DEFAULT_TTL_SECONDS) -> None: # Captured by setup(); lets sync-handler threads schedule async # broadcasts safely. None until the data plane is attached. self._loop: Optional[asyncio.AbstractEventLoop] = None - # async callback(token, entry) -> None wired by the namespace so + # async callback(token, entry) -> None wired by the data plane so # publishes reach subscribed clients without a module cycle. self._on_publish: Optional[Callable[[str, FigureEntry], Awaitable[None]]] = None # async callback(token, message, buffers, version) -> None for append @@ -293,7 +293,7 @@ def get(self, token: str) -> Optional[FigureEntry]: def get_with_rebuild_guard(self, token: str) -> tuple[Optional[FigureEntry], bool]: """Return the current entry and whether a rebuild guard remains valid. - The snapshot is atomic so namespace requests can distinguish an entry + The snapshot is atomic so data-plane requests can distinguish an entry provisionally inserted by the active rebuild from one authorized by a concurrent normal publish, which invalidates every older guard. """ @@ -695,7 +695,7 @@ def schedule_broadcast(self, token: str) -> None: """Fan a publish out to subscribers from any thread. Safe no-op before setup() (no loop yet: nobody can be subscribed - either, because the namespace is what wires the loop). + either, because the data plane is what wires the loop). """ callback = self._on_publish loop = self._loop diff --git a/python/reflex_xy/state_bridge.py b/python/reflex_xy/state_bridge.py index a451f93cc..775999b14 100644 --- a/python/reflex_xy/state_bridge.py +++ b/python/reflex_xy/state_bridge.py @@ -97,7 +97,7 @@ async def rebuild_data(app: Any, parsed: ParsedToken) -> Optional[dict[str, Any] async def rebuild_plan_figure(app: Any, composite: ParsedPlanToken) -> Optional["Figure"]: """Recover a data-bound figure: plan (local map) + columns (registry or state) + bind. Raises PlanMissError / PlanBindError for spec-aware `err` - frames; anything else fails closed in the namespace.""" + frames; anything else fails closed in the data plane.""" plan = require_plan(composite.digest) entry = registry.get_columns(composite.data_token) if entry is not None: @@ -116,7 +116,7 @@ async def rebuild_plan_figure(app: Any, composite: ParsedPlanToken) -> Optional[ def make_rebuild_hook(app: Any) -> Any: - """The namespace's RebuildHook, bound to one app instance.""" + """The data plane's RebuildHook, bound to one app instance.""" async def _rebuild(token_str: str) -> Optional["Figure"]: composite = parse_plan_token(token_str) diff --git a/python/xy/interaction.py b/python/xy/interaction.py index 77fc39a6b..f680b727a 100644 --- a/python/xy/interaction.py +++ b/python/xy/interaction.py @@ -1447,7 +1447,7 @@ def _style_tail(name: str, values: Any) -> Optional[np.ndarray]: # join copy. The spec itself names the append — `append.seq` is the apply # signal for the widget host, where the refresh rides the spec+buffers # trait update as one comm message that doubles as notebook-reopen state. - # The socket.io host wraps the same spec in an `append` message push. + # The Reflex host wraps the same spec in an `append` message push. fig._append_seq += 1 seq = fig._append_seq spec, buffers = fig.build_payload_split() diff --git a/scripts/reflex_ws_smoke.py b/scripts/reflex_ws_smoke.py index 2777b2bd5..1a7da1d2c 100644 --- a/scripts/reflex_ws_smoke.py +++ b/scripts/reflex_ws_smoke.py @@ -5,7 +5,7 @@ design: 1. ONE physical websocket to the backend carries both the app plane and the - chart data plane (socket.io namespace multiplexing) — counted via CDP. + chart data plane (Reflex channel multiplexing) — counted via CDP. 2. The charts paint real pixels from binary socket payloads (screenshot evidence; there are no HTTP data endpoints to fall back on) — including the §6 fastapi-parity drilldown chart's density surface. @@ -191,7 +191,9 @@ def backend_websockets(self) -> list[str]: for (sid, method), events in self.s._events.items(): if sid == self.sid and method == "Network.webSocketCreated": urls.extend(e.get("url", "") for e in events) - return [u for u in urls if "/_event" in u or "/_xy" in u] + # The data plane is a channel *inside* this socket, so there is one + # URL to match — a second one would mean the chart opened its own. + return [u for u in urls if "/_event" in u] def sent_ws_frames(self, needle: str) -> list[str]: """Payloads of sent websocket frames containing `needle`.""" diff --git a/scripts/verify_sdist.py b/scripts/verify_sdist.py index 168893ef4..41e75a2f8 100644 --- a/scripts/verify_sdist.py +++ b/scripts/verify_sdist.py @@ -63,7 +63,7 @@ "python/reflex_xy/assets/__init__.py", "python/reflex_xy/component.py", "python/reflex_xy/events.py", - "python/reflex_xy/namespace.py", + "python/reflex_xy/data_plane.py", "python/reflex_xy/payload_asset.py", "python/reflex_xy/py.typed", "python/reflex_xy/registry.py", diff --git a/scripts/verify_wheel.py b/scripts/verify_wheel.py index 609bc45cd..e42c27413 100644 --- a/scripts/verify_wheel.py +++ b/scripts/verify_wheel.py @@ -39,7 +39,7 @@ "reflex_xy/assets/__init__.py", "reflex_xy/component.py", "reflex_xy/events.py", - "reflex_xy/namespace.py", + "reflex_xy/data_plane.py", "reflex_xy/payload_asset.py", "reflex_xy/py.typed", "reflex_xy/registry.py", diff --git a/spec/README.md b/spec/README.md index ff69b4c78..bb292800a 100644 --- a/spec/README.md +++ b/spec/README.md @@ -52,8 +52,8 @@ Internal architecture: how the engine is built and why. flat per-axis viewport-navigation contract: capability/action/axis/source switches, `zoom_limits`, reset, and the semantic `ranges` view events. - [`reflex-integration.md`](design/reflex-integration.md) — the bundled - `xy[reflex]` integration design: figures as first-class Reflex components over a second - socket.io namespace. + `xy[reflex]` integration design: figures as first-class Reflex components + over a dedicated channel on the app's own websocket. - [`reflex-shaped-api.md`](design/reflex-shaped-api.md) — how the core package feels Reflex-shaped while keeping no Reflex dependency. - [`renderer-architecture.md`](design/renderer-architecture.md) — audit of the diff --git a/spec/api/chart-roadmap.md b/spec/api/chart-roadmap.md index df1a7764d..933b134eb 100644 --- a/spec/api/chart-roadmap.md +++ b/spec/api/chart-roadmap.md @@ -62,7 +62,7 @@ Beyond the mark set, four capability layers now ship on `main`: thread), so a kernel-less page refines instead of stretching the overview. - **Reflex-first reactive API (`python/reflex_xy/`):** xy figures as first-class Reflex components (PR #55). Chart data multiplexes onto the - app's existing websocket as a second socket.io namespace (`/_xy`) with + app's existing websocket as a dedicated Reflex channel (`/_xy`) with binary column attachments (§29 — no JSON numbers, no sidecar HTTP endpoints); the only chart state in Reflex is a token string. The `@reflex_xy.figure` computed-var decorator binds figure builders to Reflex diff --git a/spec/design/reflex-component-api-implementation.md b/spec/design/reflex-component-api-implementation.md index bfc8baaa9..ac2d422f2 100644 --- a/spec/design/reflex-component-api-implementation.md +++ b/spec/design/reflex-component-api-implementation.md @@ -202,13 +202,13 @@ Composite figure identity, minimal wire change: - The wrapper subscribes with `fig = "xyp1||"`, assembled client-side once `data.token` is non-empty. Rooms, `mid` addressing, versioning, and the attachment-cap logic in - `namespace.py` are reused unchanged — one new token prefix to parse. + `data_plane.py` are reused unchanged — one new token prefix to parse. - **`registry.py`**: column entries (token → columns + version) beside figure entries; figure cache keyed by the composite token, plus an index `data_token → {digests}` so a data republish rebuilds and broadcasts every dependent figure. Figure entries stay derived caches: TTL-sweepable, rebuildable from (plan map, data rebuild). -- **`namespace.py`**: `sub`/`msg` on `xyp1|…` → plan lookup; data resolve +- **`data_plane.py`**: `sub`/`msg` on `xyp1|…` → plan lookup; data resolve (registry hit, else rebuild); bind → publish → serve. Affinity check uses the client token embedded in the `xyd1` half. - **`state_bridge.py`**: `rebuild_data(app, parsed)` mirroring @@ -228,7 +228,7 @@ Composite figure identity, minimal wire change: - `test_factories.py` — partition + collision table, did-you-mean, TypedDict column errors (including through a foreach item var), untyped fallback, static-tier routing. -- Extend `test_socket_data_plane.py` — composite `sub`, payload, pick; +- Extend `test_data_plane.py` — composite `sub`, payload, pick; data republish fans out to all dependent plans; rebuild-on-miss for both halves; affinity refusal; plan-miss `err {resync}`. - Demo app: add one data-bound chart to `examples/reflex/` beside the diff --git a/spec/design/reflex-component-api-options.md b/spec/design/reflex-component-api-options.md index 9444091bf..f321be35e 100644 --- a/spec/design/reflex-component-api-options.md +++ b/spec/design/reflex-component-api-options.md @@ -142,7 +142,7 @@ planes: props, and small semantic events (`on_point_click`, `on_select_end`, …) — ordinary Reflex state and event handlers. Never data buffers. - **Data plane** (xy-native): binary payloads, drilldown round-trips, and - streaming appends on a second socket.io namespace (`/_xy`) **multiplexed + streaming appends on a dedicated Reflex channel (`/_xy`) **multiplexed onto the app's existing websocket**. Reflex state never sees a data byte. The pieces, end to end: diff --git a/spec/design/reflex-integration.md b/spec/design/reflex-integration.md index c18d2bfe6..0fac3bafc 100644 --- a/spec/design/reflex-integration.md +++ b/spec/design/reflex-integration.md @@ -1,20 +1,30 @@ # Reflex integration — design Status: **implementation landed** (`python/reflex_xy`, tests under -`tests/reflex_adapter/`). This document is the authoritative design; the -prototype implements it end to end over Reflex 0.9.6. The deliverable is an -integration bundled in the `xy` distribution and installed with -`xy[reflex]`. It makes a xy figure a first-class Reflex component with the +`tests/reflex_adapter/`). This document is the authoritative design. The +deliverable is an integration bundled in the `xy` distribution and installed +with `xy[reflex]`. It makes a xy figure a first-class Reflex component with the same performance contract as the notebook path: screen-bounded binary wire (§29), kernel-side canonical data (§27), stale-while-revalidate interaction (§17). +> **Unreleased dependency (temporary).** The data plane is a Reflex *channel* +> (§2), which no released Reflex ships yet — it exists on +> reflex-dev/reflex#6932. Until that lands, the `xy[reflex]` extra carries a +> git requirement for the branch and `[tool.uv.sources]` pins the whole Reflex +> workspace to it, with `[tool.hatch.metadata] allow-direct-references` to make +> the build accept that. This is deliberately unpublishable: PyPI refuses a +> direct reference, so a release cut from this tree fails at upload rather than +> shipping a version specifier that would install a Reflex where every chart +> stays blank. Replace all three with the real floor when channels are +> released. + Two decisions define this revision (superseding the HTTP-routes draft — see §8 for the audit trail): -1. **The data plane rides the app's existing websocket.** No new endpoints; - a second socket.io namespace multiplexes onto the engine.io connection - Reflex already maintains. +1. **The data plane rides the app's existing websocket.** No new endpoints and + no second connection: the `/_xy` plane is a Reflex *channel* multiplexed + onto the event websocket the app already maintains (§2). 2. **There is no figure server and no chart data in Redis.** Figures are per-process *rebuildable caches*; Reflex state (already durable and already distributed) is the only source of truth. The figure token is the @@ -33,8 +43,8 @@ state, wrong for data buffers. The integration splits every chart into: usual way. Rows and summaries are small by construction — never buffers. - **Data plane (xy-native, high-frequency, binary).** First paint, `view`/`density_view`/`pick`/`select` round-trips, streaming `append` - pushes, and full-payload refreshes — on a dedicated socket.io namespace - (`/_xy`) **carried by the same physical websocket** as the control plane. + pushes, and full-payload refreshes — on a dedicated plane named `/_xy` + **carried by the same physical websocket** as the control plane. Reflex state never sees a data byte; state diffing cost is independent of data size. @@ -54,10 +64,10 @@ proxies must be taught each route; every `/msg` pays request setup + headers; SSE is a second long-lived connection per chart with its own reconnect logic; and none of it inherits app-plane auth. The XYBF binary frame format (`python/xy/_framing.py`; versioning in [wire-protocol.md](wire-protocol.md) -§7) exists because HTTP bodies need framing — socket.io attachments -already carry length-delimited binary, so on this transport the framing +§7) exists because HTTP bodies need framing — a Reflex channel frame already +carries length-delimited binary attachments, so on this transport the framing layer disappears too. XYBF remains in `python/xy/_framing.py` (re-exported -from `xy.channel`) for HTTP/export hosts; the namespace does not use it. +from `xy.channel`) for HTTP/export hosts; the data plane does not use it. ### The cost we accept (recorded, §28 spirit) @@ -67,72 +77,67 @@ from `xy.channel`) for HTTP/export hosts; the namespace does not use it. is single-digit MB; if it ever matters, chunked payload emission (bounded frames interleaved with other traffic) fits behind the same events without protocol change. -- **Version coupling.** The wrapper mirrors Reflex's socket options - (`transports`, ws subprotocol, `?token=` query) so the manager cache - merges the connections. Those names are pinned by - `tests/reflex_adapter/test_assets.py` — a Reflex upgrade that renames - them fails loudly in CI, not silently in prod. -- **One engine.io connection per tab** stays the invariant. If a chart page +- **Version coupling.** The wrapper depends on exactly one Reflex export, + `getChannel` from `$/utils/state`, and the backend on one method, + `app.register_channel`. Both are pinned by + `tests/reflex_adapter/test_assets.py` and the adapter suite — a Reflex + upgrade that renames either fails loudly in CI, not silently in prod. This + is a deliberate narrowing: the previous socket.io carrier had to mirror + Reflex's whole `io()` option set (engine.io mount path, `transports`, ws + subprotocol, `?token=` query) just to make socket.io-client's manager cache + merge the two connections, and every one of those was a way to silently end + up with a second socket or none at all. +- **One websocket per tab** stays the invariant, now structurally rather than + by option-matching: the chart never constructs a connection. If a chart page somehow loads without state enabled there is no socket at all — but figure tokens come from state, so that page has no charts either. -## 2. Transport: a second namespace on the app's socket +## 2. Transport: the `/_xy` channel -**Backend.** Reflex builds a python-socketio `AsyncServer` at app -construction and registers its `/_event` namespace on it. The adapter -registers one more namespace on the same server: +**Backend.** Reflex serves its own events on a plain websocket and +multiplexes additional *channels* onto it. The adapter registers one: ```python -app.sio.register_namespace(XYNamespace(registry, rebuild=...)) # "/_xy" +app.register_channel(XYChannel(registry, rebuild=...)) # name "/_xy" ``` -A namespace is a socket.io protocol concept, not a URL: no route, no mount, -no proxy entry. Wiring is one line in `rxconfig.py` — -`plugins=[reflex_xy.XYPlugin()]` — whose `post_compile` hook receives the -live `App` at backend-worker startup (after the socket server exists, before -any client connects), or an explicit `reflex_xy.setup(app)` for people who -prefer it in `app.py`. A lifespan task captures the serving loop (for -thread-safe fan-out from sync handlers) and runs the registry TTL sweep. - -**Frontend.** socket.io-client caches managers by -`(protocol, host, port, engine.io path)`. The wrapper connects to namespace -`/_xy` with the *same* URL and options Reflex's `connect()` uses -(`getBackendURL(env.EVENT)`, `path: endpoint.pathname`, -`transports: [env.TRANSPORT]`, `protocols: [version]`, -`query: {token: getToken()}`) — so whichever side connects first creates the -manager and the other multiplexes onto it. One websocket in the browser's -network tab, two namespaces inside it. React effect ordering means the chart -often connects first; mirroring the options exactly is what makes that safe -(the backend sees an identical connection either way). - -Reflex owns reconnection: its `reconnect()` reopens the shared manager, our -namespace socket re-CONNECTs automatically, and every mounted chart re-`sub`s -on the `connect` event. - -**Wire shape.** Metadata is one small JSON object per event; every data -column is a `bytes` value inside it, which python-socketio hoists into -binary attachments and the browser receives as `ArrayBuffer`s *in place* — -aligned, zero-copy into `Float32Array`s. No JSON numbers for data, no -base64, no custom framing (§29 preserved; the socket.io protocol already -length-prefixes attachments). - -**Attachment cap (hard browser limit).** socket.io-parser's `Decoder` ships -with `maxAttachments: 10`; one binary packet with more attachments makes the -browser throw `"too many attachments"`, which `Manager.ondata` converts into -closing the *entire shared websocket* as a parse error — the app plane then -reconnects, every chart re-`sub`s, the oversized payload is re-sent, and the -connection loops forever with no console error. The namespace therefore never -emits more than 10 attachments per packet (`_MAX_WIRE_ATTACHMENTS`): -payloads whose split layout would exceed the cap fall back to the joined -single-blob `build_payload()` form (no `buffer_layout: "split"` in the spec; -the wrapper's `toSpans` already dispatches on that flag), trading the join -copy for staying inside the parser's budget. `msg` replies are bounded by -channel construction; the namespace enforces the same cap as a contract -check and answers `err` instead of emitting an unparseable packet — on both -the reply path and the room-wide push path (`broadcast_message`, the -`reflex_xy.append` fan-out, where one oversized packet would close every -subscriber's connection at once). Regression: -`tests/reflex_adapter/test_socket_data_plane.py::` +A channel is a Reflex protocol concept, not a URL: no route, no mount, no +proxy entry. `register_channel` raises if the app has no event websocket +(state disabled) or is not on the plain-WebSocket transport, so a +misconfiguration fails at startup rather than at first paint. The channel +declares `accepts_binary = False`: every column travels server → client, and +an inbound binary frame is refused by Reflex before it reaches a handler. + +**Frontend.** `getChannel("/_xy")` (from `$/utils/state`) returns the shared +plane handle — `connected`, `emit`, `on`, `off` — riding the app's own +websocket. No second connection exists to key, cache or race, and Reflex owns +reconnection: when it reopens the socket the channel reopens with it and every +mounted chart re-`sub`s on the `connect` event. + +**Wire shape.** Metadata is one small JSON object per message and the data +columns are its binary attachments, carried *beside* the metadata in the +frame rather than inside it. Reflex pads every attachment to an 8-byte +boundary, so each column arrives as a `Uint8Array` view over the received +frame at a 4-byte-aligned offset — zero-copy into `Float32Array`s, and the +client's `toSpans`/LOD paths already honor `byteOffset`. No JSON numbers for +data, no base64, no custom framing (§29 preserved). + +**Attachment cap.** A channel frame declares its attachment count in the +header, and Reflex refuses to encode or decode more than +`MAX_MESSAGE_BUFFERS` (64) of them — an oversized payload would not be +truncated, it would simply never arrive. `_MAX_WIRE_ATTACHMENTS` takes that +number from `reflex.channels` rather than copying it, so the two cannot drift +into emitting a frame the client will reject. Payloads whose split layout +would exceed the cap fall back to the joined single-blob `build_payload()` +form (no `buffer_layout: "split"` in the spec; the wrapper's `toSpans` already +dispatches on that flag), trading the join copy for staying inside the frame's +budget — a recorded tier decision, never silent (§28). `msg` replies are +bounded by construction; the data plane enforces the same cap as a contract +check and answers `err` instead of dropping the update, on both the reply path +and the room-wide push path (`broadcast_message`, the `reflex_xy.append` +fan-out, where one oversized frame would silently lose the update for every +subscriber at once). Regression: +`tests/reflex_adapter/test_data_plane.py::` `test_sub_over_attachment_limit_ships_single_blob`, `::test_msg_reply_over_attachment_limit_answers_err_not_msg`, and `::test_broadcast_over_attachment_limit_answers_err_not_msg`. @@ -141,17 +146,21 @@ The envelope is below; the `m` payload it carries is specified field by field in `spec/design/wire-protocol.md`. ``` -client -> server (namespace /_xy) +client -> server (channel /_xy) sub {fig, px?, mid?} subscribe; join figure room; reply `payload` unsub {fig} leave the room msg {fig, v?, mid?, m} one xy.channel.handle_message dispatch -server -> client - payload {fig, version, spec, buffers, mid?} first paint / full refresh - msg {fig, version?, mid?, message, buffers} reply or push (no mid) +server -> client (metadata; the columns are the frame's attachments) + payload {fig, version, spec, mid?} first paint / full refresh + msg {fig, version?, mid?, message} reply or push (no mid) err {fig, error, resync?} failure; resync requests a new `sub` ``` +The attachments are not a field of the envelope: `XYChannel._send` passes them +as the frame's attachment list, and on the client every handler takes +`(data, buffers)`. + `mid` is a validated optional per-mount id: several charts on a page share the socket, so direct interaction replies and direct subscription payloads echo it and other mounts ignore the addressed envelope. Pushes and full-payload @@ -160,7 +169,7 @@ from each applying all M direct subscription responses after a resync. The kernel dispatch is byte-for-byte the notebook dispatch — `xy.channel.handle_message` (§3.1 of the old draft, now shipped), run off the event loop via a worker thread (the Rust kernels release the GIL) under a -per-figure lock. Namespace payload builds and interaction dispatches take the +per-figure lock. Data plane payload builds and interaction dispatches take the generation's async lock and then its synchronous figure lock, the same order as wired append. Caller-thread view-state writes take only the synchronous lock; there is no reverse acquisition. Thus payload emitter updates such as @@ -210,7 +219,7 @@ type crosses the socket unchanged and is dispatched by the shared `lod.screen_shape`, which rejects non-finite values and clamps the rest to `[16, MAX_SCREEN_DIM]` (`MAX_SCREEN_DIM = 4096`, `xy/config.py`) — a hostile client cannot make the kernel allocate an arbitrary density texture. The bound -matters more here than in the notebook: the namespace is reachable by anyone +matters more here than in the notebook: the data plane is reachable by anyone who can reach the app, so the clamp is an access-control boundary rather than a sanity check (§3.3). @@ -979,9 +988,10 @@ different worker may safely begin again at version 1. Once a room payload has mounted, a duplicate room broadcast at that same generation is ignored; this lets canonical rebuild recovery retry delivery without clearing a rows mask that was already replayed for the generation. -While disconnected, the wrapper does not enqueue kernel messages: socket.io -flushes its send buffer before its `connect` callback, which would otherwise -send old-epoch requests ahead of the resetting `sub`. +While disconnected, the wrapper does not enqueue kernel messages: the channel +buffers sends made while it is down and flushes them before the `connect` +callback runs, which would otherwise send old-epoch requests ahead of the +resetting `sub`. The guard is `plane.connected`, read off the channel handle. ## 6. Latency budget @@ -1065,10 +1075,12 @@ python/reflex_xy/ partition, schema checks, plan/data/static mount state_bridge.py token -> state_manager -> builder/data/plan rebuild hooks - namespace.py XYNamespace: sub/unsub/msg, payload/msg/err, - affinity (incl. composite), rebuild-on-miss, - binary attachments - app.py setup(app), XYPlugin (post_compile), lifespan + data_plane.py XYChannel(rx.channels.Channel): sub/unsub/msg, + payload/msg/err, affinity (incl. composite), + rebuild-on-miss, binary attachments — the whole + protocol and its one carrier (§2) + app.py setup(app) -> app.register_channel(...), + XYPlugin (post_compile), lifespan component.py chart(figure=...) -> rx.Component (local-JSX library); typed figure/data props; static tier payload_asset.py static tier: Chart -> content-addressed XYBF @@ -1100,24 +1112,29 @@ examples/fastapi/ (repo root) the same charts + a live 100M drilldown served tests/reflex_adapter/ token/registry/var/data-var/plan/factory/bridge/ payload-asset units, component compile, framework contract pins (R1/R7/R8), and a real-websocket - integration suite (uvicorn + socketio client) - covering payload/pick/select/affinity/rebuild/ - publish-broadcast/append/unsub + the composite - plan tier (fan-out, plan-miss resync, bind errs) + integration suite in test_data_plane.py (a real + rx.App under uvicorn, aiohttp speaking the channel + frame protocol) covering payload/pick/select/ + affinity/rebuild/publish-broadcast/append/unsub + + the composite plan tier (fan-out, plan-miss + resync, bind errs); test_channel_browser.py + asserts in a real browser that it shares the app's + one websocket ``` `inline()` (content-addressed pinned tokens, §3.4) lives in the package root beside `register()`/`release()`. The core `python/xy` package itself stays Reflex-free (CLAUDE.md rule). -`xy[reflex]` adds full `reflex>=0.9.6` for now — the `reflex-base` split covers -components/vars but not yet App/state-manager access; revisit when a smaller -supported surface exists. +`xy[reflex]` adds full `reflex` for now — the `reflex-base` split covers +components/vars but not yet App/state-manager access (nor channels); revisit +when a smaller supported surface exists. The extra currently names the +unreleased channel branch rather than a version floor; see § Status. **Versioning & releases.** The integration ships in every `xy` wheel and sdist, so it shares the core's version and bare `vX.Y.Z` release tags. The published -extra is dependency metadata only: it adds the supported Reflex floor without -creating another distribution or release pipeline. +extra is dependency metadata only: it adds the supported Reflex requirement +without creating another distribution or release pipeline. ## 8. Superseded: the HTTP-routes draft diff --git a/spec/design/renderer-architecture.md b/spec/design/renderer-architecture.md index 79336f1d5..b4d0d7b5a 100644 --- a/spec/design/renderer-architecture.md +++ b/spec/design/renderer-architecture.md @@ -81,7 +81,7 @@ relative mass, not as a budget (see §3 on why a line count failed as a metric). buffer list — this skips the join copy, the largest allocation of a direct-tier build. Split is what both shipping hosts use (`build_payload_split` in `python/xy/widget.py` and - `python/reflex_xy/namespace.py`); packed remains for standalone + `python/reflex_xy/data_plane.py`); packed remains for standalone export and for streaming `append`, which always re-ships packed (`python/xy/interaction.py`). `payloadBuffers` (`60_entries.ts`) and `_columnView` (`50_chartview.ts`) treat any spec/transport disagreement as a diff --git a/spec/design/view-state.md b/spec/design/view-state.md index e19de5149..cb8e90d46 100644 --- a/spec/design/view-state.md +++ b/spec/design/view-state.md @@ -359,7 +359,7 @@ are client-local (§4, §5.2). `view_nav` carries only `reset`, which is well-defined for every receiver because home ranges are client-known. All three reuse the existing `msg` envelope in both transports (anywidget -comm and the `/_xy` socket.io namespace), so Reflex room broadcast and +comm and the `/_xy` Reflex channel), so Reflex room broadcast and notebook delivery need no new plumbing. Hover payloads (§7) ride the existing hover/pick messages — no new message, larger detail. diff --git a/spec/design/wire-protocol.md b/spec/design/wire-protocol.md index c44fd4066..b6dd6def9 100644 --- a/spec/design/wire-protocol.md +++ b/spec/design/wire-protocol.md @@ -4,7 +4,7 @@ Status: **shipped**. This document specifies the message catalog dispatched by `xy.channel.handle_message` (`python/xy/channel.py`) and consumed by `js/src/54_kernel.ts`, plus the first-paint buffer layouts and the version handshake. The transport envelopes that carry these messages are separate: -the anywidget comm (`python/xy/widget.py`), the `/_xy` socket.io namespace +the anywidget comm (`python/xy/widget.py`), the `/_xy` Reflex channel ([reflex-integration.md](reflex-integration.md) §2), and the `XYBF` binary frame (`python/xy/_framing.py`, versioned in §7 below). @@ -342,7 +342,7 @@ omitted from the message clear; never pushed to history, reported by (view-state.md §5.1). All three ride the existing `msg` envelope in both transports (anywidget -comm and the `/_xy` socket.io namespace) behind the version handshake. +comm and the `/_xy` Reflex channel) behind the version handshake. ## 5. First-paint buffer layout: packed vs split @@ -361,8 +361,8 @@ spec's `columns` table is the addressing scheme, and it comes in two layouts: a `u8` column is folded into that column's own buffer, and `len` still counts only real values, so split is a byte-identical repack of packed. This is what both live hosts ship at first paint — `FigureWidget` - (`python/xy/widget.py`) and the `/_xy` namespace - (`python/reflex_xy/namespace.py`) — and on streaming append (§4), + (`python/xy/widget.py`) and the `/_xy` channel + (`python/reflex_xy/data_plane.py`) — and on streaming append (§4), with no join copy anywhere on a live path. The browser accepts genuine `ArrayBuffer` objects across JavaScript realm @@ -449,8 +449,8 @@ that progress and starts no animation clock. ## 6. Chunked base64 (standalone export only) -The comm and socket.io transports carry binary attachments natively and never -base64. Standalone HTML export has no binary channel, so `xy.export` embeds +The comm and Reflex channel transports carry binary attachments natively and +never base64. Standalone HTML export has no binary channel, so `xy.export` embeds the packed blob as chunked base64: - The blob is sliced into `_B64_CHUNK_BYTES` = 48 MiB pieces. That size is diff --git a/tests/reflex_adapter/test_assets.py b/tests/reflex_adapter/test_assets.py index e372222b1..e3ac83803 100644 --- a/tests/reflex_adapter/test_assets.py +++ b/tests/reflex_adapter/test_assets.py @@ -53,18 +53,22 @@ def test_link_client_creates_and_repairs(tmp_path): assert dst.resolve() == _client_source() -def test_wrapper_speaks_the_namespace_protocol(): - """The JSX wrapper and namespace.py must agree on event names and shapes.""" +def test_wrapper_speaks_the_data_plane_protocol(): + """The JSX wrapper and data_plane.py must agree on event names and shapes.""" jsx = (ADAPTER_ASSETS / "XYChart.jsx").read_text(encoding="utf-8") - # transport identity: same engine.io path as the app socket, /_xy namespace - assert 'nsUrl.pathname = "/_xy"' in jsx - assert "path: endpoint.pathname" in jsx + # transport identity: one channel name, matching XY_PLANE in data_plane.py, + # on the app's own websocket — no second connection to open or configure + assert 'const XY_PLANE = "/_xy"' in jsx + assert "getChannel(XY_PLANE)" in jsx + # socket.io is gone: no client, no namespace URL, no engine.io mount path + for gone in ("socket.io-client", "nsUrl", "endpoint.pathname", "env.TRANSPORT", "io("): + assert gone not in jsx, f"wrapper still carries socket.io machinery: {gone}" # client -> server events for needle in ('"sub"', '"unsub"', '"msg"'): - assert f"socket.emit({needle}" in jsx or f"emit({needle}" in jsx + assert f"plane.emit({needle}" in jsx # server -> client events for needle in ('"payload"', '"msg"', '"err"'): - assert f"socket.on({needle}" in jsx + assert f"plane.on({needle}" in jsx # binary columns go straight into typed arrays — never through JSON numbers assert "new Uint8Array(b)" in jsx assert "data.version < payloadVersion" in jsx @@ -93,11 +97,11 @@ def test_wrapper_speaks_the_namespace_protocol(): subscribe = jsx.split("const subscribe = () => {", 1)[1].split("};", 1)[0] assert "resetEpoch()" in subscribe assert jsx.count("resetEpoch();") == 3 # subscribe, disconnect, cleanup - assert "awaitingPayload || !socket.connected" in jsx + assert "awaitingPayload || !plane.connected" in jsx assert "awaitingPayload = false" in jsx - assert 'socket.on("disconnect", onDisconnect)' in jsx - assert "wireVersion > expected && socket.connected" in jsx - assert "data.resync === true && socket.connected" in jsx + assert 'plane.on("disconnect", onDisconnect)' in jsx + assert "wireVersion > expected && plane.connected" in jsx + assert "data.resync === true && plane.connected" in jsx # Rejected replies and accepted generation advances both reclaim pending # synthetic click/selection bookkeeping. assert "discardPendingReply(message)" in jsx @@ -119,8 +123,8 @@ def test_wrapper_speaks_the_namespace_protocol(): assert "data.mid == null" in jsx assert "Number.isInteger(data.version)" in jsx assert "DEFERRED_STATE_PUSH_TYPES.has(message.type)" in jsx - assert "pendingStatePushes.push({ generation, message, buffers: data.buffers || [] })" in jsx - assert "if (!deferStatePush(data, message)) discardPendingReply(message)" in jsx + assert "pendingStatePushes.push({ generation, message, buffers })" in jsx + assert "if (!deferStatePush(data, message, buffers)) discardPendingReply(message)" in jsx assert "const queued = pendingStatePushes.splice(0)" in jsx assert "for (const { generation, message, buffers } of queued)" in jsx assert "if (generation === payloadGeneration) dispatchToView(message, buffers)" in jsx @@ -135,8 +139,8 @@ def test_wrapper_speaks_the_namespace_protocol(): < replay_pushes.index("pendingStatePushes.push({ generation, message, buffers })") ) assert jsx.count("replayPendingStatePushes(nextPayloadVersion);") == 2 - on_payload = jsx.split("const onPayload = (data) => {", 1)[1].split( - "const onMsg = (data) => {", 1 + on_payload = jsx.split("const onPayload = (data, buffers) => {", 1)[1].split( + "const onMsg = (data, buffers) => {", 1 )[0] # Rebuild recovery may deliver both a room payload and a same-generation # addressed reply. Generic duplicates are ignored; addressed px-specific @@ -182,12 +186,14 @@ def test_wrapper_speaks_the_namespace_protocol(): # every older in-flight selection request (user gestures and payload # restores). Any eventual addressed reply is consumed before either the # Reflex callback or ChartView sees it. - on_msg = jsx.split("const onMsg = (data) => {", 1)[1].split("const onErr = (data) => {", 1)[0] + on_msg = jsx.split("const onMsg = (data, buffers) => {", 1)[1].split( + "const onErr = (data) => {", 1 + )[0] # A state write may overtake the append/full payload that establishes its # generation. Queue that write before the ordinary version mismatch path. assert ( on_msg.index("deferredPushGeneration > payloadVersion") - < on_msg.index("deferStatePush(data, message);") + < on_msg.index("deferStatePush(data, message, buffers);") < on_msg.index("if (wireVersion !== null && payloadVersion !== null)") ) assert ( @@ -203,7 +209,7 @@ def test_wrapper_speaks_the_namespace_protocol(): < on_msg.index("if (selectionWasInvalidated || !selectionWasPending) return;") < on_msg.index("const isRestore = restoreSelectionSeqs.delete(message.seq);") < on_msg.index("cbRef.current.onSelectEnd({") - < on_msg.index("dispatchToView(clientMessage, data.buffers || []);") + < on_msg.index("dispatchToView(clientMessage, buffers);") ) invalidate_replies = jsx.split("const invalidateSelectionReplies = () => {", 1)[1].split( "};", 1 @@ -220,7 +226,7 @@ def test_wrapper_speaks_the_namespace_protocol(): )[1] assert ( append_advance.index("payloadVersion = wireVersion;") - < append_advance.index("dispatchToView(clientMessage, data.buffers || []);") + < append_advance.index("dispatchToView(clientMessage, buffers);") < append_advance.index("replayPendingStatePushes(wireVersion);") < append_advance.index("return;") ) @@ -228,7 +234,7 @@ def test_wrapper_speaks_the_namespace_protocol(): # it must not arm new semantic view callbacks in that reset epoch. dispatch_view = jsx.split("const dispatchView = (m) => {", 1)[1].split("};", 1)[0] assert "awaitingPayload" in dispatch_view - assert "!socket.connected" in dispatch_view + assert "!plane.connected" in dispatch_view # the wrapper imports the sibling client copy, not a CDN or npm package assert 'from "./xy_client.js"' in jsx # static tier: fetch the payload asset, decode the XYBF frame, render @@ -246,10 +252,12 @@ def test_wrapper_speaks_the_namespace_protocol(): def test_same_generation_addressed_payload_invalidates_in_flight_replies(): """A px-specific payload can change shipped indices without a version bump.""" jsx = (ADAPTER_ASSETS / "XYChart.jsx").read_text(encoding="utf-8") - on_payload = jsx.split("const onPayload = (data) => {", 1)[1].split( - "const onMsg = (data) => {", 1 + on_payload = jsx.split("const onPayload = (data, buffers) => {", 1)[1].split( + "const onMsg = (data, buffers) => {", 1 + )[0] + on_msg = jsx.split("const onMsg = (data, buffers) => {", 1)[1].split( + "const onErr = (data) => {", 1 )[0] - on_msg = jsx.split("const onMsg = (data) => {", 1)[1].split("const onErr = (data) => {", 1)[0] invalidate = jsx.split("const invalidatePayloadReplies = () => {", 1)[1].split("};", 1)[0] for needle in ( @@ -294,7 +302,7 @@ def test_same_generation_addressed_payload_invalidates_in_flight_replies(): < on_msg.index("const selectionWasPending = pendingSelectionSeqs.delete(message.seq);") < on_msg.index("if (selectionWasInvalidated || !selectionWasPending) return;") < on_msg.index("cbRef.current.onSelectEnd({") - < on_msg.index("dispatchToView(clientMessage, data.buffers || []);") + < on_msg.index("dispatchToView(clientMessage, buffers);") ) @@ -333,17 +341,15 @@ def test_wrapper_discards_tailwind_scan_manifest_before_dom_props(): assert "...divProps" in jsx -def test_wrapper_mirrors_reflex_connection_options(): - """The shared-manager trick only works if our io() options match reflex's - connect() (utils/state.js). These names are the coupling surface — if - reflex renames them, this test is the early warning.""" +def test_wrapper_rides_the_app_socket_through_one_reflex_export(): + """`getChannel` is the whole coupling surface to Reflex's transport now. + + The chart opens no connection of its own: it asks Reflex for the `/_xy` + channel on the app's own websocket. That one import is what a Reflex + upgrade could rename, so this test is the early warning.""" jsx = (ADAPTER_ASSETS / "XYChart.jsx").read_text(encoding="utf-8") - for needle in ( - "getBackendURL(env.EVENT)", - "transports: [env.TRANSPORT]", - "protocols: [reflexEnvironment.version]", - "query: { token: getToken() }", - "autoUnref: false", - "reconnection: false", - ): - assert needle in jsx, f"wrapper lost reflex connection option: {needle}" + assert 'import { getChannel } from "$/utils/state";' in jsx + assert "sharedPlane = getChannel(XY_PLANE)" in jsx + # every handler takes the frame's attachments as its second argument + for handler in ("onPayload", "onMsg"): + assert f"const {handler} = (data, buffers) =>" in jsx diff --git a/tests/reflex_adapter/test_channel_browser.py b/tests/reflex_adapter/test_channel_browser.py new file mode 100644 index 000000000..67581c27e --- /dev/null +++ b/tests/reflex_adapter/test_channel_browser.py @@ -0,0 +1,169 @@ +"""A chart rendering in a real browser over the Reflex channel transport. + +The rest of the adapter suite drives the data plane from Python. This one +proves the thing that only a browser can: the wrapper opens no connection of +its own, the app's single websocket carries the chart's binary columns, and +the WebGL view paints from them. +""" + +from __future__ import annotations + +import json +from collections.abc import Generator +from pathlib import Path + +import pytest + +pytest.importorskip("playwright") + +from PIL import Image # noqa: E402 +from playwright.sync_api import WebSocket, sync_playwright # noqa: E402 +from reflex.testing import AppHarness # noqa: E402 + +# The app's event websocket, the one the chart has to share. +EVENT_PATH = "/_event" + +# Headless chromium has no GPU; xy's own browser probes use the same pair. +CHROMIUM_ARGS = ("--use-angle=swiftshader", "--enable-unsafe-swiftshader") + + +def ChannelChartApp(): + """A Reflex app with one live xy chart served over a channel.""" + import numpy as np + import reflex as rx + + import reflex_xy + import xy + + def orbits() -> "xy.Chart": + rng = np.random.default_rng(3) + count = 20_000 + theta = rng.uniform(0.0, 2.0 * np.pi, count) + radius = rng.normal(1.0, 0.05, count) + return xy.scatter_chart( + xy.scatter(radius * np.cos(theta), radius * np.sin(theta), opacity=0.6), + xy.x_axis(label="x"), + xy.y_axis(label="y"), + width="100%", + height=240, + ) + + token = reflex_xy.inline(orbits()) + + @rx.page("/") + def index(): + return rx.box( + reflex_xy.chart(token, height="240px"), + rx.text("ready", id="ready"), + ) + + app = rx.App() + reflex_xy.setup(app) + + +@pytest.fixture +def _fresh_registry(): + """Keep the registry across this module's tests. + + The package-wide autouse fixture resets it between tests, but this app + registers its figure once, when the harness imports it — a reset would + leave the subscribe with no figure to serve. + + Yields: + None; this only shadows the resetting fixture. + """ + yield + + +@pytest.fixture(scope="module") +def chart_app( + tmp_path_factory: pytest.TempPathFactory, +) -> Generator[AppHarness, None, None]: + """Build and serve the chart app. + + Args: + tmp_path_factory: pytest fixture for creating temporary directories. + + Yields: + The running harness. + """ + with AppHarness.create( + root=tmp_path_factory.mktemp("channel_chart_app"), + app_source=ChannelChartApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + + +def test_chart_paints_from_channel_binary(chart_app: AppHarness, tmp_path: Path): + """The chart paints, and its columns arrive on the app's own websocket. + + Args: + chart_app: The running harness. + tmp_path: Where to drop a screenshot of the painted chart. + """ + assert chart_app.frontend_url is not None + sockets: list[WebSocket] = [] + binary_frames: list[int] = [] + + with sync_playwright() as playwright: + browser = playwright.chromium.launch(args=list(CHROMIUM_ARGS)) + page = browser.new_page(viewport={"width": 1024, "height": 768}) + + def watch(socket: WebSocket) -> None: + sockets.append(socket) + if EVENT_PATH not in socket.url: + return # the dev server's hot-reload channel + socket.on( + "framereceived", + lambda payload: ( + binary_frames.append(len(payload)) if isinstance(payload, bytes) else None + ), + ) + + page.on("websocket", watch) + page.goto(chart_app.frontend_url) + page.wait_for_selector("#ready") + # The chart only reaches "ready" once a payload has been applied. + # A cold dev server still has xy's WebGL client bundle to transform, + # which outlasts the default wait by a wide margin. + chart = page.locator('[data-xy-slot="root"]') + chart.wait_for(state="visible", timeout=120_000) + page.wait_for_function( + "!!document.querySelector('[data-xy-context-state=\"ready\"]')", + timeout=120_000, + ) + # The accessible summary is computed from the decoded columns. + summary = page.locator('[id$="-summary"]').inner_text() + shot = tmp_path / "chart.png" + chart.screenshot(path=str(shot)) + browser.close() + + # One connection to the backend for the whole page: the chart multiplexes + # onto the app's event websocket instead of opening a data plane of its + # own. (The other socket is the dev server's hot-reload channel, which a + # built app does not have.) + backend_sockets = [socket.url for socket in sockets if EVENT_PATH in socket.url] + assert len(backend_sockets) == 1, backend_sockets + # Columns travelled as binary frames on that socket, not as JSON numbers + # or base64. + assert binary_frames, "no binary frame arrived on the app websocket" + assert max(binary_frames) > 10_000, ( + f"binary frames look too small for 20k points: {sorted(binary_frames)[-3:]}" + ) + # Axis ranges in the accessible summary are derived from the columns, so + # they only exist if the binary payload decoded into real data. + assert "ranges from" in summary, summary + # And the chart actually painted: a blank mount is one flat colour. + with Image.open(shot) as image: + colours = len(image.convert("RGB").getcolors(maxcolors=1 << 20) or []) + assert colours > 50, f"chart looks blank: {colours} distinct colours" + print( + json.dumps( + { + "summary": summary.replace("\n", " ")[:120], + "colours": colours, + "binary_frames": binary_frames, + } + ) + ) diff --git a/tests/reflex_adapter/test_socket_data_plane.py b/tests/reflex_adapter/test_data_plane.py similarity index 72% rename from tests/reflex_adapter/test_socket_data_plane.py rename to tests/reflex_adapter/test_data_plane.py index 3db9c720e..7a2910979 100644 --- a/tests/reflex_adapter/test_socket_data_plane.py +++ b/tests/reflex_adapter/test_data_plane.py @@ -1,12 +1,13 @@ """End-to-end data plane over a real websocket. -Boots the same server stack a Reflex backend uses — python-socketio -AsyncServer (with reflex's JSON config) + engine.io ASGI app mounted at -/_event under uvicorn — registers XYNamespace exactly like `setup(app)` -does, and drives it with the real socket.io client protocol. This is the -transport contract the browser wrapper (XYChart.jsx) relies on, minus the -browser: spec as JSON, columns as native binary attachments, replies -mount-addressed, tokens session-affine, registry misses rebuilt. +Boots the same server stack a Reflex backend uses — a real `rx.App()` served by +uvicorn, with the data plane registered through `app.register_channel(...)` +exactly as `setup(app)` does — and drives it with the real channel wire +protocol: JSON text frames `[event, data, channel]` outbound, and binary frames +carrying the columns as attachments inbound. This is the transport contract the +browser wrapper (XYChart.jsx) relies on, minus the browser: spec as JSON, +columns as native binary attachments beside it, replies mount-addressed, tokens +session-affine, registry misses rebuilt. """ from __future__ import annotations @@ -17,20 +18,21 @@ import socket import threading from types import SimpleNamespace -from typing import TypedDict +from typing import Any, TypedDict +import aiohttp import numpy as np import pytest import reflex as rx -import socketio import uvicorn +from reflex.event_namespace import decode_channel_frame from reflex.istate.manager.memory import StateManagerMemory -from reflex_base.utils import format as reflex_format +from reflex_base.registry import RegistrationContext import reflex_xy import xy from reflex_xy.app import wire -from reflex_xy.namespace import XYNamespace +from reflex_xy.data_plane import XY_PLANE, XYChannel from reflex_xy.plan import build_plan from reflex_xy.registry import registry from reflex_xy.state_bridge import make_rebuild_hook @@ -39,6 +41,10 @@ CLIENT_TOKEN = "11111111-2222-4333-8444-555566667777" OTHER_TOKEN = "99999999-8888-4777-8666-555544443333" +# Channel frames cap at this many attachments; the data plane's own guard is +# the same number (data_plane._MAX_WIRE_ATTACHMENTS takes it from reflex). +OVER_THE_CAP = 65 + def make_figure(n: int = 64): xs = np.linspace(0.0, 1.0, n) @@ -54,63 +60,156 @@ def free_port() -> int: @contextlib.asynccontextmanager async def data_plane_server(rebuild=None): - """AsyncServer configured like reflex's (app.py _setup_state) + XYNamespace.""" - sio = socketio.AsyncServer( - async_mode="asgi", - cors_allowed_origins="*", - json=SimpleNamespace( - dumps=staticmethod(reflex_format.json_dumps), loads=staticmethod(json.loads) - ), - transports=["websocket"], - allow_upgrades=False, - ) - namespace = XYNamespace(registry, rebuild=rebuild) - sio.register_namespace(namespace) - wire(namespace) + """A real Reflex app serving the xy channel on its own event websocket. + + An App claims the registration context it is built in, so this one is built + in a fork: the process context stays free for whatever app the rest of the + suite builds. + """ + with RegistrationContext.get().fork(): + app = rx.App() + app._state_manager = StateManagerMemory() + channel = XYChannel(registry, rebuild=rebuild) + app.register_channel(channel) + wire(channel) registry.attach_loop(asyncio.get_running_loop()) - asgi = socketio.ASGIApp(sio, socketio_path="/_event") port = free_port() - config = uvicorn.Config(asgi, host="127.0.0.1", port=port, log_level="error") + config = uvicorn.Config(app._api, host="127.0.0.1", port=port, log_level="error") server = uvicorn.Server(config) task = asyncio.create_task(server.serve()) while not server.started: await asyncio.sleep(0.01) try: - yield f"http://127.0.0.1:{port}", namespace + yield f"http://127.0.0.1:{port}", channel finally: server.should_exit = True await task -async def connect_client(base_url: str, client_token: str = CLIENT_TOKEN): - """Connect the way XYChart.jsx does: /_xy namespace, token in the query.""" - client = socketio.AsyncClient(reconnection=False) - await client.connect( - f"{base_url}?token={client_token}", - socketio_path="/_event", - namespaces=["/_xy"], - transports=["websocket"], - ) - return client - +class PlaneClient: + """One connected websocket with the `/_xy` channel open. -class Collector: - """Buffers events from one client for ordered assertions.""" + Mirrors what XYChart.jsx does through `getChannel("/_xy")`: the app's own + event websocket, one `_open` for the channel, and every data plane frame + arriving as `(metadata, attachments)`. + """ - def __init__(self, client: socketio.AsyncClient) -> None: + def __init__(self, session: aiohttp.ClientSession, ws: aiohttp.ClientWebSocketResponse): + self._session = session + self._ws = ws + self.connected = True self.payloads: asyncio.Queue = asyncio.Queue() self.messages: asyncio.Queue = asyncio.Queue() self.errors: asyncio.Queue = asyncio.Queue() - client.on("payload", self.payloads.put, namespace="/_xy") - client.on("msg", self.messages.put, namespace="/_xy") - client.on("err", self.errors.put, namespace="/_xy") + self._opened = asyncio.Event() + self._queues = { + "payload": self.payloads, + "msg": self.messages, + "err": self.errors, + } + self._reader = asyncio.create_task(self._read_forever()) + + async def _read_forever(self) -> None: + with contextlib.suppress(asyncio.CancelledError, ConnectionResetError): + async for frame in self._ws: + if frame.type == aiohttp.WSMsgType.BINARY: + event, data, channel, buffers = decode_channel_frame(frame.data) + elif frame.type == aiohttp.WSMsgType.TEXT: + decoded = json.loads(frame.data) + event = decoded[0] + data = decoded[1] if len(decoded) > 1 else None + channel = decoded[2] if len(decoded) > 2 else None + buffers = [] + else: + continue + if event == "_ping": + await self._ws.send_str(json.dumps(["_pong"])) + continue + if event == "_opened" and channel == XY_PLANE: + self._opened.set() + continue + queue = self._queues.get(event) if channel == XY_PLANE else None + if queue is not None: + queue.put_nowait((data, buffers)) + + async def emit(self, event: str, data: Any) -> None: + """Send one data plane message on the `/_xy` channel.""" + await self._ws.send_str(json.dumps([event, data, XY_PLANE])) + + async def open_plane(self) -> None: + await self.emit("_open", None) + await asyncio.wait_for(self._opened.wait(), 5.0) + + async def disconnect(self) -> None: + if not self.connected: + return + self.connected = False + self._reader.cancel() + with contextlib.suppress(asyncio.CancelledError): + await self._reader + await self._ws.close() + await self._session.close() + + +async def connect_client(base_url: str, client_token: str = CLIENT_TOKEN) -> PlaneClient: + """Connect the way XYChart.jsx does: the app socket, token in the query.""" + session = aiohttp.ClientSession() + ws = await session.ws_connect(f"{base_url.replace('http', 'ws')}/_event?token={client_token}") + client = PlaneClient(session, ws) + await client.open_plane() + return client + + +class Collector: + """Buffers events from one client for ordered assertions. + + Every queue holds `(metadata, attachments)`: the two halves of a channel + frame, kept apart the way the browser receives them. + """ + + def __init__(self, client: PlaneClient) -> None: + self.payloads = client.payloads + self.messages = client.messages + self.errors = client.errors @staticmethod async def next(queue: asyncio.Queue, timeout: float = 5.0): return await asyncio.wait_for(queue.get(), timeout) +class FakeSession: + """A channel session for the tests that drive handlers directly. + + Registering one through `on_open` means the real transport seams (rooms, + per-connection store, liveness) stay under test instead of being patched + out; only the send paths are recorded. + """ + + def __init__(self, sid: str, client_token: str = CLIENT_TOKEN) -> None: + self.sid = sid + self.client_token = client_token + self.data: dict[str, Any] = {} + self.open = True + self.rooms: set[str] = set() + self.sent: list[tuple[str, Any, list]] = [] + + def join(self, room: str) -> None: + self.rooms.add(room) + + def leave(self, room: str) -> None: + self.rooms.discard(room) + + async def send(self, event: str, data: Any, buffers: list) -> None: + self.sent.append((event, data, list(buffers))) + + +async def open_fake_session(channel: XYChannel, sid: str, **kwargs) -> FakeSession: + session = FakeSession(sid, **kwargs) + await channel.on_open(session) # type: ignore[arg-type] + return session + + def run(coro): return asyncio.run(asyncio.wait_for(coro, 60.0)) @@ -138,7 +237,7 @@ def __exit__(self, *_exc): def test_payload_build_serializes_with_view_push_per_figure(_fresh_registry, monkeypatch): """Payload emitter state and row-mask construction cannot overlap.""" - import reflex_xy.namespace as namespace_module + import reflex_xy.data_plane as data_plane_module primary = _fresh_registry.publish("primary", make_figure(8), broadcast=False) other = _fresh_registry.publish("other", make_figure(8), broadcast=False) @@ -161,17 +260,17 @@ def other_view(_figure): other_view_entered.set() return {"type": "state_patch"}, [] - namespace = XYNamespace(_fresh_registry) + channel = XYChannel(_fresh_registry) - async def emit(*_args, **_kwargs): + async def send(*_args, **_kwargs): return None - monkeypatch.setattr(namespace_module, "_build_wire_payload", blocked_payload) - monkeypatch.setattr(namespace, "emit", emit) + monkeypatch.setattr(data_plane_module, "_build_wire_payload", blocked_payload) + monkeypatch.setattr(channel, "_send", send) async def main(): tasks = [] - payload_task = asyncio.create_task(namespace._send_payload("sid", "primary", primary)) + payload_task = asyncio.create_task(channel._send_payload("sid", "primary", primary)) tasks.append(payload_task) try: assert await asyncio.to_thread(payload_started.wait, 1.0) @@ -206,7 +305,7 @@ async def main(): def test_interaction_serializes_with_view_push_per_figure(_fresh_registry, monkeypatch): """Interaction/drill state and caller-thread view writes cannot overlap.""" - import reflex_xy.namespace as namespace_module + import reflex_xy.data_plane as data_plane_module primary = _fresh_registry.publish("primary", make_figure(8), broadcast=False) other = _fresh_registry.publish("other", make_figure(8), broadcast=False) @@ -229,13 +328,13 @@ def other_view(_figure): other_view_entered.set() return {"type": "state_patch"}, [] - namespace = XYNamespace(_fresh_registry) - monkeypatch.setattr(namespace_module, "handle_message", blocked_interaction) + channel = XYChannel(_fresh_registry) + monkeypatch.setattr(data_plane_module, "handle_message", blocked_interaction) async def main(): tasks = [] interaction_task = asyncio.create_task( - namespace.on_msg( + channel.on_msg( "sid", {"fig": "primary", "v": primary.version, "m": {"type": "pick"}}, ) @@ -276,8 +375,8 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "px": 640, "mid": "m1"}, namespace="/_xy") - payload = await collector.next(collector.payloads) + await client.emit("sub", {"fig": token, "px": 640, "mid": "m1"}) + payload, buffers = await collector.next(collector.payloads) await client.disconnect() assert payload["fig"] == token assert payload["version"] == 1 @@ -285,9 +384,9 @@ async def main(): spec = payload["spec"] assert spec["buffer_layout"] == "split" assert len(spec["traces"]) == 1 - buffers = payload["buffers"] - # Binary columns arrive as raw bytes (the JS client sees ArrayBuffers): - # no base64, no JSON numbers (§29 preserved across this transport). + # Binary columns arrive as the frame's attachments, never inside the + # envelope: no base64, no JSON numbers (§29 preserved on this transport). + assert "buffers" not in payload assert all(isinstance(b, (bytes, bytearray)) for b in buffers) xcol = np.frombuffer(buffers[0], dtype=np.float32) assert len(xcol) == 64 @@ -296,31 +395,31 @@ async def main(): def test_sub_over_attachment_limit_ships_single_blob(_fresh_registry): - """socket.io-parser's browser Decoder defaults to `maxAttachments: 10` and - closes the WHOLE shared websocket ("too many attachments" -> "parse - error") on any binary packet exceeding it — which then reconnect-loops - the app. Buffer-heavy figures must fall back to the joined single-blob - payload, which the wrapper's `toSpans` handles via `buffer_layout`.""" + """A channel frame declares its attachment count, and Reflex refuses to + encode or decode more than MAX_MESSAGE_BUFFERS of them. Buffer-heavy + figures must fall back to the joined single-blob payload, which the + wrapper's `toSpans` handles via `buffer_layout`.""" async def main(): xs = np.linspace(0.0, 1.0, 64) + # Four buffers per trace (x, y, color, size): 17 traces clears the cap. figure = xy.scatter_chart( - *[xy.scatter(xs, xs * k, color=xs, size=xs) for k in (1.0, 2.0, 3.0)], + *[xy.scatter(xs, xs * k, color=xs, size=xs) for k in range(1, 18)], width=640, height=400, ).figure() _, raw = figure.build_payload_split(640) - assert len(raw) > 10, "premise: this figure must exceed the parser cap" + assert len(raw) >= OVER_THE_CAP, "premise: this figure must exceed the frame cap" token = registry.register(figure) async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "px": 640}, namespace="/_xy") - payload = await collector.next(collector.payloads) + await client.emit("sub", {"fig": token, "px": 640}) + payload, buffers = await collector.next(collector.payloads) await client.disconnect() assert payload["fig"] == token assert payload["spec"].get("buffer_layout") != "split" - assert len(payload["buffers"]) == 1 + assert len(buffers) == 1 run(main()) @@ -330,7 +429,7 @@ async def main(): [("append", True), ("selection_rows", False)], ) def test_broadcast_over_attachment_limit_answers_err_not_msg(_fresh_registry, message_type, resync): - """Room pushes over the parser cap fail loud without an invalid packet. + """Room pushes over the frame cap fail loud without an unencodable frame. Only append needs a payload resync: a generation-stamped view-state push does not itself advance the figure. @@ -338,15 +437,15 @@ def test_broadcast_over_attachment_limit_answers_err_not_msg(_fresh_registry, me async def main(): token = registry.register(make_figure(16)) - async with data_plane_server() as (url, namespace): + async with data_plane_server() as (url, channel): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "px": 640}, namespace="/_xy") + await client.emit("sub", {"fig": token, "px": 640}) await collector.next(collector.payloads) - await namespace.broadcast_message( - token, {"type": message_type}, [b"\x00" * 4] * 11, version=2 + await channel.broadcast_message( + token, {"type": message_type}, [b"\x00" * 4] * OVER_THE_CAP, version=2 ) - error = await collector.next(collector.errors) + error, _ = await collector.next(collector.errors) await client.disconnect() assert error["fig"] == token assert "attachment" in error["error"] @@ -358,28 +457,26 @@ async def main(): def test_msg_reply_over_attachment_limit_answers_err_not_msg(_fresh_registry, monkeypatch): """The `on_msg` reply guard: channel replies are bounded by construction, - so a reply over the parser's attachment cap is a contract violation — the - client must get an `err` envelope, never a `msg` whose packet the browser - parser would reject (closing the shared websocket).""" + so a reply over the frame's attachment cap is a contract violation — the + client must get an `err` envelope, never a `msg` frame Reflex would refuse + to encode (silently losing the reply).""" - from reflex_xy import namespace as namespace_module + from reflex_xy import data_plane as data_plane_module def oversized_reply(figure, message, buffers): - return {"kind": "pick"}, [b"\x00" * 4] * 11 + return {"kind": "pick"}, [b"\x00" * 4] * OVER_THE_CAP - monkeypatch.setattr(namespace_module, "handle_message", oversized_reply) + monkeypatch.setattr(data_plane_module, "handle_message", oversized_reply) async def main(): token = registry.register(make_figure(16)) async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "px": 640}, namespace="/_xy") + await client.emit("sub", {"fig": token, "px": 640}) await collector.next(collector.payloads) - await client.emit( - "msg", {"fig": token, "m": {"kind": "pick"}, "mid": "m1"}, namespace="/_xy" - ) - error = await collector.next(collector.errors) + await client.emit("msg", {"fig": token, "m": {"kind": "pick"}, "mid": "m1"}) + error, _ = await collector.next(collector.errors) await client.disconnect() assert error["fig"] == token assert "attachment" in error["error"] @@ -394,7 +491,7 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": token, "mid": "m1"}) await collector.next(collector.payloads) # pick -> exact f64 row readout, mid echoed for mount routing @@ -405,9 +502,8 @@ async def main(): "mid": "m1", "m": {"type": "pick", "trace": 0, "index": 3, "seq": 7}, }, - namespace="/_xy", ) - reply = await collector.next(collector.messages) + reply, _ = await collector.next(collector.messages) assert reply["mid"] == "m1" assert reply["message"]["type"] == "pick_result" assert reply["message"]["seq"] == 7 @@ -415,7 +511,7 @@ async def main(): assert row["x"] == pytest.approx(3 / 15) assert row["y"] == pytest.approx(3 / 15 * 3.0) - # select -> selection mask as binary buffers + # select -> selection mask as binary attachments await client.emit( "msg", { @@ -423,16 +519,15 @@ async def main(): "mid": "m1", "m": {"type": "select", "x0": 0.0, "x1": 0.5, "y0": 0.0, "y1": 3.0}, }, - namespace="/_xy", ) - sel = await collector.next(collector.messages) + sel, mask = await collector.next(collector.messages) assert sel["message"]["type"] == "selection" assert sel["message"]["total"] == 8 - assert len(sel["buffers"]) == 1 + assert len(mask) == 1 # malformed messages are dropped silently, never crash the server - await client.emit("msg", {"fig": token, "m": ["not", "a", "dict"]}, namespace="/_xy") - await client.emit("msg", "garbage", namespace="/_xy") + await client.emit("msg", {"fig": token, "m": ["not", "a", "dict"]}) + await client.emit("msg", "garbage") await client.emit( "msg", { @@ -440,9 +535,8 @@ async def main(): "mid": "m1", "m": {"type": "pick", "trace": 0, "index": 5, "seq": 8}, }, - namespace="/_xy", ) - after = await collector.next(collector.messages) + after, _ = await collector.next(collector.messages) assert after["message"]["seq"] == 8 await client.disconnect() @@ -455,7 +549,7 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": token, "mid": "m1"}) await collector.next(collector.payloads) await client.emit( "msg", @@ -472,9 +566,8 @@ async def main(): "include_rows": True, }, }, - namespace="/_xy", ) - reply = await collector.next(collector.messages) + reply, _ = await collector.next(collector.messages) await client.disconnect() message = reply["message"] assert message["version"] == 1 @@ -491,16 +584,14 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": token, "mid": "m1"}) await collector.next(collector.payloads) registry.publish(token, make_figure(16)) - payload = await collector.next(collector.payloads) + payload, _ = await collector.next(collector.payloads) assert payload["version"] == 2 message = {"type": "pick", "trace": 0, "index": 2, "seq": 21} - await client.emit( - "msg", {"fig": token, "mid": "m1", "v": 1, "m": message}, namespace="/_xy" - ) + await client.emit("msg", {"fig": token, "mid": "m1", "v": 1, "m": message}) with pytest.raises(asyncio.TimeoutError): await Collector.next(collector.messages, timeout=0.15) @@ -514,21 +605,18 @@ async def main(): "v": malformed_version, "m": message, }, - namespace="/_xy", ) with pytest.raises(asyncio.TimeoutError): await Collector.next(collector.messages, timeout=0.1) message["seq"] = 21 - await client.emit( - "msg", {"fig": token, "mid": "m1", "v": 2, "m": message}, namespace="/_xy" - ) - current = await collector.next(collector.messages) + await client.emit("msg", {"fig": token, "mid": "m1", "v": 2, "m": message}) + current, _ = await collector.next(collector.messages) assert current["message"]["seq"] == 21 message["seq"] = 22 - await client.emit("msg", {"fig": token, "mid": "m1", "m": message}, namespace="/_xy") - compatible = await collector.next(collector.messages) + await client.emit("msg", {"fig": token, "mid": "m1", "m": message}) + compatible, _ = await collector.next(collector.messages) assert compatible["message"]["seq"] == 22 await client.disconnect() @@ -544,14 +632,14 @@ def slow_handle_message(figure, content, callbacks): assert resume.wait(timeout=5) return {"type": "pick_result", "seq": 99, "row": None}, [] - monkeypatch.setattr("reflex_xy.namespace.handle_message", slow_handle_message) + monkeypatch.setattr("reflex_xy.data_plane.handle_message", slow_handle_message) async def main(): token = registry.register(make_figure(16)) async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": token, "mid": "m1"}) await collector.next(collector.payloads) await client.emit( @@ -562,13 +650,12 @@ async def main(): "v": 1, "m": {"type": "pick", "trace": 0, "index": 2, "seq": 99}, }, - namespace="/_xy", ) assert await asyncio.to_thread(started.wait, 5) registry.publish(token, make_figure(32)) resume.set() - replacement = await collector.next(collector.payloads) + replacement, _ = await collector.next(collector.payloads) assert replacement["version"] == 2 with pytest.raises(asyncio.TimeoutError): await Collector.next(collector.messages, timeout=0.15) @@ -586,14 +673,14 @@ async def main(): # be able to subscribe to this figure. thief = await connect_client(url, client_token=OTHER_TOKEN) thief_collector = Collector(thief) - await thief.emit("sub", {"fig": state_token, "mid": "m1"}, namespace="/_xy") - err = await thief_collector.next(thief_collector.errors) + await thief.emit("sub", {"fig": state_token, "mid": "m1"}) + err, _ = await thief_collector.next(thief_collector.errors) assert "another session" in err["error"] owner = await connect_client(url, client_token=CLIENT_TOKEN) owner_collector = Collector(owner) - await owner.emit("sub", {"fig": state_token, "mid": "m1"}, namespace="/_xy") - payload = await owner_collector.next(owner_collector.payloads) + await owner.emit("sub", {"fig": state_token, "mid": "m1"}) + payload, _ = await owner_collector.next(owner_collector.payloads) assert payload["fig"] == state_token await thief.disconnect() await owner.disconnect() @@ -615,10 +702,10 @@ async def main(): async with data_plane_server(rebuild=rebuild) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": state_token, "mid": "m1"}, namespace="/_xy") - payload = await collector.next(collector.payloads) + await client.emit("sub", {"fig": state_token, "mid": "m1"}) + payload, buffers = await collector.next(collector.payloads) assert payload["fig"] == state_token - assert len(payload["buffers"]) == 2 + assert len(buffers) == 2 await client.disconnect() assert rebuilt == [state_token] assert registry.get(state_token) is not None @@ -643,22 +730,20 @@ async def rebuild(token_str): await resume.wait() return make_figure(32) - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def broadcast(token, entry): broadcasts.append((token, entry)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) async def main(): + await open_fake_session(channel, "sid-1") + await open_fake_session(channel, "sid-2") data = {"fig": state_token} - first = asyncio.create_task(namespace._entry_for("sid-1", data, allow_rebuild=True)) + first = asyncio.create_task(channel._entry_for("sid-1", data, allow_rebuild=True)) await started.wait() - second = asyncio.create_task(namespace._entry_for("sid-2", data, allow_rebuild=True)) + second = asyncio.create_task(channel._entry_for("sid-2", data, allow_rebuild=True)) await asyncio.sleep(0) resume.set() results = await asyncio.gather(first, second) @@ -669,7 +754,7 @@ async def main(): assert registry.is_current(state_token, entries[0]) assert all(result[2] for result in results) assert broadcasts == [(state_token, entries[0])] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} run(main()) @@ -691,10 +776,7 @@ async def rebuild(token_str): await resume.wait() return make_figure(32) - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def broadcast(token, entry): assert token == state_token @@ -704,13 +786,14 @@ def handle(figure, message, buffers): handled.append((figure, message, buffers)) return None - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) - monkeypatch.setattr("reflex_xy.namespace.handle_message", handle) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) + monkeypatch.setattr("reflex_xy.data_plane.handle_message", handle) async def main(): + await open_fake_session(channel, "sid-1") + await open_fake_session(channel, "sid-2") first = asyncio.create_task( - namespace.on_msg( + channel.on_msg( "sid-1", {"fig": state_token, "m": {"type": "pick", "trace": 0, "index": 1}}, ) @@ -719,7 +802,7 @@ async def main(): # Version 1 also matches a fresh worker's rebuilt version. The request # must still drop because it was sent before that worker's payload. second = asyncio.create_task( - namespace.on_msg( + channel.on_msg( "sid-2", { "fig": state_token, @@ -735,7 +818,7 @@ async def main(): assert rebuild_calls == 1 assert handled == [] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} run(main()) @@ -759,10 +842,7 @@ async def rebuild(token_str): return None return make_figure(32) - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def send_error(sid, token, error, resync=False): errors.append((sid, token, error)) @@ -770,15 +850,16 @@ async def send_error(sid, token, error, resync=False): async def broadcast(token, entry): broadcasts.append((token, entry)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "_err", send_error) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "_err", send_error) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) async def main(): + for sid in ("sid-1", "sid-2", "sid-3"): + await open_fake_session(channel, sid) data = {"fig": state_token} - first = asyncio.create_task(namespace._entry_for("sid-1", data, allow_rebuild=True)) + first = asyncio.create_task(channel._entry_for("sid-1", data, allow_rebuild=True)) await started.wait() - second = asyncio.create_task(namespace._entry_for("sid-2", data, allow_rebuild=True)) + second = asyncio.create_task(channel._entry_for("sid-2", data, allow_rebuild=True)) await asyncio.sleep(0) resume.set() first_results = await asyncio.gather(first, second) @@ -789,9 +870,9 @@ async def main(): assert sorted(sid for sid, _, _ in errors) == ["sid-1", "sid-2"] assert all(token == state_token for _, token, _ in errors) assert all(error == "unknown figure token" for _, _, error in errors) - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} - retried = await namespace._entry_for("sid-3", data, allow_rebuild=True) + retried = await channel._entry_for("sid-3", data, allow_rebuild=True) await asyncio.sleep(0) assert rebuild_calls == 2 assert retried[0] == state_token @@ -799,7 +880,7 @@ async def main(): assert retried[2] assert registry.is_current(state_token, retried[1]) assert broadcasts == [(state_token, retried[1])] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} run(main()) @@ -816,7 +897,6 @@ def test_rebuild_broadcast_failure_removes_generation_and_later_sub_retries( errors = [] broadcasts = [] - joined = [] sent = [] rebuild_calls = 0 @@ -826,13 +906,7 @@ async def rebuild(token_str): rebuild_calls += 1 return make_figure(32) - namespace = XYNamespace(registry, rebuild=rebuild) - namespace._set_server( - SimpleNamespace(manager=SimpleNamespace(is_connected=lambda sid, _namespace: True)) - ) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def broadcast(token, entry): assert token == state_token @@ -844,36 +918,33 @@ async def broadcast(token, entry): async def send_error(sid, token, error, resync=False): errors.append((sid, token, error)) - async def enter_room(sid, room): - joined.append((sid, room)) - async def send_payload(sid, token, entry, **kwargs): sent.append((sid, token, entry, kwargs)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) - monkeypatch.setattr(namespace, "_err", send_error) - monkeypatch.setattr(namespace, "enter_room", enter_room) - monkeypatch.setattr(namespace, "_send_payload", send_payload) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "_err", send_error) + monkeypatch.setattr(channel, "_send_payload", send_payload) async def main(): - await namespace.on_sub("sid-1", {"fig": state_token, "mid": "m1"}) + first = await open_fake_session(channel, "sid-1") + second = await open_fake_session(channel, "sid-2") + await channel.on_sub("sid-1", {"fig": state_token, "mid": "m1"}) await asyncio.sleep(0) assert errors == [("sid-1", state_token, "rebuild failed")] assert registry.get(state_token) is None assert registry._evicted_versions == {state_token: 3} - assert joined == [] + assert first.rooms == set() assert sent == [] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} - await namespace.on_sub("sid-2", {"fig": state_token, "mid": "m2", "px": 321}) + await channel.on_sub("sid-2", {"fig": state_token, "mid": "m2", "px": 321}) await asyncio.sleep(0) assert rebuild_calls == 2 assert [entry.version for entry in broadcasts] == [3, 4] - assert joined == [("sid-2", namespace._room(state_token))] + assert second.rooms == {channel._room(state_token)} assert len(sent) == 1 sid, token, entry, kwargs = sent[0] assert (sid, token, entry.version, kwargs) == ( @@ -883,7 +954,7 @@ async def main(): {"px": 321, "mid": "m2"}, ) assert registry.is_current(state_token, entry) - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} run(main()) @@ -902,10 +973,7 @@ async def rebuild(token_str): assert token_str == state_token return make_figure(16) - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def fail_after_replacement(token, entry): nonlocal replacement @@ -917,12 +985,12 @@ async def fail_after_replacement(token, entry): async def send_error(sid, token, error, resync=False): errors.append((sid, token, error)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", fail_after_replacement) - monkeypatch.setattr(namespace, "_err", send_error) + monkeypatch.setattr(channel, "broadcast_payload", fail_after_replacement) + monkeypatch.setattr(channel, "_err", send_error) async def main(): - token, entry, initially_missing = await namespace._entry_for( + await open_fake_session(channel, "sid-1") + token, entry, initially_missing = await channel._entry_for( "sid-1", {"fig": state_token}, allow_rebuild=True ) await asyncio.sleep(0) @@ -935,7 +1003,7 @@ async def main(): assert entry.version == 2 assert registry.is_current(state_token, entry) assert errors == [] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} run(main()) @@ -957,10 +1025,7 @@ async def rebuild(token_str): assert token_str == state_token return rebuilt_figure - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def fail_then_deliver_from_publish(token, entry): nonlocal published @@ -980,14 +1045,14 @@ async def fail_then_deliver_from_publish(token, entry): async def send_error(sid, token, error, resync=False): errors.append((sid, token, error)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", fail_then_deliver_from_publish) - monkeypatch.setattr(namespace, "_err", send_error) + monkeypatch.setattr(channel, "broadcast_payload", fail_then_deliver_from_publish) + monkeypatch.setattr(channel, "_err", send_error) async def main(): registry.attach_loop(asyncio.get_running_loop()) - registry.on_publish(namespace.broadcast_payload) - token, entry, initially_missing = await namespace._entry_for( + registry.on_publish(channel.broadcast_payload) + await open_fake_session(channel, "sid-1") + token, entry, initially_missing = await channel._entry_for( "sid-1", {"fig": state_token}, allow_rebuild=True ) await asyncio.wait_for(delivered.wait(), timeout=1.0) @@ -1002,7 +1067,7 @@ async def main(): assert errors == [] assert fanouts == [(state_token, entry), (state_token, entry)] assert registry._pending_broadcasts == set() - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} run(main()) @@ -1026,20 +1091,17 @@ async def rebuild(token_str): await resume.wait() return rebuilt_figure - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def broadcast(token, entry): broadcasts.append((token, entry)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) async def main(): + await open_fake_session(channel, "sid-1") pending = asyncio.create_task( - namespace._entry_for("sid-1", {"fig": state_token}, allow_rebuild=True) + channel._entry_for("sid-1", {"fig": state_token}, allow_rebuild=True) ) await started.wait() published = registry.publish(state_token, current_figure, broadcast=False) @@ -1052,7 +1114,7 @@ async def main(): assert entry.figure is current_figure assert registry.is_current(state_token, entry) assert broadcasts == [] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} run(main()) @@ -1066,7 +1128,6 @@ def test_later_requests_bypass_slow_rebuild_after_authoritative_publish( resume = asyncio.Event() rebuild_calls = 0 current_figure = make_figure(48) - joined = [] sent = [] handled = [] @@ -1078,16 +1139,7 @@ async def rebuild(token_str): await resume.wait() return make_figure(16) - namespace = XYNamespace(registry, rebuild=rebuild) - namespace._set_server( - SimpleNamespace(manager=SimpleNamespace(is_connected=lambda sid, _namespace: True)) - ) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} - - async def enter_room(sid, room): - joined.append((sid, room)) + channel = XYChannel(registry, rebuild=rebuild) async def send_payload(sid, token, entry, **kwargs): sent.append((sid, token, entry, kwargs)) @@ -1099,15 +1151,16 @@ def handle(figure, message, buffers): handled.append((figure, message, buffers)) return None - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "enter_room", enter_room) - monkeypatch.setattr(namespace, "_send_payload", send_payload) - monkeypatch.setattr(namespace, "broadcast_payload", unexpected_broadcast) - monkeypatch.setattr("reflex_xy.namespace.handle_message", handle) + monkeypatch.setattr(channel, "_send_payload", send_payload) + monkeypatch.setattr(channel, "broadcast_payload", unexpected_broadcast) + monkeypatch.setattr("reflex_xy.data_plane.handle_message", handle) async def main(): + await open_fake_session(channel, "sid-original") + subscriber = await open_fake_session(channel, "sid-sub") + await open_fake_session(channel, "sid-msg") original = asyncio.create_task( - namespace._entry_for("sid-original", {"fig": state_token}, allow_rebuild=True) + channel._entry_for("sid-original", {"fig": state_token}, allow_rebuild=True) ) await started.wait() assert registry._active_rebuild_guards @@ -1118,10 +1171,10 @@ async def main(): message = {"type": "pick", "trace": 0, "index": 1} later_sub = asyncio.create_task( - namespace.on_sub("sid-sub", {"fig": state_token, "mid": "m1", "px": 321}) + channel.on_sub("sid-sub", {"fig": state_token, "mid": "m1", "px": 321}) ) later_msg = asyncio.create_task( - namespace.on_msg( + channel.on_msg( "sid-msg", {"fig": state_token, "v": published.version, "m": message}, ) @@ -1135,7 +1188,7 @@ async def main(): assert not blocked_at_deadline await asyncio.gather(*later_tasks) - assert joined == [("sid-sub", namespace._room(state_token))] + assert subscriber.rooms == {channel._room(state_token)} assert sent == [("sid-sub", state_token, published, {"px": 321, "mid": "m1"})] assert handled == [(current_figure, message, None)] assert not original.done() @@ -1147,7 +1200,7 @@ async def main(): assert original_result == (state_token, published, True) assert rebuild_calls == 1 assert registry.is_current(state_token, published) - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} run(main()) @@ -1177,10 +1230,7 @@ async def rebuild(token_str): await resume.wait() return make_figure(32) - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def send_error(sid, token, error, resync=False): errors.append((sid, token, error)) @@ -1188,13 +1238,14 @@ async def send_error(sid, token, error, resync=False): async def broadcast(token, entry): broadcasts.append((token, entry)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "_err", send_error) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "_err", send_error) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) async def main(): + await open_fake_session(channel, "sid-1") + await open_fake_session(channel, "sid-2") data = {"fig": state_token} - pending = asyncio.create_task(namespace._entry_for("sid-1", data, allow_rebuild=True)) + pending = asyncio.create_task(channel._entry_for("sid-1", data, allow_rebuild=True)) await started.wait() # The canonical builder evaluated to None after this rebuild began. @@ -1210,10 +1261,10 @@ async def main(): assert registry.get(state_token) is None assert registry._evicted_versions == {state_token: 2} assert broadcasts == [] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} - retried = await namespace._entry_for("sid-2", data, allow_rebuild=True) + retried = await channel._entry_for("sid-2", data, allow_rebuild=True) await asyncio.sleep(0) assert rebuild_calls == 2 @@ -1223,7 +1274,7 @@ async def main(): assert retried[2] assert registry.is_current(state_token, retried[1]) assert broadcasts == [(state_token, retried[1])] - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} run(main()) @@ -1247,26 +1298,24 @@ async def rebuild(token_str): await resume_old.wait() return make_figure(32) - namespace = XYNamespace(registry, rebuild=rebuild) - - async def get_session(_sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def broadcast(_token, _entry): return None - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) async def main(): + await open_fake_session(channel, "sid-old") + await open_fake_session(channel, "sid-new") data = {"fig": state_token} - old = asyncio.create_task(namespace._entry_for("sid-old", data, allow_rebuild=True)) + old = asyncio.create_task(channel._entry_for("sid-old", data, allow_rebuild=True)) await started.wait() registry.release(state_token) assert not registry._active_rebuild_guards newer = await asyncio.wait_for( - namespace._entry_for("sid-new", data, allow_rebuild=True), timeout=1.0 + channel._entry_for("sid-new", data, allow_rebuild=True), timeout=1.0 ) assert rebuild_calls == 2 assert newer[1] is not None @@ -1277,7 +1326,7 @@ async def main(): old_result = await old assert old_result[1] is newer[1] await asyncio.sleep(0) - assert namespace._rebuild_attempts == {} + assert channel._rebuild_attempts == {} assert registry._active_rebuild_guards == {} run(main()) @@ -1289,7 +1338,6 @@ def test_sub_sends_current_replacement_when_publish_lands_before_join(_fresh_reg state_token = build_state_token(CLIENT_TOKEN, "root.some_state", "chart") rebuilt_figure = make_figure(16) replacement_figure = make_figure(48) - joined = [] sent = [] replacement = None @@ -1297,13 +1345,7 @@ async def rebuild(token_str): assert token_str == state_token return rebuilt_figure - namespace = XYNamespace(registry, rebuild=rebuild) - namespace._set_server( - SimpleNamespace(manager=SimpleNamespace(is_connected=lambda sid, _namespace: True)) - ) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} + channel = XYChannel(registry, rebuild=rebuild) async def broadcast(token, entry): nonlocal replacement @@ -1313,22 +1355,18 @@ async def broadcast(token, entry): # joins. The direct response must therefore re-read this generation. replacement = registry.publish(state_token, replacement_figure, broadcast=False) - async def enter_room(sid, room): - joined.append((sid, room)) - async def send_payload(sid, token, entry, **kwargs): sent.append((sid, token, entry, kwargs)) - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) - monkeypatch.setattr(namespace, "enter_room", enter_room) - monkeypatch.setattr(namespace, "_send_payload", send_payload) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "_send_payload", send_payload) async def main(): - await namespace.on_sub("sid-1", {"fig": state_token, "mid": "m1", "px": 321}) + session = await open_fake_session(channel, "sid-1") + await channel.on_sub("sid-1", {"fig": state_token, "mid": "m1", "px": 321}) assert replacement is not None - assert joined == [("sid-1", namespace._room(state_token))] + assert session.rooms == {channel._room(state_token)} assert len(sent) == 1 sid, token, entry, kwargs = sent[0] assert (sid, token) == ("sid-1", state_token) @@ -1346,7 +1384,6 @@ def test_slow_sub_does_not_restore_membership_after_disconnect(_fresh_registry, state_token = build_state_token(CLIENT_TOKEN, "root.some_state", "chart") started = asyncio.Event() resume = asyncio.Event() - connected = {"sid-gone": True} sent_payloads = [] async def rebuild(token_str): @@ -1355,18 +1392,7 @@ async def rebuild(token_str): await resume.wait() return make_figure(32) - namespace = XYNamespace(registry, rebuild=rebuild) - namespace._set_server( - SimpleNamespace( - manager=SimpleNamespace(is_connected=lambda sid, _namespace: connected.get(sid, False)) - ) - ) - - async def get_session(sid): - return {"client_token": CLIENT_TOKEN} - - async def enter_room(sid, room): - raise AssertionError("disconnected SID must not re-enter a room") + channel = XYChannel(registry, rebuild=rebuild) async def send_payload(*args, **kwargs): sent_payloads.append((args, kwargs)) @@ -1374,29 +1400,27 @@ async def send_payload(*args, **kwargs): async def broadcast(*args, **kwargs): return None - monkeypatch.setattr(namespace, "get_session", get_session) - monkeypatch.setattr(namespace, "enter_room", enter_room) - monkeypatch.setattr(namespace, "_send_payload", send_payload) - monkeypatch.setattr(namespace, "broadcast_payload", broadcast) + monkeypatch.setattr(channel, "_send_payload", send_payload) + monkeypatch.setattr(channel, "broadcast_payload", broadcast) async def main(): - pending = asyncio.create_task( - namespace.on_sub("sid-gone", {"fig": state_token, "mid": "m1"}) - ) + session = await open_fake_session(channel, "sid-gone") + pending = asyncio.create_task(channel.on_sub("sid-gone", {"fig": state_token, "mid": "m1"})) await started.wait() - connected["sid-gone"] = False - await namespace.on_disconnect("sid-gone") + session.open = False + await channel.on_close(session) # type: ignore[arg-type] resume.set() await pending + assert session.rooms == set(), "a disconnected SID must not re-enter a room" assert sent_payloads == [] assert registry._rebuildable_subscribers == {} assert registry._rebuildable_tokens_by_sid == {} entry = registry.get(state_token) assert registry.sweep(now=entry.last_access + 1_000_000.0) == [state_token] assert registry._evicted_versions == {} - assert namespace._subscription_locks == {} - assert namespace._subscription_lock_users == {} + assert channel._subscription_locks == {} + assert channel._subscription_lock_users == {} run(main()) @@ -1408,15 +1432,15 @@ def test_sub_after_ttl_rebuild_fans_existing_room_before_px_reply(_fresh_registr joining mount receives exactly one addressed payload built for its px. """ - from reflex_xy import namespace as namespace_module + from reflex_xy import data_plane as data_plane_module - build_wire_payload = namespace_module._build_wire_payload + build_wire_payload = data_plane_module._build_wire_payload def tagged_build_wire_payload(figure, px=None): spec, buffers = build_wire_payload(figure, px) return {**spec, "_test_px": px}, buffers - monkeypatch.setattr(namespace_module, "_build_wire_payload", tagged_build_wire_payload) + monkeypatch.setattr(data_plane_module, "_build_wire_payload", tagged_build_wire_payload) rebuilt = [] async def rebuild(token_str): @@ -1427,29 +1451,21 @@ async def main(): state_token = build_state_token(CLIENT_TOKEN, "root.some_state", "chart") registry.publish(state_token, make_figure(16), broadcast=False) async with data_plane_server(rebuild=rebuild) as (url, _): - existing = await connect_client(url) - existing_collector = Collector(existing) - await existing.emit( - "sub", - {"fig": state_token, "px": 640, "mid": "existing"}, - namespace="/_xy", - ) - first = await existing_collector.next(existing_collector.payloads) + # Two mounts of one figure on one page: they share the tab's + # websocket, so `mid` is the only thing separating their traffic. + client = await connect_client(url) + collector = Collector(client) + await client.emit("sub", {"fig": state_token, "px": 640, "mid": "existing"}) + first, _ = await collector.next(collector.payloads) assert first["mid"] == "existing" assert first["spec"]["_test_px"] == 640 evicted = registry.get(state_token) assert registry.sweep(now=evicted.last_access + 1_000_000.0) == [state_token] - joining = await connect_client(url) - joining_collector = Collector(joining) - await joining.emit( - "sub", - {"fig": state_token, "px": 123, "mid": "joining"}, - namespace="/_xy", - ) - room_payload = await existing_collector.next(existing_collector.payloads) - direct_payload = await joining_collector.next(joining_collector.payloads) + await client.emit("sub", {"fig": state_token, "px": 123, "mid": "joining"}) + room_payload, _ = await collector.next(collector.payloads) + direct_payload, _ = await collector.next(collector.payloads) assert room_payload["version"] == 2 assert "mid" not in room_payload @@ -1458,16 +1474,47 @@ async def main(): assert direct_payload["mid"] == "joining" assert direct_payload["spec"]["_test_px"] == 123 with pytest.raises(asyncio.TimeoutError): - await Collector.next(joining_collector.payloads, timeout=0.15) + await Collector.next(collector.payloads, timeout=0.15) - await existing.disconnect() - await joining.disconnect() + await client.disconnect() assert rebuilt == [state_token] run(main()) +def test_a_second_tab_gets_its_own_client_token_and_no_affinity(_fresh_registry): + """Affinity is per tab, resolved by Reflex — not by the query string. + + Reflex mints a fresh client token when a connection presents one that is + already live, so a figure minted for the first tab is another session's as + far as the second tab is concerned. The data plane reads the resolved + token off the channel session and inherits that for free. + """ + + async def main(): + state_token = build_state_token(CLIENT_TOKEN, "root.some_state", "chart") + registry.publish(state_token, make_figure(8), broadcast=False) + async with data_plane_server() as (url, _): + first = await connect_client(url) + second = await connect_client(url) # same ?token=, new tab + first_collector = Collector(first) + second_collector = Collector(second) + + await first.emit("sub", {"fig": state_token, "mid": "m1"}) + payload, _ = await first_collector.next(first_collector.payloads) + assert payload["fig"] == state_token + + await second.emit("sub", {"fig": state_token, "mid": "m1"}) + error, _ = await second_collector.next(second_collector.errors) + assert "another session" in error["error"] + + await first.disconnect() + await second.disconnect() + + run(main()) + + def test_interaction_after_ttl_rebuild_receives_new_payload(_fresh_registry): rebuilt = [] @@ -1479,45 +1526,37 @@ async def main(): state_token = build_state_token(CLIENT_TOKEN, "root.some_state", "chart") registry.publish(state_token, make_figure(16), broadcast=False) async with data_plane_server(rebuild=rebuild) as (url, _): - first_client = await connect_client(url) - second_client = await connect_client(url) - first_collector = Collector(first_client) - second_collector = Collector(second_client) - await first_client.emit("sub", {"fig": state_token, "mid": "m1"}, namespace="/_xy") - await second_client.emit("sub", {"fig": state_token, "mid": "m2"}, namespace="/_xy") - assert (await first_collector.next(first_collector.payloads))["version"] == 1 - assert (await second_collector.next(second_collector.payloads))["version"] == 1 + # Two mounts on the page's one websocket, distinguished by `mid`. + client = await connect_client(url) + collector = Collector(client) + await client.emit("sub", {"fig": state_token, "mid": "m1"}) + await client.emit("sub", {"fig": state_token, "mid": "m2"}) + first, _ = await collector.next(collector.payloads) + second, _ = await collector.next(collector.payloads) + assert (first["version"], second["version"]) == (1, 1) + assert {first["mid"], second["mid"]} == {"m1", "m2"} registry.append(state_token, x=[2.0], y=[6.0]) - assert (await first_collector.next(first_collector.messages))["version"] == 2 - assert (await second_collector.next(second_collector.messages))["version"] == 2 + push, _ = await collector.next(collector.messages) + assert push["version"] == 2 evicted = registry.get(state_token) assert registry.sweep(now=evicted.last_access + 1_000_000.0) == [state_token] message = {"type": "pick", "trace": 0, "index": 2, "seq": 31} - await first_client.emit( - "msg", - {"fig": state_token, "mid": "m1", "v": 2, "m": message}, - namespace="/_xy", - ) - first_replacement = await first_collector.next(first_collector.payloads) - second_replacement = await second_collector.next(second_collector.payloads) - assert first_replacement["version"] == 3 - assert second_replacement["version"] == 3 + await client.emit("msg", {"fig": state_token, "mid": "m1", "v": 2, "m": message}) + replacement, _ = await collector.next(collector.payloads) + assert replacement["version"] == 3 + # The request predates this worker's authoritative payload, so the + # rebuild re-primes the room instead of answering old coordinates. with pytest.raises(asyncio.TimeoutError): - await Collector.next(first_collector.messages, timeout=0.15) + await Collector.next(collector.messages, timeout=0.15) message["seq"] = 32 - await second_client.emit( - "msg", - {"fig": state_token, "mid": "m2", "v": 3, "m": message}, - namespace="/_xy", - ) - reply = await second_collector.next(second_collector.messages) + await client.emit("msg", {"fig": state_token, "mid": "m2", "v": 3, "m": message}) + reply, _ = await collector.next(collector.messages) assert reply["version"] == 3 assert reply["message"]["seq"] == 32 - await first_client.disconnect() - await second_client.disconnect() + await client.disconnect() assert rebuilt == [state_token] @@ -1529,8 +1568,8 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": "xyfig-doesnotexist", "mid": "m1"}, namespace="/_xy") - err = await collector.next(collector.errors) + await client.emit("sub", {"fig": "xyfig-doesnotexist", "mid": "m1"}) + err, _ = await collector.next(collector.errors) assert err["error"] == "unknown figure token" await client.disconnect() @@ -1545,15 +1584,15 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") - first = await collector.next(collector.payloads) + await client.emit("sub", {"fig": token, "mid": "m1"}) + first, _ = await collector.next(collector.payloads) assert first["version"] == 1 registry.publish(token, make_figure(48)) # e.g. a dep-driven recompute - second = await collector.next(collector.payloads) + second, buffers = await collector.next(collector.payloads) assert second["version"] == 2 assert "mid" not in second - xcol = np.frombuffer(second["buffers"][0], dtype=np.float32) + xcol = np.frombuffer(buffers[0], dtype=np.float32) assert len(xcol) == 48 await client.disconnect() @@ -1561,18 +1600,16 @@ async def main(): def test_append_streams_to_subscribers(_fresh_registry): - import reflex_xy - async def main(): token = registry.register(make_figure(4)) async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": token, "mid": "m1"}) await collector.next(collector.payloads) reflex_xy.append(token, x=[2.0, 3.0], y=[6.0, 9.0]) - push = await collector.next(collector.messages) + push, _ = await collector.next(collector.messages) assert push["message"]["type"] == "append" assert push["version"] == 2 assert push.get("mid") is None # pushes are room-wide, not mount-addressed @@ -1584,22 +1621,20 @@ async def main(): def test_rows_selection_push_carries_its_figure_generation(_fresh_registry): - import reflex_xy - async def main(): token = registry.register(make_figure(8)) async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") - payload = await collector.next(collector.payloads) + await client.emit("sub", {"fig": token, "mid": "m1"}) + payload, _ = await collector.next(collector.payloads) reflex_xy.select(token, rows={0: [1, 3, 5]}) - push = await collector.next(collector.messages) + push, buffers = await collector.next(collector.messages) assert push["message"]["type"] == "selection_rows" assert push["version"] == payload["version"] == 1 assert push.get("mid") is None - assert push["buffers"] + assert buffers assert registry.get(token).version == 1 await client.disconnect() @@ -1612,9 +1647,9 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": token, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": token, "mid": "m1"}) await collector.next(collector.payloads) - await client.emit("unsub", {"fig": token, "mid": "m1"}, namespace="/_xy") + await client.emit("unsub", {"fig": token, "mid": "m1"}) await asyncio.sleep(0.05) registry.publish(token, make_figure(12)) await asyncio.sleep(0.2) @@ -1626,7 +1661,7 @@ async def main(): @pytest.mark.parametrize("departure", ["unsub", "disconnect"]) def test_subscription_departure_releases_evicted_version(_fresh_registry, departure): - """Namespace lifecycle handlers release rebuild-version tombstones once + """Data plane lifecycle handlers release rebuild-version tombstones once the last live subscriber leaves, bounding scalar metadata after eviction. """ @@ -1636,21 +1671,20 @@ async def main(): async with data_plane_server() as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": state_token, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": state_token, "mid": "m1"}) await collector.next(collector.payloads) evicted = registry.get(state_token) assert registry.sweep(now=evicted.last_access + 1_000_000.0) == [state_token] if departure == "unsub": - await client.emit("unsub", {"fig": state_token, "mid": "m1"}, namespace="/_xy") + await client.emit("unsub", {"fig": state_token, "mid": "m1"}) await asyncio.sleep(0.05) else: await client.disconnect() await asyncio.sleep(0.05) replacement = registry.publish(state_token, make_figure(8), broadcast=False) - if client.connected: - await client.disconnect() + await client.disconnect() assert replacement.version == 1 run(main()) @@ -1702,8 +1736,8 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": composite, "mid": "m1"}, namespace="/_xy") - payload = await collector.next(collector.payloads) + await client.emit("sub", {"fig": composite, "mid": "m1"}) + payload, _ = await collector.next(collector.payloads) assert payload["fig"] == composite assert payload["spec"]["traces"][0]["n_points"] == 24 # interactions round-trip against the bound figure @@ -1715,9 +1749,8 @@ async def main(): "mid": "m1", "m": {"type": "pick", "trace": 0, "index": 3, "seq": "pick:1"}, }, - namespace="/_xy", ) - reply = await collector.next(collector.messages) + reply, _ = await collector.next(collector.messages) assert reply["message"]["type"] == "pick_result" await client.disconnect() # both halves are cached now: columns and the bound figure @@ -1742,8 +1775,8 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": composite, "mid": "m1"}, namespace="/_xy") - payload = await collector.next(collector.payloads) + await client.emit("sub", {"fig": composite, "mid": "m1"}) + payload, _ = await collector.next(collector.payloads) assert payload["spec"]["traces"][0]["n_points"] == 7 await client.disconnect() @@ -1764,10 +1797,10 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": scatter_fig, "mid": "m1"}, namespace="/_xy") - first = await collector.next(collector.payloads) - await client.emit("sub", {"fig": line_fig, "mid": "m2"}, namespace="/_xy") - second = await collector.next(collector.payloads) + await client.emit("sub", {"fig": scatter_fig, "mid": "m1"}) + first, _ = await collector.next(collector.payloads) + await client.emit("sub", {"fig": line_fig, "mid": "m2"}) + second, _ = await collector.next(collector.payloads) assert {first["fig"], second["fig"]} == {scatter_fig, line_fig} # the data var recomputes (as a state delta evaluation would) @@ -1777,7 +1810,7 @@ async def main(): ) refreshed = {} for _ in range(2): - payload = await collector.next(collector.payloads) + payload, _ = await collector.next(collector.payloads) refreshed[payload["fig"]] = payload["spec"]["traces"][0]["n_points"] assert refreshed == {scatter_fig: 5, line_fig: 5} await client.disconnect() @@ -1794,8 +1827,8 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): thief = await connect_client(url, client_token=OTHER_TOKEN) thief_collector = Collector(thief) - await thief.emit("sub", {"fig": composite, "mid": "m1"}, namespace="/_xy") - error = await thief_collector.next(thief_collector.errors) + await thief.emit("sub", {"fig": composite, "mid": "m1"}) + error, _ = await thief_collector.next(thief_collector.errors) assert "another session" in error["error"] await thief.disconnect() @@ -1812,8 +1845,8 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": composite, "mid": "m1"}, namespace="/_xy") - error = await collector.next(collector.errors) + await client.emit("sub", {"fig": composite, "mid": "m1"}) + error, _ = await collector.next(collector.errors) assert "feedfacefeedfacefeed" in error["error"] assert error["resync"] is True await client.disconnect() @@ -1839,8 +1872,8 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": composite, "mid": "m1"}, namespace="/_xy") - error = await collector.next(collector.errors) + await client.emit("sub", {"fig": composite, "mid": "m1"}) + error, _ = await collector.next(collector.errors) assert "plan binds" in error["error"] assert "'x'" in error["error"] assert error.get("resync") is None @@ -1862,11 +1895,11 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": composite, "mid": "m1"}, namespace="/_xy") + await client.emit("sub", {"fig": composite, "mid": "m1"}) await collector.next(collector.payloads) registry.publish_columns(data_token, {"wrong": [1.0]}) - error = await collector.next(collector.errors) + error, _ = await collector.next(collector.errors) assert "plan binds" in error["error"] assert error["resync"] is True assert registry.get(composite) is None @@ -1883,8 +1916,8 @@ async def main(): async with data_plane_server(rebuild=make_rebuild_hook(app)) as (url, _): client = await connect_client(url) collector = Collector(client) - await client.emit("sub", {"fig": plane_data_token(), "mid": "m1"}, namespace="/_xy") - error = await collector.next(collector.errors) + await client.emit("sub", {"fig": plane_data_token(), "mid": "m1"}) + error, _ = await collector.next(collector.errors) assert error["error"] == "unknown figure token" await client.disconnect() diff --git a/tests/reflex_adapter/test_page_plan_registration.py b/tests/reflex_adapter/test_page_plan_registration.py index 3ab3fd078..6733eaa2b 100644 --- a/tests/reflex_adapter/test_page_plan_registration.py +++ b/tests/reflex_adapter/test_page_plan_registration.py @@ -78,14 +78,9 @@ def test_apps_without_unevaluated_pages_are_a_noop(): def _fake_app(pages: dict, tasks: list) -> SimpleNamespace: - """Enough of an `rx.App` for `setup()`: a socket server and task sink.""" - - class _Sio: - def register_namespace(self, namespace) -> None: - pass - + """Enough of an `rx.App` for `setup()`: a channel sink and a task sink.""" return SimpleNamespace( - sio=_Sio(), + register_channel=lambda channel: None, _unevaluated_pages=pages, register_lifespan_task=tasks.append, _state=None, diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 47a2b378b..d7e192975 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -35,12 +35,19 @@ def test_core_publishes_only_the_reflex_optional_dependency() -> None: extras = project.get("optional-dependencies") or {} assert set(extras) == {"reflex"} + # TEMPORARY, tracked in spec/design/reflex-integration.md § Status: the + # data plane needs Reflex's channel transport, which is unreleased, so the + # extra names the branch instead of a floor. A direct reference is + # unpublishable by design — the release fails at upload rather than + # shipping a floor that installs a Reflex where every chart stays blank. + # Restore the `>=` assertion when channels are released. assert any( - _dependency_name(requirement) == "reflex" and ">=0.9.6" in requirement + _dependency_name(requirement) == "reflex" + and "git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional" in requirement for requirement in extras["reflex"] ), ( - "xy[reflex] must select the supported Reflex floor while the adapter " - "source remains bundled in the xy distribution" + "xy[reflex] must select the Reflex the adapter actually needs while the " + "adapter source remains bundled in the xy distribution" ) assert {"dev", "codspeed"} <= groups.keys() group_names = { diff --git a/tests/test_tailwind_root_customization.py b/tests/test_tailwind_root_customization.py index 986e77757..5fcaa0621 100644 --- a/tests/test_tailwind_root_customization.py +++ b/tests/test_tailwind_root_customization.py @@ -431,7 +431,7 @@ def test_live_wrapper_silently_hydrates_durable_selection_and_all_axis_ranges() assert jsx.count("hydrateSelectionForRepublish(selectionToRestore);") == 2 assert jsx.count("restoreSelectionMask(selectionMaskRequest);") == 2 assert "if (isRestore) clientMessage = { ...message, suppress_event: true };" in jsx - assert "dispatchToView(clientMessage, data.buffers || [])" in jsx + assert "dispatchToView(clientMessage, buffers)" in jsx # Geometry is hydrated before the one direct mask re-request. assert jsx.index("view._applyStatePatch?.(") < jsx.rindex( "restoreSelectionMask(selectionMaskRequest);" diff --git a/uv.lock b/uv.lock index c9d6f19b5..2e1a8f416 100644 --- a/uv.lock +++ b/uv.lock @@ -146,15 +146,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, ] -[[package]] -name = "annotated-types" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, -] - [[package]] name = "anyio" version = "4.14.2" @@ -209,15 +200,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, ] -[[package]] -name = "bidict" -version = "0.23.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093, upload-time = "2024-02-18T19:09:05.748Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764, upload-time = "2024-02-18T19:09:04.156Z" }, -] - [[package]] name = "certifi" version = "2026.7.22" @@ -373,91 +355,91 @@ wheels = [ [[package]] name = "granian" -version = "2.8.0" +version = "2.8.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/22/f289f681277c8a1cd2c29177fc21bad080b270d6b60ac6e91a19cafe795a/granian-2.8.0.tar.gz", hash = "sha256:be842c6737b41beb6fe6521f9c46695a1843ec9e086a18bbbc945ed170ff28e2", size = 129256, upload-time = "2026-08-03T18:58:55.371Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/54/a18bbca2647d2faa720da32cd7e339356ab0a2dc4ec7243d015ee6a97b50/granian-2.8.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ab31b4205991954dbc6ccd8ab243f4b141a50da695bf2d9de46e56bec99bc0cf", size = 4526820, upload-time = "2026-08-03T18:56:25.927Z" }, - { url = "https://files.pythonhosted.org/packages/6c/2e/afa50e6bf9dace1dbc8ec814e2a251fc0fc09326590b90887ee9e3d1a017/granian-2.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7990e16ada156dc8dd66c8bea4688cbe14fc013e10ab8f2d554936a1fe9ee14a", size = 4329002, upload-time = "2026-08-03T18:56:27.541Z" }, - { url = "https://files.pythonhosted.org/packages/a6/af/a74dc0a2699b07ece151fd6d9a5ff151eff70254b7cde49f8039034a3e00/granian-2.8.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:10889fbe3a46f65184dd877450ba07fb653def537246bdc5c135c5eb17619388", size = 4769750, upload-time = "2026-08-03T18:56:29.171Z" }, - { url = "https://files.pythonhosted.org/packages/58/23/0b1e5beedcdefca60314d869f7e8eb25da5e741328ef31a58f1b5467fdba/granian-2.8.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87dbd544e41074a5b2b4d6ba82b1c8172c164bfc4543819f41161ad1222c4799", size = 4449131, upload-time = "2026-08-03T18:56:31.052Z" }, - { url = "https://files.pythonhosted.org/packages/f8/7a/41772d8980a33383f9c47b6cc5a9e2c2266928abe82734e83d72960f6830/granian-2.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42ffef3148f6d7387182fa088834a4ffdf48d1de42c2e61fb961a8552eadb667", size = 4986278, upload-time = "2026-08-03T18:56:32.592Z" }, - { url = "https://files.pythonhosted.org/packages/27/3a/a65c17a8caec6ad567c4ede495ab744ed6849a3a079657edc919dfb2cf1b/granian-2.8.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:df76b03542b0f9ad67c0ac6f927faa1c4a029ea001be97fdcc5d03bbea617975", size = 5087401, upload-time = "2026-08-03T18:56:35.164Z" }, - { url = "https://files.pythonhosted.org/packages/92/fb/4d805d1847d737c5f70c8ee916e439da6b801356371876dcb0a4eeab4231/granian-2.8.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2c4c3982cdc2e07db7b85bc421632b4cbf9a3855dc02eeb1300c6488126b9cf3", size = 5053305, upload-time = "2026-08-03T18:56:36.952Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a6/eaa2ba68ada39123b9c083247536a006ccc3684c479644701b48e295d43e/granian-2.8.0-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:58f97da58709a017c10564a5472854696a27278ae92083f65937213609b7e667", size = 4901784, upload-time = "2026-08-03T18:56:38.603Z" }, - { url = "https://files.pythonhosted.org/packages/27/dc/1b865720bce1fd33283e478d3151aeb01e74babcb02b3fcaa4bc0da069ba/granian-2.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:31d424ca1fd98381069e5bf684bcb78d0dd906ee20383e48a46fcb75c6bc4dc5", size = 5045412, upload-time = "2026-08-03T18:56:40.189Z" }, - { url = "https://files.pythonhosted.org/packages/2a/1c/cec72287bb2d313e74cd8a99140689151bd8eafe628276ad9035433da5ac/granian-2.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:1fb070bf50122353e316692927dc77e2fd84fde5bd17e89d83d66c3ad4b39809", size = 3126580, upload-time = "2026-08-03T18:56:41.72Z" }, - { url = "https://files.pythonhosted.org/packages/45/ab/432706e82c0bb95ecaf9aeee26d36c13b2917a358377ecf07675b363d61a/granian-2.8.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:de8fc64f423f000a0097886e0c4e8ae1bfb4b4d0699edc6244da768c05c0b40b", size = 4442542, upload-time = "2026-08-03T18:56:43.266Z" }, - { url = "https://files.pythonhosted.org/packages/2d/a5/b7835933f999a73d8fd5b15f6734f6abb40edac4d759b2490a069762c1ad/granian-2.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76fdd00bb5842a7993ce57e7d254e75d5e9d7425b49d02a341b93d618047f1fa", size = 4264376, upload-time = "2026-08-03T18:56:45.041Z" }, - { url = "https://files.pythonhosted.org/packages/18/63/5245e1d11a3920b1d7705d6748e736b07a48f1415817a2b7b0eab921b26c/granian-2.8.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:edca648754927c913dfcf52068b96418b66810017fd628d19cb1b65f78dfd9a6", size = 4812379, upload-time = "2026-08-03T18:56:46.69Z" }, - { url = "https://files.pythonhosted.org/packages/93/00/a2dd16309d39be4888fe90da677692f0148feff589438b536425ffd3d3de/granian-2.8.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:899b1af43754ee8ef6beaece26947cee3fa03487f0193d5fc17fb55435903a68", size = 4446390, upload-time = "2026-08-03T18:56:48.573Z" }, - { url = "https://files.pythonhosted.org/packages/95/87/8f9e929ac017233ce14123601765d095305b407df0a512ae8c14ea741380/granian-2.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278db6788bacb37e9e57abb429229f74c5b5f6f5dca06f66fad027a4ff6dc51c", size = 4860867, upload-time = "2026-08-03T18:56:50.346Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2e/5124c9c4d66d3e8405f3cc5fa4074d06a703546456c002587af9d3c2822a/granian-2.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5827ee36b7e5af4a104430d802cc0454913dd2f984b0b594c42ba049a1deeb61", size = 5023347, upload-time = "2026-08-03T18:56:52.17Z" }, - { url = "https://files.pythonhosted.org/packages/5a/14/d4624e7c22c7b26d1ba0e296a6c25621a6daeedd09a1399fdf9c34e2e8ec/granian-2.8.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67e1f73705aac805ec1e7e10c38946a4dd49f26e018d250014d1fd9a924dca64", size = 4993318, upload-time = "2026-08-03T18:56:53.693Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/55fd1dca67c273460fe13f622cfbcf17812b27077656bb9c7982b88e9d31/granian-2.8.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:89d4904bb657503ab41b304340c42371c9f9b01f83b6c7c136f5a0d8bff50efd", size = 4923508, upload-time = "2026-08-03T18:56:55.918Z" }, - { url = "https://files.pythonhosted.org/packages/18/b7/1ee1f572b86c5681387ca10e10750c3d35583db43aa85213bbc33f2cf6f3/granian-2.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49bbcf8c20370cba6d0d5ba1aac95f5e9d22a3e95b10b420d49337629d2f4fcc", size = 4924703, upload-time = "2026-08-03T18:56:57.783Z" }, - { url = "https://files.pythonhosted.org/packages/bc/2f/0b4e8a671e52b868140a80b67ddf665aa85622114a2dc28dc550119cbf49/granian-2.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:471e4d122518ca23776677bcd104c37bdf31377a4a8b8c668e3d6551e90213bf", size = 3112321, upload-time = "2026-08-03T18:56:59.879Z" }, - { url = "https://files.pythonhosted.org/packages/95/45/1c1f3b80b19813a8c3f025397aea4b56b62d2d422100b10498a7f13bcf35/granian-2.8.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9e28aa83940629169986615ecbcc39c026e193df41ba8264202fefba5edaa8b6", size = 4442295, upload-time = "2026-08-03T18:57:01.543Z" }, - { url = "https://files.pythonhosted.org/packages/28/1b/e686b7504e125a2dd5757f2b668c0ef4707467d04add2e42cfa9b19f9139/granian-2.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf3ed0a22327aeb1b15e36c3d56c2174a68a0dd6a57554ac5b7456fd231e258a", size = 4263150, upload-time = "2026-08-03T18:57:03.18Z" }, - { url = "https://files.pythonhosted.org/packages/bb/03/740fa22bdbeec4fa55cf017956955532ba760584a9479690442e1c831179/granian-2.8.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6848acafe50547b2f6c3f5d92b5a3d873dff97267287195a45f18a9270ca2952", size = 4812578, upload-time = "2026-08-03T18:57:04.911Z" }, - { url = "https://files.pythonhosted.org/packages/a8/f3/4971ab3775153452940c1f38dff2a141168dc2bcffb4348382ed47fe828d/granian-2.8.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f03da08e21e6d0a6b0ac6be3dca4485e2ec1a609e9349e07c390c745f0c8b29c", size = 4446673, upload-time = "2026-08-03T18:57:06.839Z" }, - { url = "https://files.pythonhosted.org/packages/82/f3/bd62b2c9830fa3bfbfbac7e07ab086a0f0b3e5ab6613fcf017a389f975ef/granian-2.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a63cb450f71760a56c80794c0c49bc638d58f8f4e9f91202a21c08014994c", size = 4859343, upload-time = "2026-08-03T18:57:08.593Z" }, - { url = "https://files.pythonhosted.org/packages/23/fd/10345aabf40982f9483671c93be9a1892ece07ca3bfe68babc4171caa946/granian-2.8.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:6ebfd8af38136054e6ea2e86b18649c5676d924fc3a40383ebbb3af6185e929e", size = 5023131, upload-time = "2026-08-03T18:57:10.981Z" }, - { url = "https://files.pythonhosted.org/packages/06/1e/42d540dae26873938dbc19cf0d692b9644c8d8a6aee668fa78c79f751897/granian-2.8.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:39b620297be07d71ff92aaf2c52f5a376a7888d251a3e953cad81620751ee0a6", size = 4993372, upload-time = "2026-08-03T18:57:13.361Z" }, - { url = "https://files.pythonhosted.org/packages/e3/09/025227fb79b3b7bcfc810922863fdbc05bf3932030d207773bf2bba5bf60/granian-2.8.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:67c1db11193797fe1de61e74ac858fbac4e4d27f1b8c4b437be40b15700fccf8", size = 4923411, upload-time = "2026-08-03T18:57:15.079Z" }, - { url = "https://files.pythonhosted.org/packages/11/a3/aae60898ffb725ebc7f2caa5055d1aa4c6aa49c8ba29dea9f559e2eeea3a/granian-2.8.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:4f4fa63ed4fe67ec12f9a26d29779f52c35cbc8c57fe337f7bea25f8c47981f6", size = 4924152, upload-time = "2026-08-03T18:57:16.83Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/5d5b9b3b02f0abe30496ad3cd7123221666fd54b0a3a3d9fa3a18c66de51/granian-2.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a1d8dce913504188d4fddb12e33515ee5bef6c4658e9eabb0bd5dd43d9c1e4de", size = 3112465, upload-time = "2026-08-03T18:57:18.622Z" }, - { url = "https://files.pythonhosted.org/packages/dc/10/1c8231d6592bce2855d002c0b82939c62bca317c82cf37ac98ed219b94d7/granian-2.8.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:55aad6e52f7b5d22c468304f5862b154e08ff231c622e956d63f4b5a7f308e36", size = 4423359, upload-time = "2026-08-03T18:57:20.484Z" }, - { url = "https://files.pythonhosted.org/packages/69/37/39b99ffff95b9cce64c9964ff21f15e75b3b5c96f0529b56ecd87a8df037/granian-2.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:95517d0f5c38cbed7b94a6d28dfb6710330b879024a9ee73dacf6b4ade638925", size = 4259820, upload-time = "2026-08-03T18:57:22.167Z" }, - { url = "https://files.pythonhosted.org/packages/e1/32/846784ed1e3b7aa84e473268a9c43cfd2c5b97cb9dd0161e4719e04ecf53/granian-2.8.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36a53d61e6d5f04af257700d2b83700d64be5f392d0d07a2cb568daa2f778c8e", size = 4805453, upload-time = "2026-08-03T18:57:24.103Z" }, - { url = "https://files.pythonhosted.org/packages/89/c6/7e24caa2211fc669076aa223867e2bdb3f0a5bb9d74bbdbe9cfb4c8b5d9a/granian-2.8.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc2f421b899d3a8615ae705016f41a6e0a4940c7005dbf58fc8962a412bd760", size = 4444078, upload-time = "2026-08-03T18:57:26.367Z" }, - { url = "https://files.pythonhosted.org/packages/ea/be/9eedfbc98b0fb6f0213adc0338d530467cd1acaa98aa026fab881c672a8f/granian-2.8.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036eac55cb9d67457b50b86a1c364d39c3f0ce4e06d86a87d3af8de7d173e721", size = 4870806, upload-time = "2026-08-03T18:57:28.289Z" }, - { url = "https://files.pythonhosted.org/packages/d4/eb/3b140540414e540a2708a4008eabfe3958c2b010ca998738fe6173300f9a/granian-2.8.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:35624cf9fe8bbb416890871e63de7f3460555ed9bf0ac69b533f796a4382a746", size = 5026508, upload-time = "2026-08-03T18:57:30.133Z" }, - { url = "https://files.pythonhosted.org/packages/8e/d4/adcec457beec4f2775ee3cc5d4ac43c795edb0adf104cb48d9d1181b0924/granian-2.8.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:09c73e7835a7bba35f14320b8e57dac1da4981c8c6d3a08cd6e9c557860bbb1b", size = 5043848, upload-time = "2026-08-03T18:57:31.992Z" }, - { url = "https://files.pythonhosted.org/packages/ee/7b/0ef38e58546d757c12d751bf8bc9ab3b16287d6cf09656ec6d53874b0ed0/granian-2.8.0-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:1bb0c4c2ac258f5e96cb5ea1d1c674c3d1b7c7bdf110ae97bae173bb003405e4", size = 4918203, upload-time = "2026-08-03T18:57:34.282Z" }, - { url = "https://files.pythonhosted.org/packages/a6/df/e832f520be4c3439148ea13b8c5b635297138bc572115284b55c4425343f/granian-2.8.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:de30f61a321571cfaa7ab1650f324b26959fce6826d341bae520cf2786368a09", size = 4933696, upload-time = "2026-08-03T18:57:36.117Z" }, - { url = "https://files.pythonhosted.org/packages/eb/40/965f20eb6cedc318d08c361fcc8b3c85efac3aadf5adf298b32f6075ebbc/granian-2.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:dca589ddf61239e08a52ec6fa7f62290cd9ab707588dc928d9b65df971ef202c", size = 3096154, upload-time = "2026-08-03T18:57:37.979Z" }, - { url = "https://files.pythonhosted.org/packages/b6/93/64cf513a32fa2f64a421b58b0b00486d03e48cdd69c367ce185140e00f62/granian-2.8.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:a3e0905fa79ab2b5752e9222fb87003b1e69f7162eebe6eeec0ab924e5e67312", size = 4320699, upload-time = "2026-08-03T18:57:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/4d/d4/4bbb6b1d9c56c9cb5ce636fc3c2d31ec0baacf6975d379b5ae4ab2c3627c/granian-2.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4c228897c11931c623ee27e07ba512a86667d7c7af0172c4334ae8a0dc66c6f6", size = 4144380, upload-time = "2026-08-03T18:57:41.668Z" }, - { url = "https://files.pythonhosted.org/packages/7b/1c/da817b9cf934fb041ae423744a1c89823af3299f91c2569fa04b4cd0f3b7/granian-2.8.0-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:640003ab77b6dc29b0c247cdb8d970cb2f4986de2e7c72849e9f5fe565eca18e", size = 4282845, upload-time = "2026-08-03T18:57:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/ba/09/35c8b5d5001ec3024a1bef4c6305582cb5e8f8a2f2e85f90eead59910593/granian-2.8.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81e12dcd0b504c8704b54c6a88733a57de21726ee9567a018f8cf7972e190753", size = 4812269, upload-time = "2026-08-03T18:57:45.884Z" }, - { url = "https://files.pythonhosted.org/packages/36/6e/99b59975f249faaa066320c4f2927102c6740de87be8421cae99c47688d1/granian-2.8.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bfd4726c4c61f39dbdb4e4e2bfe8fd0ace2cea58eb34ce720036e8e09b1c27a", size = 4748058, upload-time = "2026-08-03T18:57:47.899Z" }, - { url = "https://files.pythonhosted.org/packages/c0/83/42aeb107969349a07b7385dda0222fad830d318f1d5bdca084823650f859/granian-2.8.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:6c1aeca05c84434ecafb2297aabaaf1e39a267e66eee4420b7669cf0c47df369", size = 4842775, upload-time = "2026-08-03T18:57:50.651Z" }, - { url = "https://files.pythonhosted.org/packages/17/35/d5f6e690eecdf4a63460d65f363527fe3db69477bfd0df631f395c554a4f/granian-2.8.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:ec5281054da6e342e7be3d3d5bf764288faa2e6407d26ef5b9a909fa5b5ca44d", size = 5038742, upload-time = "2026-08-03T18:57:52.407Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e1/98b97433013a1219ed1c1238befa7aa0eb83d7bbc872e63193e847e152fe/granian-2.8.0-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:7b76586d95b798453ee89304a1bb25b1ea9301f564cd3a6a20268b8139a9cad5", size = 4944066, upload-time = "2026-08-03T18:57:54.488Z" }, - { url = "https://files.pythonhosted.org/packages/41/70/47897e417dd22c83e731d85e8f388ed29a1b88a97404063c05a2510fc11e/granian-2.8.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:7d516e7ae705e0d5f8ece085ac18b8817dc4c8adfb7f0f68e9ee529e991664b2", size = 4987791, upload-time = "2026-08-03T18:57:56.46Z" }, - { url = "https://files.pythonhosted.org/packages/b2/8e/76f58b9953a1aa1ba317ce0d96073a47dbb515d562fa524ea8a6b9564bc7/granian-2.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9383c97c12829b0b0accb3aad5011ad765e74a90d54d8381cf722ca4f7bdfc0a", size = 3082991, upload-time = "2026-08-03T18:57:58.204Z" }, - { url = "https://files.pythonhosted.org/packages/47/8e/264f9215206a177d6a0958ec6a496923c6fa0fca785a350884e9d134fce8/granian-2.8.0-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:c13e89315cfd91821399c78f1dfe5c63b95cd9b44c9da1052eee66c00e60c719", size = 4424059, upload-time = "2026-08-03T18:57:59.857Z" }, - { url = "https://files.pythonhosted.org/packages/42/bd/6c62d461da7ccb76ecc57e2e4c29a63fcb55d21a4b04fa030e849e6d0225/granian-2.8.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:f956f26d638268312b7cd583fc079cee1bc3474a29508dcb2bf7f797822912bb", size = 4259907, upload-time = "2026-08-03T18:58:01.491Z" }, - { url = "https://files.pythonhosted.org/packages/95/ed/cd6b65766c1f35718fe1d83de985ae79ebd2068ea27ab39457ab95439f54/granian-2.8.0-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8fcd0888e6ab17a14dabd7b8b3a1cda12795a754660279d2b17b6abcbaa65644", size = 4807122, upload-time = "2026-08-03T18:58:03.404Z" }, - { url = "https://files.pythonhosted.org/packages/d6/c7/36c80a53a43e20e8ecc0587c9b82e0c23ef82b26e258ff05750462fe689f/granian-2.8.0-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b771aec7246a9e220f841c24e522f493b67ad2df4a7474e4fa8f960844826c9", size = 4444740, upload-time = "2026-08-03T18:58:05.083Z" }, - { url = "https://files.pythonhosted.org/packages/0f/34/760cbeca09daae682e20a6f4a894248edae35dd5e40f27ef6fe8aab315db/granian-2.8.0-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2fdbbe31574800b2b14dcd2868be06f0e0b333817a37fc0fdae2024de2d4612", size = 4870669, upload-time = "2026-08-03T18:58:06.874Z" }, - { url = "https://files.pythonhosted.org/packages/e5/17/daad58c44a0f934ffa5991440054b738758c645ecd35a8d81266f6bdd2df/granian-2.8.0-cp315-cp315-manylinux_2_28_aarch64.whl", hash = "sha256:826bb163325f1bff16f884c98b7f109998a3a9042406c31f7f407114e8196020", size = 5026641, upload-time = "2026-08-03T18:58:08.82Z" }, - { url = "https://files.pythonhosted.org/packages/2f/8e/2ed4b28cfb482ccb3e9d6b0812f64ef40598829c53dcca9260aa93994fc5/granian-2.8.0-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:fe48c902ace46e8dfaa24585c2941b51a22b5d77d3676a502ae48caf4ba624ca", size = 5043662, upload-time = "2026-08-03T18:58:10.706Z" }, - { url = "https://files.pythonhosted.org/packages/c8/df/9afd95c900d0c4fb5d57d1de1d9340cbcad9813b0374c4ac37b0a00c710d/granian-2.8.0-cp315-cp315-musllinux_1_1_armv7l.whl", hash = "sha256:6f9876220f56a0ffc2bc41a977f6fdbe0458a8559c3f950a0497fe71e52a16e3", size = 4918816, upload-time = "2026-08-03T18:58:12.489Z" }, - { url = "https://files.pythonhosted.org/packages/16/ff/ec09ab42ba46676440715b4810aca60ef92d39dffa68669a4daa0bf01252/granian-2.8.0-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:0d797398949f8de4259926df69d0020b6897ca325672043529d9a6b702bddafe", size = 4934107, upload-time = "2026-08-03T18:58:14.417Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a0/1f2de683c90137ae5a66e89ca7aa72752edb2e0c55490442169007a9bbae/granian-2.8.0-cp315-cp315-win_amd64.whl", hash = "sha256:808986933f844f54dd9c6ea47a9e0e39cbbd12b91b315a8de1ea98abb9314e80", size = 3096056, upload-time = "2026-08-03T18:58:16.3Z" }, - { url = "https://files.pythonhosted.org/packages/fc/d2/21d2fbf8517b2c0d82bda45dfa7ed26d933a5698ac7107c43da366635223/granian-2.8.0-cp315-cp315t-macosx_10_12_x86_64.whl", hash = "sha256:8bf00fd66844846dac9278a15db864ec68c60878098ad638451fc8a3e61f845b", size = 4320343, upload-time = "2026-08-03T18:58:18.126Z" }, - { url = "https://files.pythonhosted.org/packages/94/1e/81284fa128f77dd6132ed62f29f0a099aec8622f2acd3c3fa7a733dc8375/granian-2.8.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:ca1a764c00b89509eb7a45f1479118481628380e1bd1d94c2248e097abd63017", size = 4144285, upload-time = "2026-08-03T18:58:20.122Z" }, - { url = "https://files.pythonhosted.org/packages/dd/8b/2f6a7012264011ebe6ea29afdeb333b6c50be3956b70cd59eecf248d599c/granian-2.8.0-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:042c177e75a5e67144a39476882ed735ac9558e48097a5658111adbf939c0d1e", size = 4281969, upload-time = "2026-08-03T18:58:22.433Z" }, - { url = "https://files.pythonhosted.org/packages/76/72/ff6d27931f004e231dcead6c9d5d0c252a73358462885f19e1223784c72a/granian-2.8.0-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:faa739c7674c53fb9e6b72500232e6360c13e531d8186cf5ef569ba8ccbd5f2c", size = 4813597, upload-time = "2026-08-03T18:58:24.563Z" }, - { url = "https://files.pythonhosted.org/packages/f9/8d/7501ff01a8ca751608783252729ec067a7dc498c4323ae2e31ac17c1dc30/granian-2.8.0-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04c83c5d7a387635d8c7cde11a95f0babee1cabce3c469de4494a9f93a015394", size = 4746980, upload-time = "2026-08-03T18:58:26.392Z" }, - { url = "https://files.pythonhosted.org/packages/2f/14/3f635ba0065fc36f7820704059bbc46065dd9e4fae55b28de46a91dff9f9/granian-2.8.0-cp315-cp315t-manylinux_2_28_aarch64.whl", hash = "sha256:7cd88ca58924a63eed769ce64cea3c29c876791db14988f2d6f3f6fd5cb18061", size = 4842380, upload-time = "2026-08-03T18:58:28.178Z" }, - { url = "https://files.pythonhosted.org/packages/da/6e/008efb0f414ff7c8c8d0d9112abb5fa9a93574043cbe4e5f69f9ab80caf2/granian-2.8.0-cp315-cp315t-musllinux_1_1_aarch64.whl", hash = "sha256:2052d1cf74369430b960f7731db823a1f604e375179182bba3511e88d976eb43", size = 5038154, upload-time = "2026-08-03T18:58:30.131Z" }, - { url = "https://files.pythonhosted.org/packages/da/4b/01e0f0ad66c886a55c44912385ec72e7da68ece6becf3b67bb402022b605/granian-2.8.0-cp315-cp315t-musllinux_1_1_armv7l.whl", hash = "sha256:0e96f5bdbbac30e6abff4e7c2268582734ba8a908608c95fbc9a1db5b849bc3f", size = 4946307, upload-time = "2026-08-03T18:58:32.26Z" }, - { url = "https://files.pythonhosted.org/packages/5d/50/2a961f66228426d9c95b4d799f1fea5460f34ea01749108118d81ea33eb8/granian-2.8.0-cp315-cp315t-musllinux_1_1_x86_64.whl", hash = "sha256:0d84b516c3d720d22448d935e136d8ddaabb5a8715bf839d8f28de578d35443f", size = 4987962, upload-time = "2026-08-03T18:58:34.178Z" }, - { url = "https://files.pythonhosted.org/packages/1f/0a/711050f09a1b027b13db918e7f272ff5e7f7b4699d9994fbe39f285e2e74/granian-2.8.0-cp315-cp315t-win_amd64.whl", hash = "sha256:5c4d67d96ab296164c36ef672a55251ef12c5e4060c1796fcba6c3fd82394d27", size = 3082796, upload-time = "2026-08-03T18:58:36.052Z" }, - { url = "https://files.pythonhosted.org/packages/9e/07/1b6c05cb38172fb9e7c7aeef00be1956f7b7eeb096c4929df6eb58da399d/granian-2.8.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:efcb466cfaa76391efe5e0fb336b888aa86eb4b8e6177f79f7a01ffea03a414c", size = 4516704, upload-time = "2026-08-03T18:58:38.373Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6f/c3aa2246f01fa98ed273c6e0f8f1a90f4b91afaaf6ef3104cf0802b88a2e/granian-2.8.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:018fd40bc1e4c22d367d24df1265f2a349776a20b68b756d4a52107ce8248c82", size = 4306260, upload-time = "2026-08-03T18:58:40.375Z" }, - { url = "https://files.pythonhosted.org/packages/62/8d/e13731afb5ccd64256b6d9e3b0147fc141201100d9b3f8336b557396ece1/granian-2.8.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:007fcd0bcaa9756285b8ad844729af0dedf41dbd6b3df91344f086c6db628ae2", size = 4916315, upload-time = "2026-08-03T18:58:43.066Z" }, - { url = "https://files.pythonhosted.org/packages/d9/84/1f77905ad0c4a89cb223793fb57847d4b97a435af63099d8ee98d9364d5b/granian-2.8.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4df16c414f55eb1324aa5b0f5486ea5aa39cb93e9a49ee15a83df6a987e3c5f4", size = 5074511, upload-time = "2026-08-03T18:58:44.906Z" }, - { url = "https://files.pythonhosted.org/packages/38/2e/e268ec727c3bbc397b731754a3a5f9d48f14d7c2ee13e0dac91149ef66f7/granian-2.8.0-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5d727b586bcb24a9568fccf37e25ef10c5bfcc2b0401cf1b28d0a570bdc3a4f0", size = 5046410, upload-time = "2026-08-03T18:58:47.493Z" }, - { url = "https://files.pythonhosted.org/packages/9b/3e/27d1725cd43e1348b0df74731f6423626dad6f761ec3c5e8057217fbba6f/granian-2.8.0-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:12cff22f282304378b05095484227ef55199dcb2b413e4a5f1a070c0aa5193f4", size = 4969944, upload-time = "2026-08-03T18:58:49.443Z" }, - { url = "https://files.pythonhosted.org/packages/c7/9a/3033a6c43846895af17fe01a119a6ec4fe1ffea5dc786ca4ddfa8a7c37d0/granian-2.8.0-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7fd9c8a78a55d003f36dfb9fbbd8f2369015c5176333449da719e430bcc0e0e4", size = 4976158, upload-time = "2026-08-03T18:58:51.619Z" }, - { url = "https://files.pythonhosted.org/packages/85/bb/806619a7225c5ed42d980e91809e86ecb1ba7d4b759d83d2758c769329a2/granian-2.8.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3932a061a803ff3441e249895fb080e6b12398a722d895ac6fb4c0f70122cdbb", size = 3138711, upload-time = "2026-08-03T18:58:53.561Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/80/74/9903bd396a3ea5e40163ce4946df974bfb9f7280834b1c59d727df65867c/granian-2.8.2.tar.gz", hash = "sha256:466a23e8cb44d4b407fa3db0f37aeb45ae722cad4d4b3701d6fa6b13ca54b1ef", size = 129359, upload-time = "2026-08-23T17:40:23.248Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/7c/961d2db920e9eb4fcb079f08a0209d4873f9cc5ce33e23e2dfd197be7409/granian-2.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a1da543c6fafbae059e90df5756df17095ee059c9a9ec7acabd7dd88cc273184", size = 4646222, upload-time = "2026-08-23T17:38:23.72Z" }, + { url = "https://files.pythonhosted.org/packages/cc/4c/cb16e44acceb935876599195f2dcc8a29394633aaeeb454a87066643e209/granian-2.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:54d64fba52ae5b29e7fb8489fdec5185859b0e299a6add92d4d69bf94d8684e9", size = 4470625, upload-time = "2026-08-23T17:38:25.064Z" }, + { url = "https://files.pythonhosted.org/packages/b2/27/3b85635168f5e87e6e25fbd3d5ff34066ba353add7f66659510748b8a71c/granian-2.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4053a99b6fb82e98807f854d3c6d6ebe0a49353c9eb7797999d166a99c1ae399", size = 4997931, upload-time = "2026-08-23T17:38:26.478Z" }, + { url = "https://files.pythonhosted.org/packages/70/95/2ffd4f0dd60cfba6edc0708efd5888fd5bc8898943cb8a4175b8a6758650/granian-2.8.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5ef2175682f3016589df34c0f348a7840e7513c60a1a3f60b6b78326509b5aa", size = 4560356, upload-time = "2026-08-23T17:38:27.783Z" }, + { url = "https://files.pythonhosted.org/packages/c3/d9/e7098bae4e0ec550bd28e3ac7a4ffda23e1b8659d155ed4e56076aa3a2c6/granian-2.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684fbb039483b42606bf74e8675262e1947ae7303e5a844a3194e02f2f853d51", size = 5017099, upload-time = "2026-08-23T17:38:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/65/e2/fc8d86ac636d1ac2d74145c7e4e262ecc217f25941fb4ab62f1411d5e2f8/granian-2.8.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:84fd77bb1a66d9cb06ebb68fa4480204b69ef6bb314e942ebad3f2952ea0e072", size = 5180432, upload-time = "2026-08-23T17:38:30.346Z" }, + { url = "https://files.pythonhosted.org/packages/9a/55/a83cf2a1c3c0c711c0bad5d70f194fdebab6049a661b89bf7d880c8b55cd/granian-2.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d8d2ea99f8b4412eb4c320478148e58d76e5ebbb12bb487d7c64f7b4100517b0", size = 5237694, upload-time = "2026-08-23T17:38:31.607Z" }, + { url = "https://files.pythonhosted.org/packages/cf/40/16489cc1a76560ab31306a656ca65fb856edc5ffad89fb6ad8eb9a1a22ee/granian-2.8.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:79be108e63e7812237a67a7d2c97e1ab34411d4b3f7ad537e196f6afc0803659", size = 5107893, upload-time = "2026-08-23T17:38:33.099Z" }, + { url = "https://files.pythonhosted.org/packages/58/33/4ce91368b66a471f93b55a805da3f407e5c22a8888859db775f2c81e55b6/granian-2.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b4006292f09145ce642131e2cb53e79ee12a92ef0f938d8e84e5d4d28cb7a030", size = 5119465, upload-time = "2026-08-23T17:38:34.975Z" }, + { url = "https://files.pythonhosted.org/packages/64/4e/10566f58dcd8f060e881a8b3f525610897bb3d6e6a832c02338be7d00e72/granian-2.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:f2738a9c49015c65c83a077a8c35a0e525152a6505ac267ba25d7b25a4547bb8", size = 3136927, upload-time = "2026-08-23T17:38:36.224Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/394e7ddd853f732a678eb54a60fd54334070c99b74dfe156614271a4419c/granian-2.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:15fca7c867b0477209dd02940d52a35dcf0785f70081824bca5dabf7ab0b3ba7", size = 4550249, upload-time = "2026-08-23T17:38:37.552Z" }, + { url = "https://files.pythonhosted.org/packages/27/58/a5c7d9d228e5aa3964681726ecc1f560a9179581d0b81f649d631e48ddf5/granian-2.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e45ed005bbb6cb7f77682de2c72e33797f84310f8ffd0c97d0bd5b93aae4e185", size = 4363052, upload-time = "2026-08-23T17:38:39.12Z" }, + { url = "https://files.pythonhosted.org/packages/0d/7f/6de20e29ef52bab40409e25a019419b876ddba7eba94422690c6a47539f3/granian-2.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5c6bb7a7bbedea92a6c6c200e1b01f3b5059a6c5b5b8face1fcd396682f0e29", size = 5069488, upload-time = "2026-08-23T17:38:40.8Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0d/9b86a600cc193a41ce00c46979f763bd13dc60d8a26e98d88cd5c1aa8a04/granian-2.8.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887c822fbe85e603dcab24138fcdfa02262e41737ccc016238c435e44b4a53dc", size = 4595582, upload-time = "2026-08-23T17:38:42.162Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f8/ba7e1b9769bd1723369156acd3c0191fc1785d1fd224771a7b890842bf19/granian-2.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2fbff8464c7831cc7e2dc9dd7f04301de035c44481c1fafad7e87d2e479cddd", size = 4969631, upload-time = "2026-08-23T17:38:43.613Z" }, + { url = "https://files.pythonhosted.org/packages/ba/97/de45ae209366f174ab9201a854a20143c7af1578d6d993a56e62a4b4e7ff/granian-2.8.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:7341d8672475707c733f4b6f98ca8524833aa70eaab2826f333f17214cb29132", size = 5096407, upload-time = "2026-08-23T17:38:45.051Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ca/b6c2b697ddd93c0066ce97a037ed0f754d05cf6bf3707c8bfe0246b9bab8/granian-2.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:aacebc0cbf1e4068918b0d6450ab538ad7bd4c42cd866e76bbb13f87af45def4", size = 5132279, upload-time = "2026-08-23T17:38:46.474Z" }, + { url = "https://files.pythonhosted.org/packages/82/e3/b5ce63e182a8623e1c735e60d53b0cf91f7fb0a12e588ba57a22556b5e64/granian-2.8.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:9e92f4319f2fb955f6e8f620381fe015e67c66506de73dd0e92ef0e0d10fab20", size = 5170524, upload-time = "2026-08-23T17:38:48.068Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a4/568cbde461f6685018afb107168592d98d4539fa63c4a63a87628eed5ddf/granian-2.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a55b966ce6e3cced43b1b337652fb714ea355e8cc4647045118b525e2e57c722", size = 5073762, upload-time = "2026-08-23T17:38:49.407Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d0/5603f7bdf8c5f2e58dd344323759d9c78688fd993253e28fda17e4c3b324/granian-2.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:9602e34f57f1c5c7c4c4b9b5fe11968c3223182cabfc6dbd7d7ee06e9ff25b95", size = 3150885, upload-time = "2026-08-23T17:38:50.694Z" }, + { url = "https://files.pythonhosted.org/packages/b3/3c/2b62d895c472d08f41a845497808dd8c591a82ad60fc9828fdd240cbb7e7/granian-2.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:434deec2c9af78785c93cd7f7a81f9869afc3003170e309ffc23f9b8ad6bbd35", size = 4561048, upload-time = "2026-08-23T17:38:51.971Z" }, + { url = "https://files.pythonhosted.org/packages/c7/05/96ac5277451f226941a17670f3607055b84e3e12b15944af7d420d5c9964/granian-2.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:679ac93bc56b6af17363b6577b8e36c399e0283128f76d00e6254433b26fd037", size = 4384248, upload-time = "2026-08-23T17:38:53.262Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/c58067f3d913f45307c7efa7e09d4248a3b4b1289ac5b5a56c8a0730c10f/granian-2.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae8805ea5d0dbb31d232437df9d23bf4a21a1a7e472cce05b11594662278b3b4", size = 5070839, upload-time = "2026-08-23T17:38:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d8/2fe874582f1a688f9cceef842be1ec47c5890b7e80f596cf2ddbee116fa5/granian-2.8.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35414a2eea2adf92e71762a6793412794ae32540e1103400e62dd423f38b5a7a", size = 4597622, upload-time = "2026-08-23T17:38:55.967Z" }, + { url = "https://files.pythonhosted.org/packages/43/1e/4558dd1a4df3b4fe92e5ee29f35773f9b152dba9eaf1deda28cc8437af53/granian-2.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdc50c290dc26d61891255b6e118606c1fd8fbdfba3059da199052172ecb539", size = 4982980, upload-time = "2026-08-23T17:38:57.394Z" }, + { url = "https://files.pythonhosted.org/packages/ef/33/1e3edea3be88a5b133cda591a20b227cab5a4a054c6b9a2902e63d594c06/granian-2.8.2-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:8a9d20c8a509213bf0c3235c79c3d1892aa887521dd7ea4c36a2ee40dcdb72ab", size = 5110060, upload-time = "2026-08-23T17:38:58.902Z" }, + { url = "https://files.pythonhosted.org/packages/d5/c4/764a6de6613395d85a4e6f6c26f048e95226454b2189987d1983e97f1024/granian-2.8.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:63ba5fada798ff9d7fdedc3bd1fbed60d8269195fd13d4f48c273024eb23a292", size = 5147486, upload-time = "2026-08-23T17:39:00.285Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/790a3bd672719c1d0487adaa2db4a962e401d6c0f2d61c7af5ae94b658cc/granian-2.8.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:b22cbcc8e5ca399c0b231a74bb87b4f477a59b4c4852daa7f488c0a6561b1666", size = 5173157, upload-time = "2026-08-23T17:39:01.788Z" }, + { url = "https://files.pythonhosted.org/packages/a8/45/c64bbc08bf1af0efbc5424fbb5760008b87b7e0782759c7367c59fa1d314/granian-2.8.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:43c670710b34b65693f3e36d7665b18eb819e4783d43368c8144e2e9deff6b40", size = 5083624, upload-time = "2026-08-23T17:39:03.13Z" }, + { url = "https://files.pythonhosted.org/packages/b9/12/2c7c44c5a4c1afe2841cb1f3e91fa47411cc86b3c8d5409d23e5a1873ff4/granian-2.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:000d459d3b6cc7eb43ae673ba77411e27bdc1e278b6f7e4e01cf3fcdad2d4c6d", size = 3144567, upload-time = "2026-08-23T17:39:04.446Z" }, + { url = "https://files.pythonhosted.org/packages/92/f9/69107c8b1743a41e9d125cb6d2a98cb43eea76b8d33761e0b0328aef1bb8/granian-2.8.2-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:325458915a148c878275524ddd959bfd35a83d1672369aa45df04a52c71dd5db", size = 4515603, upload-time = "2026-08-23T17:39:05.829Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a7/c71267bcb49a9f9dab7997c2463d8a452539bde8dbb25c171c3be37be6e0/granian-2.8.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3d150f1678ed5c90e3bd17db5ab66c8355f01dfc66ff46adc898e792d0cb577f", size = 4319118, upload-time = "2026-08-23T17:39:07.179Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cf/774845ff6c8bf26ceb1f439c4189bad1d31c6cd8da91f7fd88f3b6684edd/granian-2.8.2-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:89db0fbec47cc45c9044c4b91ca0ce00d6f048145eaa3f49e9d4b1e420057fd6", size = 5068503, upload-time = "2026-08-23T17:39:08.485Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9c/e24207aefdb08ffd9d07797d261117dd7f92b503416aab238b2ed7bae946/granian-2.8.2-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6521b5022e8d4fa0e7c68f5189ce00f5e83af7a36e84f0475f02612aa1c8c70e", size = 4594912, upload-time = "2026-08-23T17:39:09.94Z" }, + { url = "https://files.pythonhosted.org/packages/29/b5/41a8d350c3f9414f62c136290f5ffa866d589a7b225046be5839f5e9b199/granian-2.8.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d33a2be566fdb81fc6de918930a9cd3b434eb6d696a086ddbb0ff73c180402c", size = 4982988, upload-time = "2026-08-23T17:39:11.511Z" }, + { url = "https://files.pythonhosted.org/packages/9d/06/c80cc94cb48d39c59ddac3f83cbea7f25bd869b9c90d021932ea0b3eca8a/granian-2.8.2-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:52d59102c33717960edd3ffc4d81719509e15f06f049e6321e41ccf444d58eef", size = 5151722, upload-time = "2026-08-23T17:39:12.893Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a1/e0ab4e7ab2c24976230d7a925492c5d7337c53fcde759d793f614bb1bbaf/granian-2.8.2-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:e829a39c3ead7e91ab58cbf82800cdac4306a71805962d5e0ddb0c292d521696", size = 5186052, upload-time = "2026-08-23T17:39:14.335Z" }, + { url = "https://files.pythonhosted.org/packages/ae/2c/b88aaad8cf77d88efa9409d4defc624e9b50d223aaf5765e511a8d3f4791/granian-2.8.2-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:37536dcc0592bc7f65dcbb260173e7d5719207fdf3f8dcdc8d573bc664ad014e", size = 5170986, upload-time = "2026-08-23T17:39:15.88Z" }, + { url = "https://files.pythonhosted.org/packages/8d/02/b1ad423fe2bc981b38e42d701284aa16f39d4711e5322af5707496729e4e/granian-2.8.2-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:3a01905b1cef50c502f1866434770b2821a7ccc2cdd7b9d8ab06dee84e19720b", size = 5083593, upload-time = "2026-08-23T17:39:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/a6/f0/16d5281e21e677443afc26a504340bee8bd56194dc07a3f07bc9e5ca7903/granian-2.8.2-cp314-cp314-win_amd64.whl", hash = "sha256:23474c7cd397741bd375f2a2c66244c0406f8911619c59a260149b22f86f76c9", size = 3145278, upload-time = "2026-08-23T17:39:18.712Z" }, + { url = "https://files.pythonhosted.org/packages/a4/dc/e497711f5379b8f09595f1d3989c0fd4e9198be8d5735797e5b23841e3e6/granian-2.8.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:825481c04ecd4c8e493a9f6c4b0f35d49ddf62a5576d7247e91d8e19a4bc87ff", size = 4483204, upload-time = "2026-08-23T17:39:20.186Z" }, + { url = "https://files.pythonhosted.org/packages/3c/ac/1e0ca7917b84d302f81929cfe1dc5ee43b58a759168008474ee9b52f3a16/granian-2.8.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:df45b9f1e7ddafe4e6e51382cb39cd458e99a5536278b5c5e713dac8c698bee7", size = 4268497, upload-time = "2026-08-23T17:39:21.7Z" }, + { url = "https://files.pythonhosted.org/packages/48/2a/122ff8c770824e34b852d32b8d3ad9562b246b4740b978a5f6b616e2f4b4/granian-2.8.2-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e16cd27f6896238d9a09998e1bd2244a68b0ea43e6325f2e6107fd6497731248", size = 4408212, upload-time = "2026-08-23T17:39:23.064Z" }, + { url = "https://files.pythonhosted.org/packages/25/8d/a1a287b41da872bd9a014b6fefe80d9a224f9d709b5b0b3b4583e2ff8766/granian-2.8.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7e624b05e9c7ef50cbf7f3fb69d54a8b8e5924c21161634f02d93e2cbe845337", size = 5027091, upload-time = "2026-08-23T17:39:24.401Z" }, + { url = "https://files.pythonhosted.org/packages/74/23/3e2a836393f49e5a637049ef91a2ac1ab3088c5512fd1e3795745f152e0c/granian-2.8.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b659f4f8cfa388734550db794752dcf8fb7bcef7fa2e55ba877e961350fcb8fb", size = 4876201, upload-time = "2026-08-23T17:39:26.325Z" }, + { url = "https://files.pythonhosted.org/packages/c1/13/201a2709a0d5068d65a8b0c055d563ea8e8ca522e41520589a7629a2b62b/granian-2.8.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:77a1119ef84fbde0c4705cb09f3ebaa23807f5d4ddf4d1a5f7bf11056842b8d5", size = 5015172, upload-time = "2026-08-23T17:39:28.008Z" }, + { url = "https://files.pythonhosted.org/packages/17/41/c684ca1ed8cd2e84278d39d741cdaf39c3b8698a141e1f22370e44c54fc1/granian-2.8.2-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:8af72cee8823da6280251e53aec774abfd093588a6db9ce8193d0076851601d1", size = 5211701, upload-time = "2026-08-23T17:39:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/38/cc/0d8680d6cd9cd1f2e0629e2a999185cdb6e9c8e14e76fb31404167ab289b/granian-2.8.2-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:886e727e11706897db81d97b976c12e3613c22df299d56bde446e71906ebbc9a", size = 5160925, upload-time = "2026-08-23T17:39:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/76/83/3ef6394c090e33bc69905a630852b3931b7009f610403ca5facd7d99e046/granian-2.8.2-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:de73d86d7ae6af5b6248840c4b700a39cdb13f7ac8f5e31d74f203c8cffad8fc", size = 5116259, upload-time = "2026-08-23T17:39:33.248Z" }, + { url = "https://files.pythonhosted.org/packages/9d/09/75c9b7d78d0a15fe6b74a160fbc799d141fea9b67ef869c149bccc2de0a7/granian-2.8.2-cp314-cp314t-win_amd64.whl", hash = "sha256:144af53b25ef35e119cb15b79514600896c6f5f3bdac83f7d6c80a2a7384cfaa", size = 3109679, upload-time = "2026-08-23T17:39:34.931Z" }, + { url = "https://files.pythonhosted.org/packages/40/f6/1677a9266332a6d044247af0f89e98d89fddfa6c93ae598ed7db3be9b904/granian-2.8.2-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:63fc5f40e7e258be3f61199a73fd85f49b74d0514fbc993f5e6263fa9d104013", size = 4515394, upload-time = "2026-08-23T17:39:36.407Z" }, + { url = "https://files.pythonhosted.org/packages/03/5e/b01066c3a5695fc97654855617222c0d4e77dafd94c31dc7a1b2ed0349d1/granian-2.8.2-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:f42da6a579030774a25df67b5432ced73bd2f8eda36df11d79739059c03c4740", size = 4318475, upload-time = "2026-08-23T17:39:37.814Z" }, + { url = "https://files.pythonhosted.org/packages/7b/81/ca766e0f223cf88e8abcd1e9edc7513b0a4960f9c351d2b9bc594545293e/granian-2.8.2-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:927e248fc2225709ef82d8fbec88e1bc44286cfcb2e033e83d9bc935e863a897", size = 5067760, upload-time = "2026-08-23T17:39:40.097Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/741cc89d3820b2d771b1f318450ebbf4d6c992b98df2e9bbb07a93020321/granian-2.8.2-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbbe64f19cdceb306b91bed01ce875e3f4ffcbafedaf2d30bedbeb33682a026d", size = 4594947, upload-time = "2026-08-23T17:39:41.566Z" }, + { url = "https://files.pythonhosted.org/packages/72/47/6eb90fdedf5c90d0057c64454a75bb3d108e942b29284ab05a5bade7b70e/granian-2.8.2-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225fc15fce8201a3d341e2eaece168a6e344dcf38cace59ecf2049be286dca33", size = 4983791, upload-time = "2026-08-23T17:39:42.928Z" }, + { url = "https://files.pythonhosted.org/packages/9d/b0/e62d321d983cfe7ac4a0472b5d66ef672aeebec7c3d9d4b6ab4fbaabf4f0/granian-2.8.2-cp315-cp315-manylinux_2_28_aarch64.whl", hash = "sha256:d3c881e567ee36f791b850358154daadb5b1262a9bf8a56b2048f53586b1e678", size = 5150521, upload-time = "2026-08-23T17:39:44.354Z" }, + { url = "https://files.pythonhosted.org/packages/5b/00/8fb27a5f60bb0ebab2089153c438190f154613f7838ae6ac3af1d33ab408/granian-2.8.2-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:f20441ccb3b500c5e6368afc237257775fb893584aebc087157056f78643f3e8", size = 5185020, upload-time = "2026-08-23T17:39:45.903Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c8/5d85ca4818e74f9ac0ac71a88752a2f81655e3df787da7698667141fcd4e/granian-2.8.2-cp315-cp315-musllinux_1_1_armv7l.whl", hash = "sha256:1dc5155ccadeedafa25baea4ad2cd3003db7127257ef1eb623039b2e7087c759", size = 5170661, upload-time = "2026-08-23T17:39:47.35Z" }, + { url = "https://files.pythonhosted.org/packages/bc/30/7248eafd8742ffb47ebcfd194a211b6447445214859ececbb2b26e0d4357/granian-2.8.2-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:80c10fd8879dd5972ef67cc91255d628e860f477b0f9c9f165331132916ca637", size = 5082632, upload-time = "2026-08-23T17:39:49.201Z" }, + { url = "https://files.pythonhosted.org/packages/51/59/345032b735050959c59a12e2c8cd2def3561751824ee9c08ef0779f4f3f2/granian-2.8.2-cp315-cp315-win_amd64.whl", hash = "sha256:e4ebcde088974cb23332f921b6418448d4328873311006798e61e23ceb773376", size = 3146049, upload-time = "2026-08-23T17:39:50.663Z" }, + { url = "https://files.pythonhosted.org/packages/1d/69/0a8938c3a30fbaba97d89df23d15ac05bf5a5bd9afea318734a6ad17efaf/granian-2.8.2-cp315-cp315t-macosx_10_12_x86_64.whl", hash = "sha256:0c78a53649ce6aa238fa7da79a4a93931cacd80b7e9bdbe89b296902f2533aed", size = 4482600, upload-time = "2026-08-23T17:39:52.278Z" }, + { url = "https://files.pythonhosted.org/packages/8c/8a/dc58d836789d4eb8e488419dd1ba2a6328b9d8ffa6465319d235a9a24c50/granian-2.8.2-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c14da904d02f71b22e02004188ee0df66568415f6941ea32f124a0c07d57b88b", size = 4268982, upload-time = "2026-08-23T17:39:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/0d/8f/0533072ff8f4b6e11ce722277ec65ba88879ab654dcf3f46d20c209ad70c/granian-2.8.2-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:94ea4531e2bbe385cc2dc965e1cb33015996e808f966c0a334ee2ad8f381264b", size = 4409316, upload-time = "2026-08-23T17:39:55.293Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b2/e8e9b6a3da2892673804c59c9a7c8fb29bcf40bda99f283cd47d5dad7088/granian-2.8.2-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15104fb8e7946a6639eccd89c16d05c43ecdd493c97c415d1ad0b00cb6722540", size = 5024561, upload-time = "2026-08-23T17:39:57.321Z" }, + { url = "https://files.pythonhosted.org/packages/e4/21/03f438fbcc1ca6137f5af59ff58c7eca2f5b91bd0b443a59440304ae1fbf/granian-2.8.2-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3e58821fce2fa93406bba043eac6a8c24518e63d9ead044623d1fc92205380f", size = 4876756, upload-time = "2026-08-23T17:39:58.917Z" }, + { url = "https://files.pythonhosted.org/packages/34/53/6e2539b4c667cbaceea672b2080cc7093f58b7274c787a49c17e0b086bdb/granian-2.8.2-cp315-cp315t-manylinux_2_28_aarch64.whl", hash = "sha256:39fadbc69e5279d1b5181411d80239a0ffd1fa75422903fb97e871545c8edb5d", size = 5015270, upload-time = "2026-08-23T17:40:00.493Z" }, + { url = "https://files.pythonhosted.org/packages/f4/48/ae77db1206b2409149b4a96192354250042a7664b412346d3e5b6824665c/granian-2.8.2-cp315-cp315t-musllinux_1_1_aarch64.whl", hash = "sha256:956968b9b32a74eaade95502c1664038c978731c17bb2c4e039bbdcf0279653a", size = 5211393, upload-time = "2026-08-23T17:40:02.648Z" }, + { url = "https://files.pythonhosted.org/packages/d5/b4/0af0d59f172dfa6e56c55911e6461d7fff0d088268e02cef5e9598a9143b/granian-2.8.2-cp315-cp315t-musllinux_1_1_armv7l.whl", hash = "sha256:214d4e1b7353216e3ec16cc49d8eecb29e8949ae6e2a815891250465b7c3b0f5", size = 5161076, upload-time = "2026-08-23T17:40:04.177Z" }, + { url = "https://files.pythonhosted.org/packages/e6/77/cb8b3de1a9e33e0f9b17b74a594377c9600348758f051a2b720a82665643/granian-2.8.2-cp315-cp315t-musllinux_1_1_x86_64.whl", hash = "sha256:587f1121c44cab7df8d71b3f9bde0ac90d603096685ba212a4e193ae6fd2209c", size = 5117000, upload-time = "2026-08-23T17:40:05.907Z" }, + { url = "https://files.pythonhosted.org/packages/f5/94/0097b0b7214cedb8d39f2dc6f571fcb9b478148a11b6f6cda8ef2dda08ef/granian-2.8.2-cp315-cp315t-win_amd64.whl", hash = "sha256:c4047b3dd1b581b56808a8a5e6932bb246c81cb7de3b5eeb82b2fca23233f6b3", size = 3108913, upload-time = "2026-08-23T17:40:08.203Z" }, + { url = "https://files.pythonhosted.org/packages/9d/37/8e8a304527630457e8045ffa904864ddbeaddef7482b9681973302752151/granian-2.8.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d275ca1b6dafde6807a5b1baece9f49ecf63c2cb744f61e774800c07cac78d0d", size = 4656379, upload-time = "2026-08-23T17:40:09.864Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e6/e8195bc4847cef39cb335bd75c440c11c13d80c6dbd7c19cb59a09d75dee/granian-2.8.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:42be026b47f8bc6beda8ce01a8a193e297a93b62613340a746a06a8a17751a81", size = 4483819, upload-time = "2026-08-23T17:40:11.44Z" }, + { url = "https://files.pythonhosted.org/packages/83/6f/b4453648d3e3a812d757dde46d7fa5264b5ff5b16f1b8a6367cdac108cae/granian-2.8.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0310c68d288b7892d0ae852ec0c5e1e894a1c642deaca1e07ca18960e3336851", size = 5090340, upload-time = "2026-08-23T17:40:13.166Z" }, + { url = "https://files.pythonhosted.org/packages/a0/56/b96f84606653875cff972d418514079e634613be9845a22213045de63054/granian-2.8.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5e70dd701be4263c6b2b2f16094bcb6f6ed03fe7782165e40f850fb746a109b8", size = 5266359, upload-time = "2026-08-23T17:40:14.873Z" }, + { url = "https://files.pythonhosted.org/packages/49/69/94ba53cc13222b54747b8aedf60900d776f077548ff44749b04aa6ad859c/granian-2.8.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dac13e7f83f797e9a9106ce6d6e0263a65962188ceba74326fcfbe1d485c658b", size = 5303236, upload-time = "2026-08-23T17:40:16.564Z" }, + { url = "https://files.pythonhosted.org/packages/80/97/020970b6a28ce1faaf7867ffb027d46bcd9d52352a27e6312c517525fff0/granian-2.8.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:77dacca3c0a858b958a7442557652d182f985a3b335f43d22e65d46929975f22", size = 5065183, upload-time = "2026-08-23T17:40:18.29Z" }, + { url = "https://files.pythonhosted.org/packages/9b/9b/a2071665a342905dfdacfd774e21cf380274bc0c4da95e249b5c7b5e136e/granian-2.8.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:8475e23ea2aa9dae4bac28f3ccae403e2cd07c36162a2b4a2bf8dbe43cf28509", size = 5186529, upload-time = "2026-08-23T17:40:20.017Z" }, + { url = "https://files.pythonhosted.org/packages/8b/6a/0d333d1e2433348bcd87d0d0281c6c4abfe2a66a24c90180faa15597b7b0/granian-2.8.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f5967b021e36448d870012c0853342a119d7427ea67e3b23abb8798897bf14be", size = 3148213, upload-time = "2026-08-23T17:40:21.607Z" }, ] [package.optional-dependencies] @@ -1316,123 +1298,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/8d/d236e9c82fe315f9128885c8be3ec719f41965a1eb6b6f4b42470904cd41/pyarrow-25.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:13240f0d3dc5932ccd0bfa90cd76d835680b9d94a7661c635df4b703d40ce849", size = 28743657, upload-time = "2026-07-10T08:29:42.742Z" }, ] -[[package]] -name = "pydantic" -version = "2.13.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.46.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" }, - { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" }, - { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" }, - { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" }, - { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" }, - { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" }, - { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" }, - { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" }, - { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" }, - { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" }, - { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" }, - { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" }, - { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" }, - { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, - { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, - { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, - { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, - { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, - { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, - { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, - { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, - { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, - { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, - { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, - { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, - { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, - { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, - { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, - { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, - { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, - { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, - { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, - { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, - { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, - { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, - { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, - { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" }, - { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" }, - { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" }, - { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" }, - { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" }, - { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" }, - { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" }, - { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" }, - { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" }, - { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" }, - { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" }, - { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" }, - { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" }, - { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" }, - { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" }, - { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" }, - { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" }, - { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" }, - { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" }, - { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" }, - { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" }, - { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, - { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, - { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, - { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" }, - { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" }, - { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, - { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, - { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, - { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" }, - { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" }, - { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" }, - { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" }, -] - [[package]] name = "pygments" version = "2.20.0" @@ -1492,18 +1357,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c5/b2/1d2a993c532146dce9eca5b5942d51898021c3579ce18b2454f932a915f8/pytest_codspeed-5.0.3-py3-none-any.whl", hash = "sha256:fe2ea83c924c2250675b75686c3ee456b8cf0208d83d552e182a195fdf467378", size = 74033, upload-time = "2026-05-22T16:20:26.814Z" }, ] -[[package]] -name = "python-engineio" -version = "4.13.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "simple-websocket" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cf/56/10a529f5396df653181f747997f970dba31f8f2eac3b9a88c1f9d7bb25c3/python_engineio-4.13.4.tar.gz", hash = "sha256:413cb98d56c62f0f5ef29931592a360d437b82b3fa7ab415da3f6c7d3ebc0cb7", size = 79880, upload-time = "2026-07-31T10:30:55.852Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/3d/26e14cf47c56c9ba3c3e12cae21f24716bc3182bb52260213ec0c819d0b9/python_engineio-4.13.4-py3-none-any.whl", hash = "sha256:272de73124e255d3d2bba6f86358c1a1ba618f938f337a0c868b60550fe38719", size = 60129, upload-time = "2026-07-31T10:30:54.637Z" }, -] - [[package]] name = "python-multipart" version = "0.0.32" @@ -1513,19 +1366,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, ] -[[package]] -name = "python-socketio" -version = "5.16.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bidict" }, - { name = "python-engineio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/32/2d/ffce71017c106b75099fea569df6518c63fee5d6202ce0cfe7b01e6f22c3/python_socketio-5.16.3.tar.gz", hash = "sha256:89b136f677ae65607a84cecda9b4d6c5377b40a97582c504c25df89af16d520e", size = 128095, upload-time = "2026-06-15T22:07:04.003Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/38/8c5e72d53ff8eb27497c4f268a7f6d9121e727a50b65248288ad79a93053/python_socketio-5.16.3-py3-none-any.whl", hash = "sha256:e7ad14202a5e6448824c7c2f86161d04e13dec05992257df5c709e6a2798c041", size = 82087, upload-time = "2026-06-15T22:07:02.498Z" }, -] - [[package]] name = "pyyaml" version = "6.0.3" @@ -1595,8 +1435,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.9.8" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1604,7 +1444,6 @@ dependencies = [ { name = "packaging" }, { name = "psutil", marker = "sys_platform == 'win32'" }, { name = "python-multipart" }, - { name = "python-socketio" }, { name = "redis" }, { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1625,46 +1464,33 @@ dependencies = [ { name = "typing-extensions" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/b7/73bedfef3eeab60b3f3c675f292dddbed7061eff5524515e5b7e5c9a035f/reflex-0.9.8.tar.gz", hash = "sha256:ed0d2905c4968226e37da6999ccad77d4600a1370399afbed1038826dec3fc9b", size = 406093, upload-time = "2026-08-04T18:55:55.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/c8/d34ac31978bce63d9bddcbd3ed1522ce0f367290a5923a6e3012618c5583/reflex-0.9.8-py3-none-any.whl", hash = "sha256:4f50452f5c6540d98711bfdc138085ce5339c5b3b2cf27444b93952e10906f86", size = 660205, upload-time = "2026-08-04T18:55:53.86Z" }, -] [[package]] name = "reflex-base" -version = "0.9.8" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, - { name = "pydantic" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/5d/9d9bed0d9294276d7e4b7d9b1e6f3185fa888657d0e73a996de30012a6c7/reflex_base-0.9.8.tar.gz", hash = "sha256:e4c6c5a221920c153361f7855c8ab6dc43fc6a9f1dfce402c6d631728f313d82", size = 275540, upload-time = "2026-08-04T18:54:24.365Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/f8/16f00aceb2f8cac1d42c4ed47f91d76aa4fa242fb011e5cfe0fe27449589/reflex_base-0.9.8-py3-none-any.whl", hash = "sha256:e91c453fef26b70d058bcc926f5811d01e8b01257f033507efed22734ed3be8f", size = 315203, upload-time = "2026-08-04T18:54:25.317Z" }, -] [[package]] name = "reflex-components-code" -version = "0.9.3" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, { name = "reflex-components-lucide" }, { name = "reflex-components-radix" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/28/599dc8a3f78a0ad2cb2981c4bc2f0db7c10b3b28e2b3173b524139f549c8/reflex_components_code-0.9.3.tar.gz", hash = "sha256:a6127241d3d0ce43ca2466eb6357447ea4d596b9bbb92a1aa479413799c0bcc7", size = 19648, upload-time = "2026-08-04T18:54:19.274Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/53/729de287888513dfb0cbb267ff91ce615993fb876ec75d03acfcaf16f96b/reflex_components_code-0.9.3-py3-none-any.whl", hash = "sha256:32a3d0c6d17f8950affe0ae3768149e2f1c637d38b634813878f4ad62e4b766b", size = 24157, upload-time = "2026-08-04T18:54:20.145Z" }, -] [[package]] name = "reflex-components-core" -version = "0.9.8" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1673,144 +1499,100 @@ dependencies = [ { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ee/a5/4c9fe7f48838cae2d7059e69a3e9c5460c0cb8d6f1637d01dbc8f6de39af/reflex_components_core-0.9.8.tar.gz", hash = "sha256:a07599767a4cafe9d95e604eea1f46e45dea30569a9e35439483e2ebbccbe989", size = 109553, upload-time = "2026-08-04T18:54:30.369Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/dc/6db089f17eb00da7528375b109d71eb8992e188a1ff638fecbe4b88dc760/reflex_components_core-0.9.8-py3-none-any.whl", hash = "sha256:30a1ef058c698a4d6338716d308c205f03c5a4ea14caec50f98db4ac6fe09129", size = 177847, upload-time = "2026-08-04T18:54:28.314Z" }, -] [[package]] name = "reflex-components-dataeditor" -version = "0.9.1" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/13/a0cbecb1ea03d79b3943dcb236e07778da7b83917ad34149aa43e8b20480/reflex_components_dataeditor-0.9.1.tar.gz", hash = "sha256:eedb9a0807286f4c870bea92a0e94cac10e2c6decc6f495600810bfeb1b0c329", size = 8219, upload-time = "2026-04-27T20:56:49.894Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/dc/c7e5ac166f23a10899e44d4133f260a0be906279b1698dd63846a21d3324/reflex_components_dataeditor-0.9.1-py3-none-any.whl", hash = "sha256:8d2dec22fe0c227c44f45226624ffa87227e8ab81acab1f5f17c6dd1efee9372", size = 10776, upload-time = "2026-04-27T20:56:50.576Z" }, -] [[package]] name = "reflex-components-gridjs" -version = "0.9.1" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/ec/785dec6e349525596ffe2a0cdc2c866c4dd7586aaffe5a90b4ef72829267/reflex_components_gridjs-0.9.1.tar.gz", hash = "sha256:78f9aa0a63b06dc919b4e7b3cb23764558199aeefd3aa59fa556c6430ead9a64", size = 3226, upload-time = "2026-04-27T20:56:39.165Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/08/fac0660cc51a705552e91270c3df39e3a4292ce570e10f64cf39a1bed960/reflex_components_gridjs-0.9.1-py3-none-any.whl", hash = "sha256:02582137af88ce7c3983a3fc494b746cfb9fee5bc69a96ae03027c8a102a4b13", size = 4303, upload-time = "2026-04-27T20:56:40.302Z" }, -] [[package]] name = "reflex-components-lucide" -version = "1.0.3" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/e9/89ddcbaf1b80252e7e21864a5d71de949808e7265aaff6dbaf2972a936c2/reflex_components_lucide-1.0.3.tar.gz", hash = "sha256:3e58801dc5a1355d7cf09181b315005af52cc8936c9c937249b76c33734310e6", size = 20367, upload-time = "2026-08-04T18:54:17.804Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/32/d7eb13de1d9e79e01bd1bbe4453674bf5300b771de8e3f39ccf6a9d55661/reflex_components_lucide-1.0.3-py3-none-any.whl", hash = "sha256:c50ae0557252339a592407d6472e9b67c1a3519a875a39db6674e8efa8aded21", size = 20463, upload-time = "2026-08-04T18:54:18.603Z" }, -] [[package]] name = "reflex-components-markdown" -version = "0.9.3" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, { name = "reflex-components-core" }, { name = "reflex-components-radix" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/86/28ccdc6ba418b48539257bf794932711ccd37b4d911ea420dfc018d2a564/reflex_components_markdown-0.9.3.tar.gz", hash = "sha256:cec631217e893b21a202cb86734d204a9a268d4f5cac8c6711c19d90e09b62be", size = 8089, upload-time = "2026-06-04T01:44:13.45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/c7/72720fb15d02681466b56c5af7ca6b84831cea8f776446bfbf95af7feb9b/reflex_components_markdown-0.9.3-py3-none-any.whl", hash = "sha256:4bd8a6d0be5c4b715e855936e49ca513caf7ba470d2b07d87f60d11c53edde1d", size = 9795, upload-time = "2026-06-04T01:44:12.692Z" }, -] [[package]] name = "reflex-components-moment" -version = "0.9.3" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/0d/65d07250c6a61a9f9c006cfc23b8b4fde4a70ef5f1270a53961ee467f691/reflex_components_moment-0.9.3.tar.gz", hash = "sha256:e470f3eed6905c15189215c11bee775ddbe58b943e4d1a5aebff9a2ca1ef5dae", size = 4224, upload-time = "2026-08-04T18:54:22.486Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/28/7477b9663118d9cf602a1393a182d4e02be85e60523dda4bd859e978e811/reflex_components_moment-0.9.3-py3-none-any.whl", hash = "sha256:1645b2c67f5d753508cf732a17c270ecd41464139c1acec04b3232c8f1d4f3f8", size = 5287, upload-time = "2026-08-04T18:54:23.206Z" }, -] [[package]] name = "reflex-components-plotly" -version = "0.9.4" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/e8/45cd231f3225239ee215c7f701fc5ad4d57d31f598292ff2512e629672e4/reflex_components_plotly-0.9.4.tar.gz", hash = "sha256:bef809afc62be80e592a21dfe2e0d006f5ec86bd6b341cac43424dfdff41319b", size = 7254, upload-time = "2026-08-04T18:54:25.53Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/d9/0f0fcd90ec077779e2c030b2abd6685d52b46848730dec32996048b9245a/reflex_components_plotly-0.9.4-py3-none-any.whl", hash = "sha256:c99cc9d259231d15ebe73f4070108309e19868a74f4b1ecd776ad7f92f56d2a2", size = 8312, upload-time = "2026-08-04T18:54:24.624Z" }, -] [[package]] name = "reflex-components-radix" -version = "0.9.7" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, { name = "reflex-components-lucide" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/7b/8df7e7462e9837e1b11e1b73c34dcf1640b8b4a97ce37d7a609a31163961/reflex_components_radix-0.9.7.tar.gz", hash = "sha256:e50a5f71ac65c52a1868041225d5dc21c2d4276c036fc9b9d8685fb62bbd939a", size = 114585, upload-time = "2026-08-04T18:54:24.521Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/8b/aea526621cb00ad861f2a9b57349807674d358d21c06678241af2376ce7e/reflex_components_radix-0.9.7-py3-none-any.whl", hash = "sha256:3e9b8215b9a5f2e219926362ed807030cbf82fecfcef83450232bddcb5553ec7", size = 271699, upload-time = "2026-08-04T18:54:23.034Z" }, -] [[package]] name = "reflex-components-react-player" -version = "0.9.1" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/6c/d8baefacba10e2a91f13eadc027e17ba38a7b6d2ed083e121f5dde4e8e59/reflex_components_react_player-0.9.1.tar.gz", hash = "sha256:5ba227e1c8601cf206923d4095ad4f241fcc176937dc627e1c2deaced3803199", size = 5004, upload-time = "2026-04-27T20:56:48.576Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/96/cc6c29bc4e85c3de8915c2a2469d8b82e463f4e311486f7fded5a7399ac6/reflex_components_react_player-0.9.1-py3-none-any.whl", hash = "sha256:f9c3e4f9d8bd7e3cf56a18d9e8d83bd2980d9c57db81e7325ef1f0654a8c1847", size = 11276, upload-time = "2026-04-27T20:56:47.721Z" }, -] [[package]] name = "reflex-components-recharts" -version = "0.9.2" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/de/d987e3c68973c6f818dc73ae1d13910b70113e3221fdf8d61866d6f3582a/reflex_components_recharts-0.9.2.tar.gz", hash = "sha256:d79866b90b9968abd0998da318e8842a218f807c151de8d2b58648074efbb662", size = 32968, upload-time = "2026-08-04T18:54:25.737Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/28/49/dc5c98fbf1a8ea9828388df9e6561ed443ce4b217f1df93b7d3c3e82530e/reflex_components_recharts-0.9.2-py3-none-any.whl", hash = "sha256:fba108ad9ab049131c407dbf376b8716fb34ac03738d62ba40e02555607017b3", size = 44583, upload-time = "2026-08-04T18:54:26.618Z" }, -] [[package]] name = "reflex-components-sonner" -version = "0.9.1" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/e8/831fc0ad0074df749642da94c8baa02e47719110bdbf862a9c44fbd3c016/reflex_components_sonner-0.9.1.tar.gz", hash = "sha256:1c8a45db24a1beced3d4d90048c415811022bfae6a3b95dc8925e064edfaf1cc", size = 5628, upload-time = "2026-04-27T20:56:43.453Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/a6/9cb6672f7cf6d0d21d803ee6f22446cc5e3ab01448d01e42b7b42023dcb0/reflex_components_sonner-0.9.1-py3-none-any.whl", hash = "sha256:a6051e0f178fe5e644f936e55833bb9149126e08c6f41550b1f488ece68d794e", size = 7433, upload-time = "2026-04-27T20:56:42.148Z" }, -] [[package]] name = "reflex-hosting-cli" -version = "0.1.68" -source = { registry = "https://pypi.org/simple" } +version = "0.0.0.post3495.dev0+02dae560" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -1818,10 +1600,6 @@ dependencies = [ { name = "platformdirs" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b4/ea/fbbaf062b201929ff76ddbdf57107546de2466a4f4b83bb1a438b34d7c42/reflex_hosting_cli-0.1.68.tar.gz", hash = "sha256:c5341578134b2f7c486ec3e4a675338e2985f0ffaaa2f9a30f9a0233a0791d08", size = 50968, upload-time = "2026-08-03T19:43:17.311Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/7d/5fe9e6b2682faa21c0a3f2b86582d6c4bae6654fa145f9b552e9eed424c6/reflex_hosting_cli-0.1.68-py3-none-any.whl", hash = "sha256:1f4d3405c611da7374516dbc6837040ae0812de39483d1aa3133692a3df3836e", size = 61159, upload-time = "2026-08-03T19:43:16.227Z" }, -] [[package]] name = "rich" @@ -1861,18 +1639,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/e2/77be4fff062fa78d9b2a4dea85d14785dac5f1d0c1fb58ed52331f0ebe28/ruff-0.15.8-py3-none-win_arm64.whl", hash = "sha256:cf891fa8e3bb430c0e7fac93851a5978fc99c8fa2c053b57b118972866f8e5f2", size = 11048175, upload-time = "2026-03-26T18:40:01.06Z" }, ] -[[package]] -name = "simple-websocket" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wsproto" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300, upload-time = "2024-10-10T22:39:31.412Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842, upload-time = "2024-10-10T22:39:29.645Z" }, -] - [[package]] name = "sortedcontainers" version = "2.4.0" @@ -1952,18 +1718,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] -[[package]] -name = "typing-inspection" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, -] - [[package]] name = "uvicorn" version = "0.52.1" @@ -2090,6 +1844,161 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", size = 323166, upload-time = "2026-06-29T18:11:09.888Z" }, ] +[[package]] +name = "websockets" +version = "17.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/72/fba934cb3dff7a85d811820efffcd141ddd52b5a2a01637f64551373ff4d/websockets-17.1.tar.gz", hash = "sha256:acfea4c20bf54384883ea33b1240fc1db4f52e190823a4e2b334bc3e8bfca96a", size = 187520, upload-time = "2026-08-26T17:25:33.063Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/ad/66a74d42fb537bd44056483eae6cbb7ebb10b742c300a0bf8cee427556d4/websockets-17.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:88b882764ef65147a7a5ae13168dedbe225a04e2ff4858fe543f2c402f093e9c", size = 216984, upload-time = "2026-08-26T14:55:20.747Z" }, + { url = "https://files.pythonhosted.org/packages/70/1b/344ab22cea729e872f759b926441f7b822ab6cd106db527736afc066927f/websockets-17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98a5b2589a56a4b4f098b0a958099a4356ab904a7844f1da3841efca469af7e9", size = 214667, upload-time = "2026-08-26T14:55:22.298Z" }, + { url = "https://files.pythonhosted.org/packages/2e/42/bace574b6ae80e1a8d6935b8c5f03fb67236233ec572e976fe826ff719cf/websockets-17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:020e271205f8ab3406d7a59cd00de6dec722315924411c421bd00642f18bad86", size = 214944, upload-time = "2026-08-26T14:55:23.618Z" }, + { url = "https://files.pythonhosted.org/packages/ee/87/08e35ca4a0ffafb500a16ff461bf9561ad2b755362adb5d077d4dba9affc/websockets-17.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:65be6bda2b537fefa4b3a5ccd6ab386533ce39dd8fe62433ec90901fdc81752d", size = 224004, upload-time = "2026-08-26T14:55:24.748Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9a/00ae2e147eaa086fe8bdddd36f57216ce72b9a9dfc0b17c717005ebdacaf/websockets-17.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0c84bdef916556cbe1d5a43b423398be4dd3cba6522b463e53d848578b920695", size = 224278, upload-time = "2026-08-26T14:55:26.016Z" }, + { url = "https://files.pythonhosted.org/packages/98/e2/7aeb4e00defa68826f449392922a382ce7fdf542fe52190558dc1714e284/websockets-17.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47a62d6045c6eaa0d8f97bc2fb68b8cf90077a0cbfd4e83d6f2d2145611ee134", size = 225511, upload-time = "2026-08-26T14:55:27.183Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e4/655be3d93c3edbe1a51606073b5454ea6b1b32d87aa26253a6df952417b7/websockets-17.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34879e19bb0a3c44f9317679435aea5327fac993933a704cbf353bf1234b10c7", size = 228802, upload-time = "2026-08-26T14:55:28.431Z" }, + { url = "https://files.pythonhosted.org/packages/e4/33/98549a2afa9d68fe1b5a8e0a61cd461a43ea1ab7209bce675eea67c79190/websockets-17.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2d72879819f5145a342d0030c418702496c65a4b913ef81f5ae944dd91dd50f6", size = 226075, upload-time = "2026-08-26T14:55:29.695Z" }, + { url = "https://files.pythonhosted.org/packages/8e/6b/cbc27e014d6c292b9b2709cfd32781a2b61eb30cd4c9130e7c57e41a204a/websockets-17.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:84f25e099fdfe3b09f953d84698f729a1f7d1e99101b2787d7a28ed77b323750", size = 224846, upload-time = "2026-08-26T14:55:30.964Z" }, + { url = "https://files.pythonhosted.org/packages/10/a6/e57925f7a423d90f24559e85bac21a7f0b44c0cf4a5c0babc0759ca54bab/websockets-17.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:469355ab1af100b9380f1afb09985019f4a4b94fa1dd0e9396db4361626d7ab8", size = 222136, upload-time = "2026-08-26T14:55:32.376Z" }, + { url = "https://files.pythonhosted.org/packages/32/07/b9de0400addb542ba7c819022abc3afa46cd7e518068881bceadac69d995/websockets-17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:00679b7468b4c2b12b0757118174e8eabac56bb2f579a928a104d9554a56e098", size = 225000, upload-time = "2026-08-26T14:55:33.527Z" }, + { url = "https://files.pythonhosted.org/packages/4c/bb/af2828a1d7f2beb792af6ba56d7b02d56262070266b95d2af9ef391fbfb0/websockets-17.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a9fe648abd1d9b89aebfa30407bfdd08a0271ec5dc7d44a4c6ccd1ce22cf562a", size = 223592, upload-time = "2026-08-26T14:55:34.636Z" }, + { url = "https://files.pythonhosted.org/packages/fe/51/7379f254730c1dc7d8e4dd8d686868d8f7be55bdc94c6d3a44538840f639/websockets-17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f47aafd92aa28b941180e6da8a42b0f711851b14b81a5b6bb28dbbb1fa35152c", size = 224360, upload-time = "2026-08-26T14:55:35.777Z" }, + { url = "https://files.pythonhosted.org/packages/88/c6/fcd91320dd71dda7046df9bc60f60c70ee15c052dee21e31ed6221dc8b5d/websockets-17.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c89406fa3dcd4aa8662c6406cc5c0de1790e9614d2c3aaf03ca53a8a8ccf3405", size = 225404, upload-time = "2026-08-26T14:55:36.85Z" }, + { url = "https://files.pythonhosted.org/packages/1b/b2/655a4f939388079f80f1b3f8a1b9d40783e70a376e7423988cc9a590a09f/websockets-17.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:b3b451fd2723ad3191a209afe6f3f4bc86c83e9a85bdc255353b91803ee6aa66", size = 222982, upload-time = "2026-08-26T14:55:38.006Z" }, + { url = "https://files.pythonhosted.org/packages/87/75/37c84c4371c6aa668910d7841036c4397ea10554c07030603ccd5e44b02a/websockets-17.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:054c28db2dcec0e857e3b705d8c28012613e555b38c765d6a4f75340a4fc06a0", size = 224017, upload-time = "2026-08-26T14:55:39.39Z" }, + { url = "https://files.pythonhosted.org/packages/5e/20/8a9a94323bfcfe03bde3f9d98926bea4855856359702fe3ca0d07051ef5d/websockets-17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f8e822efd54137d8cc8310eb64635ab827a4a6c72ff08691f38aa624776d8ecb", size = 224252, upload-time = "2026-08-26T14:55:40.498Z" }, + { url = "https://files.pythonhosted.org/packages/3d/dd/aa66e6500188cd40306abeb92c9a738ca6dd7029d8d8532c538055ab5daf/websockets-17.1-cp311-cp311-win32.whl", hash = "sha256:dcb8d5f7edef7a399d322cf28d4c4e6f98dab64d301c8f50581a1080e5198142", size = 217484, upload-time = "2026-08-26T14:55:41.763Z" }, + { url = "https://files.pythonhosted.org/packages/01/a2/cdf3b551f0b9177023afd3a45d3b431a0d4064951008c4321a8b42ac2288/websockets-17.1-cp311-cp311-win_amd64.whl", hash = "sha256:b1bc819c6db90e8f91a38250a1ab4c058261871aa52d2fe36382eddedf146dee", size = 217779, upload-time = "2026-08-26T14:55:42.942Z" }, + { url = "https://files.pythonhosted.org/packages/e0/13/51253dbed7d16a4bb87b05110ad3bf12165f410e915f6da1edd4186d8dc1/websockets-17.1-cp311-cp311-win_arm64.whl", hash = "sha256:edadce7a22052056fd4384543019856b34850363c9d387929f677ae01d79709c", size = 217710, upload-time = "2026-08-26T14:55:44.016Z" }, + { url = "https://files.pythonhosted.org/packages/a6/0d/098f23c4c858e5de9459ffc554fa07d5493fbcfca7f040b5800cf1cecc35/websockets-17.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:76dd004f59115087c7b700474cb18f01325e37250032e19396c08ae41448e4b3", size = 217015, upload-time = "2026-08-26T14:55:45.194Z" }, + { url = "https://files.pythonhosted.org/packages/13/86/bc1317b1a4d8c4688e2a7e564b5e004dab44c2534d7ca05de6ae9a863fca/websockets-17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:581fa678ef46f4277cc8491312468e582f8ad609dbab907ba6096a08c6a0ff98", size = 214692, upload-time = "2026-08-26T14:55:46.366Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e7/df821761772beaa48c211ee0e234930b35c1473778470773823f56d3911b/websockets-17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:87f0d5e77548b0c40c8464cdb6108792e7e53f487c6400028a4ec28a8afbe5ab", size = 214959, upload-time = "2026-08-26T14:55:47.885Z" }, + { url = "https://files.pythonhosted.org/packages/3e/92/c3fb72f11764812fc648bf3838d224972427b348e8b3989d9e0a9df87da3/websockets-17.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:882af300d2c6a092b93767d5de03c7bb56dfb06314140c8e872d3f48e09f7b74", size = 224278, upload-time = "2026-08-26T14:55:49.241Z" }, + { url = "https://files.pythonhosted.org/packages/fb/05/9f82d090c8d2d861604147ef6dfb938a90b039f9358d5193f1df62558593/websockets-17.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0c863507ada5805517ca6dff1c524dcd42942efe6304dacf06700878398d21a6", size = 224557, upload-time = "2026-08-26T14:55:50.348Z" }, + { url = "https://files.pythonhosted.org/packages/8a/50/5cbf677b865290fe36819ff00615826e7edc1df38786f770123ff39a933d/websockets-17.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d41ef69d5416fbc1d98cf96c37be6192d10fd101c3e0f8b3ddc36e09432b3c08", size = 225791, upload-time = "2026-08-26T14:55:51.75Z" }, + { url = "https://files.pythonhosted.org/packages/c1/1c/eb8a032285243381b09a221ae384c972d5000453ad136add4d1595cec798/websockets-17.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5aefe78e6a3077fe22b5e64b04666a85a3eb8b934d40e8595a693adcbceb6f11", size = 228574, upload-time = "2026-08-26T14:55:52.922Z" }, + { url = "https://files.pythonhosted.org/packages/69/85/413736251cb3ac04ce84cbd90e893d9a36a9698d4820b323aff3aa187e50/websockets-17.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f64e001bb7fa89b9f32cfa600bf8e9ac8ca26759d9b92ae01453ee303d9cd7b4", size = 226428, upload-time = "2026-08-26T14:55:54.263Z" }, + { url = "https://files.pythonhosted.org/packages/d2/2b/a08bcc7fa1ca81a10f84ba32b6e6edd73a913f4b0c2640eed1fd626efacd/websockets-17.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:677014a073bcb1fbaa7e21144786864f16c08f856d66834f611eceb9006cbab8", size = 225184, upload-time = "2026-08-26T14:55:55.943Z" }, + { url = "https://files.pythonhosted.org/packages/e5/8a/3bd2d0cf6b148c8c866d5d9fdcde30c04bfd81fdfac86813e69377eb4448/websockets-17.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0de501b7f2db11e83739ac20e2d33d46da4604b829f506c24be80e7def069391", size = 222430, upload-time = "2026-08-26T14:55:57.103Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c9/8e891ae342668735eabbbc669895e15195e4b45f24a4beeb58af76f414c7/websockets-17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f62114a54117e4948a1e414e89521f7fe1e3c2f83f2a571a06a4fc6718b0900a", size = 225227, upload-time = "2026-08-26T14:55:58.375Z" }, + { url = "https://files.pythonhosted.org/packages/e1/6f/c816f332dca11425e9bda7c07f7573eb5c5f8a735849d02b0d81e8ee20fa/websockets-17.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:eec113a5b41d124ef42ff56b0d74a6da3fd986400038eab9e58ee42a4024e837", size = 223831, upload-time = "2026-08-26T14:55:59.664Z" }, + { url = "https://files.pythonhosted.org/packages/53/67/5e91d5308ce24fc1ec74f56536c12f4888bad45ff5ea50f3180f8c518c57/websockets-17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5f051f8030a51815dc00e24bd2e5f1435af095c1cc111d747ac6e2a3620d7641", size = 224600, upload-time = "2026-08-26T14:56:00.873Z" }, + { url = "https://files.pythonhosted.org/packages/bb/96/faa298ecf2570d35b0eb37caddf4992178d907e108ed74bfffb6bc092c29/websockets-17.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:655a8e28010f09fd6fa317e857afab3af7647f33e41dee88fa421e92086d1090", size = 225707, upload-time = "2026-08-26T14:56:02.001Z" }, + { url = "https://files.pythonhosted.org/packages/0b/12/5710d2482ca5061c1eec5eb46f6313837c760d4115b1795c85b6c08be4e3/websockets-17.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dc2b79afc074d2f3e64b26539350f697fe1b85ea1c49ea24eb588f247b053ce1", size = 223263, upload-time = "2026-08-26T14:56:03.092Z" }, + { url = "https://files.pythonhosted.org/packages/27/47/0c30f4eebfd1d93fae779d268f678d48847fb98516f5200849574eee8820/websockets-17.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e4bd7eacb87d8cf3ed70d6392c770a0d92441f05d7d2a3efafb5bc171d5e3067", size = 224244, upload-time = "2026-08-26T14:56:04.321Z" }, + { url = "https://files.pythonhosted.org/packages/41/33/46c256195a1255079ae23d1b1267b2e1843dc5f46a67f973cdf2a3523dff/websockets-17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ccbf3f4a9890d50b3a08ee04029fde30a03bfdeffaa19977628bf17251764e60", size = 224520, upload-time = "2026-08-26T14:56:05.521Z" }, + { url = "https://files.pythonhosted.org/packages/06/9a/aef0792731df4352e5f417369b532b3325fe434765ca90c193f594ae1e67/websockets-17.1-cp312-cp312-win32.whl", hash = "sha256:7e724f843fa6a0614aece65a7c73e51d0f4412ca41dccac13c3caf98e69536bb", size = 217485, upload-time = "2026-08-26T14:56:06.715Z" }, + { url = "https://files.pythonhosted.org/packages/50/23/493ecfdaf32898e5ea24dc900e33e5e317f9662d5d9ab2d44b2e111b4e1c/websockets-17.1-cp312-cp312-win_amd64.whl", hash = "sha256:617243e19a0992095956f406ee9cd3bc4ba92862d83cb1d83bb59ce574412bec", size = 217786, upload-time = "2026-08-26T14:56:08.055Z" }, + { url = "https://files.pythonhosted.org/packages/97/3d/91954e2f7876f74ce1213e9b92c65a63b559cc4b942a931ebeb351cd9932/websockets-17.1-cp312-cp312-win_arm64.whl", hash = "sha256:9f4a08ff7cb68c27b18e09223cc6304e01d0f82d5a240d251266dfd2e6e44729", size = 217711, upload-time = "2026-08-26T14:56:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/1d/31/5f6450a7879f4f063ef08897cc385ea3ce3f1fe17f08b11e3fd959abdf27/websockets-17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2a0162a6372110a5601cb5c9fd826635cedf69f3e110c545dd19774e040b970e", size = 217006, upload-time = "2026-08-26T14:56:10.509Z" }, + { url = "https://files.pythonhosted.org/packages/d0/2a/c1b006fc861695d2aa4e35327b842015ce1d98cf8f99241829b3d6460bfc/websockets-17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:829dba1bc049779de9b332088c1a6a9858e96bd67e50b6b644a95e02b67836bc", size = 214690, upload-time = "2026-08-26T14:56:11.681Z" }, + { url = "https://files.pythonhosted.org/packages/46/69/66e5b7d01445e0eeb1d4ab419c30315f2c90cf7a8a8cd4ecc47f894dba54/websockets-17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd8f47dbf2e8adb15c847215f83436de3fdb120b51fdae0fbbdf69fd97a3ad80", size = 214947, upload-time = "2026-08-26T14:56:12.923Z" }, + { url = "https://files.pythonhosted.org/packages/07/ce/033cafe2d2538562efa876b9149a2c7a0f7787870a4b1bb6e28adc9ceb6b/websockets-17.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9f4c0377a83e163a303514fdfab501dbe379bdc13e5b9312a91d112658b29dce", size = 224329, upload-time = "2026-08-26T14:56:14.212Z" }, + { url = "https://files.pythonhosted.org/packages/34/c7/e1c2e8a67f6cc0aa43abe0046fb3b7a020980649e6a843751dc7ce9eb170/websockets-17.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c3241d684a76eaaef8b2dc789afde4343cd3aad55ea81e4e8ab3605b529bae51", size = 224611, upload-time = "2026-08-26T14:56:15.702Z" }, + { url = "https://files.pythonhosted.org/packages/be/de/07c6d48eb3d2069709410c851e7de10ab83d752c4bd09862899627c2729b/websockets-17.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e5f5c7a893507d0e83a80b88aefd6522f7e882cd53f9722c6f23f5a020c9557c", size = 225848, upload-time = "2026-08-26T14:56:16.962Z" }, + { url = "https://files.pythonhosted.org/packages/f3/dd/3c68572d20509648cc2fb6f50ccf3deeb4b87270f2c8966e99476e278ea3/websockets-17.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:00bf34b64501e3477e81fc281532ff3cbf4da26633c10b63979d5085d46602d3", size = 227290, upload-time = "2026-08-26T14:56:18.204Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4a/8f6651c8a22093539c9215af0c5bbf217b87b382c99d2112039b92d593c2/websockets-17.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ce0305b702b20d1e1d60a9aaace6bc89970e1753565543f310d549eab22c2435", size = 226476, upload-time = "2026-08-26T14:56:19.459Z" }, + { url = "https://files.pythonhosted.org/packages/f5/be/f6fc33cea86b1127fd1297b18c107e81580ab55a73a39f9a934441ef321f/websockets-17.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29176d8b429cfa0fa443c473878d37a5c06cfd0cb36b71ba4314accc71e05906", size = 225233, upload-time = "2026-08-26T14:56:20.939Z" }, + { url = "https://files.pythonhosted.org/packages/cb/83/65edaf05f7c9b1dea82f4d252fdc37706a84571646f06119a27b0a16fe19/websockets-17.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3709a1ab30b4b922027d22f68d2b61a0656a91680ac894a537624e6be7dd7f7c", size = 222488, upload-time = "2026-08-26T14:56:22.208Z" }, + { url = "https://files.pythonhosted.org/packages/07/42/d1169c2f7f1f0032b0d4b0c00f0711a070cd7c735de37bfeb876bc0f9606/websockets-17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:43bd0c1ceb924d67f5c1a5254d8361dd9d94246e6331a726064dfa2917880780", size = 225295, upload-time = "2026-08-26T14:56:23.445Z" }, + { url = "https://files.pythonhosted.org/packages/a6/f4/64e2a386c3899b917c2933225c9b47887874229d159797f3bf1a11c20d51/websockets-17.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:1fce0f43e0d41422e0b2cad6561e1970df22f212f4c7e884967df7cf591b031c", size = 223891, upload-time = "2026-08-26T14:56:24.647Z" }, + { url = "https://files.pythonhosted.org/packages/26/b3/dfb5c482f7e310a3432fdbb045ddfe6d34114680e89a233d4ff900a32961/websockets-17.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4031152769179ab8dcdeafc7b0e58052a49117560a28671700b47b2c7b717aad", size = 224661, upload-time = "2026-08-26T14:56:26.027Z" }, + { url = "https://files.pythonhosted.org/packages/a4/cf/94865130a336029f46412adc127c4fbe380f46172b90ce251369e35c4302/websockets-17.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a06f3b5085176763182449559e20391d7ce616a8972a9f7a33deda87ea6d4f3c", size = 225766, upload-time = "2026-08-26T14:56:27.455Z" }, + { url = "https://files.pythonhosted.org/packages/96/34/eb8c658f86dfe562ed49a887a27424bfe9e618c26ea6f865b093d075d3a6/websockets-17.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:77b37cceca17291897c3c73bd30a7c7c7909593554b5da574ec852af83c1742a", size = 223323, upload-time = "2026-08-26T14:56:28.807Z" }, + { url = "https://files.pythonhosted.org/packages/1b/7e/2629609652ece5ca0c7ac235927dd4511b08131e3a5d53439b798fddf002/websockets-17.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d8e83333385cac6030a5167fd18bf96cc6c58b914c308e683f05b0cf94bc8dd0", size = 224276, upload-time = "2026-08-26T14:56:29.991Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/8525737fe840b38e5f40956c198fb586a4fac1e07144d41a5b949b989cf8/websockets-17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:073c5c3f7e127041fa9d34a9e29ceefee8c3cafbd267ed2927318f425144380d", size = 224558, upload-time = "2026-08-26T14:56:31.184Z" }, + { url = "https://files.pythonhosted.org/packages/74/ab/3a958c6cbcf74b118f601c20a80ac8bd5e8dfec0bcf7345116feaeefb121/websockets-17.1-cp313-cp313-win32.whl", hash = "sha256:2afb58c7ba48b329d56769f8dfd89f394efe587b65ef806bae810a484d6d3608", size = 217475, upload-time = "2026-08-26T14:56:32.431Z" }, + { url = "https://files.pythonhosted.org/packages/22/36/fb521f0f2994c25509651f169efe5582dddd8713d57a0757ba87859372ef/websockets-17.1-cp313-cp313-win_amd64.whl", hash = "sha256:0340bbef6bfbe16da888b3983d666a4db4954ac3253c38f13bc7aba0c7db5a2f", size = 217784, upload-time = "2026-08-26T14:56:33.608Z" }, + { url = "https://files.pythonhosted.org/packages/68/92/9b8419584681a12a7534b746dfb2737c466efe2455483e2fbf8b941a04ec/websockets-17.1-cp313-cp313-win_arm64.whl", hash = "sha256:7a72efa3bf4fa3a6669a54420a472ad056da3973d827f10e3a536da463f926c2", size = 217715, upload-time = "2026-08-26T14:56:34.865Z" }, + { url = "https://files.pythonhosted.org/packages/90/0d/500cf5daea09d4669dff3a7d67159094a0bd6c4ef130381404f6edd3eb5f/websockets-17.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0c9982938980e086da59f70d05f9418cd143401a601a0faac10fa48f7bb1cd3e", size = 217048, upload-time = "2026-08-26T14:56:36.03Z" }, + { url = "https://files.pythonhosted.org/packages/97/12/5b12c6168aa269cffbfd24d177cd492b130120403a418c7e89462e27b4ac/websockets-17.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:57b39dc8541cf7ed3f639da82bf7451060483967f9e733da1f8173e4095f0642", size = 214737, upload-time = "2026-08-26T14:56:37.43Z" }, + { url = "https://files.pythonhosted.org/packages/0c/36/e453e5106e4e2416f008ac222837c2f1637a063b08008afcd1088889b631/websockets-17.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:96abdecbaae746851b87c3a36cb4a661df93ca3d92f114270f79228bf1d00de6", size = 214955, upload-time = "2026-08-26T14:56:38.71Z" }, + { url = "https://files.pythonhosted.org/packages/dd/30/0204bb86176db02cdfc678ce65ed808a66fab87d250ce61a8790800a60b0/websockets-17.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d9fc873e239c5abeb150bc24dbd1a7af23a9254526383ce0a077f5e20adbeb19", size = 224331, upload-time = "2026-08-26T14:56:39.924Z" }, + { url = "https://files.pythonhosted.org/packages/46/c8/d8372256e00c4e3cab1115c45075d1eeedb642a3f2b42bd70c4deae03f06/websockets-17.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f42912fa9eb4cb7c7ec9fde9b3332ba339eb8a8811981043d4029599f3d950b", size = 224685, upload-time = "2026-08-26T14:56:41.169Z" }, + { url = "https://files.pythonhosted.org/packages/12/7d/650355b8f67f908ff99603351d4458d1a0b787d627950a47c38db7e25308/websockets-17.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f98bf378d7a5be047a044a1a27c987a8f355e10e3b5754617dbe756248cbc5ce", size = 225927, upload-time = "2026-08-26T14:56:42.359Z" }, + { url = "https://files.pythonhosted.org/packages/34/6c/a9ffa5b903579eed76017870f055d75ecc73988d9d0c9b65a92ba0bf2a27/websockets-17.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d334d11398086bb5559606cb42d51c013ea7c061c7db701521392373d3c087f5", size = 227300, upload-time = "2026-08-26T14:56:43.538Z" }, + { url = "https://files.pythonhosted.org/packages/9b/5d/4551c2269066af7481ee44605a0813770961615b5b5da3e87a8f5cb859ea/websockets-17.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c27336b1a0ac56569493e858497870347854372395f50483725f8cdacc5a45c", size = 226533, upload-time = "2026-08-26T14:56:44.669Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/237a99233e5c445759a613831b3a92e91905afc064dc3bd0ad33c35fd1e2/websockets-17.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:67258b00302a5aaf0b267771c7014b13429abd7ea17eebc4c55bd935ff101555", size = 225280, upload-time = "2026-08-26T14:56:45.83Z" }, + { url = "https://files.pythonhosted.org/packages/d3/b5/e9407a91613d1d1cd932414143a1012096b26674a782fc55a0bd23217ee4/websockets-17.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:455ffeea0879d313205df1e745e5883e1feb7f31ecd26be882f5f0babd3db04f", size = 222540, upload-time = "2026-08-26T14:56:47.053Z" }, + { url = "https://files.pythonhosted.org/packages/db/d2/db76628db0577b783205d9779f64d8e373416b04c62d1546be4b75dc8540/websockets-17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f7233eaf441a345a5943a929fd4b5ea3278f11aed35a9ed0f3106b8cb3ca846a", size = 225354, upload-time = "2026-08-26T14:56:48.32Z" }, + { url = "https://files.pythonhosted.org/packages/a9/4c/2174181c067b89a74ae18e2650c2ac29959f4b796afe876ab3f4d30d642c/websockets-17.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c65da239a5ad553619804c1f9d65c1a0b3005381c6158ee14da2c7444cbd0c78", size = 223867, upload-time = "2026-08-26T14:56:49.579Z" }, + { url = "https://files.pythonhosted.org/packages/df/75/274decb9a8253561b5be3261e02a6676fc8ecdf31e95b722e53d5bfb8fd2/websockets-17.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9fa1ffa08c81a4f809cdab6129f8e55bee4650b9d6d3461019dda73aacd146b6", size = 224652, upload-time = "2026-08-26T14:56:50.885Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e6/49824f1fb4db7656d2f7492b1d8be16147b759d909490e32f4776843ee64/websockets-17.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:406b8107943a43ef4649b1e0cb0cdc052bbf08fe1c8905a623c4af9586e5cebb", size = 225822, upload-time = "2026-08-26T14:56:52.356Z" }, + { url = "https://files.pythonhosted.org/packages/b8/6a/5dc43838c0b02a95f42c47a0de33c5ddd7767a9feeb4d0d8777ac1cfefe4/websockets-17.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:4e8ffcb486c8490a34a4cef5e4409d8da5a1cb1681e5bf7d786ce5e84aa8540d", size = 223379, upload-time = "2026-08-26T14:56:53.699Z" }, + { url = "https://files.pythonhosted.org/packages/c2/62/585637cf06d6b321232f79c55dc14d65518d12cf87c94c44f5864068810e/websockets-17.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:fb88076df585b69c5761c387c0081aa87d7b9eb1b205a6535ca4777e25650d81", size = 224330, upload-time = "2026-08-26T14:56:55.184Z" }, + { url = "https://files.pythonhosted.org/packages/de/68/c3b234a6a1366b6ab5bbfaa4434a1b946e1dc4e8ddd6824bfd93a8835b7f/websockets-17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5d4724255fb8398acd9e583b97eb2279cec20e0bd0f9a94bf75f6056ef9f13da", size = 224622, upload-time = "2026-08-26T14:56:56.393Z" }, + { url = "https://files.pythonhosted.org/packages/6a/d4/84cf3d1376f5d8207f55f43c1c818babd6b89447f5dcd01f18a6d5526796/websockets-17.1-cp314-cp314-win32.whl", hash = "sha256:be3f0129c5654517b2abf07dcb75bb1d9479759a4ccfb569e8293579e9fc029a", size = 217036, upload-time = "2026-08-26T14:56:57.652Z" }, + { url = "https://files.pythonhosted.org/packages/d0/0f/9e7ac63c5d7cb642952200814f584318e65146df008b7d375d5d9c6b2c97/websockets-17.1-cp314-cp314-win_amd64.whl", hash = "sha256:2a4dc6ef83f4559e0d05f313a375cb38f63c986096a9da99fe94fdd779d313e5", size = 217382, upload-time = "2026-08-26T14:56:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/54/bb/1ae6b91f7f3ac05f5c9f14a72dc2181c115ff370bcd8a7f10f02c174adfd/websockets-17.1-cp314-cp314-win_arm64.whl", hash = "sha256:46c0331c9eaaf73a559f3a9e388466be0df96eb83d40f06f1ca6ab6613b35c82", size = 217268, upload-time = "2026-08-26T14:57:00.654Z" }, + { url = "https://files.pythonhosted.org/packages/b3/f0/f65644d0e0b2b90918a8c41503841cc4072a58f2bf76c09bc36e751fc0dd/websockets-17.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d411ea5ca18ac1b12c0c94be88b60c18ca641ac43bcdfdf1c9f79d46cdbe1603", size = 217379, upload-time = "2026-08-26T14:57:02.181Z" }, + { url = "https://files.pythonhosted.org/packages/ff/35/4c46d1f620ac1a30f92b6eae78ee40a772a93f568647ca7ccdc5ea283cf8/websockets-17.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:07fa3e7c30e2c577928d359b56bf872a3e0cbcc15553eaa0907c1ee86344b56f", size = 214911, upload-time = "2026-08-26T14:57:03.478Z" }, + { url = "https://files.pythonhosted.org/packages/04/6e/4587e8406d7c1188e97b9cf466c081e93399380d447f885bfce81626cd37/websockets-17.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6de9acef07e3a78e9567fcd26c29011a4da8f050b13004bbf880a0fd82a6eea5", size = 215115, upload-time = "2026-08-26T14:57:04.692Z" }, + { url = "https://files.pythonhosted.org/packages/ec/06/1381c8fff525041025909eb80ace32489194a00ba22a0a8d428030afcc84/websockets-17.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ea0ed9373b880115911d9d39634bccc95b8ce590c9c42e8589f5cacc3ef3cee2", size = 224696, upload-time = "2026-08-26T14:57:05.899Z" }, + { url = "https://files.pythonhosted.org/packages/36/9d/9034e867dc85340be058619751742b895f722326e83100d110063461ca07/websockets-17.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50903d335bfda026c2fa11dd9aed09d8cbee0c451e3a85122a9acb041b7dc69b", size = 224975, upload-time = "2026-08-26T14:57:07.262Z" }, + { url = "https://files.pythonhosted.org/packages/40/eb/ed03aa3cae748ebf6397e5d44028f433f746bad09dc568ff754fda3a3c9b/websockets-17.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a74531ce81af587f906ab42f194032388fcff8fc7938402e5917c9147a39441", size = 226151, upload-time = "2026-08-26T14:57:08.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c9/cc1964a096d16f3b73cb1ee5f14f277f5a3bcac07c6e8f9a1dcded99f4c8/websockets-17.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8fbf28e639544503b7d1c96452a5e5e043e4108d89b1f3fa02910603622d19db", size = 228292, upload-time = "2026-08-26T14:57:09.846Z" }, + { url = "https://files.pythonhosted.org/packages/1a/26/46da6dd0363c2db2e4876fd59a40fd40c1943a82d7018d0a33afbce47d52/websockets-17.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f612dc57f00c07cf4aa2673f7cbceabd654ad2457b7e639f061b794d6e11f9fd", size = 226722, upload-time = "2026-08-26T14:57:11.118Z" }, + { url = "https://files.pythonhosted.org/packages/78/98/ecd8f5e1c5d0e54c08ebc5c66852271112166db68107cb0e17ca1bf25009/websockets-17.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1c7ac77401227212dc6e849182feee50d57cf456ec6329ffd6979c94bb136c5c", size = 225451, upload-time = "2026-08-26T14:57:12.601Z" }, + { url = "https://files.pythonhosted.org/packages/65/4d/da8d2760db53e17aae763738b6ba834b1fcf16813d3632f3edb6951e1ec8/websockets-17.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:32a2a68d989d6e5b74a9d5095415c51189ebae29fceb7cf2b64a1c0318a81256", size = 223003, upload-time = "2026-08-26T14:57:13.875Z" }, + { url = "https://files.pythonhosted.org/packages/a4/40/ea401c141a79c5b1d0021a0dab9d0df2051c108f1620fbb39a6e7c714c3b/websockets-17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:aec00f018d34c67500ff0438dc314b40277be4a1b983cbacbf53ccf7db63e257", size = 225704, upload-time = "2026-08-26T14:57:15.091Z" }, + { url = "https://files.pythonhosted.org/packages/e1/8e/07ab3f44215d89840d5385fdcaaab1fed8caeffa67c6899e15062957c12c/websockets-17.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0014eaff8ad5b3b43feda2279f9d34bf2eaae040720b9fbbb55944b10f40b14d", size = 224192, upload-time = "2026-08-26T14:57:16.3Z" }, + { url = "https://files.pythonhosted.org/packages/58/93/ccf1af0a23e5748d4e22292a377d78d15cf294d7e707bbb11a8990ae6bd5/websockets-17.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:db9d7ee47f3ba531e278be539af39e2c7c7d28fb94897b6cd1120d63b0ef5922", size = 225082, upload-time = "2026-08-26T14:57:17.531Z" }, + { url = "https://files.pythonhosted.org/packages/e2/db/e32200f99ce282e728d2929f2c429db353cf3282db7d0eba99eb32c9fec1/websockets-17.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:ff3e2ba7a9f0a110b0555452e9b5a03a34e11662544e01beea15f144b48ba7b7", size = 226101, upload-time = "2026-08-26T14:57:18.802Z" }, + { url = "https://files.pythonhosted.org/packages/28/3d/e7a6e9777b29433620167c98f3caaff0d6b08b1239a273ef7f7fd1393349/websockets-17.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6da17fc94bd270f5987b10bee113461ac36a36a98b0481ddcc98056e5a90001a", size = 223794, upload-time = "2026-08-26T14:57:20.313Z" }, + { url = "https://files.pythonhosted.org/packages/48/05/ac569090726dedd6656f3ee28b0c02dfb1ba76e898dceaccc2987a237cef/websockets-17.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:e8dc3fa6d6b7ead3f9de57895f41b116a28787548e066365d9d90f7356bcaad2", size = 224567, upload-time = "2026-08-26T14:57:21.634Z" }, + { url = "https://files.pythonhosted.org/packages/14/50/4ef62941111db6b31193f4fabbb65f845a5177579040cb8fe0d774d25034/websockets-17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b65d5fe48219dc2d5e158de9e6514e75600f379cc7e37108d35f31764c155566", size = 224993, upload-time = "2026-08-26T14:57:22.86Z" }, + { url = "https://files.pythonhosted.org/packages/28/42/2b95ada4ea19bf3a2072b68669ce4f4afb212690b727d31640576287fd68/websockets-17.1-cp314-cp314t-win32.whl", hash = "sha256:2cce251f3e2469b99b6802b55435bcdd07123b41870f54c87b336183af9d7e68", size = 217168, upload-time = "2026-08-26T14:57:24.466Z" }, + { url = "https://files.pythonhosted.org/packages/32/0a/67d5ee08dd8060a37d612fd40a625b5376ad19ae48fe1c8ad428c278b817/websockets-17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8f6c38cdcaf98a911d7acc25577f2f9e710f3a2fc2bde1563556784320196b51", size = 217508, upload-time = "2026-08-26T14:57:25.983Z" }, + { url = "https://files.pythonhosted.org/packages/76/a3/822005d0c674451d2411027b878cdc128a2b7ea5a30d337d9e279da22eba/websockets-17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:d1e2f5fa2b6d01f0d85b4f223fea7ed1d504be282a02a81bd2be4817ef7a2f03", size = 217425, upload-time = "2026-08-26T14:57:27.324Z" }, + { url = "https://files.pythonhosted.org/packages/de/d5/99a6c6a1eb5d5ae9f45f59a3c97f4e3b21f310eb404a547fb3e7d2fc054c/websockets-17.1-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:88381602e379165b66244b2ebc29f9b23ea0851fbe63ae157f91ca324f072d6f", size = 216970, upload-time = "2026-08-26T14:57:28.575Z" }, + { url = "https://files.pythonhosted.org/packages/a6/0e/1e7f6e833728193958d3ed3d67b5d57c3c7cfa948abf94d4bc553257c954/websockets-17.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:88bc5138e53903a85c354e59df7ba73ce306f7b09724cef74dba121e60a88ce2", size = 214699, upload-time = "2026-08-26T14:57:29.862Z" }, + { url = "https://files.pythonhosted.org/packages/07/00/95d39549f86e34425a0412bcbe61708dd1fc46af654e2134a6c4389102ad/websockets-17.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:3546ef55b3a074494106508bc6505c73825970d2d9505f7bf53882b3e88b0d1e", size = 214927, upload-time = "2026-08-26T14:57:31.148Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ff/b442415fc4f7f9943b0fc8e8eebaa13923ca73361e167c439ba634eecbd9/websockets-17.1-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9ae55d24241fc055f22aea3ac924559069848bd0ad4ea065fdd72d2194685fe8", size = 224373, upload-time = "2026-08-26T14:57:32.833Z" }, + { url = "https://files.pythonhosted.org/packages/a8/dd/b83537aae4cf61615b9d8b2dbb235c0030ba85457a6d934798273814600f/websockets-17.1-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d7b349265fad6244013eecd99df8d83c12bf3013943e431f4fadd5bffc37db42", size = 224801, upload-time = "2026-08-26T14:57:34.041Z" }, + { url = "https://files.pythonhosted.org/packages/76/83/5ab0abed58454909e8dbab45086ac68ee4556d7a8ada26735addc909b903/websockets-17.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc5789e5ea182b77a38881383ada5347202a6c66f4857d054e075290e80b604b", size = 225967, upload-time = "2026-08-26T14:57:35.292Z" }, + { url = "https://files.pythonhosted.org/packages/4b/26/e2412f2b998a8c1dfc00c0709ff6ee0c634dd0b0b4f92bdfe9667876b71c/websockets-17.1-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ce13c7d233239e739600a57d4a73c1192ad8259e655a4d55aa1a454242bc809d", size = 227664, upload-time = "2026-08-26T14:57:36.493Z" }, + { url = "https://files.pythonhosted.org/packages/ec/25/0dd4495df3c0e02f6db705312ba85ab9b2dd42257dc23eb0da10066e4844/websockets-17.1-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1036189bd34b0bc1b10a4679321e2c7968af317efe6e8e4c1c5141c4254fb5bb", size = 226447, upload-time = "2026-08-26T14:57:37.781Z" }, + { url = "https://files.pythonhosted.org/packages/be/67/6df3f63ffc48f08126ed0cd2fd2a41092967c3e364f8ec100deae90b6d77/websockets-17.1-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e78fd4b7b2c5086a38671c9c882c1e643385eccea360b5b1fda4a105e590087e", size = 225343, upload-time = "2026-08-26T14:57:39.133Z" }, + { url = "https://files.pythonhosted.org/packages/b1/8d/a8479bbb09ff054907d141123d8f52fb6ae5ac39c6dbe39e6a02a8408309/websockets-17.1-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:46e7a10bf04318c7b0c0273791925ae5e1cbe4a11e34aa934d2ef27862058a80", size = 222748, upload-time = "2026-08-26T14:57:40.478Z" }, + { url = "https://files.pythonhosted.org/packages/40/fb/4c3d2a3269cde3f3087916de9c3d9fc5d7196b46846d8c3a9ae59ad0a884/websockets-17.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:33e45c7ea38428e740a7f233555d71df0b875cef7fc080acebc9654475e35335", size = 225453, upload-time = "2026-08-26T14:57:41.859Z" }, + { url = "https://files.pythonhosted.org/packages/7f/1c/6467b401d19408f34e1c7389c222c2c7e1dfdf08c551190269b5eabc726c/websockets-17.1-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:6e63c01803be425ff062b7f7fc201a74def1d49fc94a2410dd17375df75936e9", size = 224112, upload-time = "2026-08-26T14:57:43.136Z" }, + { url = "https://files.pythonhosted.org/packages/c5/5f/744e032ac80e11039a7447657ebabb46e9b5c2dbcec83be571335212932f/websockets-17.1-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:722ec21717eec6477bce582147a28acdfe034e604239466a6a95daedb863e774", size = 224646, upload-time = "2026-08-26T14:57:44.871Z" }, + { url = "https://files.pythonhosted.org/packages/9f/47/bcb9128d9afc4d0934d9192e2a24897ca2f7a63df2654904915349c6c46d/websockets-17.1-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:e74e41f0ad12ff1e8983e349daef79d37cc8280c743ce9d134d6c74c18dab5d6", size = 225797, upload-time = "2026-08-26T14:57:46.338Z" }, + { url = "https://files.pythonhosted.org/packages/c7/e0/b058047b7cf565e1105b10ef6b6b24a6ebe3575678c7dc75a645334705a7/websockets-17.1-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:12fe8984a32dbfd084e0603f1a8d740c0180cb85b3174585c54a80d2455a8394", size = 223605, upload-time = "2026-08-26T14:57:48.175Z" }, + { url = "https://files.pythonhosted.org/packages/b9/69/fc1555bff884de363f1bf9eebf2836dbeb29fa7e4f957debb7bbcf43abba/websockets-17.1-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:01dcb47deebc40b38fd4a493b9b9f4d0a704b7bec6f35e4d34085b329abce71a", size = 224508, upload-time = "2026-08-26T14:57:49.407Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/648d4e68621688b19093b06f7b497d520952e68cdea1c1b54371fe9491de/websockets-17.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f4c45ee2512d3757b5e6c67c5a34e435143f2ecb7df3324f9fd888688c45c0f4", size = 224767, upload-time = "2026-08-26T14:57:50.799Z" }, + { url = "https://files.pythonhosted.org/packages/58/93/f8342b55864f71df13eb8e9ef7dce691b87a87f04f75bb8a1385b3336e7c/websockets-17.1-cp315-cp315-win32.whl", hash = "sha256:0f4f50dfe2cc810fc4e2de979b35e83bf8bb4bccdc6fe472d93762ea7b1d5927", size = 217003, upload-time = "2026-08-26T14:57:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f0/7b5fdb774c245e0b6217009e2a24d2105c1a64923949f33be41aa7959302/websockets-17.1-cp315-cp315-win_amd64.whl", hash = "sha256:4af784f3e436f65b355c117c6497320f2b5cf6a559295cb1c4c7338e335d45cc", size = 217300, upload-time = "2026-08-26T14:57:53.492Z" }, + { url = "https://files.pythonhosted.org/packages/76/33/1fe6ed1b5087516115ca451b2c240314b010647071f8fc3bd78a21e4dddb/websockets-17.1-cp315-cp315-win_arm64.whl", hash = "sha256:d58159af7835fde09c462394293c0d7aaf8fb4557d8f8e5699f5e722ccae013d", size = 217214, upload-time = "2026-08-26T14:57:54.88Z" }, + { url = "https://files.pythonhosted.org/packages/94/ca/ed02e75996a266d76c5fcb5dd9b930db4cf2b388ca5fa3d2a72086f81568/websockets-17.1-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:1a5cf4e7bbe3ca499e6a289206cb4fcb7444b09919e129bd517f57d5fa192c13", size = 217282, upload-time = "2026-08-26T14:57:56.108Z" }, + { url = "https://files.pythonhosted.org/packages/bd/7d/d536f5bc89ea5b52fd1c1727c59fabafee6bc41f5ce92c3bd2f83047908c/websockets-17.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:416b4bc8789a1865a3ff643ec4ee073a5f52402d0dbeafd27b1798d5dd6b6a51", size = 214863, upload-time = "2026-08-26T14:57:57.355Z" }, + { url = "https://files.pythonhosted.org/packages/37/37/944cf17bad668e9be1247e6314f88a48b9faf7c250e383410db8b38af0b9/websockets-17.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:259f45358c76d3b18489e3e80636cdbe807e05ecf1b10fdf1a779106d23d0c8e", size = 215073, upload-time = "2026-08-26T14:57:58.719Z" }, + { url = "https://files.pythonhosted.org/packages/74/bf/3267966cc1bbc2b8fa62fd329651b0af502df1f5d1c0eed027ff339d6aa8/websockets-17.1-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d9d01e8ede41fea4f5a847dad9d628355f74905f437a5b6856d67aa66d193800", size = 225229, upload-time = "2026-08-26T14:58:00.235Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d8/85ea722f483510abb39fc71aafb4465d17cf9051a275ab036874ff3c300c/websockets-17.1-cp315-cp315t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a7b35181a14cbfcae163b4de545d22abfd07d06c2c41ca69cfcd99251d6888ab", size = 225500, upload-time = "2026-08-26T14:58:01.994Z" }, + { url = "https://files.pythonhosted.org/packages/50/ce/64c7d00005bd0d15ecb5c5fcb7fb2597b6b92ddd16c4fa6bbc3d2835ad63/websockets-17.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a8e768a048c2220697477ce2e67e4345dc9f693d0ee6af53945b5e30227c6a7", size = 226829, upload-time = "2026-08-26T14:58:03.327Z" }, + { url = "https://files.pythonhosted.org/packages/b4/dc/096c67940fb957e667ca3c542818150434eb0388c6fdc90b3a502f3c3e96/websockets-17.1-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:880069d21cc33a558dcf180924a546d1ecf8ada5be3e4e70acee87019d706a24", size = 228457, upload-time = "2026-08-26T14:58:04.78Z" }, + { url = "https://files.pythonhosted.org/packages/51/fe/f2331b6b7ccc67589891da354fa46a5cb79e95f83b9fd0e734d77f1f2140/websockets-17.1-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cec1bb8f22abccc8d20f8ca63df9be41600c26c190f4b97ee86c675fd4a863a6", size = 227265, upload-time = "2026-08-26T14:58:06.102Z" }, + { url = "https://files.pythonhosted.org/packages/47/a5/fb1642302f8ec77ca922203074f155a9831a5128ad75e725059a476d1227/websockets-17.1-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f3a1d577e081667dda7f8e5b4796e6e32f9713c93e2a3d930669519840a3c623", size = 226143, upload-time = "2026-08-26T14:58:07.464Z" }, + { url = "https://files.pythonhosted.org/packages/d7/41/7133fcfb63f5562750b269d6a845c689dde6a2c6407286da395beea19ddd/websockets-17.1-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc053f9e95a76213c5eb7ed95779f7daf0d2bf0e4e03073629ebfa43a033f151", size = 223501, upload-time = "2026-08-26T14:58:08.766Z" }, + { url = "https://files.pythonhosted.org/packages/64/b1/82b36bfabc79ff2d383a1fc043cee6a13f794ef4f6bf1b4810ad6988cf6f/websockets-17.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:bb0efe019480a1c93e168ce96479273aaebd672fc8c350d5eed1e507ababb1b8", size = 226330, upload-time = "2026-08-26T14:58:09.987Z" }, + { url = "https://files.pythonhosted.org/packages/41/7d/5b511b9bf6e9ad331e6ff902fcbcc71c3794d10ef3b5efe80ccb8f0a7861/websockets-17.1-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:615746b12b26a3fd4077bc6fbeb277a1c192a45dd57b531d07ad9ed5c52a9a7a", size = 224980, upload-time = "2026-08-26T14:58:11.303Z" }, + { url = "https://files.pythonhosted.org/packages/e0/50/aed08f25301f8eef23be903ff9319fcf35630ca2bdec9d226f7d804dd5b3/websockets-17.1-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:1a20136d61f9ca3a31493732762661fafc2c20e8861930214e21afc6a8a692a2", size = 225478, upload-time = "2026-08-26T14:58:12.543Z" }, + { url = "https://files.pythonhosted.org/packages/3e/47/0d63d4168536b4682c9d19b7399443b1176f25dbb68878374fa716670230/websockets-17.1-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:2786cbd273ab69c22612db8a41229ddf2c158060b17b5928884bf388d07887f3", size = 226588, upload-time = "2026-08-26T14:58:14.457Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/844bd0b6386fc81ed6a55f4b6dd26f01c6987eda205afa10175ea12b2164/websockets-17.1-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:b1c323fc3be1dc3f87f6c59458cb7d9e13dcbbf971d6c3f3e2bbaf58d3bfcdfe", size = 224336, upload-time = "2026-08-26T14:58:15.778Z" }, + { url = "https://files.pythonhosted.org/packages/96/18/03709c84bc88ec4dcea68d4be4ccd07d611073dec111203a5bf45af8809d/websockets-17.1-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:12c8e2b25df59755954a04dfa09c990b96691025aaf7eafd19ed6da24b09c18d", size = 225197, upload-time = "2026-08-26T14:58:17.141Z" }, + { url = "https://files.pythonhosted.org/packages/27/cf/0d1c694b6466c89e875b85b32b51312c472cf6708eee91914866f5087dde/websockets-17.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f58f58b4b29bbea2a3635e2c56eff4a3adab011fe383802a9e542e31b97085fc", size = 225493, upload-time = "2026-08-26T14:58:18.521Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f5/99857c3dd9676749f33e3668665a34ad6099505fb8d75eb084f49f7807a9/websockets-17.1-cp315-cp315t-win32.whl", hash = "sha256:f78a3ffb1994304db2c0c4588e4d1a518079b557054fa3bb985a6f5e50ff49a3", size = 217130, upload-time = "2026-08-26T14:58:20.037Z" }, + { url = "https://files.pythonhosted.org/packages/2c/84/77599922ab441bfe61508f97dab2c71f8e114d31793993ea54011db16199/websockets-17.1-cp315-cp315t-win_amd64.whl", hash = "sha256:ad68c28a27246fed109a4409393d677b7e1388345cbbd2f5aee5c182d8506110", size = 217448, upload-time = "2026-08-26T14:58:21.382Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3c/8b9a225b523f06a9389be81f1b0ab07c49bec6014742e6aa359c1f920f1f/websockets-17.1-cp315-cp315t-win_arm64.whl", hash = "sha256:e552e0037230ac16e5f568de7012041344d1b18c9feed30ec2891b8eba55af81", size = 217372, upload-time = "2026-08-26T14:58:22.807Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e4/af4abbcf07eac6a725ec6f865611526b2b0c23d482723de551bec667880d/websockets-17.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:10ecb38ffc05e1841b619d99c725307a223ef9ad58e7b1ed33311d472dc43918", size = 214602, upload-time = "2026-08-26T14:58:25.211Z" }, + { url = "https://files.pythonhosted.org/packages/4d/fe/819fba7ba35f92b639333da7355041c07dd50048f9c76fba0b8e292a6483/websockets-17.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17aa424ab61620aad21b36b2240efc87b500cc496e7d0e999a5c2ae99395e886", size = 214874, upload-time = "2026-08-26T14:58:26.689Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a7/d370ab794f47fbeea648d17ad08caf0bb50131d6c04b7ad83e6af63c405a/websockets-17.1-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:764cf7bfa149365f32b7a0fd9fed32debdac29dd06295d5635cde1745b446cd8", size = 215821, upload-time = "2026-08-26T17:25:23.616Z" }, + { url = "https://files.pythonhosted.org/packages/9b/6b/251b00fe634e2a9c2cb5d6390e0e97cec55e3d18dd09b4b976620eed5d7b/websockets-17.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8d1b108bd8f5f6a8b90801f6db3b3858d5deca889acfdb8ac497bbb24e4b0edf", size = 215714, upload-time = "2026-08-26T17:25:26.295Z" }, + { url = "https://files.pythonhosted.org/packages/c4/b1/37fe0c96c206b4208a072c3a74add6a72af4b8228be3f5435163c5a6d099/websockets-17.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a62d8c424383c9dc769ff3672018df822603117e32686e567d452ed035b6fb2e", size = 216608, upload-time = "2026-08-26T17:25:28.134Z" }, + { url = "https://files.pythonhosted.org/packages/be/7e/75a0a491b512412e08333b9f8412757af6186fe1c598186261002de1a793/websockets-17.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8196d217eeca52b9235ee1f8a684a09885a5f953d5a31e80ef915bf2c5c94f9d", size = 217870, upload-time = "2026-08-26T17:25:29.745Z" }, + { url = "https://files.pythonhosted.org/packages/41/63/23572870e01836a98346075b9e17a8bc24a6ddd9800a3204ceee58677f3c/websockets-17.1-py3-none-any.whl", hash = "sha256:f221081107b8c48184d99f7019604486376e7ef826037e70aad6b02540732c23", size = 211134, upload-time = "2026-08-26T17:25:31.397Z" }, +] + [[package]] name = "widgetsnbextension" version = "4.0.15" @@ -2174,18 +2083,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, ] -[[package]] -name = "wsproto" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/79/12135bdf8b9c9367b8701c2c19a14c913c120b882d50b014ca0d38083c2c/wsproto-1.3.2.tar.gz", hash = "sha256:b86885dcf294e15204919950f666e06ffc6c7c114ca900b060d6e16293528294", size = 50116, upload-time = "2025-11-20T18:18:01.871Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl", hash = "sha256:61eea322cdf56e8cc904bd3ad7573359a242ba65688716b0710a5eb12beab584", size = 24405, upload-time = "2025-11-20T18:18:00.454Z" }, -] - [[package]] name = "xy" source = { editable = "." } @@ -2215,13 +2112,14 @@ dev = [ { name = "starlette" }, { name = "ty" }, { name = "uvicorn" }, + { name = "websockets" }, ] [package.metadata] requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", specifier = ">=0.9.6" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional" }, ] provides-extras = ["reflex"] @@ -2238,6 +2136,7 @@ dev = [ { name = "starlette", specifier = ">=0.36" }, { name = "ty" }, { name = "uvicorn", specifier = ">=0.23" }, + { name = "websockets", specifier = ">=12" }, ] [[package]] From 7c7de9a32a1de9fdeb909a0542d7800c5bf38397 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 12 Sep 2026 22:36:05 +0200 Subject: [PATCH 02/17] Address PR review: per-app channel attachment, pinned Reflex commit, runnable browser test --- .github/workflows/ci.yml | 29 +++- .gitignore | 4 + docs/app/pyproject.toml | 15 +- docs/app/uv.lock | 48 +++--- news/505.bugfix.md | 9 ++ pyproject.toml | 30 +++- python/reflex_xy/app.py | 99 +++++++++--- python/reflex_xy/assets/XYChart.jsx | 40 +++-- python/reflex_xy/data_plane.py | 45 ++++-- python/reflex_xy/state_bridge.py | 33 +++- scripts/reflex_ws_smoke.py | 23 ++- scripts/verify_ci_workflow.py | 12 +- spec/design/reflex-integration.md | 44 ++++-- spec/design/view-state.md | 6 +- spec/design/wire-protocol.md | 6 +- tests/reflex_adapter/test_assets.py | 26 +++- tests/reflex_adapter/test_channel_browser.py | 102 ++++++++----- tests/reflex_adapter/test_data_plane.py | 26 +++- tests/reflex_adapter/test_setup_attachment.py | 135 +++++++++++++++++ tests/test_dependencies.py | 44 +++++- uv.lock | 142 ++++++++++++++++-- 21 files changed, 730 insertions(+), 188 deletions(-) create mode 100644 news/505.bugfix.md create mode 100644 tests/reflex_adapter/test_setup_attachment.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ff632478..1653cef40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,6 +139,15 @@ jobs: run: | uv sync --locked --extra reflex --group dev + # The Chromium installed above belongs to the *npm* playwright, which xy's + # own probes only use for an executable path. The Reflex channel browser + # test drives the Python bindings, and those pin their own browser + # revision — so install through them too, or the one test that proves the + # chart shares the app's websocket fails to launch. + - name: Install Chromium (Playwright, Python bindings) + run: | + .venv/bin/playwright install --with-deps chromium chromium-headless-shell + - name: Verify bundled Reflex integration import run: | .venv/bin/python -c "import importlib.metadata as m, reflex_xy; assert reflex_xy.__version__ == m.version('xy')" @@ -191,8 +200,19 @@ jobs: # defect: fail rather than skip, so the browser layer cannot pass by # absence. (A crash or non-zero exit already fails unconditionally.) export XY_REQUIRE_BROWSER=1 + # Keep the painted-chart screenshot from the Reflex channel browser + # test; it is uploaded below as the visual evidence for that run. + export XY_BROWSER_EVIDENCE="$PWD/browser-evidence" .venv/bin/pytest -q + - name: Upload browser evidence + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: browser-evidence + if-no-files-found: warn + path: browser-evidence/ + # End-to-end: a real Figure (line decimation + scatter) through to_html's # exact payload path, rendered in Chromium, pixels read back. Complements # the stdlib smoke, which hand-builds payloads. (Was dead code — audit @@ -645,7 +665,12 @@ jobs: XY_REQUIRE_CARGO: "1" run: | uv venv smoke-native - uv pip install --no-cache -p smoke-native dist/*.tar.gz numpy anywidget "reflex>=0.9.6" + # The adapter needs Reflex's channel transport, unreleased today, so + # there is no version floor to name here — and these smokes only + # `import reflex_xy` (which pulls no Reflex), so installing the + # framework at all would be theatre. Add `[reflex]` back once + # channels ship and the extra names a real floor again. + uv pip install --no-cache -p smoke-native dist/*.tar.gz numpy anywidget ./smoke-native/bin/python - <<'PY' import importlib.metadata as metadata @@ -666,7 +691,7 @@ jobs: XY_SKIP_CARGO: "1" run: | uv venv smoke-no-rust - uv pip install --no-cache -p smoke-no-rust dist/*.tar.gz numpy anywidget "reflex>=0.9.6" + uv pip install --no-cache -p smoke-no-rust dist/*.tar.gz numpy anywidget ./smoke-no-rust/bin/python - <<'PY' import importlib.metadata as metadata diff --git a/.gitignore b/.gitignore index b4238b74f..7e44cc842 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,7 @@ node_modules/ python/xy/static/index.js python/xy/static/standalone.js **/assets/external/ + +# Browser evidence kept by the Reflex channel test when XY_BROWSER_EVIDENCE is +# set (CI uploads it as an artifact); local runs default to pytest's tmp_path. +/browser-evidence/ diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index adb1f7a8f..dba6e95ef 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -5,16 +5,17 @@ description = "Documentation site for XY." requires-python = ">=3.11" # TEMPORARY: these four normally track reflex-dev/reflex@main, but `xy[reflex]` # requires the unreleased channel transport (reflex-dev/reflex#6932) and uv -# refuses two URLs for one package. They therefore point at the same branch the -# root pyproject does — all from one repo, so the framework is never half -# branch and half main. Restore `@main` when channels land there. +# refuses two URLs for one package. They therefore pin the same immutable +# commit the root pyproject does — all from one repo, so the framework is never +# half fork and half main, and no install can pick up unreviewed framework +# code. Restore `@main` when channels land there. dependencies = [ "numpy", "pillow", - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional", - "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional#subdirectory=packages/reflex-components-internal", - "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional#subdirectory=packages/reflex-docgen", - "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional#subdirectory=packages/reflex-site-shared", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7", + "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7#subdirectory=packages/reflex-components-internal", + "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7#subdirectory=packages/reflex-docgen", + "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7#subdirectory=packages/reflex-site-shared", "xy[reflex]", ] diff --git a/docs/app/uv.lock b/docs/app/uv.lock index 16bf81cf8..0613a7b5d 100644 --- a/docs/app/uv.lock +++ b/docs/app/uv.lock @@ -1064,7 +1064,7 @@ wheels = [ [[package]] name = "reflex" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1096,7 +1096,7 @@ dependencies = [ [[package]] name = "reflex-base" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1107,7 +1107,7 @@ dependencies = [ [[package]] name = "reflex-components-code" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1118,7 +1118,7 @@ dependencies = [ [[package]] name = "reflex-components-core" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1131,7 +1131,7 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1140,7 +1140,7 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1148,7 +1148,7 @@ dependencies = [ [[package]] name = "reflex-components-internal" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex" }, ] @@ -1156,7 +1156,7 @@ dependencies = [ [[package]] name = "reflex-components-lucide" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1164,7 +1164,7 @@ dependencies = [ [[package]] name = "reflex-components-markdown" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1175,7 +1175,7 @@ dependencies = [ [[package]] name = "reflex-components-moment" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1183,7 +1183,7 @@ dependencies = [ [[package]] name = "reflex-components-plotly" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1192,7 +1192,7 @@ dependencies = [ [[package]] name = "reflex-components-radix" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1202,7 +1202,7 @@ dependencies = [ [[package]] name = "reflex-components-react-player" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1211,7 +1211,7 @@ dependencies = [ [[package]] name = "reflex-components-recharts" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1219,7 +1219,7 @@ dependencies = [ [[package]] name = "reflex-components-sonner" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "reflex-docgen" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "griffelib" }, { name = "mistletoe" }, @@ -1240,7 +1240,7 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -1252,12 +1252,12 @@ dependencies = [ [[package]] name = "reflex-integrations-docs" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } [[package]] name = "reflex-site-shared" version = "0.0.3.post248.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "email-validator" }, { name = "httpx" }, @@ -1632,7 +1632,7 @@ reflex = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7" }, ] provides-extras = ["reflex"] @@ -1680,10 +1680,10 @@ dev = [ requires-dist = [ { name = "numpy" }, { name = "pillow" }, - { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional" }, - { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=make-sio-optional" }, - { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=make-sio-optional" }, - { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=make-sio-optional" }, + { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7" }, + { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=02dae5601eed0b678703a049db21634f83b625e7" }, + { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=02dae5601eed0b678703a049db21634f83b625e7" }, + { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=02dae5601eed0b678703a049db21634f83b625e7" }, { name = "xy", extras = ["reflex"], editable = "../../" }, ] diff --git a/news/505.bugfix.md b/news/505.bugfix.md new file mode 100644 index 000000000..3094f0a62 --- /dev/null +++ b/news/505.bugfix.md @@ -0,0 +1,9 @@ +`reflex_xy.setup(app)` is now idempotent per *app* rather than per process. +With more than one `rx.App` alive in a process — a hot reload, an AppHarness +test, two apps built side by side — setting up a second app used to leave the +first one's subscribers stranded (registry fan-out pointed only at the newest +channel), and setting the first one up again raised +`RuntimeError: A channel named '/_xy' is already registered`. Attachment is now +keyed on the app, and publishes, pushes and errors fan out to every attached +app. The app is held weakly throughout, so a superseded one is collected rather +than kept alive by the data plane. diff --git a/pyproject.toml b/pyproject.toml index 14dae9655..bfd05247e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,15 +25,21 @@ dependencies = [ # more, so a version specifier here would be a lie in either direction: # `>=0.9.6` admits versions where every chart stays blank, and a guessed # `>=0.10` names a release that does not exist. The git requirement is the -# honest statement of what this integration needs, it keeps `uv sync` working -# for contributors, and uv resolves the rest of that repo's workspace -# (reflex-base, the component packages) from the same branch, so the framework -# is never half branch and half release. `docs/app/pyproject.toml` points its -# own Reflex requirements at the same branch for the same reason. Replace all -# of it with the real floor the moment channels are released (see the Status -# note in the design doc). +# honest statement of what this integration needs, and it keeps `uv sync` +# working for contributors. +# +# It names an immutable *commit*, not the branch: the lockfile only protects +# `uv sync --locked`, so a branch ref here would let a bare +# `pip install xy[reflex]` — or any `uv lock` regeneration — resolve framework +# code nobody reviewed. uv resolves the rest of that repo's workspace +# (reflex-base, the component packages) from the same commit, so the framework +# is never half branch and half release, and `docs/app/pyproject.toml` pins the +# same commit for the same reason. Bumping means editing all six requirement +# strings plus both lockfiles — that friction is the point. Replace the lot +# with the real floor the moment channels are released (see the design doc's +# Status note). reflex = [ - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7", ] [project.urls] @@ -68,6 +74,14 @@ dev = [ "aiohttp>=3.14.3", "uvicorn>=0.23", "websockets>=12", + # Drives a real browser at a real Reflex app in + # tests/reflex_adapter/test_channel_browser.py: the only place the + # single-shared-websocket claim is checked end to end. xy's other browser + # probes speak CDP directly and only borrow playwright's *Node* package for + # a Chromium path, which is why the Python one has to be named here — left + # out, the test silently skips and nothing verifies the transport. + # Pinned with docs/app so one `playwright install` serves both. + "playwright==1.61.0", # Parses .binder/environment.yml in tests/test_binder_config.py so the # Binder contract is asserted on structure, not string transcription. "pyyaml>=6", diff --git a/python/reflex_xy/app.py b/python/reflex_xy/app.py index 16bbcb5c0..edfd6b0ea 100644 --- a/python/reflex_xy/app.py +++ b/python/reflex_xy/app.py @@ -24,7 +24,7 @@ import contextlib import inspect import warnings -from collections.abc import Coroutine +from collections.abc import Callable, Coroutine, Sequence from typing import Any, Optional, cast from reflex.plugins import Plugin @@ -32,7 +32,7 @@ from .data_plane import XYChannel from .handles import FigureHandle, token_of from .registry import _figure_of, registry -from .state_bridge import make_rebuild_hook +from .state_bridge import app_ref, make_rebuild_hook from .tokens import BUILDER_ATTR, PROBE_ATTR from .vars import AsyncFigureVar, FigureVar @@ -48,27 +48,46 @@ "setup", ] -_channel: Optional[XYChannel] = None -# The app the current channel is attached to. Idempotency is per app, not -# per process: a hot reload (and AppHarness) re-imports the app module, and -# the new App gets its own websocket that must be attached to. -_setup_app: Any = None +# Attached (app accessor, channel) pairs. Attachment is per *app*, not per +# process: a hot reload (and AppHarness) re-imports the app module, and the new +# App gets its own websocket that must be attached to. An App is unhashable, so +# this is an identity list rather than a dict, and `app_ref` keeps the app +# weakly so a replaced one does not outlive its reload. +_attached: "list[tuple[Callable[[], Any], XYChannel]]" = [] + + +def _live_planes() -> list[XYChannel]: + """Attached channels whose app is still alive (forgetting the rest).""" + live: list[XYChannel] = [] + for pair in list(_attached): + resolve_app, channel = pair + if resolve_app() is None: + _attached.remove(pair) + else: + live.append(channel) + return live def setup(app: Any) -> XYChannel: - """Attach the xy data plane to a Reflex app (idempotent). + """Attach the xy data plane to a Reflex app (idempotent *per app*). The plane is a Reflex channel on the app's own event websocket. Reflex's `register_channel` refuses an app that cannot carry one — state disabled, or a non-WebSocket transport — so a misconfiguration fails here at startup rather than as a blank chart in the browser. + + Idempotency is keyed on the app itself, which matters once more than one + App exists in a process: keying on "the most recent app" instead would hand + an already-attached app a second channel, and Reflex rejects a duplicate + channel name outright. """ - global _channel, _setup_app - if _channel is not None and _setup_app is app: - return _channel + for resolve_app, channel in _attached: + if resolve_app() is app: + return channel channel = XYChannel(registry, rebuild=make_rebuild_hook(app)) app.register_channel(channel) - wire(channel) + _attached.append((app_ref(app), channel)) + wire_attached() def _lifespan() -> Coroutine[Any, Any, None]: # Deliberately a *sync* function returning the sweep coroutine, not an @@ -83,8 +102,6 @@ def _lifespan() -> Coroutine[Any, Any, None]: return _xy_lifespan() app.register_lifespan_task(_lifespan) - _channel = channel - _setup_app = app return channel @@ -134,12 +151,58 @@ def _ensure_page_plans(app: Any) -> None: def wire(channel: XYChannel) -> None: - """Point the registry's fan-out seams at the data plane (setup and tests).""" + """Point the registry's fan-out seams at one data plane (tests).""" registry.on_publish(channel.broadcast_payload) registry.on_push(channel.broadcast_message) registry.on_error(channel.broadcast_error) +def wire_attached() -> None: + """Point the registry's fan-out seams at *every* attached data plane. + + The registry is process-global; apps are not. A hot reload, an AppHarness + test, or simply two Apps built in one process each get their own channel, + and pointing the seams at the newest one alone would silently strand the + subscribers of every other live app — their figures would keep updating + server-side and never push. Fanning out costs one extra payload build per + additional *live* app, which is exactly the case that would otherwise be + broken; with the single app of a normal deployment it is the same work as + `wire`. + """ + registry.on_publish(_fan_out_payload) + registry.on_push(_fan_out_message) + registry.on_error(_fan_out_error) + + +async def _fan_out(calls: "Sequence[Coroutine[Any, Any, None]]") -> None: + """Await every fan-out, then re-raise the first failure. + + One app's transport failing must not swallow the others' deliveries — that + is the whole point of fanning out — but the error still has to surface the + way a single-plane send does, so it is raised after the rest have run. + """ + results = await asyncio.gather(*calls, return_exceptions=True) + for result in results: + if isinstance(result, BaseException): + raise result + + +async def _fan_out_payload(token: str, entry: Any) -> None: + await _fan_out([plane.broadcast_payload(token, entry) for plane in _live_planes()]) + + +async def _fan_out_message( + token: str, message: dict, buffers: Any = None, version: Optional[int] = None +) -> None: + await _fan_out( + [plane.broadcast_message(token, message, buffers, version) for plane in _live_planes()] + ) + + +async def _fan_out_error(token: str, error: str, resync: bool = False) -> None: + await _fan_out([plane.broadcast_error(token, error, resync) for plane in _live_planes()]) + + async def _xy_lifespan() -> None: """Capture the serving loop, then sweep idle figures forever.""" registry.attach_loop(asyncio.get_running_loop()) @@ -335,7 +398,5 @@ def clear_selection(token: "str | FigureHandle") -> None: def reset_setup_for_tests() -> None: - """Forget the wired data plane (test isolation only).""" - global _channel, _setup_app - _channel = None - _setup_app = None + """Forget every attached data plane (test isolation only).""" + _attached.clear() diff --git a/python/reflex_xy/assets/XYChart.jsx b/python/reflex_xy/assets/XYChart.jsx index 7aebe4bad..05bc79937 100644 --- a/python/reflex_xy/assets/XYChart.jsx +++ b/python/reflex_xy/assets/XYChart.jsx @@ -61,8 +61,20 @@ let sharedPlane = null; // room membership is per-connection, not per-mount). const subCounts = new Map(); -// The data plane's channel name, matching XY_PLANE in data_plane.py. +// The wire vocabulary. Every one of these mirrors a constant of the same name +// in data_plane.py, and tests/reflex_adapter/test_assets.py asserts the two +// declarations agree — so a rename on either side fails there rather than +// silently producing a client that talks past the server. const XY_PLANE = "/_xy"; +const EVENT_SUB = "sub"; +const EVENT_UNSUB = "unsub"; +const EVENT_MSG = "msg"; +const EVENT_PAYLOAD = "payload"; +const EVENT_ERR = "err"; +// Connection lifecycle, owned by Reflex's channel handle rather than by the +// data plane protocol, so these have no server-side counterpart. +const EVENT_CONNECT = "connect"; +const EVENT_DISCONNECT = "disconnect"; /** * The shared xy data plane: one Reflex channel on the app's own websocket. @@ -473,7 +485,7 @@ export function XYChart(props) { // A reconnect can land on a fresh worker whose rebuilt figure starts at // version 1. Versions are monotonic only within this subscription epoch. resetEpoch(); - plane.emit("sub", { fig: liveToken, px: el.clientWidth || null, mid }); + plane.emit(EVENT_SUB, { fig: liveToken, px: el.clientWidth || null, mid }); }; const emitMessage = (m) => { @@ -482,7 +494,7 @@ export function XYChart(props) { if (awaitingPayload || !plane.connected) return; const envelope = { fig: liveToken, mid, m }; if (payloadVersion !== null) envelope.v = payloadVersion; - plane.emit("msg", envelope); + plane.emit(EVENT_MSG, envelope); }; const withSelectionSeq = (m) => ({ @@ -933,10 +945,10 @@ export function XYChart(props) { resetEpoch(); }; - plane.on("payload", onPayload); - plane.on("msg", onMsg); - plane.on("err", onErr); - plane.on("disconnect", onDisconnect); + plane.on(EVENT_PAYLOAD, onPayload); + plane.on(EVENT_MSG, onMsg); + plane.on(EVENT_ERR, onErr); + plane.on(EVENT_DISCONNECT, onDisconnect); // Resubscribe on every (re)connect: after the app plane reconnects the // shared manager, rooms are gone and — on another backend node — the // figure itself may need a state-driven rebuild. `sub` triggers both. @@ -947,7 +959,7 @@ export function XYChart(props) { errResyncs = 0; subscribe(); }; - plane.on("connect", onConnect); + plane.on(EVENT_CONNECT, onConnect); subCounts.set(liveToken, (subCounts.get(liveToken) || 0) + 1); if (plane.connected) subscribe(); @@ -974,15 +986,15 @@ export function XYChart(props) { destroyed = true; if (tracksClickInput) el.removeEventListener("click", rememberClick, true); resetEpoch(); - plane.off("payload", onPayload); - plane.off("msg", onMsg); - plane.off("err", onErr); - plane.off("disconnect", onDisconnect); - plane.off("connect", onConnect); + plane.off(EVENT_PAYLOAD, onPayload); + plane.off(EVENT_MSG, onMsg); + plane.off(EVENT_ERR, onErr); + plane.off(EVENT_DISCONNECT, onDisconnect); + plane.off(EVENT_CONNECT, onConnect); const remaining = (subCounts.get(liveToken) || 1) - 1; if (remaining <= 0) { subCounts.delete(liveToken); - if (plane.connected) plane.emit("unsub", { fig: liveToken, mid }); + if (plane.connected) plane.emit(EVENT_UNSUB, { fig: liveToken, mid }); } else { subCounts.set(liveToken, remaining); } diff --git a/python/reflex_xy/data_plane.py b/python/reflex_xy/data_plane.py index 889ca0b46..7762dab17 100644 --- a/python/reflex_xy/data_plane.py +++ b/python/reflex_xy/data_plane.py @@ -54,13 +54,31 @@ if TYPE_CHECKING: from xy._figure import Figure -__all__ = ["XY_PLANE", "XYChannel"] +__all__ = [ + "EVENT_ERR", + "EVENT_MSG", + "EVENT_PAYLOAD", + "EVENT_SUB", + "EVENT_UNSUB", + "XY_PLANE", + "XYChannel", +] #: Channel name for the chart data plane. A channel name is part of Reflex's #: websocket protocol, not a URL: it needs no route, no mount, and no #: reverse-proxy entry beyond what the app's websocket already has. XY_PLANE = "/_xy" +#: The wire vocabulary, named on both sides of it: `XYChart.jsx` declares the +#: same five strings, and `tests/reflex_adapter/test_assets.py` asserts the two +#: declarations match — so a rename here fails there rather than silently +#: producing a client that talks past the server. +EVENT_SUB = "sub" # client -> server: subscribe, join the figure room +EVENT_UNSUB = "unsub" # client -> server: leave the room +EVENT_MSG = "msg" # both ways: one kernel dispatch, its reply, or a push +EVENT_PAYLOAD = "payload" # server -> client: first paint / full refresh +EVENT_ERR = "err" # server -> client: failure, optionally asking for a resync + # One payload/message is screen-bounded by construction (§29); these caps are # the transport's fail-closed backstop, not a tuning knob. _MAX_PX_HINT = 8192 @@ -241,9 +259,9 @@ async def on_message( ) -> None: """Dispatch one inbound message to the data plane handlers.""" handler = { - "sub": self.on_sub, - "unsub": self.on_unsub, - "msg": self.on_msg, + EVENT_SUB: self.on_sub, + EVENT_UNSUB: self.on_unsub, + EVENT_MSG: self.on_msg, }.get(event) if handler is not None: await handler(session.sid, data) @@ -320,7 +338,7 @@ async def _send_payload( } if mid is not None: envelope["mid"] = mid - await self._send("payload", envelope, _buffer_bytes(raw), to=sid) + await self._send(EVENT_PAYLOAD, envelope, _buffer_bytes(raw), to=sid) async def on_unsub(self, sid: str, data: Any) -> None: token = self._token_of(data) @@ -378,7 +396,10 @@ async def on_msg(self, sid: str, data: Any) -> None: # Channel replies are bounded by construction, so this is a # contract check. await self._send( - "err", {"fig": token, "error": "reply exceeds wire attachment limit"}, [], to=sid + EVENT_ERR, + {"fig": token, "error": "reply exceeds wire attachment limit"}, + [], + to=sid, ) return envelope: dict[str, Any] = { @@ -391,7 +412,7 @@ async def on_msg(self, sid: str, data: Any) -> None: mid = self._mid_of(data) if mid is not None: envelope["mid"] = mid - await self._send("msg", envelope, wire_buffers, to=sid) + await self._send(EVENT_MSG, envelope, wire_buffers, to=sid) # -- server-side pushes (append/refresh fan-out) --------------------------- @@ -411,7 +432,7 @@ async def broadcast_message( # advanced; view-state pushes carry a generation stamp but do not # mutate the figure payload. await self._send( - "err", + EVENT_ERR, { "fig": token, "error": "push exceeds wire attachment limit", @@ -427,7 +448,7 @@ async def broadcast_message( } if version is not None: envelope["version"] = version - await self._send("msg", envelope, wire_buffers, room=self._room(token)) + await self._send(EVENT_MSG, envelope, wire_buffers, room=self._room(token)) async def broadcast_payload(self, token: str, entry: FigureEntry) -> None: """Push a full refreshed payload (figure rebuilt) to subscribers.""" @@ -436,7 +457,7 @@ async def broadcast_payload(self, token: str, entry: FigureEntry) -> None: if not self.registry.is_current(token, entry): return await self._send( - "payload", + EVENT_PAYLOAD, { "fig": token, "version": entry.version, @@ -682,7 +703,7 @@ async def _err( envelope: dict[str, Any] = {"fig": token, "error": error} if resync: envelope["resync"] = True - await self._send("err", envelope, [], to=sid) + await self._send(EVENT_ERR, envelope, [], to=sid) async def broadcast_error(self, token: str, error: str, resync: bool = False) -> None: """Room-wide err frame for server-side failures with no request to @@ -690,4 +711,4 @@ async def broadcast_error(self, token: str, error: str, resync: bool = False) -> envelope: dict[str, Any] = {"fig": token, "error": error} if resync: envelope["resync"] = True - await self._send("err", envelope, [], room=self._room(token)) + await self._send(EVENT_ERR, envelope, [], room=self._room(token)) diff --git a/python/reflex_xy/state_bridge.py b/python/reflex_xy/state_bridge.py index 775999b14..c2c2d38f3 100644 --- a/python/reflex_xy/state_bridge.py +++ b/python/reflex_xy/state_bridge.py @@ -25,6 +25,8 @@ from __future__ import annotations import inspect +import weakref +from collections.abc import Callable from typing import TYPE_CHECKING, Any, Optional from .data_vars import validate_columns @@ -115,10 +117,39 @@ async def rebuild_plan_figure(app: Any, composite: ParsedPlanToken) -> Optional[ return plan.bind(columns, source=source).figure() +def app_ref(app: Any) -> Callable[[], Any]: + """A zero-argument accessor for ``app`` that does not keep it alive. + + The data plane holds on to the app for as long as it is attached, and a + strong capture would make every hot reload's App — and the state manager + behind it — immortal. Objects that refuse weak references (test doubles, + mostly; a real ``rx.App`` supports them) fall back to a strong capture + rather than making ``setup`` fail on them. + + Args: + app: The Reflex app to reference. + + Returns: + A callable returning the app, or None once it has been collected. + """ + try: + return weakref.ref(app) + except TypeError: + return lambda: app + + def make_rebuild_hook(app: Any) -> Any: - """The data plane's RebuildHook, bound to one app instance.""" + """The data plane's RebuildHook, bound weakly to one app instance. + + An App that has been collected can no longer rebuild anything from state, + so the hook fails closed exactly as it does for an unknown token. + """ + resolve_app = app_ref(app) async def _rebuild(token_str: str) -> Optional["Figure"]: + app = resolve_app() + if app is None: + return None composite = parse_plan_token(token_str) if composite is not None: return await rebuild_plan_figure(app, composite) diff --git a/scripts/reflex_ws_smoke.py b/scripts/reflex_ws_smoke.py index 1a7da1d2c..1edc14187 100644 --- a/scripts/reflex_ws_smoke.py +++ b/scripts/reflex_ws_smoke.py @@ -184,16 +184,18 @@ def wait_for(self, expression: str, *, timeout_s: float = 60.0, label: str = "co time.sleep(0.25) raise SystemExit(f"timeout waiting for {label}; last={last!r}") - def backend_websockets(self) -> list[str]: - """Websockets to the app backend (excludes vite's dev-mode HMR socket).""" + def websockets(self) -> list[str]: + """Every websocket the page opened, including vite's dev-mode HMR one.""" self.eval("1") # pump queued CDP events urls: list[str] = [] for (sid, method), events in self.s._events.items(): if sid == self.sid and method == "Network.webSocketCreated": urls.extend(e.get("url", "") for e in events) - # The data plane is a channel *inside* this socket, so there is one - # URL to match — a second one would mean the chart opened its own. - return [u for u in urls if "/_event" in u] + return urls + + def backend_websockets(self) -> list[str]: + """Websockets to the app backend (excludes vite's dev-mode HMR socket).""" + return [u for u in self.websockets() if "/_event" in u] def sent_ws_frames(self, needle: str) -> list[str]: """Payloads of sent websocket frames containing `needle`.""" @@ -261,10 +263,17 @@ def main() -> None: ) print("mounted views:", probe.eval("Array.from(window.__xy_views.keys()).sort()")) - # 2) exactly one physical websocket to the backend for both planes + # 2) exactly one physical websocket to the backend for both planes. + # Checked in two parts, because the `/_event` filter alone cannot + # see a regression: a chart that opened its own data plane would + # land on some other URL and simply drop out of the count. So name + # the plane explicitly first, then count what is left. time.sleep(1.5) + own = [u for u in probe.websockets() if "/_xy" in u] + if own: + failures.append(f"the chart opened its own data plane socket: {own}") ws = probe.backend_websockets() - print(f"backend websockets: {len(ws)}") + print(f"backend websockets: {len(ws)} (of {len(probe.websockets())} total)") if len(ws) != 1: failures.append(f"expected exactly 1 backend websocket (shared transport), got {ws}") diff --git a/scripts/verify_ci_workflow.py b/scripts/verify_ci_workflow.py index 0b7a9073f..8d9977eaf 100644 --- a/scripts/verify_ci_workflow.py +++ b/scripts/verify_ci_workflow.py @@ -815,8 +815,11 @@ def validate_ci_workflow(path: Path = DEFAULT_CI_WORKFLOW) -> list[str]: "scripts/verify_benchmark_report.py transport.json --kind transport-loopback", "scripts/check_regressions.py --scatter scatter.json --kernel kernel.json", "--transport transport.json --emit-md spec/benchmarks/metrics.md", - "Upload regression benchmark report", - "if: always()", + # Name and condition paired, not two independent needles: this job now + # has a second `if: always()` upload (the browser evidence), which a + # bare needle would satisfy on its behalf — letting *this* step lose + # its condition and stop uploading after a failed gate, silently. + "- name: Upload regression benchmark report\n if: always()", "actions/upload-artifact@", "regression-benchmark-report", "if-no-files-found: warn", @@ -1081,7 +1084,10 @@ def validate_ci_workflow(path: Path = DEFAULT_CI_WORKFLOW) -> list[str]: "Rust-backed sdist install contract", "XY_REQUIRE_CARGO", "uv pip install --no-cache", - '"reflex>=0.9.6"', + # No Reflex requirement: the adapter needs the unreleased channel + # transport, so there is no floor to name, and this smoke only + # `import reflex_xy` — which pulls no Reflex at all. Restore the + # `xy[reflex]` install (and assert on it here) once channels ship. "import reflex_xy", "import xy.kernels as kernels", 'kernels.BACKEND == "native"', diff --git a/spec/design/reflex-integration.md b/spec/design/reflex-integration.md index 0fac3bafc..0e0f77c38 100644 --- a/spec/design/reflex-integration.md +++ b/spec/design/reflex-integration.md @@ -11,13 +11,19 @@ same performance contract as the notebook path: screen-bounded binary wire > **Unreleased dependency (temporary).** The data plane is a Reflex *channel* > (§2), which no released Reflex ships yet — it exists on > reflex-dev/reflex#6932. Until that lands, the `xy[reflex]` extra carries a -> git requirement for the branch and `[tool.uv.sources]` pins the whole Reflex -> workspace to it, with `[tool.hatch.metadata] allow-direct-references` to make -> the build accept that. This is deliberately unpublishable: PyPI refuses a -> direct reference, so a release cut from this tree fails at upload rather than +> git requirement naming one immutable commit on that branch, with +> `[tool.hatch.metadata] allow-direct-references` to make the build accept it. +> Two properties are deliberate. It is **unpublishable**: PyPI refuses a direct +> reference, so a release cut from this tree fails at upload rather than > shipping a version specifier that would install a Reflex where every chart -> stays blank. Replace all three with the real floor when channels are -> released. +> stays blank. And it is a **commit, not the branch**: the lockfiles only bind +> `uv sync --locked`, so a branch ref would let a bare `pip install xy[reflex]` +> or any `uv lock` regeneration pull framework code nobody reviewed. The same +> commit is pinned by `docs/app/pyproject.toml`'s four Reflex requirements — uv +> refuses two URLs for one package — and +> `tests/test_dependencies.py::test_docs_app_pins_the_same_reflex_commit` keeps +> the six strings in step. Replace the lot with the real floor when channels +> are released. Two decisions define this revision (superseding the HTTP-routes draft — see §8 for the audit trail): @@ -161,6 +167,14 @@ The attachments are not a field of the envelope: `XYChannel._send` passes them as the frame's attachment list, and on the client every handler takes `(data, buffers)`. +The five event names are declared as constants on both sides — +`EVENT_SUB`/`EVENT_UNSUB`/`EVENT_MSG`/`EVENT_PAYLOAD`/`EVENT_ERR` in +`data_plane.py` and again in `XYChart.jsx` — and +`tests/reflex_adapter/test_assets.py` reads the Python ones and asserts the +JavaScript declarations match. This is the one seam where the two halves could +drift without any other test noticing: a renamed event on one side alone +produces a client that talks past the server, with no error anywhere. + `mid` is a validated optional per-mount id: several charts on a page share the socket, so direct interaction replies and direct subscription payloads echo it and other mounts ignore the addressed envelope. Pushes and full-payload @@ -211,7 +225,7 @@ totality contract). This section records only what is specific to this host. **`view_change` does not reach the kernel here.** The wrapper intercepts the outgoing message and invokes the Reflex `on_view_change` prop directly (`dispatchView` in `python/reflex_xy/assets/XYChart.jsx`), because -the namespace registers no Python-side view callback (§5). Every other request +the data plane registers no Python-side view callback (§5). Every other request type crosses the socket unchanged and is dispatched by the shared `handle_message`. @@ -345,8 +359,8 @@ replacement is never removed. ### 3.3 Access control -The connection's `?token=` (the Reflex client token) is captured at -namespace connect. A state token embeds the client token it was minted for, +The connection's `?token=` (the Reflex client token) is resolved by Reflex +and read off the channel session when it opens. A state token embeds the client token it was minted for, and `sub`/`msg` refuse a figure whose embedded client token differs from the connection's (`err: figure belongs to another session`). Tokens carry nothing their own client doesn't already know. When Reflex grows real @@ -438,10 +452,10 @@ figure/data memory, not correctness. While at least one rebuildable subscriber remains, both the sweep and an explicit release retain only the removed token's scalar version so a republish on the same worker stays monotonic; the figure and its data buffers are released. If an interaction is the first touch after -eviction, the namespace +eviction, the data plane rebuilds, sends every subscribed mount a replacement payload room-wide, and drops the old-generation interaction for the triggering client to retry. If a -new `sub` is first, the namespace broadcasts the rebuild to existing room +new `sub` is first, the data plane broadcasts the rebuild to existing room members before joining the requester, then sends that mount one `mid`-addressed payload built for its own `px` hint. The direct path re-reads the current entry after joining the room: a normal replacement that landed before the join is @@ -675,7 +689,7 @@ refused as a subscription outright. re-binds every mounted dependent through the `data token → {digests}` index — fresh figures, bumped versions, coalesced room broadcasts, exactly the figure-var republish machinery. The index is added to when a composite -binds (namespace `sub`) and pruned on **every transition that can end the +binds (a data-plane `sub`) and pruned on **every transition that can end the mount**: the last unsubscribe or disconnect for the composite token, its entry's release, failed-rebuild cleanup, the TTL sweep, and a republish that finds it unmounted (`_unbind_plan_if_unmounted_locked`). "Bounded by @@ -836,7 +850,7 @@ impossible — the JS that renders a payload is always the build that shipped with the Python that produced it. One renderer for notebooks, static export, and Reflex. -The wrapper: opens/reuses the shared namespace socket, `sub`s with the +The wrapper: takes the shared `/_xy` channel, `sub`s with the element's measured width, builds a `ChartView` for the first `payload`, and passes later full payloads to `ChartView.updatePayload` (preserving keyed animation state; destroy + rebuild is only the compatibility fallback), @@ -844,7 +858,7 @@ bridges `comm` to `msg` events, and forwards semantic events into Reflex's event system via the component's event-trigger props (`props.onPointHover(row)` → `addEvents(...)` → the user's handler). Client-side niceties: `view_change` resolves locally (no kernel round-trip; -the namespace registers no Python callbacks), `click` issues a tagged `pick` +the data plane registers no Python callbacks), `click` issues a tagged `pick` so `on_point_click` delivers the exact row, `selection` replies pair with the brush rect that produced them. @@ -976,7 +990,7 @@ def remember_view(self, event: dict): reflex_xy.chart(figure=Dash.cloud, on_view_change=Dash.remember_view) ``` -Every kernel request echoes the last payload version as `v`; the namespace +Every kernel request echoes the last payload version as `v`; the data plane silently rejects requests for another figure version and drops an explicitly malformed `v`. Omitted `v` remains accepted for compatibility. Replies echo the operation version; room-wide append pushes carry the newly bumped version, diff --git a/spec/design/view-state.md b/spec/design/view-state.md index cb8e90d46..4f92ade96 100644 --- a/spec/design/view-state.md +++ b/spec/design/view-state.md @@ -223,10 +223,10 @@ which does converge room-wide. Path: per-generation operation lease plus entry-local synchronous figure lock → one wire message (§8) → pushed room-wide as a `msg` event on the `/_xy` -namespace → every client in the room applies it through the §3 mutation path +channel → every client in the room applies it through the §3 mutation path with `source: "api"`. Message construction and version capture are atomic with -namespace payload/interaction kernels and an append's mutation and version -bump, while different figures remain independent. Namespace work that also +data-plane payload/interaction kernels and an append's mutation and version +bump, while different figures remain independent. Data-plane work that also needs the generation's async lock always acquires async then synchronous; caller-thread view writes acquire only the synchronous lock, so the order has no reverse edge. Multi-client semantics are therefore identical to `append` diff --git a/spec/design/wire-protocol.md b/spec/design/wire-protocol.md index b6dd6def9..3a5990297 100644 --- a/spec/design/wire-protocol.md +++ b/spec/design/wire-protocol.md @@ -106,7 +106,7 @@ gate. This is the one request type a host may withhold: on the Reflex host it never reaches the kernel, because `XYChart.jsx` intercepts the outgoing message and invokes the `on_view_change` prop directly -(`python/reflex_xy/assets/XYChart.jsx`) — that namespace +(`python/reflex_xy/assets/XYChart.jsx`) — that channel registers no Python-side view callback. **`select`** — box select. Edges are ordered by `lod.normalize_window` with @@ -305,7 +305,7 @@ non-atomically, the client listens to *both* change events, defers a torn pair — a column that no longer fits its buffer — without consuming the seq, and keys applied state on (seq, buffers identity), so the write that completes the pair re-fires the apply and repairs even a same-shape tear. -The `/_xy` namespace has no synced traits, so it wraps the +The `/_xy` channel has no synced traits, so it wraps the same spec and buffers in a room-wide `msg` push. In both cases the client reads the buffer layout from `spec.buffer_layout`, never from the shape of what arrived (§5). @@ -320,7 +320,7 @@ out of the client's history stack. A document the client cannot validate logged — never partially applied. Built by `Figure.state_patch_message`; senders are `FigureWidget.set_view`/`select`/`clear_selection` (anywidget comm) and `reflex_xy.set_view`/`select`/`clear_selection` (room-wide on the -`/_xy` namespace). +`/_xy` channel). **`view_nav`** — `{type, op: "reset", axes?}`, no buffers. Navigation to the home ranges, well-defined for every receiver because home ranges are diff --git a/tests/reflex_adapter/test_assets.py b/tests/reflex_adapter/test_assets.py index e3ac83803..b1a06ca79 100644 --- a/tests/reflex_adapter/test_assets.py +++ b/tests/reflex_adapter/test_assets.py @@ -8,6 +8,7 @@ import reflex_xy import xy +from reflex_xy import data_plane from reflex_xy.assets import _client_source, _link_client ADAPTER_ASSETS = pathlib.Path(reflex_xy.__file__).parent / "assets" @@ -56,19 +57,28 @@ def test_link_client_creates_and_repairs(tmp_path): def test_wrapper_speaks_the_data_plane_protocol(): """The JSX wrapper and data_plane.py must agree on event names and shapes.""" jsx = (ADAPTER_ASSETS / "XYChart.jsx").read_text(encoding="utf-8") - # transport identity: one channel name, matching XY_PLANE in data_plane.py, - # on the app's own websocket — no second connection to open or configure - assert 'const XY_PLANE = "/_xy"' in jsx + # transport identity: one channel name on the app's own websocket — no + # second connection to open or configure. The name itself comes from + # data_plane.py rather than a literal, so a rename there fails here. + assert f'const XY_PLANE = "{data_plane.XY_PLANE}"' in jsx assert "getChannel(XY_PLANE)" in jsx # socket.io is gone: no client, no namespace URL, no engine.io mount path for gone in ("socket.io-client", "nsUrl", "endpoint.pathname", "env.TRANSPORT", "io("): assert gone not in jsx, f"wrapper still carries socket.io machinery: {gone}" + # Both sides name the same five events, and take their names from the same + # place: this is the one point where the Python and JavaScript halves of + # the protocol can drift apart without any other test noticing. + for constant in ("EVENT_SUB", "EVENT_UNSUB", "EVENT_MSG", "EVENT_PAYLOAD", "EVENT_ERR"): + event = getattr(data_plane, constant) + assert f'const {constant} = "{event}"' in jsx, ( + f"XYChart.jsx does not declare {constant} = {event!r} the way data_plane.py does" + ) # client -> server events - for needle in ('"sub"', '"unsub"', '"msg"'): - assert f"plane.emit({needle}" in jsx + for constant in ("EVENT_SUB", "EVENT_UNSUB", "EVENT_MSG"): + assert f"plane.emit({constant}" in jsx # server -> client events - for needle in ('"payload"', '"msg"', '"err"'): - assert f"plane.on({needle}" in jsx + for constant in ("EVENT_PAYLOAD", "EVENT_MSG", "EVENT_ERR"): + assert f"plane.on({constant}" in jsx # binary columns go straight into typed arrays — never through JSON numbers assert "new Uint8Array(b)" in jsx assert "data.version < payloadVersion" in jsx @@ -99,7 +109,7 @@ def test_wrapper_speaks_the_data_plane_protocol(): assert jsx.count("resetEpoch();") == 3 # subscribe, disconnect, cleanup assert "awaitingPayload || !plane.connected" in jsx assert "awaitingPayload = false" in jsx - assert 'plane.on("disconnect", onDisconnect)' in jsx + assert "plane.on(EVENT_DISCONNECT, onDisconnect)" in jsx assert "wireVersion > expected && plane.connected" in jsx assert "data.resync === true && plane.connected" in jsx # Rejected replies and accepted generation advances both reclaim pending diff --git a/tests/reflex_adapter/test_channel_browser.py b/tests/reflex_adapter/test_channel_browser.py index 67581c27e..4e9168246 100644 --- a/tests/reflex_adapter/test_channel_browser.py +++ b/tests/reflex_adapter/test_channel_browser.py @@ -9,23 +9,38 @@ from __future__ import annotations import json +import os from collections.abc import Generator from pathlib import Path import pytest -pytest.importorskip("playwright") +# This is the only check of the single-shared-websocket claim, so a missing +# browser must not quietly turn it into a pass. `XY_REQUIRE_BROWSER=1` — what +# CI sets — makes both the Python package and the browser binary hard +# requirements; without it a bare checkout still skips. +REQUIRE_BROWSER = os.environ.get("XY_REQUIRE_BROWSER") == "1" +if not REQUIRE_BROWSER: + pytest.importorskip("playwright") from PIL import Image # noqa: E402 +from playwright.sync_api import Error as PlaywrightError # noqa: E402 from playwright.sync_api import WebSocket, sync_playwright # noqa: E402 from reflex.testing import AppHarness # noqa: E402 +from reflex_xy.data_plane import XY_PLANE # noqa: E402 + # The app's event websocket, the one the chart has to share. EVENT_PATH = "/_event" # Headless chromium has no GPU; xy's own browser probes use the same pair. CHROMIUM_ARGS = ("--use-angle=swiftshader", "--enable-unsafe-swiftshader") +# Where to keep the painted-chart screenshot. CI points this at an uploaded +# artifact directory so the evidence outlives the run; locally it defaults to +# pytest's tmp_path. +EVIDENCE_DIR = os.environ.get("XY_BROWSER_EVIDENCE") + def ChannelChartApp(): """A Reflex app with one live xy chart served over a channel.""" @@ -106,43 +121,59 @@ def test_chart_paints_from_channel_binary(chart_app: AppHarness, tmp_path: Path) sockets: list[WebSocket] = [] binary_frames: list[int] = [] + shot = Path(EVIDENCE_DIR or tmp_path) / "chart.png" + shot.parent.mkdir(parents=True, exist_ok=True) + with sync_playwright() as playwright: - browser = playwright.chromium.launch(args=list(CHROMIUM_ARGS)) - page = browser.new_page(viewport={"width": 1024, "height": 768}) - - def watch(socket: WebSocket) -> None: - sockets.append(socket) - if EVENT_PATH not in socket.url: - return # the dev server's hot-reload channel - socket.on( - "framereceived", - lambda payload: ( - binary_frames.append(len(payload)) if isinstance(payload, bytes) else None - ), + try: + browser = playwright.chromium.launch(args=list(CHROMIUM_ARGS)) + except PlaywrightError as error: # no browser binary installed + if REQUIRE_BROWSER: + raise + pytest.skip(f"chromium is not installed for playwright: {error}") + # Explicitly, rather than by leaving it to the sync_playwright exit: a + # failing assertion inside the block would otherwise leave the Chromium + # process up until the whole context unwinds, and those accumulate. + try: + page = browser.new_page(viewport={"width": 1024, "height": 768}) + + def watch(socket: WebSocket) -> None: + sockets.append(socket) + if EVENT_PATH not in socket.url: + return # the dev server's hot-reload channel + socket.on( + "framereceived", + lambda payload: ( + binary_frames.append(len(payload)) if isinstance(payload, bytes) else None + ), + ) + + page.on("websocket", watch) + page.goto(chart_app.frontend_url) + page.wait_for_selector("#ready") + # The chart only reaches "ready" once a payload has been applied. + # A cold dev server still has xy's WebGL client bundle to transform, + # which outlasts the default wait by a wide margin. + chart = page.locator('[data-xy-slot="root"]') + chart.wait_for(state="visible", timeout=120_000) + page.wait_for_function( + "!!document.querySelector('[data-xy-context-state=\"ready\"]')", + timeout=120_000, ) - - page.on("websocket", watch) - page.goto(chart_app.frontend_url) - page.wait_for_selector("#ready") - # The chart only reaches "ready" once a payload has been applied. - # A cold dev server still has xy's WebGL client bundle to transform, - # which outlasts the default wait by a wide margin. - chart = page.locator('[data-xy-slot="root"]') - chart.wait_for(state="visible", timeout=120_000) - page.wait_for_function( - "!!document.querySelector('[data-xy-context-state=\"ready\"]')", - timeout=120_000, - ) - # The accessible summary is computed from the decoded columns. - summary = page.locator('[id$="-summary"]').inner_text() - shot = tmp_path / "chart.png" - chart.screenshot(path=str(shot)) - browser.close() - + # The accessible summary is computed from the decoded columns. + summary = page.locator('[id$="-summary"]').inner_text() + chart.screenshot(path=str(shot)) + finally: + browser.close() + + # The chart opened nothing of its own. Checked first and by name, because + # the count below cannot see it: a self-opened data plane would land on + # some other URL and simply drop out of the filter. + own_sockets = [socket.url for socket in sockets if XY_PLANE in socket.url] + assert not own_sockets, f"the chart opened its own data plane socket: {own_sockets}" # One connection to the backend for the whole page: the chart multiplexes - # onto the app's event websocket instead of opening a data plane of its - # own. (The other socket is the dev server's hot-reload channel, which a - # built app does not have.) + # onto the app's event websocket. (The other socket is the dev server's + # hot-reload channel, which a built app does not have.) backend_sockets = [socket.url for socket in sockets if EVENT_PATH in socket.url] assert len(backend_sockets) == 1, backend_sockets # Columns travelled as binary frames on that socket, not as JSON numbers @@ -164,6 +195,7 @@ def watch(socket: WebSocket) -> None: "summary": summary.replace("\n", " ")[:120], "colours": colours, "binary_frames": binary_frames, + "screenshot": str(shot), } ) ) diff --git a/tests/reflex_adapter/test_data_plane.py b/tests/reflex_adapter/test_data_plane.py index 7a2910979..4030c4601 100644 --- a/tests/reflex_adapter/test_data_plane.py +++ b/tests/reflex_adapter/test_data_plane.py @@ -18,7 +18,7 @@ import socket import threading from types import SimpleNamespace -from typing import Any, TypedDict +from typing import Any, Optional, TypedDict import aiohttp import numpy as np @@ -103,6 +103,7 @@ def __init__(self, session: aiohttp.ClientSession, ws: aiohttp.ClientWebSocketRe self.messages: asyncio.Queue = asyncio.Queue() self.errors: asyncio.Queue = asyncio.Queue() self._opened = asyncio.Event() + self.reader_error: Optional[BaseException] = None self._queues = { "payload": self.payloads, "msg": self.messages, @@ -111,6 +112,19 @@ def __init__(self, session: aiohttp.ClientSession, ws: aiohttp.ClientWebSocketRe self._reader = asyncio.create_task(self._read_forever()) async def _read_forever(self) -> None: + try: + await self._read_frames() + except (asyncio.CancelledError, ConnectionResetError): + raise # ordinary teardown + except Exception as error: # noqa: BLE001 - the wire is what's under test + # A malformed frame is the failure this suite exists to catch, so + # it must not surface as "everything timed out". Hand it to every + # waiter instead of dying quietly with an unretrieved exception. + self.reader_error = error + for queue in self._queues.values(): + queue.put_nowait(error) + + async def _read_frames(self) -> None: with contextlib.suppress(asyncio.CancelledError, ConnectionResetError): async for frame in self._ws: if frame.type == aiohttp.WSMsgType.BINARY: @@ -146,7 +160,10 @@ async def disconnect(self) -> None: return self.connected = False self._reader.cancel() - with contextlib.suppress(asyncio.CancelledError): + # Any reader failure was already handed to the waiters, so teardown + # only has to retrieve it — re-raising here would replace a test's real + # assertion failure with a confusing one from the cleanup path. + with contextlib.suppress(BaseException): await self._reader await self._ws.close() await self._session.close() @@ -175,7 +192,10 @@ def __init__(self, client: PlaneClient) -> None: @staticmethod async def next(queue: asyncio.Queue, timeout: float = 5.0): - return await asyncio.wait_for(queue.get(), timeout) + frame = await asyncio.wait_for(queue.get(), timeout) + if isinstance(frame, BaseException): + raise AssertionError("the data plane reader failed") from frame + return frame class FakeSession: diff --git a/tests/reflex_adapter/test_setup_attachment.py b/tests/reflex_adapter/test_setup_attachment.py new file mode 100644 index 000000000..3fa466ae2 --- /dev/null +++ b/tests/reflex_adapter/test_setup_attachment.py @@ -0,0 +1,135 @@ +"""`setup(app)` attaches per app, not per process. + +The registry is a process-global cache while Apps are not: a hot reload +re-imports the app module, AppHarness builds one per test, and nothing stops +two Apps coexisting in one interpreter. These tests pin the two consequences — +`setup` must never hand an already-attached app a second channel (Reflex +rejects a duplicate channel name outright), and registry fan-out must reach +every live app rather than only the most recent one. +""" + +from __future__ import annotations + +import asyncio +import gc + +import numpy as np +import pytest +import reflex as rx +from reflex.istate.manager.memory import StateManagerMemory +from reflex_base.registry import RegistrationContext + +import xy +from reflex_xy import app as adapter_app +from reflex_xy.app import setup + + +def make_app(): + """A real `rx.App`. + + An App claims the registration context it is built in and refuses to share + it, so every App after the first is built in a fork — which is exactly the + shape this module is about: several Apps, one process. + """ + try: + context = RegistrationContext.get() + except LookupError: + app = rx.App() # the first App in this process claims the context + else: + with context.fork(): + app = rx.App() + app._state_manager = StateManagerMemory() + return app + + +def make_figure(n: int = 8): + xs = np.linspace(0.0, 1.0, n) + return xy.scatter_chart(xy.scatter(xs, xs * 3.0), width=640, height=400).figure() + + +def test_setup_is_idempotent_for_one_app(): + app = make_app() + first = setup(app) + assert setup(app) is first + assert list(app._channels) == [first.name] + + +def test_revisiting_an_app_does_not_register_a_second_channel(): + """A → B → A. Keying idempotency on "the most recent app" would build a + second channel for A here, and `App.register_channel` raises on the + duplicate name — turning an ordinary multi-app process into a crash.""" + app_a, app_b = make_app(), make_app() + channel_a = setup(app_a) + channel_b = setup(app_b) + + assert channel_a is not channel_b + assert setup(app_a) is channel_a # must not raise + assert list(app_a._channels) == [channel_a.name] + assert list(app_b._channels) == [channel_b.name] + + +def test_publish_fans_out_to_every_live_app(_fresh_registry, monkeypatch): + """The second app must not silently strand the first app's subscribers.""" + registry = _fresh_registry + app_a, app_b = make_app(), make_app() + channel_a = setup(app_a) + channel_b = setup(app_b) + delivered: list[tuple[str, object]] = [] + + for channel in (channel_a, channel_b): + + async def broadcast(token, entry, _channel=channel): + delivered.append((token, _channel)) + + monkeypatch.setattr(channel, "broadcast_payload", broadcast) + + async def main(): + registry.attach_loop(asyncio.get_running_loop()) + token = registry.register(make_figure()) + registry.publish(token, make_figure(12)) + await asyncio.sleep(0) # let the scheduled fan-out task run + await asyncio.sleep(0) + return token + + token = asyncio.run(main()) + assert sorted(channel is channel_b for _, channel in delivered) == [False, True] + assert {name for name, _ in delivered} == {token} + + +def test_one_failing_plane_does_not_swallow_the_others(_fresh_registry, monkeypatch): + registry = _fresh_registry + app_a, app_b = make_app(), make_app() + channel_a, channel_b = setup(app_a), setup(app_b) + reached = [] + + async def boom(token, entry): + raise RuntimeError("transport failed") + + async def ok(token, entry): + reached.append(token) + + monkeypatch.setattr(channel_a, "broadcast_payload", boom) + monkeypatch.setattr(channel_b, "broadcast_payload", ok) + + async def main(): + entry = registry.publish("tok", make_figure(), broadcast=False) + with pytest.raises(RuntimeError, match="transport failed"): + await adapter_app._fan_out_payload("tok", entry) + + asyncio.run(main()) + assert reached == ["tok"], "the healthy plane must still have received the payload" + + +def test_a_collected_app_stops_receiving_fan_out(): + """A hot reload replaces the App; the old one must not be kept alive by + the attachment list, nor keep receiving broadcasts once collected.""" + app_a, app_b = make_app(), make_app() + setup(app_a) + setup(app_b) + assert len(adapter_app._live_planes()) == 2 + + del app_a + gc.collect() + + assert len(adapter_app._live_planes()) == 1 + assert len(adapter_app._attached) == 1 diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index d7e192975..4261e9f08 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -8,6 +8,19 @@ ROOT = Path(__file__).resolve().parents[1] CORE_PACKAGE = ROOT / "python" / "xy" +# TEMPORARY, tracked in spec/design/reflex-integration.md § Status: the data +# plane needs Reflex's channel transport, which is unreleased, so `xy[reflex]` +# names an immutable commit instead of a version floor. A direct reference is +# unpublishable by design — a release cut from this tree fails at upload rather +# than shipping a floor that installs a Reflex where every chart stays blank. +# It is a commit and not the branch so that an install which bypasses the +# lockfile still gets the reviewed framework code. Restore the `>=` +# assertion, and drop `test_docs_app_pins_the_same_reflex_commit`, when +# channels are released. +REFLEX_REQUIREMENT = ( + "git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7" +) + def _dependency_name(requirement: str) -> str: requirement = requirement.split(";", 1)[0].strip() @@ -35,15 +48,8 @@ def test_core_publishes_only_the_reflex_optional_dependency() -> None: extras = project.get("optional-dependencies") or {} assert set(extras) == {"reflex"} - # TEMPORARY, tracked in spec/design/reflex-integration.md § Status: the - # data plane needs Reflex's channel transport, which is unreleased, so the - # extra names the branch instead of a floor. A direct reference is - # unpublishable by design — the release fails at upload rather than - # shipping a floor that installs a Reflex where every chart stays blank. - # Restore the `>=` assertion when channels are released. assert any( - _dependency_name(requirement) == "reflex" - and "git+https://github.com/benedikt-bartscher/reflex.git@make-sio-optional" in requirement + _dependency_name(requirement) == "reflex" and REFLEX_REQUIREMENT in requirement for requirement in extras["reflex"] ), ( "xy[reflex] must select the Reflex the adapter actually needs while the " @@ -62,6 +68,28 @@ def test_core_publishes_only_the_reflex_optional_dependency() -> None: ) +def test_docs_app_pins_the_same_reflex_commit() -> None: + """Six requirement strings name this commit; they have to agree. + + uv refuses two URLs for one package, so the docs app cannot resolve at all + if its Reflex requirements drift from the root extra's — and a half-updated + pin would otherwise only surface as a resolution error in a separate CI job. + """ + docs = tomllib.loads(ROOT.joinpath("docs/app/pyproject.toml").read_text(encoding="utf-8")) + requirements = (docs.get("project") or {}).get("dependencies") or [] + reflex_requirements = [ + requirement + for requirement in requirements + if _dependency_name(requirement).startswith("reflex") + ] + + assert reflex_requirements, "the docs app must depend on Reflex" + for requirement in reflex_requirements: + assert REFLEX_REQUIREMENT in requirement, ( + f"docs/app pins a different Reflex than xy[reflex]: {requirement}" + ) + + def test_core_package_does_not_import_reflex() -> None: forbidden = ("reflex", "reflex_core", "reflex_base") violations: list[str] = [] diff --git a/uv.lock b/uv.lock index 2e1a8f416..09be1a8da 100644 --- a/uv.lock +++ b/uv.lock @@ -447,6 +447,83 @@ reload = [ { name = "watchfiles" }, ] +[[package]] +name = "greenlet" +version = "3.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/d8/7cc97c142388aef03f622e001c572c4f84e9252a439549d483f555771970/greenlet-3.5.5.tar.gz", hash = "sha256:adb4bae02e91a8e863e48b177e4014bdcac8a6b5e047ea1df687a61534b85e6c", size = 207585, upload-time = "2026-08-10T15:09:36.136Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/a3/07297917485ee2ca85bc3c8dc6ed85ad3fffcf424047fba62671dba68e97/greenlet-3.5.5-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:be63afcbbccfad3dd95a1ba12ada84dab2ef32031973d80b5b92df67fa763a61", size = 294165, upload-time = "2026-08-10T13:25:17.987Z" }, + { url = "https://files.pythonhosted.org/packages/db/51/6f732f9314cda54c5fd48a7620c7160f4f286967e8045ad94b9d66ce80b7/greenlet-3.5.5-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a268024ce2d7d2b04694bf1594058981a9fa663d1df4b762dee499211ed7c1c", size = 613610, upload-time = "2026-08-10T14:14:33.829Z" }, + { url = "https://files.pythonhosted.org/packages/d8/c0/b27589e25d220289edcd4d582b2b17b83058d1a56d53d971b6ea1a34f10d/greenlet-3.5.5-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:35cbb8bf55ace57fbccb4fb8622c4521713acd8691e77f4696d416ea7ca527da", size = 625481, upload-time = "2026-08-10T14:27:23.647Z" }, + { url = "https://files.pythonhosted.org/packages/39/82/5c873dbb4fb001d22fbbd50e80d4c1b0181ddae106856132160f84b94e88/greenlet-3.5.5-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:abc8bc8d9f935cd685457545b6a53863a877fdc12c2c0f5ee9beee18d9db139c", size = 633329, upload-time = "2026-08-10T14:30:06.062Z" }, + { url = "https://files.pythonhosted.org/packages/51/2d/f2c928218ac52f26d7a2c188c171d1b7e728b23782cb3347e7b4fce1493a/greenlet-3.5.5-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cc6df89ec5302337adc9cf096221cbed2510fd444b0e0f1586cf0470740864", size = 624562, upload-time = "2026-08-10T13:40:48.064Z" }, + { url = "https://files.pythonhosted.org/packages/70/12/f7df98e72a8eb4a7edfec5a08d6d1a4ab53a52c95ba0b2ea6c10b8dd9bd0/greenlet-3.5.5-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:3134291427bb0f3526e9d90311988caf336eb43730e95244997a4fb15f45144f", size = 428145, upload-time = "2026-08-10T14:30:01.071Z" }, + { url = "https://files.pythonhosted.org/packages/3e/4a/92fc51d5d35912f4f06eec037ba347985defd0be47463a010a325634d9d2/greenlet-3.5.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d9b454c5fc48aeaa7c4337813dbf513a6870468e426438a04d922c6d0fe63db", size = 1584909, upload-time = "2026-08-10T14:15:04.343Z" }, + { url = "https://files.pythonhosted.org/packages/ac/58/ed98b80ac5738c149a5258544843c45601ade1fd70f61740cdaead6351b3/greenlet-3.5.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03551ed792cb1b4fc0277a0c60dfd8c343894a0ba06fe60dcd22f568b433da39", size = 1651184, upload-time = "2026-08-10T13:40:28.879Z" }, + { url = "https://files.pythonhosted.org/packages/d8/be/b582ceb80cefdf9d8da34078714e4b12b3d16f509dee0f65e40a5cc8fc7d/greenlet-3.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:ab3df3dffb58bf70564e93a5cec7941e4d9faa5a36cc4234a10d3131afe04f53", size = 323280, upload-time = "2026-08-10T13:26:07.495Z" }, + { url = "https://files.pythonhosted.org/packages/4d/18/5313c4c58598c38b0373c013e4ff2b3e6d258aaaa338f373335ebecdaddd/greenlet-3.5.5-cp311-cp311-win_arm64.whl", hash = "sha256:2b70a766135540c472ac1393d57c2e1b4a2eb85bf526a1e41e6d096173a8cee5", size = 307785, upload-time = "2026-08-10T13:28:34.874Z" }, + { url = "https://files.pythonhosted.org/packages/2e/7e/9ecd0285e3153532ae07aeb88063c43c72b4221cf0d4d123b02f3682e3ff/greenlet-3.5.5-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:49520f0c95a48b42cf55414b8e8479beb274ea70431afc33e3f79903c71f4380", size = 295809, upload-time = "2026-08-10T13:25:34.023Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/60e4bbcc89252037b18087f2ec16405d5b2d5be42dde191bbf3667e96102/greenlet-3.5.5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55272212cbc5f43d1d723725ab931f1939969b7e9523882ca58b55061769d053", size = 611910, upload-time = "2026-08-10T14:14:35.18Z" }, + { url = "https://files.pythonhosted.org/packages/a4/17/cd5134be659cd4a443e7a61ae670dabec165a814c51162916d637b6dd38e/greenlet-3.5.5-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655bca754a2ef4efcb0eb48a94d3f4593536d0f3d48f8ed44343c01d16a92f95", size = 624198, upload-time = "2026-08-10T14:27:25.229Z" }, + { url = "https://files.pythonhosted.org/packages/9b/30/87c212b5c684d0e72974f1063b7a9687631e8985902c06e1016542c874e7/greenlet-3.5.5-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ca5d6ae0739e5764f2cfcfaa562ac5a990cbdaedca93251c5e3cf07c362371f", size = 629504, upload-time = "2026-08-10T14:30:07.967Z" }, + { url = "https://files.pythonhosted.org/packages/78/ac/5c5b959999b6f09c3026b5dfe171575bc3121c5236ce74f495096f25b203/greenlet-3.5.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:147b25a42e5ca5be3d42356e8f608b37af715a1c196e9bf9d1627f3341adfe1d", size = 621439, upload-time = "2026-08-10T13:40:49.391Z" }, + { url = "https://files.pythonhosted.org/packages/63/2c/eb487fafc9f50ffff2b1e0b697f70fb34bf150821c08ab225aacf5583a7e/greenlet-3.5.5-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:1b5ed9162c0c098e0bbc2cf88a94f433c1b8926f831745252e099e5d83e17759", size = 432462, upload-time = "2026-08-10T14:30:02.309Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8b/6acf112ed8aee499f25b4d6949820fb02ac950ff9c1f3d793bd5be0599f2/greenlet-3.5.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:27493374cff1d1b7919dc8126547f2aea582737e3046147b434b1e12de56389b", size = 1581342, upload-time = "2026-08-10T14:15:05.653Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d7/734e5f198888876b42d7616ff6644c075baf6b8a2412deadd6b0e1b8b20c/greenlet-3.5.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:12e2ee66c2aba86133f10fd99d6a8856c6d351ffb7be0e4d52ef2cc5fbb705b2", size = 1645744, upload-time = "2026-08-10T13:40:30.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/30/1f42b88dc587b5899ee50616ad56ee40cafaf225df4fb829f10183c62a5c/greenlet-3.5.5-cp312-cp312-win_amd64.whl", hash = "sha256:49ddacd36af37735fab103846f4ee4d18a492dde72730d1699c0c8ebe30d9f18", size = 324171, upload-time = "2026-08-10T13:28:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/76/e5/4dee4d8d2e603fe5fdd7b444e63219f7b9bd852c60c6214511c7157cbe88/greenlet-3.5.5-cp312-cp312-win_arm64.whl", hash = "sha256:5f1b1ff4828cdc1aba4266aff814085d04a1d07959287219af021b838b265d52", size = 308362, upload-time = "2026-08-10T13:26:46.839Z" }, + { url = "https://files.pythonhosted.org/packages/fb/3d/8cef5f724ec0d4add2af8961d504535ec60c3cca9e464f6d03bdba29d85b/greenlet-3.5.5-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:b79fd2a5bc099b5e744f34c4c9a58954a5f4cb7529fb4b6e8446057d61b6edaa", size = 294730, upload-time = "2026-08-10T13:27:51.206Z" }, + { url = "https://files.pythonhosted.org/packages/88/4b/8e7aa3f514273aecff30a16ab1bac09ff54cfc7e6860fdd8058c37ff2499/greenlet-3.5.5-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:634cf15a233a949136879dd388e25d3296e16f3f1e217d2456797b8579ebc6ed", size = 614536, upload-time = "2026-08-10T14:14:36.589Z" }, + { url = "https://files.pythonhosted.org/packages/85/48/4e95e9dd5a8a397dc6a6345dd7f1935113d0fca4f85e89d3976da9cd988d/greenlet-3.5.5-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:499adea519f748407fc6806d20eedabac2884fd73b9f38d81236e190ba20dfef", size = 626924, upload-time = "2026-08-10T14:27:27.048Z" }, + { url = "https://files.pythonhosted.org/packages/0e/84/eaa476d6bf3816828d0d70e80dcc36bf30a058233bd889e707e693f6e860/greenlet-3.5.5-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7278591501941bb2456af102bb9cd59aab48c6cfd6e2dd68fa1290bb0c49a42", size = 632726, upload-time = "2026-08-10T14:30:09.874Z" }, + { url = "https://files.pythonhosted.org/packages/89/5d/398a1c71fa7a277deeb376c999979de6786f08fc2d5747a0b9d6e11738dd/greenlet-3.5.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2eabb980975cba5b93a95f6f69287d05fc05ac955bfd6a320a7c083eeb52c0b0", size = 623906, upload-time = "2026-08-10T13:40:50.501Z" }, + { url = "https://files.pythonhosted.org/packages/d0/f2/0cc2849ede68579291e9c59b3ab6ec1958f98681cca5b14d8fc75bf674a4/greenlet-3.5.5-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:4dfc7c4470354e7b09184d1a3a985761053a2fd694ddb5b5c80242afc2c8c90b", size = 434966, upload-time = "2026-08-10T14:30:03.729Z" }, + { url = "https://files.pythonhosted.org/packages/04/1b/745450fc5ea9e0cb17d840d248f284db3363de736d362c7d2d883e3eadba/greenlet-3.5.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:03115c2e0a371999bf8ae616aa8d653f96641d4705c457aebaa187276e9f7537", size = 1581430, upload-time = "2026-08-10T14:15:06.853Z" }, + { url = "https://files.pythonhosted.org/packages/d4/29/d51b296e3191bb15d3d81ec375af1909e4466c0f395d744ed475801798a9/greenlet-3.5.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4441153ffba21b90d3ca89fe3d31f5c093ae6c0bf0cfdfc98f54cde22f95b62e", size = 1645684, upload-time = "2026-08-10T13:40:32.133Z" }, + { url = "https://files.pythonhosted.org/packages/12/63/369f1a1625e64e9e31df3963c6044056e3fdfa3fa3fdba3c54ffefa6e987/greenlet-3.5.5-cp313-cp313-win_amd64.whl", hash = "sha256:95c5b1f4b3a193f8a0c2de4bfdcb48d119f7f1063941f1de1f2168051b3e52dd", size = 324075, upload-time = "2026-08-10T13:26:58.974Z" }, + { url = "https://files.pythonhosted.org/packages/45/78/649cb5c09d4d81f6dd1444e75474a7206784743283a21d24171562ac4899/greenlet-3.5.5-cp313-cp313-win_arm64.whl", hash = "sha256:1af90aa4bc129883b340cdd6957a3bc74f60528a4993bbd1f53aaebe1d9981cc", size = 308260, upload-time = "2026-08-10T13:27:50.795Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/080e881fa2be95ff1ddbd6994b2bab3b1a78df3b3fcab39306011764fcc7/greenlet-3.5.5-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d4a389a852e392a6366058651a20fa5ba40d979865aa81bea2ccbdc44805070d", size = 295309, upload-time = "2026-08-10T13:26:03.032Z" }, + { url = "https://files.pythonhosted.org/packages/25/cc/0ac614e6586c0e42d4cc281a5819150f4f43685744a4c5ff77139286409d/greenlet-3.5.5-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70b157cd319873e8b544ddc2de158f55bbd0a9b0218c8ce9332039801518e328", size = 661185, upload-time = "2026-08-10T14:14:37.867Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b9/6808725354be8ad305dfe5172377664fc9642d4fc043be246b3314cf4482/greenlet-3.5.5-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8bdfd1424abcf26832961e766570cae79efdb9599d709088c9cb6ef82b194926", size = 673419, upload-time = "2026-08-10T14:27:28.652Z" }, + { url = "https://files.pythonhosted.org/packages/eb/52/f005d579acde46c3d1cc3cab1c9f3d5708c8a3006a4120e8cf5da801afe9/greenlet-3.5.5-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d98ef6f92e67c6dbf299dbfd8facc1b0d2d9cedf91e325e73b3d0373fe4309d8", size = 677863, upload-time = "2026-08-10T14:30:11.663Z" }, + { url = "https://files.pythonhosted.org/packages/42/2e/40c509967da7f254680826a2fa0dd22138ec79946c70b97542d74cde8b43/greenlet-3.5.5-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:182de51c6b572a705f2fafaab2e783bcf7d2760940229dfe73086cbae037af3e", size = 670822, upload-time = "2026-08-10T13:40:51.833Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8a/a75f8a2bdcef3c358a3147cdc9db3aa83755f0a038f766ab0bedb66f512c/greenlet-3.5.5-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:159df1942d88e8f784cbb38d6f18bdb365cd11319cfbb3e89623de2b97892d53", size = 480554, upload-time = "2026-08-10T14:30:05.171Z" }, + { url = "https://files.pythonhosted.org/packages/2d/22/c3c2eee4a8fe191d6d1d183086c56133d646024e3d70bfd414829f64560b/greenlet-3.5.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8fec3f165dfe332e490c3247c0f6c23b0bfc45f06496ad7f00ddb00e3d35e4dc", size = 1628469, upload-time = "2026-08-10T14:15:08.11Z" }, + { url = "https://files.pythonhosted.org/packages/f7/87/25babd09b94cb1f03e71db815fde463f0262e40cfbd953d58a8d77311351/greenlet-3.5.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c6ce25fee6cabc8bf22cb8b52e642cbb821be5b9aec8094d07ff03378141b8e9", size = 1691952, upload-time = "2026-08-10T13:40:33.502Z" }, + { url = "https://files.pythonhosted.org/packages/2e/3d/5cc9701117ea4dc0eb7bf1f4f9b7888a6e2e5277ddfae095805ace50f2b6/greenlet-3.5.5-cp314-cp314-win_amd64.whl", hash = "sha256:7dffc5c859fe6059974df1e37d7923d654a83e2ae18fdd616994270e001115e1", size = 327458, upload-time = "2026-08-10T13:27:02.868Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6b/594fa2de7fae7629168a404a4305d7d7e31a5742c50a801b1839543cb93d/greenlet-3.5.5-cp314-cp314-win_arm64.whl", hash = "sha256:5e2afcfc4d4305dd715809b03da5cbe437c8984f61d8917751eb5fe4aefa3e07", size = 311146, upload-time = "2026-08-10T13:27:25.046Z" }, + { url = "https://files.pythonhosted.org/packages/24/e0/50cd600b469e5734c72709b6b1838b6bc63f307b573c772c3132d6ecfe92/greenlet-3.5.5-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:0e5a7de979d764aea1f5b6e95cf92b5b37741b9823702041f34b126e7f690277", size = 305471, upload-time = "2026-08-10T13:26:20.568Z" }, + { url = "https://files.pythonhosted.org/packages/75/a3/77acd66dfc6387b5219b2080806c0cabb73c10eb1bb44b413c40a62015ba/greenlet-3.5.5-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fef01bd457f11fc158b130ca0027a3c365693280e8e231b65bdaf57999f39f5b", size = 672470, upload-time = "2026-08-10T14:14:39.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/71/0d178142dca3ec19f46fb2212ae73d30ad53b9d548dc64804086033a7089/greenlet-3.5.5-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5173a72310725a74afc82c164f0e52cb8ad0de62f2bb623f24f6c0cc07d80272", size = 679973, upload-time = "2026-08-10T14:27:30.072Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ac/0d7887aa4bbfc9eba075cc428244dfc96f623478454d5ec81180d0d6bd5a/greenlet-3.5.5-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5e9ec2e7c98e895fcea0c5cc57b2606cf86ece6d0a56578f3eb225e2af4f0387", size = 681587, upload-time = "2026-08-10T14:30:13.519Z" }, + { url = "https://files.pythonhosted.org/packages/6e/31/46eb8567302eaf787abf88d09df014e14ae3baf460af1b8b0efdbd3efcd5/greenlet-3.5.5-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44f08341873200ba8a60a8bc14ace3d91f1754f7fa7bc66157714a8cd420a476", size = 676634, upload-time = "2026-08-10T13:40:53.004Z" }, + { url = "https://files.pythonhosted.org/packages/4f/18/8d58ba1c429b0383e3219a3d0e0bba241d0444d8ed05b73349953c7d7c7b/greenlet-3.5.5-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:102817506f6090b5176c746a82603341a549b40e5c3d5b72a4c672228a918c41", size = 510175, upload-time = "2026-08-10T14:30:07.047Z" }, + { url = "https://files.pythonhosted.org/packages/a3/e9/b88bbf5b29970cb84172dc2c32aa3e5e579ceb94c808e81c826454138850/greenlet-3.5.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d246c0db9a2513cd45f019ba178ea4d4d4705bd210ee465e2c15d76a1ab13874", size = 1637320, upload-time = "2026-08-10T14:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/6d/8c/7631ed29cc6f0392f11830076e172ce4885e70b0bc2c1bce1731176d4b4e/greenlet-3.5.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:72507285b5caa1d17904a3f7c322ca780823a54170a0e04ec3f37bcc60d4db71", size = 1697412, upload-time = "2026-08-10T13:40:34.924Z" }, + { url = "https://files.pythonhosted.org/packages/da/0f/f7dd935f9c4cb1be49098770587f54d8a78518e55c89bce86c4fb4109057/greenlet-3.5.5-cp314-cp314t-win_amd64.whl", hash = "sha256:7805655781fb8f28a55d05fe57ed61f5f10f1892fb587673e3bb5264f28041f0", size = 331514, upload-time = "2026-08-10T13:29:20.611Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e5/681b01f8fbc1b55232822f99e8f8afeb78a55a7c76a7bf9dbdc7ccb03a6d/greenlet-3.5.5-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:c0db80fcd5b8aece93f66c64f78a786bbb6b96c5fe63ef5a5a4581ecf8bab206", size = 295975, upload-time = "2026-08-10T13:28:45.985Z" }, + { url = "https://files.pythonhosted.org/packages/11/f2/69b488cd9e7267bf4b0fe8cdebf25d8d6df680d21bdf41150d23e23d6652/greenlet-3.5.5-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b241c32f912ada659808d68e308c568baf577eebf757d15471472de0c18cfad", size = 666823, upload-time = "2026-08-10T14:14:40.222Z" }, + { url = "https://files.pythonhosted.org/packages/84/d4/d5bc2fdebbdda0c94555925ba79948b8395d75a7f6a36cc85dce5bab9f11/greenlet-3.5.5-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ef6a08349401d8eaf3cb12688ac8557de95788556b8631ef17555a4a173022c0", size = 677613, upload-time = "2026-08-10T14:27:31.543Z" }, + { url = "https://files.pythonhosted.org/packages/65/53/4e13642efc4d7ad6554ecb2242a5be42666b2e1a067323e88dfc0124a04b/greenlet-3.5.5-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37faa97daccb6d9f4c2141ce3118d023c3c5506864a7d8bdf726f665018c1f76", size = 681436, upload-time = "2026-08-10T14:30:14.839Z" }, + { url = "https://files.pythonhosted.org/packages/bd/93/542d8a3a90f3b35c6ad8bf7e56a03010287f2cafa289a5b7985b5207db39/greenlet-3.5.5-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f2e3d061b8e13aec2f0441689b3c71b244a20e5d274a52cb0f7e31bd1d139552", size = 675930, upload-time = "2026-08-10T13:40:54.205Z" }, + { url = "https://files.pythonhosted.org/packages/cd/32/188447c9a468d6977d2989397226b0c6b65ab6f4cf943f931643328512fc/greenlet-3.5.5-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:b18007dc2473a7942fd157366b55f01da6fed7ce85318591005b419e0a439474", size = 487404, upload-time = "2026-08-10T14:30:08.903Z" }, + { url = "https://files.pythonhosted.org/packages/52/b5/89c9f2e8460d71101037d47a1feed11928615a5edd42370be290e0657eeb/greenlet-3.5.5-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:9ab5f5b93655e77fe0d6c2dfd22b5eac751bb1f876d8ec21761b7c1fb9266007", size = 1633878, upload-time = "2026-08-10T14:15:10.693Z" }, + { url = "https://files.pythonhosted.org/packages/b8/60/297de93f3b02ac78a5e04d32bb8bbe3080f4a73d8ed95016561463b70618/greenlet-3.5.5-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f0e5a21bd4452a88cf032fc43c4a5b307ab1380eacb63b5988f9c0317885e773", size = 1696597, upload-time = "2026-08-10T13:40:36.252Z" }, + { url = "https://files.pythonhosted.org/packages/18/25/54c6eaff4f337fb670215e89eb2d00d9499487b658e709d4b477be4a342e/greenlet-3.5.5-cp315-cp315-win_amd64.whl", hash = "sha256:469dbb0a78625642f4a626cfd0c6e8bccc0385b5e49189b6308bbe849ec88a8e", size = 327700, upload-time = "2026-08-10T13:28:06.752Z" }, + { url = "https://files.pythonhosted.org/packages/67/67/857e88a36301caa0e029870132c2478bd55d896630321432afab03a3115f/greenlet-3.5.5-cp315-cp315-win_arm64.whl", hash = "sha256:2d57406c3efd32d7a81e17a674314e8bd00792cdab49ea3228a49aa1bfb2e769", size = 311750, upload-time = "2026-08-10T13:34:08.815Z" }, + { url = "https://files.pythonhosted.org/packages/10/e2/3144c0a116067ac1e30457b0139a94d60d1d36a86e015de68e9ac87cb3bc/greenlet-3.5.5-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:68184dfcf50ccaa8e864770fe0633a7e27250ea9329f8192ef47ee9ecfd78e1c", size = 306387, upload-time = "2026-08-10T13:27:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/5c/a1/cb4223a7e9b9f43b8807e8eb212358bfe2dfaa174a9ea2889eb1714dcba2/greenlet-3.5.5-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ec0dc0e59dc9c61af5c47348365ccbbd7addfafe0a93b00336ff3da2907bdc6", size = 676472, upload-time = "2026-08-10T14:14:41.417Z" }, + { url = "https://files.pythonhosted.org/packages/9e/cd/a154b4498e5d8f12ada291cfb3b8d596eadde2177f5bf09a9be699d2a446/greenlet-3.5.5-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e604f58e35833fc46ef20302bcb314dddbfd3fcf33a4f936216d51dd678d63ae", size = 684238, upload-time = "2026-08-10T14:27:32.946Z" }, + { url = "https://files.pythonhosted.org/packages/ce/f4/e450a68a152f819491d8c7df6a8254e761d87e6a78759268961f8c5bd4dd/greenlet-3.5.5-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2888a3a38bc5ee5bb6c438372197152e815837e4fab7ed7a1f86ef18ffd58ad1", size = 686022, upload-time = "2026-08-10T14:30:15.96Z" }, + { url = "https://files.pythonhosted.org/packages/bf/bb/b0031d260c2968a3c87deebc51d80c64e499377f993aafe06ee3b7488cc2/greenlet-3.5.5-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:40239b5384f96da3963585cc6d7eaa9b56f8ae67e8d92cc82dd9e202fc847de3", size = 681246, upload-time = "2026-08-10T13:40:55.402Z" }, + { url = "https://files.pythonhosted.org/packages/18/23/17e63d6bf3b9c9b9dbea981b7f643a71f79603bdfb4f1c3a9cf353e22aed/greenlet-3.5.5-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:1e8d9391fe77f15649589a907cef972dbbd6352ef7ff7dc0492f658c0c26495f", size = 516951, upload-time = "2026-08-10T14:30:10.907Z" }, + { url = "https://files.pythonhosted.org/packages/9a/07/da554b71ab88e649da146e1065d86a48a5c5d92e50ab74ef41b504aa7f56/greenlet-3.5.5-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:a1eaccf5c3a1d3e46dead602c72e6836731e8e245c9de6a27764567b6b62d4c0", size = 1642735, upload-time = "2026-08-10T14:15:11.92Z" }, + { url = "https://files.pythonhosted.org/packages/78/76/26a3782a051677668af9d92beaa47cd87ba9dd5072f762961144a03dd4c6/greenlet-3.5.5-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:19e4e026fe20691f333b8eb1a3bc9625eceba8c3f9d62ec5a6f8581afbc6b5a5", size = 1700925, upload-time = "2026-08-10T13:40:37.656Z" }, + { url = "https://files.pythonhosted.org/packages/28/d9/fe7baf4190c2ae71f267efb9de21b3172bb35bc0ed1ef53dd6027d658e33/greenlet-3.5.5-cp315-cp315t-win_amd64.whl", hash = "sha256:712aee154f648bde84634654bb38bb78c69ac640c37a45c9effed800735049d8", size = 331829, upload-time = "2026-08-10T13:26:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/df/af/419a4e383bd600858a9b67e9b280a60fdc383ee3f2fe5b6c0c1ef04e74d1/greenlet-3.5.5-cp315-cp315t-win_arm64.whl", hash = "sha256:7f049911ee81a16a03c33d5450d8d5867d27f596ca5fb201b86f4524e874468b", size = 315093, upload-time = "2026-08-10T13:29:34.949Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -1048,6 +1125,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7d/68/d8d58938dfb1370b266a1a729e6d77a985be23689a0496498ee17b2cbf90/platformdirs-4.11.0-py3-none-any.whl", hash = "sha256:360ccded2b7fce0af0ff80cc8f5942a1c5d99b0e856033acb030bfc634709e74", size = 23247, upload-time = "2026-07-21T13:09:35.422Z" }, ] +[[package]] +name = "playwright" +version = "1.61.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet" }, + { name = "pyee" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/ee/31e4e0db36588b817a10b299a0285082545fde7d36543c2abe498bb3d61a/playwright-1.61.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:ff138c3a604f69911e9d42fd036e55c2a171e5616edf04c1e7f60a2a285540b0", size = 43421877, upload-time = "2026-06-29T10:32:48.428Z" }, + { url = "https://files.pythonhosted.org/packages/42/35/71395dd3ecc798965be4a3ef8c443217d4abca168e7cb34536304f9489e6/playwright-1.61.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:009588c2a7e499bc5a8b425b61fa65490968bbda9cd69e0cf2cff10f8304659a", size = 42205016, upload-time = "2026-06-29T10:32:52.104Z" }, + { url = "https://files.pythonhosted.org/packages/f4/44/323164cf5cd1647bdefce76ffce27651aadb959d089b48f53ea40918276e/playwright-1.61.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:9f7de4536088d12037c13a52b7ea34b59270b78926bb56935070597ffac6b1af", size = 43421884, upload-time = "2026-06-29T10:32:55.773Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f8/a35bf179e4ba2522c1893635094a64e407572547bd61528820fc0abc87fe/playwright-1.61.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:54f3b39f6eab832e33458c1dd7da0b5682aedab3b09ae731b5c59fa12fd2024e", size = 47421381, upload-time = "2026-06-29T10:32:59.903Z" }, + { url = "https://files.pythonhosted.org/packages/b7/eb/e3f922348ec17c315f98c463f72faa1181a1c3de0bfe31a8d2edf6561723/playwright-1.61.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93454322ade8c11d5d6c211bfd91bdfb9ffb4810e3e026371bcbc4bec1b7ee4c", size = 47120545, upload-time = "2026-06-29T10:33:03.574Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a6/5be4e52b40a9c0c8a073e7c5b0785c05cf5a9ea8f8a7b5b260e32d970342/playwright-1.61.0-py3-none-win32.whl", hash = "sha256:372d55a6f1248fa1dd47599686980cb8fb5bbe6fcda59eab793eb657c11d8a9b", size = 37844841, upload-time = "2026-06-29T10:33:07.361Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fd/2b78036e5fbe9d5f5645bbe08a1eac7160c51243c0093963edbcf67c35d9/playwright-1.61.0-py3-none-win_amd64.whl", hash = "sha256:35c6cc4589a5d00964a59d7b3e59641e0aac0c02f15479a7af77d20f6bc79597", size = 37844846, upload-time = "2026-06-29T10:33:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/1b0f3c4ee4eb0514bc805b5c2f9a223e5b6de4f11a926f5235d51d0fc81b/playwright-1.61.0-py3-none-win_arm64.whl", hash = "sha256:e9fcbffcf557a8620fdedd92491eb59a32d18e23d6f3b4f6214b952be324fe51", size = 33955127, upload-time = "2026-06-29T10:33:14.008Z" }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -1298,6 +1394,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/8d/d236e9c82fe315f9128885c8be3ec719f41965a1eb6b6f4b42470904cd41/pyarrow-25.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:13240f0d3dc5932ccd0bfa90cd76d835680b9d94a7661c635df4b703d40ce849", size = 28743657, upload-time = "2026-07-10T08:29:42.742Z" }, ] +[[package]] +name = "pyee" +version = "13.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/04/e7c1fe4dc78a6fdbfd6c337b1c3732ff543b8a397683ab38378447baa331/pyee-13.0.1.tar.gz", hash = "sha256:0b931f7c14535667ed4c7e0d531716368715e860b988770fc7eb8578d1f67fc8", size = 31655, upload-time = "2026-02-14T21:12:28.044Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/b4d4827c93ef43c01f599ef31453ccc1c132b353284fc6c87d535c233129/pyee-13.0.1-py3-none-any.whl", hash = "sha256:af2f8fede4171ef667dfded53f96e2ed0d6e6bd7ee3bb46437f77e3b57689228", size = 15659, upload-time = "2026-02-14T21:12:26.263Z" }, +] + [[package]] name = "pygments" version = "2.20.0" @@ -1436,7 +1544,7 @@ wheels = [ [[package]] name = "reflex" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1468,7 +1576,7 @@ dependencies = [ [[package]] name = "reflex-base" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1479,7 +1587,7 @@ dependencies = [ [[package]] name = "reflex-components-code" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1490,7 +1598,7 @@ dependencies = [ [[package]] name = "reflex-components-core" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1503,7 +1611,7 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1512,7 +1620,7 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1520,7 +1628,7 @@ dependencies = [ [[package]] name = "reflex-components-lucide" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1528,7 +1636,7 @@ dependencies = [ [[package]] name = "reflex-components-markdown" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1539,7 +1647,7 @@ dependencies = [ [[package]] name = "reflex-components-moment" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1547,7 +1655,7 @@ dependencies = [ [[package]] name = "reflex-components-plotly" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1556,7 +1664,7 @@ dependencies = [ [[package]] name = "reflex-components-radix" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1566,7 +1674,7 @@ dependencies = [ [[package]] name = "reflex-components-react-player" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1575,7 +1683,7 @@ dependencies = [ [[package]] name = "reflex-components-recharts" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, ] @@ -1583,7 +1691,7 @@ dependencies = [ [[package]] name = "reflex-components-sonner" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1592,7 +1700,7 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=make-sio-optional#02dae5601eed0b678703a049db21634f83b625e7" } +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -2105,6 +2213,7 @@ dev = [ { name = "aiohttp" }, { name = "hypothesis" }, { name = "pillow" }, + { name = "playwright" }, { name = "pyarrow" }, { name = "pytest" }, { name = "pyyaml" }, @@ -2119,7 +2228,7 @@ dev = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=make-sio-optional" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7" }, ] provides-extras = ["reflex"] @@ -2129,6 +2238,7 @@ dev = [ { name = "aiohttp", specifier = ">=3.14.3" }, { name = "hypothesis", specifier = ">=6" }, { name = "pillow", specifier = ">=10" }, + { name = "playwright", specifier = "==1.61.0" }, { name = "pyarrow", specifier = ">=15" }, { name = "pytest", specifier = ">=8" }, { name = "pyyaml", specifier = ">=6" }, From 651e2c1ea3c181c2cf6de202894be767d0838fc5 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 12 Sep 2026 22:42:56 +0200 Subject: [PATCH 03/17] Bump the pinned Reflex channel commit to ea517ec4 --- docs/app/pyproject.toml | 8 ++-- docs/app/uv.lock | 87 +++++++++++++++++++------------------- pyproject.toml | 2 +- tests/test_dependencies.py | 2 +- uv.lock | 62 +++++++++++++-------------- 5 files changed, 81 insertions(+), 80 deletions(-) diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index dba6e95ef..7dee613e6 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -12,10 +12,10 @@ requires-python = ">=3.11" dependencies = [ "numpy", "pillow", - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7", - "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7#subdirectory=packages/reflex-components-internal", - "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7#subdirectory=packages/reflex-docgen", - "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7#subdirectory=packages/reflex-site-shared", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02", + "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02#subdirectory=packages/reflex-components-internal", + "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02#subdirectory=packages/reflex-docgen", + "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02#subdirectory=packages/reflex-site-shared", "xy[reflex]", ] diff --git a/docs/app/uv.lock b/docs/app/uv.lock index 0613a7b5d..a97f6c8e5 100644 --- a/docs/app/uv.lock +++ b/docs/app/uv.lock @@ -1063,8 +1063,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1095,8 +1095,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1106,8 +1106,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1117,8 +1117,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1130,8 +1130,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1139,32 +1139,32 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-internal" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1174,16 +1174,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1191,8 +1191,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1201,8 +1201,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1210,16 +1210,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1227,8 +1227,8 @@ dependencies = [ [[package]] name = "reflex-docgen" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "griffelib" }, { name = "mistletoe" }, @@ -1239,8 +1239,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -1251,13 +1251,13 @@ dependencies = [ [[package]] name = "reflex-integrations-docs" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } [[package]] name = "reflex-site-shared" -version = "0.0.3.post248.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.3.post252.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "email-validator" }, { name = "httpx" }, @@ -1632,7 +1632,7 @@ reflex = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, ] provides-extras = ["reflex"] @@ -1642,6 +1642,7 @@ dev = [ { name = "aiohttp", specifier = ">=3.14.3" }, { name = "hypothesis", specifier = ">=6" }, { name = "pillow", specifier = ">=10" }, + { name = "playwright", specifier = "==1.61.0" }, { name = "pyarrow", specifier = ">=15" }, { name = "pytest", specifier = ">=8" }, { name = "pyyaml", specifier = ">=6" }, @@ -1680,10 +1681,10 @@ dev = [ requires-dist = [ { name = "numpy" }, { name = "pillow" }, - { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7" }, - { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=02dae5601eed0b678703a049db21634f83b625e7" }, - { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=02dae5601eed0b678703a049db21634f83b625e7" }, - { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=02dae5601eed0b678703a049db21634f83b625e7" }, + { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, + { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, + { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, + { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, { name = "xy", extras = ["reflex"], editable = "../../" }, ] diff --git a/pyproject.toml b/pyproject.toml index bfd05247e..6659723d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ # with the real floor the moment channels are released (see the design doc's # Status note). reflex = [ - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02", ] [project.urls] diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 4261e9f08..713a6dbcc 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -18,7 +18,7 @@ # assertion, and drop `test_docs_app_pins_the_same_reflex_commit`, when # channels are released. REFLEX_REQUIREMENT = ( - "git+https://github.com/benedikt-bartscher/reflex.git@02dae5601eed0b678703a049db21634f83b625e7" + "git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02" ) diff --git a/uv.lock b/uv.lock index 09be1a8da..14defe30b 100644 --- a/uv.lock +++ b/uv.lock @@ -1543,8 +1543,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1575,8 +1575,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1586,8 +1586,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1597,8 +1597,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1610,8 +1610,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1619,24 +1619,24 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1646,16 +1646,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1663,8 +1663,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1673,8 +1673,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1682,16 +1682,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1699,8 +1699,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3495.dev0+02dae560" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=02dae5601eed0b678703a049db21634f83b625e7#02dae5601eed0b678703a049db21634f83b625e7" } +version = "0.0.0.post3499.dev0+ea517ec4" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -2228,7 +2228,7 @@ dev = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=02dae5601eed0b678703a049db21634f83b625e7" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, ] provides-extras = ["reflex"] From e8d11f603d312a4ce90ddb405b661dacf9f9727a Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 12 Sep 2026 22:57:11 +0200 Subject: [PATCH 04/17] Fail the data plane tests when the reader broke but nothing read the error --- tests/reflex_adapter/test_data_plane.py | 32 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/reflex_adapter/test_data_plane.py b/tests/reflex_adapter/test_data_plane.py index 4030c4601..8958ac210 100644 --- a/tests/reflex_adapter/test_data_plane.py +++ b/tests/reflex_adapter/test_data_plane.py @@ -160,13 +160,19 @@ async def disconnect(self) -> None: return self.connected = False self._reader.cancel() - # Any reader failure was already handed to the waiters, so teardown - # only has to retrieve it — re-raising here would replace a test's real - # assertion failure with a confusing one from the cleanup path. - with contextlib.suppress(BaseException): + # Only the two outcomes teardown can legitimately produce: the + # cancellation just requested, and a reset from the socket going away. + # Anything else is a defect and should reach the test. + with contextlib.suppress(asyncio.CancelledError, ConnectionResetError): await self._reader await self._ws.close() await self._session.close() + if self.reader_error is not None: + # The failure was handed to every waiter, but a test that finished + # its assertions without reading again would never have popped it — + # and a broken wire must not leave the suite green. Raised after the + # socket is closed so a failing test still tears down cleanly. + raise AssertionError("the data plane reader failed") from self.reader_error async def connect_client(base_url: str, client_token: str = CLIENT_TOKEN) -> PlaneClient: @@ -389,6 +395,24 @@ async def main(): assert other.active_operations == 0 +def test_a_broken_frame_fails_the_test_even_if_nothing_reads_it(_fresh_registry): + """The harness must not let a broken wire pass as a green run. + + A malformed frame reaches waiters through the queues, but a test that has + finished its assertions never pops again — so teardown is the last place + the failure can still be noticed. + """ + + async def main(): + async with data_plane_server() as (url, _): + client = await connect_client(url) + client.reader_error = ValueError("frame did not decode") + with pytest.raises(AssertionError, match="reader failed"): + await client.disconnect() + + run(main()) + + def test_sub_delivers_spec_and_binary_columns(_fresh_registry): async def main(): token = registry.register(make_figure(64)) From c4154ca059175de82faf5a262f83e5f24c562932 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 12 Sep 2026 23:11:47 +0200 Subject: [PATCH 05/17] Bump the pinned Reflex channel commit to b8580ed1 --- docs/app/pyproject.toml | 8 ++-- docs/app/uv.lock | 86 +++++++++++++++++++------------------- pyproject.toml | 2 +- tests/test_dependencies.py | 2 +- uv.lock | 62 +++++++++++++-------------- 5 files changed, 80 insertions(+), 80 deletions(-) diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index 7dee613e6..6199cb51f 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -12,10 +12,10 @@ requires-python = ">=3.11" dependencies = [ "numpy", "pillow", - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02", - "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02#subdirectory=packages/reflex-components-internal", - "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02#subdirectory=packages/reflex-docgen", - "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02#subdirectory=packages/reflex-site-shared", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa", + "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa#subdirectory=packages/reflex-components-internal", + "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa#subdirectory=packages/reflex-docgen", + "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa#subdirectory=packages/reflex-site-shared", "xy[reflex]", ] diff --git a/docs/app/uv.lock b/docs/app/uv.lock index a97f6c8e5..f69f5debb 100644 --- a/docs/app/uv.lock +++ b/docs/app/uv.lock @@ -1063,8 +1063,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1095,8 +1095,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1106,8 +1106,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1117,8 +1117,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1130,8 +1130,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1139,32 +1139,32 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-internal" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1174,16 +1174,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1191,8 +1191,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1201,8 +1201,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1210,16 +1210,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1227,8 +1227,8 @@ dependencies = [ [[package]] name = "reflex-docgen" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "griffelib" }, { name = "mistletoe" }, @@ -1239,8 +1239,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -1251,13 +1251,13 @@ dependencies = [ [[package]] name = "reflex-integrations-docs" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } [[package]] name = "reflex-site-shared" -version = "0.0.3.post252.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.3.post253.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "email-validator" }, { name = "httpx" }, @@ -1632,7 +1632,7 @@ reflex = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa" }, ] provides-extras = ["reflex"] @@ -1681,10 +1681,10 @@ dev = [ requires-dist = [ { name = "numpy" }, { name = "pillow" }, - { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, - { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, - { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, - { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, + { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa" }, + { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=b8580ed1337487671569d5964ea362296005d8fa" }, + { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=b8580ed1337487671569d5964ea362296005d8fa" }, + { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=b8580ed1337487671569d5964ea362296005d8fa" }, { name = "xy", extras = ["reflex"], editable = "../../" }, ] diff --git a/pyproject.toml b/pyproject.toml index 6659723d1..2251575b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ # with the real floor the moment channels are released (see the design doc's # Status note). reflex = [ - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa", ] [project.urls] diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 713a6dbcc..0f37b1953 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -18,7 +18,7 @@ # assertion, and drop `test_docs_app_pins_the_same_reflex_commit`, when # channels are released. REFLEX_REQUIREMENT = ( - "git+https://github.com/benedikt-bartscher/reflex.git@ea517ec4d665aeddfab9f245aa155db0dfd5cd02" + "git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa" ) diff --git a/uv.lock b/uv.lock index 14defe30b..c88ae4933 100644 --- a/uv.lock +++ b/uv.lock @@ -1543,8 +1543,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1575,8 +1575,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1586,8 +1586,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1597,8 +1597,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1610,8 +1610,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1619,24 +1619,24 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1646,16 +1646,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1663,8 +1663,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1673,8 +1673,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1682,16 +1682,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1699,8 +1699,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3499.dev0+ea517ec4" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02#ea517ec4d665aeddfab9f245aa155db0dfd5cd02" } +version = "0.0.0.post3500.dev0+b8580ed1" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -2228,7 +2228,7 @@ dev = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=ea517ec4d665aeddfab9f245aa155db0dfd5cd02" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa" }, ] provides-extras = ["reflex"] From 875fa44c3d48ad606a4e140b47369f36cc7c71db Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 12 Sep 2026 23:35:17 +0200 Subject: [PATCH 06/17] Check upload conditions structurally, align the browser gate, and exercise the reader for real --- scripts/verify_ci_workflow.py | 40 ++++++++++++++--- tests/reflex_adapter/test_channel_browser.py | 11 +++-- tests/reflex_adapter/test_data_plane.py | 33 +++++++++++--- tests/test_verify_ci_workflow.py | 46 ++++++++++++++++++++ 4 files changed, 115 insertions(+), 15 deletions(-) diff --git a/scripts/verify_ci_workflow.py b/scripts/verify_ci_workflow.py index 8d9977eaf..e72cdc5f9 100644 --- a/scripts/verify_ci_workflow.py +++ b/scripts/verify_ci_workflow.py @@ -500,6 +500,30 @@ def _named_step_blocks(job_text: str) -> dict[str, str]: return blocks +def _require_step_condition( + errors: list[str], jobs: dict[str, str], job: str, step: str, condition: str, description: str +) -> None: + """Require one named step to carry ``if: `` as a real YAML key. + + Substring matching cannot do this job once a second step in the same job + uses the same condition: the needle is satisfied by the neighbour while the + step it was written for quietly loses its own. Reading the step's direct + ``if`` key answers the actual question, and ignores the condition appearing + in a comment (``_yaml_code_lines`` strips those). + """ + block = _named_step_blocks(jobs.get(job, "")).get(step) + if block is None: + errors.append(f"missing required CI step {step!r}") + return + values, unsafe = _step_direct_key_values(block, "if") + if unsafe or values != [condition]: + found = ", ".join(values) if values else "no direct `if` key" + errors.append( + f"CI {job} job step {step!r} missing {description}: expected a direct " + f"`if: {condition}` key, found {found}" + ) + + def _require_step_contains( errors: list[str], job_text: str, step: str, description: str, *needles: str ) -> None: @@ -815,17 +839,23 @@ def validate_ci_workflow(path: Path = DEFAULT_CI_WORKFLOW) -> list[str]: "scripts/verify_benchmark_report.py transport.json --kind transport-loopback", "scripts/check_regressions.py --scatter scatter.json --kernel kernel.json", "--transport transport.json --emit-md spec/benchmarks/metrics.md", - # Name and condition paired, not two independent needles: this job now - # has a second `if: always()` upload (the browser evidence), which a - # bare needle would satisfy on its behalf — letting *this* step lose - # its condition and stop uploading after a failed gate, silently. - "- name: Upload regression benchmark report\n if: always()", + "Upload regression benchmark report", "actions/upload-artifact@", "regression-benchmark-report", "if-no-files-found: warn", "spec/benchmarks/metrics.md", "transport.json", ) + # Both uploads in this job have to survive a failed gate — the regression + # report is the evidence for *why* it failed, the browser screenshot the + # evidence for what the chart looked like. Checked structurally, one step + # at a time, because they share a condition that a substring needle would + # let either of them borrow from the other. + for step, description in ( + ("Upload regression benchmark report", "artifact upload after a failed gate"), + ("Upload browser evidence", "screenshot upload after a failed gate"), + ): + _require_step_condition(errors, jobs, "test", step, "always()", description) test_job = jobs.get("test", "") _require_step_runs_exactly( errors, diff --git a/tests/reflex_adapter/test_channel_browser.py b/tests/reflex_adapter/test_channel_browser.py index 4e9168246..9f7a01074 100644 --- a/tests/reflex_adapter/test_channel_browser.py +++ b/tests/reflex_adapter/test_channel_browser.py @@ -16,10 +16,13 @@ import pytest # This is the only check of the single-shared-websocket claim, so a missing -# browser must not quietly turn it into a pass. `XY_REQUIRE_BROWSER=1` — what -# CI sets — makes both the Python package and the browser binary hard -# requirements; without it a bare checkout still skips. -REQUIRE_BROWSER = os.environ.get("XY_REQUIRE_BROWSER") == "1" +# browser must not quietly turn it into a pass. `XY_REQUIRE_BROWSER` — which CI +# sets — makes both the Python package and the browser binary hard +# requirements; without it a bare checkout still skips. Read for truthiness, +# not for the literal "1", so this gate opens on exactly the same values as the +# sibling one in tests/conftest.py: a mismatch there would fail every other +# browser probe while leaving this one skipping. +REQUIRE_BROWSER = bool(os.environ.get("XY_REQUIRE_BROWSER")) if not REQUIRE_BROWSER: pytest.importorskip("playwright") diff --git a/tests/reflex_adapter/test_data_plane.py b/tests/reflex_adapter/test_data_plane.py index 8958ac210..98a72d42e 100644 --- a/tests/reflex_adapter/test_data_plane.py +++ b/tests/reflex_adapter/test_data_plane.py @@ -16,6 +16,7 @@ import contextlib import json import socket +import sys import threading from types import SimpleNamespace from typing import Any, Optional, TypedDict @@ -395,18 +396,38 @@ async def main(): assert other.active_operations == 0 -def test_a_broken_frame_fails_the_test_even_if_nothing_reads_it(_fresh_registry): +def test_a_broken_frame_fails_the_test_even_if_nothing_reads_it(_fresh_registry, monkeypatch): """The harness must not let a broken wire pass as a green run. - A malformed frame reaches waiters through the queues, but a test that has - finished its assertions never pops again — so teardown is the last place - the failure can still be noticed. + Both halves have to hold: the reader has to *record* a decode failure + rather than die quietly, and teardown has to raise it. A test that has + finished its assertions never pops a queue again, so teardown is the last + place the failure can be noticed — and a reader that silently stopped + recording would make every other test in this file vacuous. + + The frame really is decoded here; only the decoder is replaced, because a + real server cannot be made to emit a frame its own encoder would refuse. """ + def explode(frame): + raise ValueError("frame did not decode") + async def main(): + token = registry.register(make_figure(8)) async with data_plane_server() as (url, _): - client = await connect_client(url) - client.reader_error = ValueError("frame did not decode") + client = await connect_client(url) # opened before the decoder breaks + # Patched on this module object: the reader resolves the decoder + # as a global here, and a dotted path would patch a second import + # of this file rather than the one running. + monkeypatch.setattr(sys.modules[__name__], "decode_channel_frame", explode) + await client.emit("sub", {"fig": token, "mid": "m1"}) + + # The error reaches the waiters rather than stranding them. + with pytest.raises(AssertionError, match="reader failed"): + await Collector.next(client.payloads) + assert isinstance(client.reader_error, ValueError) + + # And teardown raises it too, for the test that never reads again. with pytest.raises(AssertionError, match="reader failed"): await client.disconnect() diff --git a/tests/test_verify_ci_workflow.py b/tests/test_verify_ci_workflow.py index 929371093..f6fd44489 100644 --- a/tests/test_verify_ci_workflow.py +++ b/tests/test_verify_ci_workflow.py @@ -1321,6 +1321,52 @@ def test_ci_workflow_rejects_regression_upload_that_skips_after_failures( assert any("test job" in error and "if: always()" in error for error in errors) +def test_ci_workflow_rejects_browser_evidence_upload_that_skips_after_failures( + tmp_path: Path, +) -> None: + """The screenshot is only evidence if it survives the run that failed.""" + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + path = tmp_path / "ci.yml" + path.write_text( + workflow.replace( + " - name: Upload browser evidence\n if: always()\n", + " - name: Upload browser evidence\n", + ), + encoding="utf-8", + ) + + errors = verify_ci_workflow.validate_workflow(path) + + assert any("Upload browser evidence" in error and "if: always()" in error for error in errors) + + +def test_ci_workflow_rejects_upload_condition_that_only_survives_in_a_comment( + tmp_path: Path, +) -> None: + """The condition is read as a YAML key, not matched as text. + + Two steps in this job share `if: always()`, so a substring needle can be + satisfied by the neighbour — or by the condition lingering in a comment + after the real key is gone — while the upload silently stops running. + """ + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + path = tmp_path / "ci.yml" + path.write_text( + workflow.replace( + " - name: Upload regression benchmark report\n if: always()\n", + " - name: Upload regression benchmark report\n # if: always()\n", + ), + encoding="utf-8", + ) + + errors = verify_ci_workflow.validate_workflow(path) + + assert any( + "Upload regression benchmark report" in error and "if: always()" in error + for error in errors + ) + + def test_ci_workflow_rejects_missing_wheel_upload(tmp_path: Path) -> None: workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") path = tmp_path / "ci.yml" From ebcd09815d36487b239989ced3a1394ea6b03461 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 12 Sep 2026 23:43:32 +0200 Subject: [PATCH 07/17] Keep the browser harness app in a self-deleting temp dir --- tests/reflex_adapter/test_channel_browser.py | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/reflex_adapter/test_channel_browser.py b/tests/reflex_adapter/test_channel_browser.py index 9f7a01074..173de8d2a 100644 --- a/tests/reflex_adapter/test_channel_browser.py +++ b/tests/reflex_adapter/test_channel_browser.py @@ -10,6 +10,7 @@ import json import os +import tempfile from collections.abc import Generator from pathlib import Path @@ -94,21 +95,23 @@ def _fresh_registry(): @pytest.fixture(scope="module") -def chart_app( - tmp_path_factory: pytest.TempPathFactory, -) -> Generator[AppHarness, None, None]: +def chart_app() -> Generator[AppHarness, None, None]: """Build and serve the chart app. - Args: - tmp_path_factory: pytest fixture for creating temporary directories. + The root is a self-deleting temp dir rather than `tmp_path_factory`: a + compiled Reflex app is ~200 MB of `node_modules` and `.web`, and pytest + keeps its last three runs, so borrowing that retention would leave most of + a gigabyte behind per run — enough to fill a tmpfs `/tmp` after an + afternoon of local runs and make every *other* browser probe fail for want + of space. CI gets one run per job either way. Yields: The running harness. """ - with AppHarness.create( - root=tmp_path_factory.mktemp("channel_chart_app"), - app_source=ChannelChartApp, - ) as harness: + with ( + tempfile.TemporaryDirectory(prefix="xy-channel-chart-app-") as root, + AppHarness.create(root=Path(root), app_source=ChannelChartApp) as harness, + ): assert harness.app_instance is not None, "app is not running" yield harness From 62ebcf3f445acbacfa0912e0208361da783e5d47 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sun, 13 Sep 2026 00:26:56 +0200 Subject: [PATCH 08/17] Reject duplicate workflow step names; bump the pinned Reflex commit to 46cecf59 --- docs/app/pyproject.toml | 8 +-- docs/app/uv.lock | 86 ++++++++++++++++---------------- pyproject.toml | 2 +- scripts/verify_ci_workflow.py | 46 ++++++++++++++++- tests/test_dependencies.py | 2 +- tests/test_verify_ci_workflow.py | 30 +++++++++++ uv.lock | 62 +++++++++++------------ 7 files changed, 154 insertions(+), 82 deletions(-) diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index 6199cb51f..64db70b11 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -12,10 +12,10 @@ requires-python = ">=3.11" dependencies = [ "numpy", "pillow", - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa", - "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa#subdirectory=packages/reflex-components-internal", - "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa#subdirectory=packages/reflex-docgen", - "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa#subdirectory=packages/reflex-site-shared", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0", + "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0#subdirectory=packages/reflex-components-internal", + "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0#subdirectory=packages/reflex-docgen", + "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0#subdirectory=packages/reflex-site-shared", "xy[reflex]", ] diff --git a/docs/app/uv.lock b/docs/app/uv.lock index f69f5debb..82b1534d4 100644 --- a/docs/app/uv.lock +++ b/docs/app/uv.lock @@ -1063,8 +1063,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1095,8 +1095,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1106,8 +1106,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1117,8 +1117,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1130,8 +1130,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1139,32 +1139,32 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-internal" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1174,16 +1174,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1191,8 +1191,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1201,8 +1201,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1210,16 +1210,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1227,8 +1227,8 @@ dependencies = [ [[package]] name = "reflex-docgen" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "griffelib" }, { name = "mistletoe" }, @@ -1239,8 +1239,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -1251,13 +1251,13 @@ dependencies = [ [[package]] name = "reflex-integrations-docs" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } [[package]] name = "reflex-site-shared" -version = "0.0.3.post253.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.3.post254.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "email-validator" }, { name = "httpx" }, @@ -1632,7 +1632,7 @@ reflex = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, ] provides-extras = ["reflex"] @@ -1681,10 +1681,10 @@ dev = [ requires-dist = [ { name = "numpy" }, { name = "pillow" }, - { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa" }, - { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=b8580ed1337487671569d5964ea362296005d8fa" }, - { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=b8580ed1337487671569d5964ea362296005d8fa" }, - { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=b8580ed1337487671569d5964ea362296005d8fa" }, + { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, + { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, + { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, + { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, { name = "xy", extras = ["reflex"], editable = "../../" }, ] diff --git a/pyproject.toml b/pyproject.toml index 2251575b7..6c8301a65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ # with the real floor the moment channels are released (see the design doc's # Status note). reflex = [ - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0", ] [project.urls] diff --git a/scripts/verify_ci_workflow.py b/scripts/verify_ci_workflow.py index e72cdc5f9..4f7500095 100644 --- a/scripts/verify_ci_workflow.py +++ b/scripts/verify_ci_workflow.py @@ -489,17 +489,57 @@ def _step_sequence_blocks(job_text: str) -> list[str]: return ["\n".join(block) for block in blocks] +def _step_names(job_text: str) -> list[str]: + """Return every step name in the job's ``steps:`` sequence, in order.""" + names: list[str] = [] + for block in _step_sequence_blocks(job_text): + first = _strip_yaml_comment(block.splitlines()[0]) + match = re.match(r"^ - name:\s*(.+?)\s*$", first) + if match is not None: + names.append(match.group(1)) + return names + + def _named_step_blocks(job_text: str) -> dict[str, str]: - """Return named blocks from the job's actual ``steps:`` sequence.""" + """Return *unambiguously* named blocks from the job's ``steps:`` sequence. + + Actions permits two steps to share a name, and a dict keyed by name would + silently keep the last one — so a step that lost a required `if` or `run` + could be vouched for by a later namesake that still has it. A duplicated + name is therefore dropped entirely: every `_require_step_*` lookup then + reports the step as missing instead of validating the wrong block. + `_require_unique_step_names` turns that into a message naming the clash. + """ blocks: dict[str, str] = {} + duplicated = {name for name in _step_names(job_text) if _step_names(job_text).count(name) > 1} for block in _step_sequence_blocks(job_text): first = _strip_yaml_comment(block.splitlines()[0]) match = re.match(r"^ - name:\s*(.+?)\s*$", first) - if match is not None: + if match is not None and match.group(1) not in duplicated: blocks[match.group(1)] = block return blocks +def _require_unique_step_names( + errors: list[str], jobs: dict[str, str], workflow_label: str +) -> None: + """Every step name in a job must identify exactly one step. + + Structural gates address steps by name, so a repeated name is an ambiguity + the gates cannot resolve: the duplicate may carry the condition or command + the original was required to have, leaving the real step unchecked. + """ + for job, block in jobs.items(): + names = _step_names(block) + duplicated = sorted({name for name in names if names.count(name) > 1}) + if duplicated: + errors.append( + f"{workflow_label} {job} job repeats step names {duplicated} — the " + "structural gates address steps by name, so a namesake can satisfy a " + "check the step it shadows no longer passes" + ) + + def _require_step_condition( errors: list[str], jobs: dict[str, str], job: str, step: str, condition: str, description: str ) -> None: @@ -759,6 +799,7 @@ def validate_ci_workflow(path: Path = DEFAULT_CI_WORKFLOW) -> list[str]: errors.append("CI workflow must not set shell-init environment variables") _require_docs_spec_pr_paths_ignored(errors, text, "CI") _require_unshallow_checkouts(errors, text, "CI") + _require_unique_step_names(errors, jobs, "CI") missing_jobs = sorted(REQUIRED_CI_JOBS - set(jobs)) if missing_jobs: errors.append(f"CI workflow missing required jobs: {missing_jobs}") @@ -1174,6 +1215,7 @@ def validate_codspeed_workflow(path: Path = DEFAULT_CODSPEED_WORKFLOW) -> list[s errors: list[str] = [] _require_unique_workflow_structure(errors, text, "CodSpeed", REQUIRED_CODSPEED_JOBS) _require_docs_spec_pr_paths_ignored(errors, text, "CodSpeed") + _require_unique_step_names(errors, jobs, "CodSpeed") _require_trigger_with_direct_option( errors, text, diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 0f37b1953..b5d9173e3 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -18,7 +18,7 @@ # assertion, and drop `test_docs_app_pins_the_same_reflex_commit`, when # channels are released. REFLEX_REQUIREMENT = ( - "git+https://github.com/benedikt-bartscher/reflex.git@b8580ed1337487671569d5964ea362296005d8fa" + "git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0" ) diff --git a/tests/test_verify_ci_workflow.py b/tests/test_verify_ci_workflow.py index f6fd44489..b22ce34b5 100644 --- a/tests/test_verify_ci_workflow.py +++ b/tests/test_verify_ci_workflow.py @@ -1367,6 +1367,36 @@ def test_ci_workflow_rejects_upload_condition_that_only_survives_in_a_comment( ) +def test_ci_workflow_rejects_a_same_named_step_vouching_for_its_shadow( + tmp_path: Path, +) -> None: + """A namesake must not satisfy a check the step it shadows no longer passes. + + Actions allows two steps to share a name, so addressing steps by name is + ambiguous: strip the condition from the real upload, add a conditioned + step of the same name after it, and a last-one-wins lookup would validate + the decoy while the artifact silently stops uploading after a failed gate. + """ + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + jobs = verify_ci_workflow._job_blocks(workflow) + real = verify_ci_workflow._named_step_blocks(jobs["test"])["Upload regression benchmark report"] + decoy = ( + " - name: Upload regression benchmark report\n" + " if: always()\n" + " run: echo decoy\n" + ) + path = tmp_path / "ci.yml" + path.write_text( + workflow.replace(real, real.replace(" if: always()\n", "", 1) + decoy), + encoding="utf-8", + ) + + errors = verify_ci_workflow.validate_workflow(path) + + assert any("repeats step names" in error for error in errors) + assert any("missing required CI step" in error for error in errors) + + def test_ci_workflow_rejects_missing_wheel_upload(tmp_path: Path) -> None: workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") path = tmp_path / "ci.yml" diff --git a/uv.lock b/uv.lock index c88ae4933..6d288d699 100644 --- a/uv.lock +++ b/uv.lock @@ -1543,8 +1543,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1575,8 +1575,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1586,8 +1586,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1597,8 +1597,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1610,8 +1610,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1619,24 +1619,24 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1646,16 +1646,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1663,8 +1663,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1673,8 +1673,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1682,16 +1682,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1699,8 +1699,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3500.dev0+b8580ed1" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=b8580ed1337487671569d5964ea362296005d8fa#b8580ed1337487671569d5964ea362296005d8fa" } +version = "0.0.0.post3501.dev0+46cecf59" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -2228,7 +2228,7 @@ dev = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=b8580ed1337487671569d5964ea362296005d8fa" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, ] provides-extras = ["reflex"] From 353f32fc215339ad590006b4a5aee8bc30776507 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sun, 13 Sep 2026 00:51:30 +0200 Subject: [PATCH 09/17] Normalize workflow step names before comparing them --- scripts/verify_ci_workflow.py | 56 +++++++++++++++++++++++++++----- tests/test_verify_ci_workflow.py | 56 ++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/scripts/verify_ci_workflow.py b/scripts/verify_ci_workflow.py index 4f7500095..899bff9f3 100644 --- a/scripts/verify_ci_workflow.py +++ b/scripts/verify_ci_workflow.py @@ -489,14 +489,35 @@ def _step_sequence_blocks(job_text: str) -> list[str]: return ["\n".join(block) for block in blocks] -def _step_names(job_text: str) -> list[str]: - """Return every step name in the job's ``steps:`` sequence, in order.""" - names: list[str] = [] +def _decode_step_name(raw: str) -> tuple[Optional[str], bool]: + """Return a step's name as YAML reads it, and whether the spelling is safe. + + Two steps named ``Upload it`` and ``"Upload it"`` are the same step name to + Actions but different strings to a lexer, so comparing raw text would let a + quoted namesake slip past both the duplicate check and the by-name lookup. + Quoted spellings are therefore normalized exactly as mapping keys are. + Anything a line-local lexer cannot resolve — a block scalar, node + properties, an empty name — fails closed instead of being guessed at. + + Args: + raw: The text following ``name:`` on the step's first line. + + Returns: + The decoded name, or None with a True flag when it is unsupported. + """ + if not raw or raw[0] in {"|", ">", "&", "!", "*"}: + return None, True + return _decode_yaml_key(raw) + + +def _step_names(job_text: str) -> list[tuple[Optional[str], bool]]: + """Return ``(name, unsafe)`` for every named step, in sequence order.""" + names: list[tuple[Optional[str], bool]] = [] for block in _step_sequence_blocks(job_text): first = _strip_yaml_comment(block.splitlines()[0]) match = re.match(r"^ - name:\s*(.+?)\s*$", first) if match is not None: - names.append(match.group(1)) + names.append(_decode_step_name(match.group(1))) return names @@ -509,14 +530,26 @@ def _named_step_blocks(job_text: str) -> dict[str, str]: name is therefore dropped entirely: every `_require_step_*` lookup then reports the step as missing instead of validating the wrong block. `_require_unique_step_names` turns that into a message naming the clash. + + Names are compared after decoding, so quoting one of a pair cannot hide the + collision, and a name whose spelling cannot be decoded is dropped too. """ + decoded = _step_names(job_text) + unusable = { + name + for name, unsafe in decoded + if unsafe or [candidate for candidate, _ in decoded].count(name) > 1 + } blocks: dict[str, str] = {} - duplicated = {name for name in _step_names(job_text) if _step_names(job_text).count(name) > 1} for block in _step_sequence_blocks(job_text): first = _strip_yaml_comment(block.splitlines()[0]) match = re.match(r"^ - name:\s*(.+?)\s*$", first) - if match is not None and match.group(1) not in duplicated: - blocks[match.group(1)] = block + if match is None: + continue + name, unsafe = _decode_step_name(match.group(1)) + if unsafe or name is None or name in unusable: + continue + blocks[name] = block return blocks @@ -530,7 +563,14 @@ def _require_unique_step_names( the original was required to have, leaving the real step unchecked. """ for job, block in jobs.items(): - names = _step_names(block) + decoded = _step_names(block) + if any(unsafe for _name, unsafe in decoded): + errors.append( + f"{workflow_label} {job} job has a step name this checker cannot resolve " + "(block scalar, node property, or unsupported escape) — the structural " + "gates address steps by name and cannot verify one they cannot read" + ) + names = [name for name, unsafe in decoded if not unsafe and name is not None] duplicated = sorted({name for name in names if names.count(name) > 1}) if duplicated: errors.append( diff --git a/tests/test_verify_ci_workflow.py b/tests/test_verify_ci_workflow.py index b22ce34b5..2ba863d20 100644 --- a/tests/test_verify_ci_workflow.py +++ b/tests/test_verify_ci_workflow.py @@ -1397,6 +1397,62 @@ def test_ci_workflow_rejects_a_same_named_step_vouching_for_its_shadow( assert any("missing required CI step" in error for error in errors) +def test_ci_workflow_rejects_a_quoted_namesake_shadowing_a_step(tmp_path: Path) -> None: + """`"Upload it"` and `Upload it` are one name to Actions, two to a lexer. + + Comparing raw text would miss the collision entirely: the duplicate check + would not fire and the by-name lookup would find whichever spelling the + gate happens to ask for, leaving its namesake unguarded. + """ + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + name = "Upload regression benchmark report" + jobs = verify_ci_workflow._job_blocks(workflow) + real = verify_ci_workflow._named_step_blocks(jobs["test"])[name] + quoted_real = real.replace(f"- name: {name}", f'- name: "{name}"', 1) + decoy = f" - name: {name}\n if: always()\n run: echo decoy\n" + path = tmp_path / "ci.yml" + path.write_text( + workflow.replace(real, quoted_real.replace(" if: always()\n", "", 1) + decoy), + encoding="utf-8", + ) + + errors = verify_ci_workflow.validate_workflow(path) + + assert any("repeats step names" in error and name in error for error in errors) + + +def test_ci_workflow_rejects_a_step_name_it_cannot_resolve(tmp_path: Path) -> None: + """A name spelled as a block scalar is unreadable to a line-local lexer. + + Guessing at it would be worse than refusing: the gates address steps by + name, so a name they cannot read is a step they cannot verify. + """ + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + path = tmp_path / "ci.yml" + path.write_text( + workflow.replace( + "- name: Upload regression benchmark report", + "- name: >-\n Upload regression benchmark report", + 1, + ), + encoding="utf-8", + ) + + errors = verify_ci_workflow.validate_workflow(path) + + assert any("cannot resolve" in error for error in errors) + + +def test_ci_workflow_accepts_a_quoted_step_name_with_no_namesake(tmp_path: Path) -> None: + """Normalizing names must not make ordinary quoting a failure.""" + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + name = "Upload regression benchmark report" + path = tmp_path / "ci.yml" + path.write_text(workflow.replace(f"- name: {name}", f'- name: "{name}"', 1), encoding="utf-8") + + assert verify_ci_workflow.validate_workflow(path) == [] + + def test_ci_workflow_rejects_missing_wheel_upload(tmp_path: Path) -> None: workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") path = tmp_path / "ci.yml" From 16ec8fec0e03c0d72cd62e2f9fcf7cc782b9e4ef Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sun, 13 Sep 2026 01:17:01 +0200 Subject: [PATCH 10/17] Bump the pinned Reflex channel commit to 609b2f51 --- docs/app/pyproject.toml | 8 ++-- docs/app/uv.lock | 86 +++++++++++++++++++------------------- pyproject.toml | 2 +- tests/test_dependencies.py | 2 +- uv.lock | 62 +++++++++++++-------------- 5 files changed, 80 insertions(+), 80 deletions(-) diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index 64db70b11..8579b24f2 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -12,10 +12,10 @@ requires-python = ">=3.11" dependencies = [ "numpy", "pillow", - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0", - "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0#subdirectory=packages/reflex-components-internal", - "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0#subdirectory=packages/reflex-docgen", - "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0#subdirectory=packages/reflex-site-shared", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0", + "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0#subdirectory=packages/reflex-components-internal", + "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0#subdirectory=packages/reflex-docgen", + "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0#subdirectory=packages/reflex-site-shared", "xy[reflex]", ] diff --git a/docs/app/uv.lock b/docs/app/uv.lock index 82b1534d4..af72b9a47 100644 --- a/docs/app/uv.lock +++ b/docs/app/uv.lock @@ -1063,8 +1063,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1095,8 +1095,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1106,8 +1106,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1117,8 +1117,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1130,8 +1130,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1139,32 +1139,32 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-internal" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1174,16 +1174,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1191,8 +1191,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1201,8 +1201,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1210,16 +1210,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1227,8 +1227,8 @@ dependencies = [ [[package]] name = "reflex-docgen" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "griffelib" }, { name = "mistletoe" }, @@ -1239,8 +1239,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -1251,13 +1251,13 @@ dependencies = [ [[package]] name = "reflex-integrations-docs" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } [[package]] name = "reflex-site-shared" -version = "0.0.3.post254.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.3.post255.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "email-validator" }, { name = "httpx" }, @@ -1632,7 +1632,7 @@ reflex = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, ] provides-extras = ["reflex"] @@ -1681,10 +1681,10 @@ dev = [ requires-dist = [ { name = "numpy" }, { name = "pillow" }, - { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, - { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, - { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, - { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, + { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, + { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, + { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, + { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, { name = "xy", extras = ["reflex"], editable = "../../" }, ] diff --git a/pyproject.toml b/pyproject.toml index 6c8301a65..be4daba09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ # with the real floor the moment channels are released (see the design doc's # Status note). reflex = [ - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0", ] [project.urls] diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index b5d9173e3..1a9e047bb 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -18,7 +18,7 @@ # assertion, and drop `test_docs_app_pins_the_same_reflex_commit`, when # channels are released. REFLEX_REQUIREMENT = ( - "git+https://github.com/benedikt-bartscher/reflex.git@46cecf595bb48a6200bb0047b60acc19306133b0" + "git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0" ) diff --git a/uv.lock b/uv.lock index 6d288d699..ad78d8b0d 100644 --- a/uv.lock +++ b/uv.lock @@ -1543,8 +1543,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1575,8 +1575,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1586,8 +1586,8 @@ dependencies = [ [[package]] name = "reflex-components-code" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1597,8 +1597,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1610,8 +1610,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1619,24 +1619,24 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1646,16 +1646,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1663,8 +1663,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1673,8 +1673,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1682,16 +1682,16 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1699,8 +1699,8 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3501.dev0+46cecf59" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=46cecf595bb48a6200bb0047b60acc19306133b0#46cecf595bb48a6200bb0047b60acc19306133b0" } +version = "0.0.0.post3502.dev0+609b2f51" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } dependencies = [ { name = "click" }, { name = "httpx" }, @@ -2228,7 +2228,7 @@ dev = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=46cecf595bb48a6200bb0047b60acc19306133b0" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, ] provides-extras = ["reflex"] From 001b776f07c9dad2746932e288b03fa394a81519 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 17 Oct 2026 13:37:58 +0200 Subject: [PATCH 11/17] Bump the pinned Reflex channel commit to 7ff41648 The channel transport now opens a session only for a socket whose first frame is `_connect`, acknowledged with `_handshake`, as websocket.js already does on open. The data plane test client sends it before opening `/_xy`; without it the backend never linked the socket's token and every raw-websocket test timed out waiting for `_opened`. The new commit carries Reflex main up to 5ae5dcd5, which the docs app from main relies on, and drops python-socketio from the docs lock now that it is an optional Reflex extra. --- docs/app/pyproject.toml | 8 +- docs/app/uv.lock | 98 ++++++++++++++----------- pyproject.toml | 2 +- tests/reflex_adapter/test_data_plane.py | 14 +++- tests/test_dependencies.py | 2 +- uv.lock | 76 +++++++++++-------- 6 files changed, 118 insertions(+), 82 deletions(-) diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index 8579b24f2..70aa485cd 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -12,10 +12,10 @@ requires-python = ">=3.11" dependencies = [ "numpy", "pillow", - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0", - "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0#subdirectory=packages/reflex-components-internal", - "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0#subdirectory=packages/reflex-docgen", - "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0#subdirectory=packages/reflex-site-shared", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@7ff416484825edd118ef4182ffcd29583f8e2103", + "reflex-components-internal @ git+https://github.com/benedikt-bartscher/reflex.git@7ff416484825edd118ef4182ffcd29583f8e2103#subdirectory=packages/reflex-components-internal", + "reflex-docgen @ git+https://github.com/benedikt-bartscher/reflex.git@7ff416484825edd118ef4182ffcd29583f8e2103#subdirectory=packages/reflex-docgen", + "reflex-site-shared @ git+https://github.com/benedikt-bartscher/reflex.git@7ff416484825edd118ef4182ffcd29583f8e2103#subdirectory=packages/reflex-site-shared", "xy[reflex]", ] diff --git a/docs/app/uv.lock b/docs/app/uv.lock index abd0c96fa..701a974f2 100644 --- a/docs/app/uv.lock +++ b/docs/app/uv.lock @@ -1065,8 +1065,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1097,8 +1097,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1106,10 +1106,20 @@ dependencies = [ { name = "typing-extensions" }, ] +[[package]] +name = "reflex-build-sdk" +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-build-sdk&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } + +[package.optional-dependencies] +httpx = [ + { name = "httpx" }, +] + [[package]] name = "reflex-components-code" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1119,8 +1129,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1132,8 +1142,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1141,32 +1151,32 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-internal" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1176,16 +1186,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1193,8 +1203,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1203,8 +1213,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1212,16 +1222,17 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, + { name = "reflex-components-core" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1229,8 +1240,8 @@ dependencies = [ [[package]] name = "reflex-docgen" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "griffelib" }, { name = "mistletoe" }, @@ -1241,25 +1252,26 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "click" }, { name = "httpx" }, { name = "packaging" }, { name = "platformdirs" }, + { name = "reflex-build-sdk", extra = ["httpx"] }, { name = "rich" }, ] [[package]] name = "reflex-integrations-docs" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Fintegrations-docs&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } [[package]] name = "reflex-site-shared" -version = "0.0.3.post255.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.4.dev570+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "email-validator" }, { name = "httpx" }, @@ -1573,7 +1585,7 @@ reflex = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=7ff416484825edd118ef4182ffcd29583f8e2103" }, ] provides-extras = ["reflex"] @@ -1622,10 +1634,10 @@ dev = [ requires-dist = [ { name = "numpy" }, { name = "pillow" }, - { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, - { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, - { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, - { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, + { name = "reflex", git = "https://github.com/benedikt-bartscher/reflex.git?rev=7ff416484825edd118ef4182ffcd29583f8e2103" }, + { name = "reflex-components-internal", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-internal&rev=7ff416484825edd118ef4182ffcd29583f8e2103" }, + { name = "reflex-docgen", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-docgen&rev=7ff416484825edd118ef4182ffcd29583f8e2103" }, + { name = "reflex-site-shared", git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-site-shared&rev=7ff416484825edd118ef4182ffcd29583f8e2103" }, { name = "xy", extras = ["reflex"], editable = "../../" }, ] diff --git a/pyproject.toml b/pyproject.toml index be4daba09..349509a89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ # with the real floor the moment channels are released (see the design doc's # Status note). reflex = [ - "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0", + "reflex @ git+https://github.com/benedikt-bartscher/reflex.git@7ff416484825edd118ef4182ffcd29583f8e2103", ] [project.urls] diff --git a/tests/reflex_adapter/test_data_plane.py b/tests/reflex_adapter/test_data_plane.py index 98a72d42e..39eaa5b31 100644 --- a/tests/reflex_adapter/test_data_plane.py +++ b/tests/reflex_adapter/test_data_plane.py @@ -92,7 +92,8 @@ class PlaneClient: """One connected websocket with the `/_xy` channel open. Mirrors what XYChart.jsx does through `getChannel("/_xy")`: the app's own - event websocket, one `_open` for the channel, and every data plane frame + event websocket, opened by a `_connect` frame the backend acknowledges + with `_handshake`, one `_open` for the channel, and every data plane frame arriving as `(metadata, attachments)`. """ @@ -103,6 +104,7 @@ def __init__(self, session: aiohttp.ClientSession, ws: aiohttp.ClientWebSocketRe self.payloads: asyncio.Queue = asyncio.Queue() self.messages: asyncio.Queue = asyncio.Queue() self.errors: asyncio.Queue = asyncio.Queue() + self._handshaken = asyncio.Event() self._opened = asyncio.Event() self.reader_error: Optional[BaseException] = None self._queues = { @@ -141,6 +143,9 @@ async def _read_frames(self) -> None: if event == "_ping": await self._ws.send_str(json.dumps(["_pong"])) continue + if event == "_handshake": + self._handshaken.set() + continue if event == "_opened" and channel == XY_PLANE: self._opened.set() continue @@ -152,6 +157,12 @@ async def emit(self, event: str, data: Any) -> None: """Send one data plane message on the `/_xy` channel.""" await self._ws.send_str(json.dumps([event, data, XY_PLANE])) + async def open_session(self) -> None: + # The backend opens a session only for a socket whose first frame is + # `_connect`, as websocket.js sends on open; it carries no boot event. + await self._ws.send_str(json.dumps(["_connect", {}])) + await asyncio.wait_for(self._handshaken.wait(), 5.0) + async def open_plane(self) -> None: await self.emit("_open", None) await asyncio.wait_for(self._opened.wait(), 5.0) @@ -181,6 +192,7 @@ async def connect_client(base_url: str, client_token: str = CLIENT_TOKEN) -> Pla session = aiohttp.ClientSession() ws = await session.ws_connect(f"{base_url.replace('http', 'ws')}/_event?token={client_token}") client = PlaneClient(session, ws) + await client.open_session() await client.open_plane() return client diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 1a9e047bb..2b447b804 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -18,7 +18,7 @@ # assertion, and drop `test_docs_app_pins_the_same_reflex_commit`, when # channels are released. REFLEX_REQUIREMENT = ( - "git+https://github.com/benedikt-bartscher/reflex.git@609b2f515fc9d00e9a63a056d00a7782c77323b0" + "git+https://github.com/benedikt-bartscher/reflex.git@7ff416484825edd118ef4182ffcd29583f8e2103" ) diff --git a/uv.lock b/uv.lock index ad78d8b0d..d7717da46 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 5 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.12'", @@ -1543,8 +1543,8 @@ wheels = [ [[package]] name = "reflex" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "click" }, { name = "granian", extra = ["reload"] }, @@ -1575,8 +1575,8 @@ dependencies = [ [[package]] name = "reflex-base" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-base&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, @@ -1584,10 +1584,20 @@ dependencies = [ { name = "typing-extensions" }, ] +[[package]] +name = "reflex-build-sdk" +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-build-sdk&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } + +[package.optional-dependencies] +httpx = [ + { name = "httpx" }, +] + [[package]] name = "reflex-components-code" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-code&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1597,8 +1607,8 @@ dependencies = [ [[package]] name = "reflex-components-core" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-core&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "python-multipart" }, { name = "reflex-base" }, @@ -1610,8 +1620,8 @@ dependencies = [ [[package]] name = "reflex-components-dataeditor" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-dataeditor&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1619,24 +1629,24 @@ dependencies = [ [[package]] name = "reflex-components-gridjs" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-gridjs&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-lucide" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-lucide&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-markdown" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-markdown&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-code" }, @@ -1646,16 +1656,16 @@ dependencies = [ [[package]] name = "reflex-components-moment" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-moment&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, ] [[package]] name = "reflex-components-plotly" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-plotly&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1663,8 +1673,8 @@ dependencies = [ [[package]] name = "reflex-components-radix" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-radix&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1673,8 +1683,8 @@ dependencies = [ [[package]] name = "reflex-components-react-player" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-react-player&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-core" }, @@ -1682,16 +1692,17 @@ dependencies = [ [[package]] name = "reflex-components-recharts" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-recharts&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, + { name = "reflex-components-core" }, ] [[package]] name = "reflex-components-sonner" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-components-sonner&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "reflex-base" }, { name = "reflex-components-lucide" }, @@ -1699,13 +1710,14 @@ dependencies = [ [[package]] name = "reflex-hosting-cli" -version = "0.0.0.post3502.dev0+609b2f51" -source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=609b2f515fc9d00e9a63a056d00a7782c77323b0#609b2f515fc9d00e9a63a056d00a7782c77323b0" } +version = "0.0.1.dev3817+7ff41648" +source = { git = "https://github.com/benedikt-bartscher/reflex.git?subdirectory=packages%2Freflex-hosting-cli&rev=7ff416484825edd118ef4182ffcd29583f8e2103#7ff416484825edd118ef4182ffcd29583f8e2103" } dependencies = [ { name = "click" }, { name = "httpx" }, { name = "packaging" }, { name = "platformdirs" }, + { name = "reflex-build-sdk", extra = ["httpx"] }, { name = "rich" }, ] @@ -2228,7 +2240,7 @@ dev = [ requires-dist = [ { name = "anywidget", specifier = ">=0.9" }, { name = "numpy", specifier = ">=1.24" }, - { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=609b2f515fc9d00e9a63a056d00a7782c77323b0" }, + { name = "reflex", marker = "extra == 'reflex'", git = "https://github.com/benedikt-bartscher/reflex.git?rev=7ff416484825edd118ef4182ffcd29583f8e2103" }, ] provides-extras = ["reflex"] From 116f00bebab760c2d4a1b6aaf377edb81d64e747 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 17 Oct 2026 14:27:59 +0200 Subject: [PATCH 12/17] Fan a cache-miss rebuild out to every attached app A rebuild published its new generation through its own channel only, while a normal publish fans out through the registry's publish seam to every attached app. With two live apps serving one token, the other app's subscribers kept the old version and their hover, pick and selection requests were dropped as stale. Send the rebuild through the seam with an awaitable registry.fan_out, so a failed send still retracts the inserted generation; a channel used outside setup() has no seam and keeps serving its own room. --- python/reflex_xy/data_plane.py | 7 +++- python/reflex_xy/registry.py | 13 ++++++++ spec/design/reflex-integration.md | 4 ++- tests/reflex_adapter/test_setup_attachment.py | 32 +++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/python/reflex_xy/data_plane.py b/python/reflex_xy/data_plane.py index 7762dab17..4856407d1 100644 --- a/python/reflex_xy/data_plane.py +++ b/python/reflex_xy/data_plane.py @@ -619,7 +619,12 @@ async def _run_rebuild_attempt( return entry, None try: - await self.broadcast_payload(token, entry) + # Through the registry's seam, which reaches the subscribers of + # every attached app: one left on the old version would have + # its requests dropped as stale. A channel used on its own, + # outside setup(), has no seam and serves its own room. + if not await self.registry.fan_out(token, entry): + await self.broadcast_payload(token, entry) except Exception: # noqa: BLE001 - payload build/send is a protocol boundary # A failed generation must not poison later cache hits. Remove # only the generation this attempt inserted; if a normal diff --git a/python/reflex_xy/registry.py b/python/reflex_xy/registry.py index 37f379d2d..02f0d54fe 100644 --- a/python/reflex_xy/registry.py +++ b/python/reflex_xy/registry.py @@ -691,6 +691,19 @@ def bump(self, token: str, *, expected: Optional[FigureEntry] = None) -> Optiona entry.touch() return entry + async def fan_out(self, token: str, entry: FigureEntry) -> bool: + """Push ``entry`` to subscribers through the publish seam, awaiting it. + + Unlike ``schedule_broadcast``, the caller sees a failed send, so a + cache-miss rebuild can retract the generation it could not deliver. + Returns whether a seam is wired; nothing is sent when none is. + """ + callback = self._on_publish + if callback is None: + return False + await callback(token, entry) + return True + def schedule_broadcast(self, token: str) -> None: """Fan a publish out to subscribers from any thread. diff --git a/spec/design/reflex-integration.md b/spec/design/reflex-integration.md index 0e0f77c38..132c05693 100644 --- a/spec/design/reflex-integration.md +++ b/spec/design/reflex-integration.md @@ -453,7 +453,9 @@ remains, both the sweep and an explicit release retain only the removed token's scalar version so a republish on the same worker stays monotonic; the figure and its data buffers are released. If an interaction is the first touch after eviction, the data plane -rebuilds, sends every subscribed mount a replacement payload room-wide, and +rebuilds, sends every subscribed mount a replacement payload room-wide (in +every app attached in the process, through the registry seam a normal publish +fans out on), and drops the old-generation interaction for the triggering client to retry. If a new `sub` is first, the data plane broadcasts the rebuild to existing room members before joining the requester, then sends that mount one `mid`-addressed diff --git a/tests/reflex_adapter/test_setup_attachment.py b/tests/reflex_adapter/test_setup_attachment.py index 3fa466ae2..f93b35df9 100644 --- a/tests/reflex_adapter/test_setup_attachment.py +++ b/tests/reflex_adapter/test_setup_attachment.py @@ -96,6 +96,38 @@ async def main(): assert {name for name, _ in delivered} == {token} +def test_a_rebuild_fans_out_to_every_live_app(monkeypatch): + """A cache-miss rebuild in one app reaches the other app's subscribers too. + + The rebuilt generation carries a new version; a subscriber left on the old + one would have its hover, pick and selection requests dropped as stale. + """ + app_a, app_b = make_app(), make_app() + channel_a, channel_b = setup(app_a), setup(app_b) + delivered: list[tuple[object, object]] = [] + + for channel in (channel_a, channel_b): + + async def broadcast(token, entry, _channel=channel): + delivered.append((_channel, entry)) + + monkeypatch.setattr(channel, "broadcast_payload", broadcast) + + async def rebuild(token): + return make_figure() + + monkeypatch.setattr(channel_a, "_rebuild", rebuild) + + async def main(): + return await channel_a._start_rebuild_attempt("evicted") + + entry, failure = asyncio.run(main()) + + assert failure is None + assert {id(channel) for channel, _ in delivered} == {id(channel_a), id(channel_b)} + assert all(sent is entry for _, sent in delivered) + + def test_one_failing_plane_does_not_swallow_the_others(_fresh_registry, monkeypatch): registry = _fresh_registry app_a, app_b = make_app(), make_app() From fd4cbed3367211916493bcc93f4e1f1266d5c5e8 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 17 Oct 2026 14:27:59 +0200 Subject: [PATCH 13/17] Fail data plane test setup at once when the reader stops The handshake and channel-open waits ran out their five-second timeout when the reader had already stopped on a malformed frame or a socket the backend closed, hiding the cause, and a client that failed setup leaked its aiohttp session. Wait for the step or the reader, raise the reader's error or the close code, and close the socket and session on any setup failure. --- tests/reflex_adapter/test_data_plane.py | 89 ++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 8 deletions(-) diff --git a/tests/reflex_adapter/test_data_plane.py b/tests/reflex_adapter/test_data_plane.py index 39eaa5b31..bdcdb0571 100644 --- a/tests/reflex_adapter/test_data_plane.py +++ b/tests/reflex_adapter/test_data_plane.py @@ -161,13 +161,39 @@ async def open_session(self) -> None: # The backend opens a session only for a socket whose first frame is # `_connect`, as websocket.js sends on open; it carries no boot event. await self._ws.send_str(json.dumps(["_connect", {}])) - await asyncio.wait_for(self._handshaken.wait(), 5.0) + await self._await_setup(self._handshaken, "the handshake") async def open_plane(self) -> None: await self.emit("_open", None) - await asyncio.wait_for(self._opened.wait(), 5.0) + await self._await_setup(self._opened, "the channel opened") - async def disconnect(self) -> None: + async def _await_setup(self, step: asyncio.Event, what: str) -> None: + """Wait for one setup step, failing at once if the reader stops first. + + A malformed frame or a socket the backend closed ends the reader; the + cause belongs in the failure, not behind a timeout. + """ + waiter = asyncio.ensure_future(step.wait()) + try: + await asyncio.wait( + {waiter, self._reader}, timeout=5.0, return_when=asyncio.FIRST_COMPLETED + ) + finally: + waiter.cancel() + if step.is_set(): + return + if self.reader_error is not None: + raise AssertionError( + f"the data plane reader failed before {what}" + ) from self.reader_error + if self._reader.done(): + raise AssertionError( + f"the backend closed the socket (code {self._ws.close_code}) before {what}" + ) + raise TimeoutError(f"no {what} within 5s") + + async def close(self) -> None: + """Stop reading and close the socket and its session, raising nothing.""" if not self.connected: return self.connected = False @@ -179,6 +205,11 @@ async def disconnect(self) -> None: await self._reader await self._ws.close() await self._session.close() + + async def disconnect(self) -> None: + if not self.connected: + return + await self.close() if self.reader_error is not None: # The failure was handed to every waiter, but a test that finished # its assertions without reading again would never have popped it — @@ -188,12 +219,26 @@ async def disconnect(self) -> None: async def connect_client(base_url: str, client_token: str = CLIENT_TOKEN) -> PlaneClient: - """Connect the way XYChart.jsx does: the app socket, token in the query.""" + """Connect the way XYChart.jsx does: the app socket, token in the query. + + A client that cannot finish setup is closed, session included, before the + failure propagates. + """ session = aiohttp.ClientSession() - ws = await session.ws_connect(f"{base_url.replace('http', 'ws')}/_event?token={client_token}") - client = PlaneClient(session, ws) - await client.open_session() - await client.open_plane() + client: Optional[PlaneClient] = None + try: + ws = await session.ws_connect( + f"{base_url.replace('http', 'ws')}/_event?token={client_token}" + ) + client = PlaneClient(session, ws) + await client.open_session() + await client.open_plane() + except BaseException: + if client is None: + await session.close() + else: + await client.close() + raise return client @@ -408,6 +453,34 @@ async def main(): assert other.active_operations == 0 +def test_a_refused_session_fails_setup_at_once_and_closes_it(monkeypatch): + """A socket the backend refuses fails `connect_client` with the cause. + + Without a client token the backend never links the socket and closes it + before the handshake. The setup waits must notice the reader stopping + rather than run out their timeout, and the session must not leak. + """ + sessions: list[aiohttp.ClientSession] = [] + open_session = aiohttp.ClientSession + + def recording_session() -> aiohttp.ClientSession: + sessions.append(session := open_session()) + return session + + monkeypatch.setattr(aiohttp, "ClientSession", recording_session) + + async def main(): + async with data_plane_server() as (url, _): + loop = asyncio.get_running_loop() + started = loop.time() + with pytest.raises(AssertionError, match=r"closed the socket .* before the handshake"): + await connect_client(url, client_token="") + assert loop.time() - started < 2.0 + + run(main()) + assert [session.closed for session in sessions] == [True] + + def test_a_broken_frame_fails_the_test_even_if_nothing_reads_it(_fresh_registry, monkeypatch): """The harness must not let a broken wire pass as a green run. From 1b63ca8051679c6fc2639cbc9e05709ec6eda8e2 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 17 Oct 2026 15:00:09 +0200 Subject: [PATCH 14/17] Describe the app-wide rebuild fan-out on the new-sub path too A new `sub` rebuilds through the same attempt as an interaction, so its room broadcast also goes through the registry seam to every attached app. State that once for both paths instead of only for the interaction. --- spec/design/reflex-integration.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/design/reflex-integration.md b/spec/design/reflex-integration.md index 132c05693..86cece407 100644 --- a/spec/design/reflex-integration.md +++ b/spec/design/reflex-integration.md @@ -453,13 +453,14 @@ remains, both the sweep and an explicit release retain only the removed token's scalar version so a republish on the same worker stays monotonic; the figure and its data buffers are released. If an interaction is the first touch after eviction, the data plane -rebuilds, sends every subscribed mount a replacement payload room-wide (in -every app attached in the process, through the registry seam a normal publish -fans out on), and +rebuilds, sends every subscribed mount a replacement payload room-wide, and drops the old-generation interaction for the triggering client to retry. If a new `sub` is first, the data plane broadcasts the rebuild to existing room members before joining the requester, then sends that mount one `mid`-addressed -payload built for its own `px` hint. The direct path re-reads the current entry +payload built for its own `px` hint. On either path the rebuild's room +broadcast goes through the registry seam a normal publish fans out on, so it +reaches the subscribers of every app attached in the process, not only those +of the app that rebuilt. The direct path re-reads the current entry after joining the room: a normal replacement that landed before the join is sent directly, while a replacement after the join reaches the mount through the room broadcast. Concurrent same-token misses share the complete rebuild From bd25f5993a21b36f8eee66375a0d275cbe0772ef Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 17 Oct 2026 18:10:03 +0200 Subject: [PATCH 15/17] Keep a rebuilt generation another app received and find step names anywhere A rebuild's payload fan-out raised when any attached app failed, so the rebuild removed a generation the healthy apps' subscribers already held. Payload fan-out now raises only when no app received it and logs the per-app failures otherwise. The CI verifier read a step's name only from its first line, missing a name after a leading `uses` and quoted `name` keys, so duplicate step names went undetected. Step names are now read as direct keys of the step mapping. --- python/reflex_xy/app.py | 24 +++++-- scripts/verify_ci_workflow.py | 32 +++++---- spec/design/reflex-integration.md | 4 +- tests/reflex_adapter/test_setup_attachment.py | 69 +++++++++++++++++-- tests/test_verify_ci_workflow.py | 52 ++++++++++++++ 5 files changed, 157 insertions(+), 24 deletions(-) diff --git a/python/reflex_xy/app.py b/python/reflex_xy/app.py index edfd6b0ea..d83f37f86 100644 --- a/python/reflex_xy/app.py +++ b/python/reflex_xy/app.py @@ -23,6 +23,7 @@ import asyncio import contextlib import inspect +import logging import warnings from collections.abc import Callable, Coroutine, Sequence from typing import Any, Optional, cast @@ -36,6 +37,8 @@ from .tokens import BUILDER_ATTR, PROBE_ATTR from .vars import AsyncFigureVar, FigureVar +_logger = logging.getLogger("reflex_xy") + __all__ = [ "FigureProbeError", "XYPlugin", @@ -174,21 +177,32 @@ def wire_attached() -> None: registry.on_error(_fan_out_error) -async def _fan_out(calls: "Sequence[Coroutine[Any, Any, None]]") -> None: +async def _fan_out( + calls: "Sequence[Coroutine[Any, Any, None]]", *, partial_ok: bool = False +) -> None: """Await every fan-out, then re-raise the first failure. One app's transport failing must not swallow the others' deliveries — that is the whole point of fanning out — but the error still has to surface the way a single-plane send does, so it is raised after the rest have run. + With ``partial_ok`` it is only logged once another app was delivered to. """ results = await asyncio.gather(*calls, return_exceptions=True) - for result in results: - if isinstance(result, BaseException): - raise result + failures = [result for result in results if isinstance(result, BaseException)] + if not failures: + return + if not partial_ok or len(failures) == len(results): + raise failures[0] + for failure in failures: + _logger.error("reflex_xy: an attached app missed a fan-out", exc_info=failure) async def _fan_out_payload(token: str, entry: Any) -> None: - await _fan_out([plane.broadcast_payload(token, entry) for plane in _live_planes()]) + # A payload some app received is a delivered generation: raising would make + # a rebuild retract it from that app's subscribers. + await _fan_out( + [plane.broadcast_payload(token, entry) for plane in _live_planes()], partial_ok=True + ) async def _fan_out_message( diff --git a/scripts/verify_ci_workflow.py b/scripts/verify_ci_workflow.py index 899bff9f3..da442b095 100644 --- a/scripts/verify_ci_workflow.py +++ b/scripts/verify_ci_workflow.py @@ -500,7 +500,7 @@ def _decode_step_name(raw: str) -> tuple[Optional[str], bool]: properties, an empty name — fails closed instead of being guessed at. Args: - raw: The text following ``name:`` on the step's first line. + raw: The raw value of the step's ``name`` key. Returns: The decoded name, or None with a True flag when it is unsupported. @@ -510,15 +510,25 @@ def _decode_step_name(raw: str) -> tuple[Optional[str], bool]: return _decode_yaml_key(raw) +def _step_name(block: str) -> Optional[tuple[Optional[str], bool]]: + """Return a step's decoded ``(name, unsafe)``, or None for an unnamed step. + + The ``name`` key is read like any direct key of the step mapping, so it + counts after a leading ``uses`` and under a quoted spelling. A step whose + keys include one the decoder cannot read, which might be ``name``, or that + repeats ``name``, fails closed. + """ + values, unsafe = _step_direct_key_values(block, "name") + if unsafe or len(values) > 1: + return None, True + return _decode_step_name(values[0]) if values else None + + def _step_names(job_text: str) -> list[tuple[Optional[str], bool]]: """Return ``(name, unsafe)`` for every named step, in sequence order.""" - names: list[tuple[Optional[str], bool]] = [] - for block in _step_sequence_blocks(job_text): - first = _strip_yaml_comment(block.splitlines()[0]) - match = re.match(r"^ - name:\s*(.+?)\s*$", first) - if match is not None: - names.append(_decode_step_name(match.group(1))) - return names + return [ + name for block in _step_sequence_blocks(job_text) if (name := _step_name(block)) is not None + ] def _named_step_blocks(job_text: str) -> dict[str, str]: @@ -542,11 +552,9 @@ def _named_step_blocks(job_text: str) -> dict[str, str]: } blocks: dict[str, str] = {} for block in _step_sequence_blocks(job_text): - first = _strip_yaml_comment(block.splitlines()[0]) - match = re.match(r"^ - name:\s*(.+?)\s*$", first) - if match is None: + if (named := _step_name(block)) is None: continue - name, unsafe = _decode_step_name(match.group(1)) + name, unsafe = named if unsafe or name is None or name in unusable: continue blocks[name] = block diff --git a/spec/design/reflex-integration.md b/spec/design/reflex-integration.md index 86cece407..c4eb053ac 100644 --- a/spec/design/reflex-integration.md +++ b/spec/design/reflex-integration.md @@ -355,7 +355,9 @@ that raise answer `err {fig, error}`; the client logs and shows an empty mount rather than crashing the page. During rebuild, payload construction or room fan-out failures likewise answer `err` and remove only the generation that attempt inserted, so a later subscription retries; a concurrent normal -replacement is never removed. +replacement is never removed. A fan-out counts as failed only when no attached +app received the payload: one app failing while another received it is logged +and the generation kept, since the healthy app's subscribers already hold it. ### 3.3 Access control diff --git a/tests/reflex_adapter/test_setup_attachment.py b/tests/reflex_adapter/test_setup_attachment.py index f93b35df9..6a438a73e 100644 --- a/tests/reflex_adapter/test_setup_attachment.py +++ b/tests/reflex_adapter/test_setup_attachment.py @@ -12,6 +12,7 @@ import asyncio import gc +import logging import numpy as np import pytest @@ -128,11 +129,13 @@ async def main(): assert all(sent is entry for _, sent in delivered) -def test_one_failing_plane_does_not_swallow_the_others(_fresh_registry, monkeypatch): - registry = _fresh_registry - app_a, app_b = make_app(), make_app() - channel_a, channel_b = setup(app_a), setup(app_b) - reached = [] +def _one_plane_fails(monkeypatch, channel_a, channel_b) -> list[str]: + """Make app A's payload delivery fail while app B's succeeds. + + Returns: + The tokens app B received. + """ + reached: list[str] = [] async def boom(token, entry): raise RuntimeError("transport failed") @@ -142,6 +145,35 @@ async def ok(token, entry): monkeypatch.setattr(channel_a, "broadcast_payload", boom) monkeypatch.setattr(channel_b, "broadcast_payload", ok) + return reached + + +def test_one_failing_plane_does_not_swallow_the_others(_fresh_registry, monkeypatch, caplog): + """A payload another app received is delivered; the failing app is logged.""" + registry = _fresh_registry + app_a, app_b = make_app(), make_app() + channel_a, channel_b = setup(app_a), setup(app_b) + reached = _one_plane_fails(monkeypatch, channel_a, channel_b) + + async def main(): + entry = registry.publish("tok", make_figure(), broadcast=False) + await adapter_app._fan_out_payload("tok", entry) + + with caplog.at_level(logging.ERROR, logger="reflex_xy"): + asyncio.run(main()) + assert reached == ["tok"], "the healthy plane must still have received the payload" + assert ["transport failed" in str(r.exc_info) for r in caplog.records] == [True] + + +def test_a_payload_no_plane_received_still_raises(_fresh_registry, monkeypatch): + """With every app failing, the error surfaces as a single-plane send's does.""" + registry = _fresh_registry + channel = setup(make_app()) + + async def boom(token, entry): + raise RuntimeError("transport failed") + + monkeypatch.setattr(channel, "broadcast_payload", boom) async def main(): entry = registry.publish("tok", make_figure(), broadcast=False) @@ -149,7 +181,32 @@ async def main(): await adapter_app._fan_out_payload("tok", entry) asyncio.run(main()) - assert reached == ["tok"], "the healthy plane must still have received the payload" + + +def test_a_rebuild_keeps_a_generation_another_app_received(_fresh_registry, monkeypatch): + """One app failing to receive a rebuild must not retract it from the others. + + Their subscribers already hold the rebuilt version; removing the entry + would turn their next versioned interaction into another cache miss. + """ + registry = _fresh_registry + app_a, app_b = make_app(), make_app() + channel_a, channel_b = setup(app_a), setup(app_b) + reached = _one_plane_fails(monkeypatch, channel_a, channel_b) + + async def rebuild(token): + return make_figure() + + monkeypatch.setattr(channel_a, "_rebuild", rebuild) + + async def main(): + return await channel_a._start_rebuild_attempt("evicted") + + entry, failure = asyncio.run(main()) + + assert failure is None + assert reached == ["evicted"] + assert registry.get("evicted") is entry def test_a_collected_app_stops_receiving_fan_out(): diff --git a/tests/test_verify_ci_workflow.py b/tests/test_verify_ci_workflow.py index 2ba863d20..e62f39f12 100644 --- a/tests/test_verify_ci_workflow.py +++ b/tests/test_verify_ci_workflow.py @@ -5,6 +5,8 @@ import sys from pathlib import Path +import pytest + # Actions are pinned to full commit SHAs (`@<40-hex> # vX`) per the org policy, # so fixtures strip a step by its action *path*, not a version tag — a SHA bump # must not silently turn these negative tests into no-ops. @@ -1421,6 +1423,56 @@ def test_ci_workflow_rejects_a_quoted_namesake_shadowing_a_step(tmp_path: Path) assert any("repeats step names" in error and name in error for error in errors) +@pytest.mark.parametrize( + "decoy", + [ + pytest.param( + " - uses: actions/checkout@v6\n name: {name}\n if: always()\n", + id="name-after-uses", + ), + pytest.param( + ' - "name": {name}\n if: always()\n run: echo decoy\n', + id="quoted-name-key", + ), + ], +) +def test_ci_workflow_rejects_a_namesake_in_any_step_spelling(tmp_path: Path, decoy: str) -> None: + """A step's name key is its name wherever it sits and however it is quoted. + + Reading only a first-line ``- name:`` missed a namesake that starts with + ``uses`` or quotes its key, so the duplicate check never saw it. + """ + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + name = "Upload regression benchmark report" + real = verify_ci_workflow._named_step_blocks(verify_ci_workflow._job_blocks(workflow)["test"])[ + name + ] + path = tmp_path / "ci.yml" + path.write_text(workflow.replace(real, real + decoy.format(name=name)), encoding="utf-8") + + errors = verify_ci_workflow.validate_workflow(path) + + assert any("repeats step names" in error and name in error for error in errors) + + +def test_ci_workflow_finds_a_step_named_after_its_uses_key(tmp_path: Path) -> None: + """A step that starts with ``uses`` and names itself after it is still found.""" + workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8") + name = "Upload regression benchmark report" + real = verify_ci_workflow._named_step_blocks(verify_ci_workflow._job_blocks(workflow)["test"])[ + name + ] + lines = real.splitlines() + uses = next(line for line in lines if line.startswith(" uses:")) + reordered = [f" - {uses.strip()}", f" name: {name}"] + [ + line for line in lines[1:] if line != uses + ] + path = tmp_path / "ci.yml" + path.write_text(workflow.replace(real, "\n".join(reordered)), encoding="utf-8") + + assert verify_ci_workflow.validate_workflow(path) == [] + + def test_ci_workflow_rejects_a_step_name_it_cannot_resolve(tmp_path: Path) -> None: """A name spelled as a block scalar is unreadable to a line-local lexer. From de704ce40c46ed182b7a1806d22535382746a8c3 Mon Sep 17 00:00:00 2001 From: Benedikt Bartscher Date: Sat, 17 Oct 2026 19:27:12 +0200 Subject: [PATCH 16/17] Resync the apps that missed a fanned-out payload Keeping a generation one app failed to receive left that app's subscribers on the old version, whose requests are dropped as stale. Each app that missed the payload now gets a resync err in its room, so its subscribers subscribe again; a resync that fails too is logged. The log lines name the figure token. --- python/reflex_xy/app.py | 47 +++++++++++----- spec/design/reflex-integration.md | 2 + tests/reflex_adapter/test_setup_attachment.py | 56 ++++++++++++++++--- 3 files changed, 83 insertions(+), 22 deletions(-) diff --git a/python/reflex_xy/app.py b/python/reflex_xy/app.py index d83f37f86..cf6105835 100644 --- a/python/reflex_xy/app.py +++ b/python/reflex_xy/app.py @@ -177,32 +177,49 @@ def wire_attached() -> None: registry.on_error(_fan_out_error) -async def _fan_out( - calls: "Sequence[Coroutine[Any, Any, None]]", *, partial_ok: bool = False -) -> None: +async def _fan_out(calls: "Sequence[Coroutine[Any, Any, None]]") -> None: """Await every fan-out, then re-raise the first failure. One app's transport failing must not swallow the others' deliveries — that is the whole point of fanning out — but the error still has to surface the way a single-plane send does, so it is raised after the rest have run. - With ``partial_ok`` it is only logged once another app was delivered to. """ results = await asyncio.gather(*calls, return_exceptions=True) - failures = [result for result in results if isinstance(result, BaseException)] - if not failures: - return - if not partial_ok or len(failures) == len(results): - raise failures[0] - for failure in failures: - _logger.error("reflex_xy: an attached app missed a fan-out", exc_info=failure) + for result in results: + if isinstance(result, BaseException): + raise result async def _fan_out_payload(token: str, entry: Any) -> None: - # A payload some app received is a delivered generation: raising would make - # a rebuild retract it from that app's subscribers. - await _fan_out( - [plane.broadcast_payload(token, entry) for plane in _live_planes()], partial_ok=True + """Fan a payload out, raising only when no attached app received it. + + A payload some app received is a delivered generation, which a rebuild must + not retract from its subscribers. An app that missed it asks its own to + resync instead: on the old version, their requests are dropped as stale. + """ + planes = _live_planes() + results = await asyncio.gather( + *(plane.broadcast_payload(token, entry) for plane in planes), return_exceptions=True ) + missed = [ + (plane, result) + for plane, result in zip(planes, results, strict=True) + if isinstance(result, BaseException) + ] + if not missed: + return + if len(missed) == len(planes): + raise missed[0][1] + for _, failure in missed: + _logger.error( + "reflex_xy: an attached app missed figure %s's payload", token, exc_info=failure + ) + try: + await _fan_out( + [plane.broadcast_error(token, "payload delivery failed", True) for plane, _ in missed] + ) + except Exception: # noqa: BLE001 - the payload already reached another app + _logger.exception("reflex_xy: could not ask figure %s's subscribers to resync", token) async def _fan_out_message( diff --git a/spec/design/reflex-integration.md b/spec/design/reflex-integration.md index c4eb053ac..258a20642 100644 --- a/spec/design/reflex-integration.md +++ b/spec/design/reflex-integration.md @@ -358,6 +358,8 @@ attempt inserted, so a later subscription retries; a concurrent normal replacement is never removed. A fan-out counts as failed only when no attached app received the payload: one app failing while another received it is logged and the generation kept, since the healthy app's subscribers already hold it. +The failing app's room gets `err {resync: true}` instead, so its subscribers +subscribe again rather than send requests dropped as stale. ### 3.3 Access control diff --git a/tests/reflex_adapter/test_setup_attachment.py b/tests/reflex_adapter/test_setup_attachment.py index 6a438a73e..ddb8b4829 100644 --- a/tests/reflex_adapter/test_setup_attachment.py +++ b/tests/reflex_adapter/test_setup_attachment.py @@ -129,13 +129,17 @@ async def main(): assert all(sent is entry for _, sent in delivered) -def _one_plane_fails(monkeypatch, channel_a, channel_b) -> list[str]: +def _one_plane_fails( + monkeypatch, channel_a, channel_b +) -> tuple[list[str], list[tuple[str, str, bool]]]: """Make app A's payload delivery fail while app B's succeeds. Returns: - The tokens app B received. + The tokens app B received, and the ``(app, token, resync)`` error + broadcasts either app sent. """ reached: list[str] = [] + errors: list[tuple[str, str, bool]] = [] async def boom(token, entry): raise RuntimeError("transport failed") @@ -143,17 +147,29 @@ async def boom(token, entry): async def ok(token, entry): reached.append(token) + def record(app): + async def broadcast_error(token, error, resync=False): + errors.append((app, token, resync)) + + return broadcast_error + monkeypatch.setattr(channel_a, "broadcast_payload", boom) monkeypatch.setattr(channel_b, "broadcast_payload", ok) - return reached + monkeypatch.setattr(channel_a, "broadcast_error", record("a")) + monkeypatch.setattr(channel_b, "broadcast_error", record("b")) + return reached, errors def test_one_failing_plane_does_not_swallow_the_others(_fresh_registry, monkeypatch, caplog): - """A payload another app received is delivered; the failing app is logged.""" + """A payload another app received is delivered; the failing app resyncs. + + Its subscribers keep the old version, whose requests are dropped as stale, + so only a resubscribe brings them back. + """ registry = _fresh_registry app_a, app_b = make_app(), make_app() channel_a, channel_b = setup(app_a), setup(app_b) - reached = _one_plane_fails(monkeypatch, channel_a, channel_b) + reached, errors = _one_plane_fails(monkeypatch, channel_a, channel_b) async def main(): entry = registry.publish("tok", make_figure(), broadcast=False) @@ -162,7 +178,32 @@ async def main(): with caplog.at_level(logging.ERROR, logger="reflex_xy"): asyncio.run(main()) assert reached == ["tok"], "the healthy plane must still have received the payload" - assert ["transport failed" in str(r.exc_info) for r in caplog.records] == [True] + assert errors == [("a", "tok", True)] + assert [ + ("tok" in r.getMessage(), "transport failed" in str(r.exc_info)) for r in caplog.records + ] == [(True, True)] + + +def test_a_failed_resync_is_only_logged(_fresh_registry, monkeypatch, caplog): + """A resync the failing app cannot send either must not undo the delivery.""" + registry = _fresh_registry + app_a, app_b = make_app(), make_app() + channel_a, channel_b = setup(app_a), setup(app_b) + reached, _ = _one_plane_fails(monkeypatch, channel_a, channel_b) + + async def resync_fails(token, error, resync=False): + raise RuntimeError("resync failed") + + monkeypatch.setattr(channel_a, "broadcast_error", resync_fails) + + async def main(): + entry = registry.publish("tok", make_figure(), broadcast=False) + await adapter_app._fan_out_payload("tok", entry) + + with caplog.at_level(logging.ERROR, logger="reflex_xy"): + asyncio.run(main()) + assert reached == ["tok"] + assert ["resync failed" in str(r.exc_info) for r in caplog.records] == [False, True] def test_a_payload_no_plane_received_still_raises(_fresh_registry, monkeypatch): @@ -192,7 +233,7 @@ def test_a_rebuild_keeps_a_generation_another_app_received(_fresh_registry, monk registry = _fresh_registry app_a, app_b = make_app(), make_app() channel_a, channel_b = setup(app_a), setup(app_b) - reached = _one_plane_fails(monkeypatch, channel_a, channel_b) + reached, errors = _one_plane_fails(monkeypatch, channel_a, channel_b) async def rebuild(token): return make_figure() @@ -206,6 +247,7 @@ async def main(): assert failure is None assert reached == ["evicted"] + assert errors == [("a", "evicted", True)] assert registry.get("evicted") is entry From 95c0ff0544ed311f734af889aac8ce5d2a170c93 Mon Sep 17 00:00:00 2001 From: Farhan Ali Raza Date: Tue, 27 Oct 2026 14:00:15 +0500 Subject: [PATCH 17/17] Remove local validation artifacts from the source tree --- node_modules | 1 - python/xy/_native_lib/libxy_core.so | Bin 1304808 -> 0 bytes 2 files changed, 1 deletion(-) delete mode 120000 node_modules delete mode 100755 python/xy/_native_lib/libxy_core.so diff --git a/node_modules b/node_modules deleted file mode 120000 index f25e2d555..000000000 --- a/node_modules +++ /dev/null @@ -1 +0,0 @@ -/tools/node_modules \ No newline at end of file diff --git a/python/xy/_native_lib/libxy_core.so b/python/xy/_native_lib/libxy_core.so deleted file mode 100755 index e90938f9a4d361b08eca60ec239f229918d8b33b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1304808 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

s?dmMJh57ryP^}z-+$iYS|;o&Db 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

5k~!pRBgf{oa46=N3`c(SM`u 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%0D$##zKX)xQqd)2QVKCQo(aI1E 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

-<6($#mW7f(CbfeCU2SId}WJs2QEoh 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ⅆ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 z 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