arrayview 0.25.0__tar.gz → 0.25.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {arrayview-0.25.0 → arrayview-0.25.1}/PKG-INFO +1 -1
- {arrayview-0.25.0 → arrayview-0.25.1}/pyproject.toml +1 -1
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/__init__.py +1 -1
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_io.py +2 -2
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_launcher.py +181 -26
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_server.py +1 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_api.py +130 -10
- {arrayview-0.25.0 → arrayview-0.25.1}/uv.lock +1 -1
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/frontend-designer/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/invocation-consistency/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/modes-consistency/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/running-code.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/session-management.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/tracing.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/todo-workflow/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.github/copilot-instructions.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.github/workflows/docs.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.github/workflows/python-publish.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.gitignore +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.ignore +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/AGENTS.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/ROUTER.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/SETUP.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/SYNC.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/architecture.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/conventions.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/decisions.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/frontend.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/lifecycle.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/project-state.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/render-pipeline.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/setup.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/context/stack.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/INDEX.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/README.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/add-file-format.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/add-server-endpoint.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/animation-verify.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/debug-render.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/debug-vscode-extension-python.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/extend-compare-mode.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/extract-server-route-module.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/patterns/frontend-change.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/setup.sh +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.mex/sync.sh +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.opencode/opencode.json +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.playwright-cli/theme-dark.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.python-version +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/.vscode/settings.json +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/AGENTS.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/CONTRIBUTING.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/DESIGN.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/LICENSE +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/README.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/comparing.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/configuration.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/display.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/index.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/lifecycle.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/loading.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/logo.png +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/measurement.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/remote.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/stylesheets/extra.css +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/docs/viewing.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/matlab/arrayview.m +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/mkdocs.yml +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/plans/2026-04-14-immersive-animation.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/plans/2026-05-07-unified-colormap-picker.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/plans/egg-placement-mockup.html +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/plans/refactoring_plan.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/plans/webview/LOG.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/scripts/demo.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/scripts/release.sh +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/ARCHITECTURE.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/__main__.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_analysis.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_app.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_codex_open.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_config.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_diff.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_icon.png +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_imaging.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_lifecycle.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_overlays.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_platform.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_render.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_analysis.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_export.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_loading.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_persistence.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_preload.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_query.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_rendering.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_segmentation.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_state.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_vectorfield.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_routes_websocket.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_segmentation.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_session.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_shell.html +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_stdio_server.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_synthetic_mri.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_torch.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_vectorfield.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_viewer.html +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_vscode.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_vscode_browser.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_vscode_extension.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_vscode_shm.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/_vscode_signal.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/src/arrayview/gsap.min.js +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/capture_v_animation.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/conftest.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/lifecycle_matrix.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_backend_shared.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_browser.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_cli.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_colorbar_hover_highlight.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_command_reachability.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_config.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_cross_mode_parametrized.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_interactions.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_large_arrays.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_lifecycle_contract.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_loading_server.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_mode_consistency.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_mode_entry_batching.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_mode_matrix.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_mode_roundtrip.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_nifti_meta.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_rgb_pixel_art.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_stdio_server.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_torch.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_view_component_integration.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/test_view_component_unit.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/ui_audit.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/v_anim_frames/.gitkeep +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/tests/visual_smoke.py +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/vscode-extension/AGENTS.md +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/vscode-extension/LICENSE +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/vscode-extension/extension.js +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/vscode-extension/lifecycle_helpers.js +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/vscode-extension/package.json +0 -0
- {arrayview-0.25.0 → arrayview-0.25.1}/vscode-extension/test_lifecycle_helpers.js +0 -0
|
@@ -67,7 +67,7 @@ def list_mat_keys(filepath):
|
|
|
67
67
|
for k, v in mat.items():
|
|
68
68
|
if k.startswith("_"):
|
|
69
69
|
continue
|
|
70
|
-
if isinstance(v, np.ndarray) and v.ndim >= 1:
|
|
70
|
+
if isinstance(v, np.ndarray) and v.ndim >= 1 and v.dtype.kind in ("b", "i", "u", "f", "c"):
|
|
71
71
|
keys.append({"key": k, "shape": list(v.shape), "dtype": str(v.dtype)})
|
|
72
72
|
return keys
|
|
73
73
|
except NotImplementedError:
|
|
@@ -77,7 +77,7 @@ def list_mat_keys(filepath):
|
|
|
77
77
|
keys = []
|
|
78
78
|
for k in f.keys():
|
|
79
79
|
ds = f[k]
|
|
80
|
-
if isinstance(ds, h5py.Dataset) and len(ds.shape) >= 1:
|
|
80
|
+
if isinstance(ds, h5py.Dataset) and len(ds.shape) >= 1 and ds.dtype.kind in ("b", "i", "u", "f", "c"):
|
|
81
81
|
keys.append({"key": k, "shape": list(ds.shape), "dtype": str(ds.dtype)})
|
|
82
82
|
f.close()
|
|
83
83
|
return keys
|
|
@@ -448,6 +448,17 @@ def _open_webview_cli(
|
|
|
448
448
|
Returns True once the child has imported pywebview and created the window.
|
|
449
449
|
Returns False if it crashed; in that case the caller should fall back to browser.
|
|
450
450
|
"""
|
|
451
|
+
opened, _proc = _open_webview_cli_tracked(url, win_w, win_h, shell_port=shell_port)
|
|
452
|
+
return opened
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def _open_webview_cli_tracked(
|
|
456
|
+
url: str,
|
|
457
|
+
win_w: int,
|
|
458
|
+
win_h: int,
|
|
459
|
+
shell_port: int | None = None,
|
|
460
|
+
) -> tuple[bool, subprocess.Popen | None]:
|
|
461
|
+
"""Launch pywebview and return the child process when startup succeeds."""
|
|
451
462
|
import tempfile
|
|
452
463
|
|
|
453
464
|
_vprint("[ArrayView] Launching native window (PyWebView)...", flush=True)
|
|
@@ -483,21 +494,64 @@ def _open_webview_cli(
|
|
|
483
494
|
)
|
|
484
495
|
if stderr_out:
|
|
485
496
|
_vprint(f"[ArrayView] webview stderr: {stderr_out}", flush=True)
|
|
486
|
-
return False
|
|
497
|
+
return False, None
|
|
487
498
|
if os.path.exists(ready_file):
|
|
488
499
|
try:
|
|
489
500
|
os.unlink(ready_file)
|
|
490
501
|
except OSError:
|
|
491
502
|
pass
|
|
492
503
|
_vprint("[ArrayView] Native window started successfully", flush=True)
|
|
493
|
-
return True
|
|
504
|
+
return True, proc
|
|
494
505
|
time.sleep(0.02)
|
|
495
506
|
try:
|
|
496
507
|
os.unlink(ready_file)
|
|
497
508
|
except OSError:
|
|
498
509
|
pass
|
|
499
510
|
_vprint("[ArrayView] Native window started successfully", flush=True)
|
|
500
|
-
return True
|
|
511
|
+
return True, proc
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def _server_viewer_connections_seen(port: int, timeout: float = 0.5) -> int:
|
|
515
|
+
"""Return the daemon's monotonic viewer WebSocket connection count."""
|
|
516
|
+
url = f"http://{_LOOPBACK_HOST}:{port}/ping"
|
|
517
|
+
try:
|
|
518
|
+
with urllib.request.urlopen(url, timeout=timeout) as resp:
|
|
519
|
+
if resp.status != 200:
|
|
520
|
+
return 0
|
|
521
|
+
payload = json.loads(resp.read().decode("utf-8"))
|
|
522
|
+
if payload.get("ok") is True and payload.get("service") == "arrayview":
|
|
523
|
+
return int(
|
|
524
|
+
payload.get("viewer_connections_seen")
|
|
525
|
+
or payload.get("viewer_sockets")
|
|
526
|
+
or 0
|
|
527
|
+
)
|
|
528
|
+
except Exception:
|
|
529
|
+
pass
|
|
530
|
+
return 0
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def _wait_for_viewer_connection(
|
|
534
|
+
port: int,
|
|
535
|
+
*,
|
|
536
|
+
before: int,
|
|
537
|
+
timeout: float = 8.0,
|
|
538
|
+
) -> bool:
|
|
539
|
+
"""Wait until the backend has accepted a new viewer WebSocket connection."""
|
|
540
|
+
deadline = time.monotonic() + timeout
|
|
541
|
+
while time.monotonic() < deadline:
|
|
542
|
+
if _server_viewer_connections_seen(port, timeout=0.3) > before:
|
|
543
|
+
return True
|
|
544
|
+
time.sleep(0.1)
|
|
545
|
+
return False
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def _terminate_native_process(proc: subprocess.Popen | None) -> None:
|
|
549
|
+
if proc is None or proc.poll() is not None:
|
|
550
|
+
return
|
|
551
|
+
try:
|
|
552
|
+
proc.terminate()
|
|
553
|
+
except Exception:
|
|
554
|
+
return
|
|
501
555
|
|
|
502
556
|
|
|
503
557
|
# ── Server Port Utilities ─────────────────────────────────────────
|
|
@@ -809,7 +863,15 @@ def _open_cli_existing_server_view(
|
|
|
809
863
|
return
|
|
810
864
|
if notify_webview and not notified:
|
|
811
865
|
url_shell = _shell_url(port, sid, name, compare_sids=compare_sids)
|
|
812
|
-
|
|
866
|
+
seen_before = _server_viewer_connections_seen(port)
|
|
867
|
+
opened, proc = _open_webview_cli_tracked(url_shell, 1200, 800)
|
|
868
|
+
if not opened or not _wait_for_viewer_connection(port, before=seen_before):
|
|
869
|
+
if opened:
|
|
870
|
+
_vprint(
|
|
871
|
+
"[ArrayView] Native window did not connect to the backend; falling back to browser",
|
|
872
|
+
flush=True,
|
|
873
|
+
)
|
|
874
|
+
_terminate_native_process(proc)
|
|
813
875
|
_vprint("[ArrayView] Falling back to browser", flush=True)
|
|
814
876
|
_print_viewer_location(url)
|
|
815
877
|
_open_browser(
|
|
@@ -993,7 +1055,9 @@ def _handle_cli_spawned_daemon(
|
|
|
993
1055
|
)
|
|
994
1056
|
|
|
995
1057
|
early_webview_opened = False
|
|
1058
|
+
early_webview_proc = None
|
|
996
1059
|
early_webview_notified = False
|
|
1060
|
+
early_webview_connected = False
|
|
997
1061
|
if (
|
|
998
1062
|
use_webview
|
|
999
1063
|
and not is_remote
|
|
@@ -1001,7 +1065,7 @@ def _handle_cli_spawned_daemon(
|
|
|
1001
1065
|
and not compare_files
|
|
1002
1066
|
):
|
|
1003
1067
|
url_shell_early = _shell_url(port, sid, name)
|
|
1004
|
-
early_webview_opened =
|
|
1068
|
+
early_webview_opened, early_webview_proc = _open_webview_cli_tracked(
|
|
1005
1069
|
url_shell_early, 1400, 900, shell_port=port
|
|
1006
1070
|
)
|
|
1007
1071
|
|
|
@@ -1019,6 +1083,7 @@ def _handle_cli_spawned_daemon(
|
|
|
1019
1083
|
sys.exit(1)
|
|
1020
1084
|
|
|
1021
1085
|
if early_webview_opened:
|
|
1086
|
+
seen_before = _server_viewer_connections_seen(port)
|
|
1022
1087
|
try:
|
|
1023
1088
|
notify_result = _notify_existing_session(
|
|
1024
1089
|
port,
|
|
@@ -1030,6 +1095,21 @@ def _handle_cli_spawned_daemon(
|
|
|
1030
1095
|
early_webview_notified = bool(notify_result.get("notified"))
|
|
1031
1096
|
except Exception:
|
|
1032
1097
|
early_webview_notified = False
|
|
1098
|
+
if early_webview_notified:
|
|
1099
|
+
early_webview_connected = _wait_for_viewer_connection(
|
|
1100
|
+
port,
|
|
1101
|
+
before=seen_before,
|
|
1102
|
+
)
|
|
1103
|
+
if not early_webview_connected:
|
|
1104
|
+
_vprint(
|
|
1105
|
+
"[ArrayView] Native window did not connect to the backend; falling back to browser",
|
|
1106
|
+
flush=True,
|
|
1107
|
+
)
|
|
1108
|
+
_terminate_native_process(early_webview_proc)
|
|
1109
|
+
|
|
1110
|
+
should_retry_webview = use_webview and not (
|
|
1111
|
+
early_webview_opened and not early_webview_connected
|
|
1112
|
+
)
|
|
1033
1113
|
|
|
1034
1114
|
_open_cli_spawned_view(
|
|
1035
1115
|
port=port,
|
|
@@ -1037,14 +1117,14 @@ def _handle_cli_spawned_daemon(
|
|
|
1037
1117
|
compare_sids=compare_sids,
|
|
1038
1118
|
overlay_sid=overlay_sid,
|
|
1039
1119
|
dims_override=dims_override,
|
|
1040
|
-
use_webview=
|
|
1120
|
+
use_webview=should_retry_webview,
|
|
1041
1121
|
name=name,
|
|
1042
1122
|
base_file=base_file,
|
|
1043
1123
|
watch=watch,
|
|
1044
1124
|
window_mode=window_mode,
|
|
1045
1125
|
floating=floating,
|
|
1046
1126
|
is_remote=is_remote,
|
|
1047
|
-
webview_already_opened=
|
|
1127
|
+
webview_already_opened=early_webview_connected,
|
|
1048
1128
|
)
|
|
1049
1129
|
|
|
1050
1130
|
|
|
@@ -1075,7 +1155,15 @@ def _open_cli_spawned_view(
|
|
|
1075
1155
|
if webview_already_opened:
|
|
1076
1156
|
return
|
|
1077
1157
|
url_shell = _shell_url(port, sid, name, compare_sids=compare_sids)
|
|
1078
|
-
|
|
1158
|
+
seen_before = _server_viewer_connections_seen(port)
|
|
1159
|
+
opened, proc = _open_webview_cli_tracked(url_shell, 1400, 900)
|
|
1160
|
+
if not opened or not _wait_for_viewer_connection(port, before=seen_before):
|
|
1161
|
+
if opened:
|
|
1162
|
+
_vprint(
|
|
1163
|
+
"[ArrayView] Native window did not connect to the backend; falling back to browser",
|
|
1164
|
+
flush=True,
|
|
1165
|
+
)
|
|
1166
|
+
_terminate_native_process(proc)
|
|
1079
1167
|
_vprint("[ArrayView] Falling back to browser", flush=True)
|
|
1080
1168
|
_print_viewer_location(url)
|
|
1081
1169
|
_open_browser(
|
|
@@ -2621,7 +2709,16 @@ def _serve_daemon(
|
|
|
2621
2709
|
from arrayview._io import load_data, load_data_with_meta, list_array_keys
|
|
2622
2710
|
|
|
2623
2711
|
try:
|
|
2624
|
-
|
|
2712
|
+
# Multi-array .npz/.mat: load the first array so the session is
|
|
2713
|
+
# created, then store keys so the viewer can show a picker.
|
|
2714
|
+
_array_keys = None
|
|
2715
|
+
if (filepath.endswith(".npz") or filepath.endswith(".mat")) and not cleanup:
|
|
2716
|
+
try:
|
|
2717
|
+
_array_keys = list_array_keys(filepath)
|
|
2718
|
+
except Exception:
|
|
2719
|
+
pass
|
|
2720
|
+
_load_key = _array_keys[0]["key"] if _array_keys and len(_array_keys) > 1 else None
|
|
2721
|
+
data, spatial_meta = load_data_with_meta(filepath, key=_load_key)
|
|
2625
2722
|
if cleanup:
|
|
2626
2723
|
try:
|
|
2627
2724
|
os.unlink(filepath)
|
|
@@ -2632,15 +2729,9 @@ def _serve_daemon(
|
|
|
2632
2729
|
)
|
|
2633
2730
|
session.sid = sid
|
|
2634
2731
|
session.spatial_meta = spatial_meta
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
keys = list_array_keys(filepath)
|
|
2639
|
-
if len(keys) > 1:
|
|
2640
|
-
session.array_keys = keys
|
|
2641
|
-
session.array_filepath = filepath
|
|
2642
|
-
except Exception:
|
|
2643
|
-
pass
|
|
2732
|
+
if _array_keys and len(_array_keys) > 1:
|
|
2733
|
+
session.array_keys = _array_keys
|
|
2734
|
+
session.array_filepath = filepath
|
|
2644
2735
|
if spatial_meta is not None:
|
|
2645
2736
|
session.original_volume = data
|
|
2646
2737
|
if rgb:
|
|
@@ -3165,10 +3256,62 @@ def arrayview():
|
|
|
3165
3256
|
# --diagnose: print detection results and exit
|
|
3166
3257
|
if getattr(args, "diagnose", False):
|
|
3167
3258
|
import json as _json
|
|
3259
|
+
import importlib.util as _importlib_util
|
|
3168
3260
|
from ._platform import (
|
|
3169
3261
|
_find_vscode_ipc_hook,
|
|
3170
3262
|
_in_jupyter,
|
|
3171
3263
|
)
|
|
3264
|
+
from arrayview._config import CONFIG_PATH, get_window_default, load_config
|
|
3265
|
+
from arrayview._platform import detect_environment
|
|
3266
|
+
|
|
3267
|
+
_det_env = detect_environment()
|
|
3268
|
+
_config_window = get_window_default(_det_env)
|
|
3269
|
+
_in_vs = _in_vscode_terminal()
|
|
3270
|
+
_is_remote = _is_vscode_remote()
|
|
3271
|
+
_can_native = _can_native_window()
|
|
3272
|
+
_window_plan = _resolve_cli_window_mode(
|
|
3273
|
+
explicit_window=args.window,
|
|
3274
|
+
browser_flag=args.browser,
|
|
3275
|
+
config_window=_config_window,
|
|
3276
|
+
in_vscode_terminal=_in_vs,
|
|
3277
|
+
is_vscode_remote=_is_remote,
|
|
3278
|
+
can_native_window=_can_native,
|
|
3279
|
+
)
|
|
3280
|
+
|
|
3281
|
+
def _localhost_candidates() -> list[dict[str, object]]:
|
|
3282
|
+
out = []
|
|
3283
|
+
try:
|
|
3284
|
+
infos = socket.getaddrinfo(
|
|
3285
|
+
_LOOPBACK_HOST,
|
|
3286
|
+
args.port,
|
|
3287
|
+
type=socket.SOCK_STREAM,
|
|
3288
|
+
)
|
|
3289
|
+
except Exception as exc:
|
|
3290
|
+
return [{"error": str(exc)}]
|
|
3291
|
+
for family, socktype, proto, _canon, sockaddr in infos:
|
|
3292
|
+
out.append(
|
|
3293
|
+
{
|
|
3294
|
+
"family": getattr(socket.AddressFamily(family), "name", str(family)),
|
|
3295
|
+
"socktype": socktype,
|
|
3296
|
+
"proto": proto,
|
|
3297
|
+
"sockaddr": str(sockaddr),
|
|
3298
|
+
}
|
|
3299
|
+
)
|
|
3300
|
+
return out
|
|
3301
|
+
|
|
3302
|
+
def _bind_probe(port: int) -> dict[str, object]:
|
|
3303
|
+
try:
|
|
3304
|
+
sock = _make_loopback_socket(port)
|
|
3305
|
+
except Exception as exc:
|
|
3306
|
+
return {"ok": False, "error": str(exc)}
|
|
3307
|
+
try:
|
|
3308
|
+
return {
|
|
3309
|
+
"ok": True,
|
|
3310
|
+
"family": getattr(socket.AddressFamily(sock.family), "name", str(sock.family)),
|
|
3311
|
+
"sockname": str(sock.getsockname()),
|
|
3312
|
+
}
|
|
3313
|
+
finally:
|
|
3314
|
+
sock.close()
|
|
3172
3315
|
|
|
3173
3316
|
diag: dict = {
|
|
3174
3317
|
"env": {
|
|
@@ -3182,28 +3325,40 @@ def arrayview():
|
|
|
3182
3325
|
"WAYLAND_DISPLAY": os.environ.get("WAYLAND_DISPLAY"),
|
|
3183
3326
|
},
|
|
3184
3327
|
"detection": {
|
|
3185
|
-
"in_vscode_terminal":
|
|
3186
|
-
"is_vscode_remote":
|
|
3328
|
+
"in_vscode_terminal": _in_vs,
|
|
3329
|
+
"is_vscode_remote": _is_remote,
|
|
3187
3330
|
"in_vscode_tunnel": _in_vscode_tunnel(),
|
|
3188
|
-
"can_native_window":
|
|
3331
|
+
"can_native_window": _can_native,
|
|
3189
3332
|
"in_jupyter": _in_jupyter(),
|
|
3190
3333
|
"vscode_ipc_hook_recovered": _find_vscode_ipc_hook(),
|
|
3191
3334
|
},
|
|
3335
|
+
"launch_plan": {
|
|
3336
|
+
**_window_plan,
|
|
3337
|
+
"port": args.port,
|
|
3338
|
+
"port_in_use": _port_in_use(args.port),
|
|
3339
|
+
"arrayview_server_alive": _server_alive(args.port),
|
|
3340
|
+
},
|
|
3341
|
+
"loopback": {
|
|
3342
|
+
"host": _LOOPBACK_HOST,
|
|
3343
|
+
"getaddrinfo": _localhost_candidates(),
|
|
3344
|
+
"bind_probe": _bind_probe(0),
|
|
3345
|
+
},
|
|
3346
|
+
"native_dependencies": {
|
|
3347
|
+
"qtpy": _importlib_util.find_spec("qtpy") is not None,
|
|
3348
|
+
"gi": _importlib_util.find_spec("gi") is not None,
|
|
3349
|
+
"webview": _importlib_util.find_spec("webview") is not None,
|
|
3350
|
+
},
|
|
3192
3351
|
"pid": os.getpid(),
|
|
3193
3352
|
"ppid": os.getppid(),
|
|
3194
3353
|
"platform": sys.platform,
|
|
3195
3354
|
"python": sys.executable,
|
|
3196
3355
|
}
|
|
3197
|
-
from arrayview._config import CONFIG_PATH, get_window_default, load_config
|
|
3198
|
-
from arrayview._platform import detect_environment
|
|
3199
|
-
|
|
3200
|
-
_det_env = detect_environment()
|
|
3201
3356
|
diag["config"] = {
|
|
3202
3357
|
"detected_environment": _det_env,
|
|
3203
3358
|
"config_file": CONFIG_PATH,
|
|
3204
3359
|
"config_contents": load_config() or None,
|
|
3205
3360
|
"ARRAYVIEW_WINDOW": os.environ.get("ARRAYVIEW_WINDOW") or None,
|
|
3206
|
-
"resolved_window_pref":
|
|
3361
|
+
"resolved_window_pref": _config_window,
|
|
3207
3362
|
}
|
|
3208
3363
|
print(_json.dumps(diag, indent=2))
|
|
3209
3364
|
return
|
|
@@ -2186,7 +2186,7 @@ class TestCliOpenHelpers:
|
|
|
2186
2186
|
monkeypatch.setattr(launcher, "_vprint", lambda *args, **kwargs: calls.append(args))
|
|
2187
2187
|
monkeypatch.setattr(
|
|
2188
2188
|
launcher,
|
|
2189
|
-
"
|
|
2189
|
+
"_open_webview_cli_tracked",
|
|
2190
2190
|
lambda *args, **kwargs: (_ for _ in ()).throw(AssertionError("unexpected")),
|
|
2191
2191
|
)
|
|
2192
2192
|
monkeypatch.setattr(
|
|
@@ -2217,7 +2217,9 @@ class TestCliOpenHelpers:
|
|
|
2217
2217
|
|
|
2218
2218
|
opened = []
|
|
2219
2219
|
printed = []
|
|
2220
|
-
monkeypatch.setattr(
|
|
2220
|
+
monkeypatch.setattr(
|
|
2221
|
+
launcher, "_open_webview_cli_tracked", lambda *args, **kwargs: (False, None)
|
|
2222
|
+
)
|
|
2221
2223
|
monkeypatch.setattr(
|
|
2222
2224
|
launcher, "_print_viewer_location", lambda url: printed.append(url)
|
|
2223
2225
|
)
|
|
@@ -2256,6 +2258,104 @@ class TestCliOpenHelpers:
|
|
|
2256
2258
|
}
|
|
2257
2259
|
]
|
|
2258
2260
|
|
|
2261
|
+
def test_open_cli_existing_server_view_falls_back_when_native_never_connects(
|
|
2262
|
+
self, monkeypatch
|
|
2263
|
+
):
|
|
2264
|
+
import arrayview._launcher as launcher
|
|
2265
|
+
|
|
2266
|
+
opened = []
|
|
2267
|
+
terminated = []
|
|
2268
|
+
proc = type(
|
|
2269
|
+
"P",
|
|
2270
|
+
(),
|
|
2271
|
+
{
|
|
2272
|
+
"poll": lambda self: None,
|
|
2273
|
+
"terminate": lambda self: terminated.append(True),
|
|
2274
|
+
},
|
|
2275
|
+
)()
|
|
2276
|
+
monkeypatch.setattr(
|
|
2277
|
+
launcher, "_open_webview_cli_tracked", lambda *args, **kwargs: (True, proc)
|
|
2278
|
+
)
|
|
2279
|
+
monkeypatch.setattr(launcher, "_server_viewer_connections_seen", lambda port: 4)
|
|
2280
|
+
monkeypatch.setattr(
|
|
2281
|
+
launcher, "_wait_for_viewer_connection", lambda *args, **kwargs: False
|
|
2282
|
+
)
|
|
2283
|
+
monkeypatch.setattr(launcher, "_print_viewer_location", lambda url: None)
|
|
2284
|
+
monkeypatch.setattr(
|
|
2285
|
+
launcher,
|
|
2286
|
+
"_open_browser",
|
|
2287
|
+
lambda url, **kwargs: opened.append({"url": url, **kwargs}),
|
|
2288
|
+
)
|
|
2289
|
+
monkeypatch.setattr(launcher, "_vprint", lambda *args, **kwargs: None)
|
|
2290
|
+
|
|
2291
|
+
launcher._open_cli_existing_server_view(
|
|
2292
|
+
port=8000,
|
|
2293
|
+
sid="sid_base",
|
|
2294
|
+
compare_sids=[],
|
|
2295
|
+
overlay_sid=None,
|
|
2296
|
+
dims_override=None,
|
|
2297
|
+
notify_webview=True,
|
|
2298
|
+
notified=False,
|
|
2299
|
+
name="base.npy",
|
|
2300
|
+
base_file="/tmp/base.npy",
|
|
2301
|
+
watch=False,
|
|
2302
|
+
window_mode="native",
|
|
2303
|
+
floating=False,
|
|
2304
|
+
)
|
|
2305
|
+
|
|
2306
|
+
assert terminated == [True]
|
|
2307
|
+
assert opened[0]["url"] == "http://localhost:8000/?sid=sid_base"
|
|
2308
|
+
assert opened[0]["blocking"] is True
|
|
2309
|
+
|
|
2310
|
+
def test_open_cli_spawned_view_falls_back_when_native_never_connects(
|
|
2311
|
+
self, monkeypatch
|
|
2312
|
+
):
|
|
2313
|
+
import arrayview._launcher as launcher
|
|
2314
|
+
|
|
2315
|
+
opened = []
|
|
2316
|
+
terminated = []
|
|
2317
|
+
proc = type(
|
|
2318
|
+
"P",
|
|
2319
|
+
(),
|
|
2320
|
+
{
|
|
2321
|
+
"poll": lambda self: None,
|
|
2322
|
+
"terminate": lambda self: terminated.append(True),
|
|
2323
|
+
},
|
|
2324
|
+
)()
|
|
2325
|
+
monkeypatch.setattr(
|
|
2326
|
+
launcher, "_open_webview_cli_tracked", lambda *args, **kwargs: (True, proc)
|
|
2327
|
+
)
|
|
2328
|
+
monkeypatch.setattr(launcher, "_server_viewer_connections_seen", lambda port: 0)
|
|
2329
|
+
monkeypatch.setattr(
|
|
2330
|
+
launcher, "_wait_for_viewer_connection", lambda *args, **kwargs: False
|
|
2331
|
+
)
|
|
2332
|
+
monkeypatch.setattr(launcher, "_print_viewer_location", lambda url: None)
|
|
2333
|
+
monkeypatch.setattr(
|
|
2334
|
+
launcher,
|
|
2335
|
+
"_open_browser",
|
|
2336
|
+
lambda url, **kwargs: opened.append({"url": url, **kwargs}),
|
|
2337
|
+
)
|
|
2338
|
+
monkeypatch.setattr(launcher, "_vprint", lambda *args, **kwargs: None)
|
|
2339
|
+
|
|
2340
|
+
launcher._open_cli_spawned_view(
|
|
2341
|
+
port=8000,
|
|
2342
|
+
sid="sid_base",
|
|
2343
|
+
compare_sids=[],
|
|
2344
|
+
overlay_sid=None,
|
|
2345
|
+
dims_override=None,
|
|
2346
|
+
use_webview=True,
|
|
2347
|
+
name="base.npy",
|
|
2348
|
+
watch=False,
|
|
2349
|
+
window_mode="native",
|
|
2350
|
+
floating=False,
|
|
2351
|
+
is_remote=False,
|
|
2352
|
+
base_file="/tmp/base.npy",
|
|
2353
|
+
)
|
|
2354
|
+
|
|
2355
|
+
assert terminated == [True]
|
|
2356
|
+
assert opened[0]["url"] == "http://localhost:8000/?sid=sid_base"
|
|
2357
|
+
assert opened[0]["blocking"] is False
|
|
2358
|
+
|
|
2259
2359
|
def test_open_cli_spawned_view_overlay_browser_path_starts_watch(self, monkeypatch):
|
|
2260
2360
|
import arrayview._launcher as launcher
|
|
2261
2361
|
|
|
@@ -2264,7 +2364,7 @@ class TestCliOpenHelpers:
|
|
|
2264
2364
|
watched = []
|
|
2265
2365
|
monkeypatch.setattr(
|
|
2266
2366
|
launcher,
|
|
2267
|
-
"
|
|
2367
|
+
"_open_webview_cli_tracked",
|
|
2268
2368
|
lambda *args, **kwargs: (_ for _ in ()).throw(AssertionError("unexpected")),
|
|
2269
2369
|
)
|
|
2270
2370
|
monkeypatch.setattr(
|
|
@@ -2485,6 +2585,7 @@ class TestCliOpenHelpers:
|
|
|
2485
2585
|
|
|
2486
2586
|
events = []
|
|
2487
2587
|
opened = []
|
|
2588
|
+
proc = type("P", (), {"poll": lambda self: None, "terminate": lambda self: None})()
|
|
2488
2589
|
|
|
2489
2590
|
monkeypatch.setattr(
|
|
2490
2591
|
launcher.subprocess,
|
|
@@ -2493,14 +2594,16 @@ class TestCliOpenHelpers:
|
|
|
2493
2594
|
)
|
|
2494
2595
|
monkeypatch.setattr(
|
|
2495
2596
|
launcher,
|
|
2496
|
-
"
|
|
2497
|
-
lambda *args, **kwargs: events.append(("webview", args, kwargs)) or True,
|
|
2597
|
+
"_open_webview_cli_tracked",
|
|
2598
|
+
lambda *args, **kwargs: events.append(("webview", args, kwargs)) or (True, proc),
|
|
2498
2599
|
)
|
|
2499
2600
|
monkeypatch.setattr(
|
|
2500
2601
|
launcher,
|
|
2501
2602
|
"_wait_for_port",
|
|
2502
2603
|
lambda *args, **kwargs: events.append(("wait", args, kwargs)) or True,
|
|
2503
2604
|
)
|
|
2605
|
+
monkeypatch.setattr(launcher, "_server_viewer_connections_seen", lambda port: 0)
|
|
2606
|
+
monkeypatch.setattr(launcher, "_wait_for_viewer_connection", lambda *args, **kwargs: True)
|
|
2504
2607
|
monkeypatch.setattr(launcher, "_load_compare_sids", lambda port, files: [])
|
|
2505
2608
|
monkeypatch.setattr(
|
|
2506
2609
|
launcher,
|
|
@@ -2540,25 +2643,40 @@ class TestCliOpenHelpers:
|
|
|
2540
2643
|
assert events[1][2]["shell_port"] == 8000
|
|
2541
2644
|
assert opened[0]["webview_already_opened"] is True
|
|
2542
2645
|
|
|
2543
|
-
def
|
|
2646
|
+
def test_handle_cli_spawned_daemon_falls_back_when_early_native_never_connects(
|
|
2544
2647
|
self, monkeypatch
|
|
2545
2648
|
):
|
|
2546
2649
|
import arrayview._launcher as launcher
|
|
2547
2650
|
|
|
2548
2651
|
opened = []
|
|
2652
|
+
terminated = []
|
|
2653
|
+
proc = type(
|
|
2654
|
+
"P",
|
|
2655
|
+
(),
|
|
2656
|
+
{
|
|
2657
|
+
"poll": lambda self: None,
|
|
2658
|
+
"terminate": lambda self: terminated.append(True),
|
|
2659
|
+
},
|
|
2660
|
+
)()
|
|
2549
2661
|
|
|
2550
2662
|
monkeypatch.setattr(
|
|
2551
2663
|
launcher.subprocess,
|
|
2552
2664
|
"Popen",
|
|
2553
2665
|
lambda cmd, *args, **kwargs: object(),
|
|
2554
2666
|
)
|
|
2555
|
-
monkeypatch.setattr(
|
|
2667
|
+
monkeypatch.setattr(
|
|
2668
|
+
launcher, "_open_webview_cli_tracked", lambda *args, **kwargs: (True, proc)
|
|
2669
|
+
)
|
|
2556
2670
|
monkeypatch.setattr(launcher, "_wait_for_port", lambda *args, **kwargs: True)
|
|
2557
2671
|
monkeypatch.setattr(launcher, "_load_compare_sids", lambda port, files: [])
|
|
2672
|
+
monkeypatch.setattr(launcher, "_server_viewer_connections_seen", lambda port: 0)
|
|
2673
|
+
monkeypatch.setattr(
|
|
2674
|
+
launcher, "_wait_for_viewer_connection", lambda *args, **kwargs: False
|
|
2675
|
+
)
|
|
2558
2676
|
monkeypatch.setattr(
|
|
2559
2677
|
launcher,
|
|
2560
2678
|
"_notify_existing_session",
|
|
2561
|
-
lambda *args, **kwargs: {"notified":
|
|
2679
|
+
lambda *args, **kwargs: {"notified": True},
|
|
2562
2680
|
)
|
|
2563
2681
|
monkeypatch.setattr(
|
|
2564
2682
|
launcher,
|
|
@@ -2586,7 +2704,9 @@ class TestCliOpenHelpers:
|
|
|
2586
2704
|
demo_cleanup=False,
|
|
2587
2705
|
)
|
|
2588
2706
|
|
|
2589
|
-
assert
|
|
2707
|
+
assert terminated == [True]
|
|
2708
|
+
assert opened[0]["use_webview"] is False
|
|
2709
|
+
assert opened[0]["webview_already_opened"] is False
|
|
2590
2710
|
|
|
2591
2711
|
def test_handle_cli_spawned_daemon_does_not_early_open_remote_webview(
|
|
2592
2712
|
self, monkeypatch
|
|
@@ -2602,7 +2722,7 @@ class TestCliOpenHelpers:
|
|
|
2602
2722
|
)
|
|
2603
2723
|
monkeypatch.setattr(
|
|
2604
2724
|
launcher,
|
|
2605
|
-
"
|
|
2725
|
+
"_open_webview_cli_tracked",
|
|
2606
2726
|
lambda *args, **kwargs: (_ for _ in ()).throw(AssertionError("unexpected")),
|
|
2607
2727
|
)
|
|
2608
2728
|
monkeypatch.setattr(launcher, "_wait_for_port", lambda *args, **kwargs: True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/element-attributes.md
RENAMED
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/playwright-tests.md
RENAMED
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/request-mocking.md
RENAMED
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/running-code.md
RENAMED
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/session-management.md
RENAMED
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/storage-state.md
RENAMED
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/test-generation.md
RENAMED
|
File without changes
|
|
File without changes
|
{arrayview-0.25.0 → arrayview-0.25.1}/.agents/skills/playwright-cli/references/video-recording.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|