arrayview 0.31.1__tar.gz → 0.31.2__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.
Files changed (231) hide show
  1. {arrayview-0.31.1 → arrayview-0.31.2}/PKG-INFO +1 -1
  2. {arrayview-0.31.1 → arrayview-0.31.2}/pyproject.toml +1 -1
  3. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_instance_registry.py +6 -0
  4. arrayview-0.31.2/src/arrayview/_overlays.py +150 -0
  5. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_rendering.py +12 -1
  6. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_websocket.py +15 -1
  7. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_vscode_browser.py +2 -1
  8. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_api.py +51 -0
  9. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_lifecycle_contract.py +6 -0
  10. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_vscode_ack_protocol.py +7 -0
  11. {arrayview-0.31.1 → arrayview-0.31.2}/uv.lock +1 -1
  12. {arrayview-0.31.1 → arrayview-0.31.2}/vscode-extension/test_lifecycle_helpers.js +8 -6
  13. arrayview-0.31.1/src/arrayview/_overlays.py +0 -76
  14. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/frontend-designer/SKILL.md +0 -0
  15. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/invocation-consistency/SKILL.md +0 -0
  16. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/modes-consistency/SKILL.md +0 -0
  17. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/SKILL.md +0 -0
  18. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
  19. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
  20. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
  21. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/running-code.md +0 -0
  22. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/session-management.md +0 -0
  23. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
  24. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
  25. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/tracing.md +0 -0
  26. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
  27. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/todo-workflow/SKILL.md +0 -0
  28. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
  29. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
  30. {arrayview-0.31.1 → arrayview-0.31.2}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
  31. {arrayview-0.31.1 → arrayview-0.31.2}/.github/copilot-instructions.md +0 -0
  32. {arrayview-0.31.1 → arrayview-0.31.2}/.github/workflows/docs.yml +0 -0
  33. {arrayview-0.31.1 → arrayview-0.31.2}/.github/workflows/launch-contracts.yml +0 -0
  34. {arrayview-0.31.1 → arrayview-0.31.2}/.github/workflows/python-publish.yml +0 -0
  35. {arrayview-0.31.1 → arrayview-0.31.2}/.gitignore +0 -0
  36. {arrayview-0.31.1 → arrayview-0.31.2}/.ignore +0 -0
  37. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/AGENTS.md +0 -0
  38. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/ROUTER.md +0 -0
  39. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/SETUP.md +0 -0
  40. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/SYNC.md +0 -0
  41. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/architecture.md +0 -0
  42. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/conventions.md +0 -0
  43. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/decisions.md +0 -0
  44. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/frontend.md +0 -0
  45. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/lifecycle.md +0 -0
  46. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/project-state.md +0 -0
  47. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/render-pipeline.md +0 -0
  48. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/setup.md +0 -0
  49. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/context/stack.md +0 -0
  50. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/INDEX.md +0 -0
  51. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/README.md +0 -0
  52. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/add-file-format.md +0 -0
  53. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/add-server-endpoint.md +0 -0
  54. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/animation-verify.md +0 -0
  55. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/debug-render.md +0 -0
  56. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/debug-vscode-extension-python.md +0 -0
  57. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/extend-compare-mode.md +0 -0
  58. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/extract-server-route-module.md +0 -0
  59. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/patterns/frontend-change.md +0 -0
  60. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/setup.sh +0 -0
  61. {arrayview-0.31.1 → arrayview-0.31.2}/.mex/sync.sh +0 -0
  62. {arrayview-0.31.1 → arrayview-0.31.2}/.opencode/opencode.json +0 -0
  63. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
  64. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
  65. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
  66. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
  67. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
  68. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
  69. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
  70. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
  71. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
  72. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
  73. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
  74. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
  75. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
  76. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
  77. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
  78. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
  79. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
  80. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
  81. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
  82. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
  83. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
  84. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
  85. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
  86. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
  87. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
  88. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
  89. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
  90. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
  91. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
  92. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
  93. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
  94. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
  95. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
  96. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
  97. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
  98. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
  99. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
  100. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
  101. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
  102. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
  103. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
  104. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
  105. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
  106. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
  107. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
  108. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
  109. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
  110. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
  111. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
  112. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
  113. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
  114. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
  115. {arrayview-0.31.1 → arrayview-0.31.2}/.playwright-cli/theme-dark.yml +0 -0
  116. {arrayview-0.31.1 → arrayview-0.31.2}/.python-version +0 -0
  117. {arrayview-0.31.1 → arrayview-0.31.2}/.vscode/settings.json +0 -0
  118. {arrayview-0.31.1 → arrayview-0.31.2}/AGENTS.md +0 -0
  119. {arrayview-0.31.1 → arrayview-0.31.2}/CONTRIBUTING.md +0 -0
  120. {arrayview-0.31.1 → arrayview-0.31.2}/DESIGN.md +0 -0
  121. {arrayview-0.31.1 → arrayview-0.31.2}/LICENSE +0 -0
  122. {arrayview-0.31.1 → arrayview-0.31.2}/README.md +0 -0
  123. {arrayview-0.31.1 → arrayview-0.31.2}/docs/comparing.md +0 -0
  124. {arrayview-0.31.1 → arrayview-0.31.2}/docs/configuration.md +0 -0
  125. {arrayview-0.31.1 → arrayview-0.31.2}/docs/display.md +0 -0
  126. {arrayview-0.31.1 → arrayview-0.31.2}/docs/foreign-hosts.md +0 -0
  127. {arrayview-0.31.1 → arrayview-0.31.2}/docs/index.md +0 -0
  128. {arrayview-0.31.1 → arrayview-0.31.2}/docs/launch-routing-refactor.md +0 -0
  129. {arrayview-0.31.1 → arrayview-0.31.2}/docs/lifecycle.md +0 -0
  130. {arrayview-0.31.1 → arrayview-0.31.2}/docs/loading.md +0 -0
  131. {arrayview-0.31.1 → arrayview-0.31.2}/docs/logo.png +0 -0
  132. {arrayview-0.31.1 → arrayview-0.31.2}/docs/measurement.md +0 -0
  133. {arrayview-0.31.1 → arrayview-0.31.2}/docs/remote.md +0 -0
  134. {arrayview-0.31.1 → arrayview-0.31.2}/docs/stylesheets/extra.css +0 -0
  135. {arrayview-0.31.1 → arrayview-0.31.2}/docs/viewing.md +0 -0
  136. {arrayview-0.31.1 → arrayview-0.31.2}/docs/vscode-window-routing-plan.md +0 -0
  137. {arrayview-0.31.1 → arrayview-0.31.2}/experiments/ws_tunnel_diag/ws_tunnel_diag.py +0 -0
  138. {arrayview-0.31.1 → arrayview-0.31.2}/matlab/arrayview.m +0 -0
  139. {arrayview-0.31.1 → arrayview-0.31.2}/mkdocs.yml +0 -0
  140. {arrayview-0.31.1 → arrayview-0.31.2}/plans/2026-04-14-immersive-animation.md +0 -0
  141. {arrayview-0.31.1 → arrayview-0.31.2}/plans/2026-05-07-unified-colormap-picker.md +0 -0
  142. {arrayview-0.31.1 → arrayview-0.31.2}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
  143. {arrayview-0.31.1 → arrayview-0.31.2}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
  144. {arrayview-0.31.1 → arrayview-0.31.2}/plans/egg-placement-mockup.html +0 -0
  145. {arrayview-0.31.1 → arrayview-0.31.2}/plans/refactoring_plan.md +0 -0
  146. {arrayview-0.31.1 → arrayview-0.31.2}/plans/roi-analysis-requirements.md +0 -0
  147. {arrayview-0.31.1 → arrayview-0.31.2}/plans/webview/LOG.md +0 -0
  148. {arrayview-0.31.1 → arrayview-0.31.2}/scripts/demo.py +0 -0
  149. {arrayview-0.31.1 → arrayview-0.31.2}/scripts/release.sh +0 -0
  150. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/ARCHITECTURE.md +0 -0
  151. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/__init__.py +0 -0
  152. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/__main__.py +0 -0
  153. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_analysis.py +0 -0
  154. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_app.py +0 -0
  155. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_codex_open.py +0 -0
  156. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_config.py +0 -0
  157. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_diff.py +0 -0
  158. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_icon.png +0 -0
  159. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_imaging.py +0 -0
  160. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_io.py +0 -0
  161. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_launch_plan.py +0 -0
  162. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_launcher.py +0 -0
  163. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_lifecycle.py +0 -0
  164. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_platform.py +0 -0
  165. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_render.py +0 -0
  166. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_analysis.py +0 -0
  167. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_export.py +0 -0
  168. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_loading.py +0 -0
  169. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_persistence.py +0 -0
  170. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_preload.py +0 -0
  171. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_query.py +0 -0
  172. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_segmentation.py +0 -0
  173. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_state.py +0 -0
  174. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_routes_vectorfield.py +0 -0
  175. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_segmentation.py +0 -0
  176. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_server.py +0 -0
  177. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_session.py +0 -0
  178. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_session_spec.py +0 -0
  179. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_shell.html +0 -0
  180. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_synthetic_mri.py +0 -0
  181. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_torch.py +0 -0
  182. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_vectorfield.py +0 -0
  183. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_viewer.html +0 -0
  184. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_vscode.py +0 -0
  185. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_vscode_extension.py +0 -0
  186. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/_vscode_signal.py +0 -0
  187. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/arrayview-opener.vsix +0 -0
  188. {arrayview-0.31.1 → arrayview-0.31.2}/src/arrayview/gsap.min.js +0 -0
  189. {arrayview-0.31.1 → arrayview-0.31.2}/tests/capture_v_animation.py +0 -0
  190. {arrayview-0.31.1 → arrayview-0.31.2}/tests/conftest.py +0 -0
  191. {arrayview-0.31.1 → arrayview-0.31.2}/tests/lifecycle_matrix.py +0 -0
  192. {arrayview-0.31.1 → arrayview-0.31.2}/tests/make_vectorfield_test_arrays.py +0 -0
  193. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_backend_shared.py +0 -0
  194. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_browser.py +0 -0
  195. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_cli.py +0 -0
  196. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_colorbar_hover_highlight.py +0 -0
  197. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_command_reachability.py +0 -0
  198. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_config.py +0 -0
  199. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_cross_mode_parametrized.py +0 -0
  200. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_display_opener_results.py +0 -0
  201. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_doctor_commands.py +0 -0
  202. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_instance_registry.py +0 -0
  203. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_interactions.py +0 -0
  204. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_invocation_contract_matrix.py +0 -0
  205. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_io.py +0 -0
  206. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_large_arrays.py +0 -0
  207. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_launch_diagnostics.py +0 -0
  208. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_launch_plan.py +0 -0
  209. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_loading_server.py +0 -0
  210. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_mode_consistency.py +0 -0
  211. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_mode_matrix.py +0 -0
  212. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_mode_roundtrip.py +0 -0
  213. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_nifti_meta.py +0 -0
  214. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_nifti_series.py +0 -0
  215. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_rgb_pixel_art.py +0 -0
  216. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_safe_server_stop.py +0 -0
  217. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_server_identity_status.py +0 -0
  218. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_session_spec.py +0 -0
  219. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_torch.py +0 -0
  220. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_view_component_integration.py +0 -0
  221. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_view_component_unit.py +0 -0
  222. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_view_handle_lifecycle.py +0 -0
  223. {arrayview-0.31.1 → arrayview-0.31.2}/tests/test_view_launch_execution.py +0 -0
  224. {arrayview-0.31.1 → arrayview-0.31.2}/tests/ui_audit.py +0 -0
  225. {arrayview-0.31.1 → arrayview-0.31.2}/tests/v_anim_frames/.gitkeep +0 -0
  226. {arrayview-0.31.1 → arrayview-0.31.2}/tests/visual_smoke.py +0 -0
  227. {arrayview-0.31.1 → arrayview-0.31.2}/vscode-extension/AGENTS.md +0 -0
  228. {arrayview-0.31.1 → arrayview-0.31.2}/vscode-extension/LICENSE +0 -0
  229. {arrayview-0.31.1 → arrayview-0.31.2}/vscode-extension/extension.js +0 -0
  230. {arrayview-0.31.1 → arrayview-0.31.2}/vscode-extension/lifecycle_helpers.js +0 -0
  231. {arrayview-0.31.1 → arrayview-0.31.2}/vscode-extension/package.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arrayview
3
- Version: 0.31.1
3
+ Version: 0.31.2
4
4
  Summary: Fast multi-dimensional array viewer
5
5
  Project-URL: Home, https://github.com/oscarvanderheide/arrayview
6
6
  Project-URL: Source, https://github.com/oscarvanderheide/arrayview
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arrayview"
7
- version = "0.31.1"
7
+ version = "0.31.2"
8
8
  description = "Fast multi-dimensional array viewer"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.12"
@@ -115,11 +115,17 @@ def _windows_process_start(pid: int) -> str | None:
115
115
  handle = kernel32.OpenProcess(0x1000, False, pid)
116
116
  if not handle:
117
117
  return None
118
+ still_active = 259
119
+ exit_code = ctypes.c_ulong()
118
120
  creation = ctypes.c_ulonglong()
119
121
  exit_time = ctypes.c_ulonglong()
120
122
  kernel = ctypes.c_ulonglong()
121
123
  user = ctypes.c_ulonglong()
122
124
  try:
125
+ if not kernel32.GetExitCodeProcess(handle, ctypes.byref(exit_code)):
126
+ return None
127
+ if exit_code.value != still_active:
128
+ return None
123
129
  ok = kernel32.GetProcessTimes(handle, ctypes.byref(creation),
124
130
  ctypes.byref(exit_time), ctypes.byref(kernel),
125
131
  ctypes.byref(user))
@@ -0,0 +1,150 @@
1
+ """Shared overlay compositing helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+ from arrayview._render import (
8
+ _build_mosaic_grid,
9
+ _composite_overlay_mask,
10
+ _extract_overlay_mask,
11
+ _overlay_is_label_map,
12
+ )
13
+
14
+
15
+ def _parse_hex_color(hex_str: str) -> np.ndarray | None:
16
+ """Parse a 6-char hex RGB color."""
17
+ h = hex_str.strip().lstrip("#")
18
+ if len(h) != 6:
19
+ return None
20
+ try:
21
+ return np.array(
22
+ [int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)],
23
+ dtype=np.uint8,
24
+ )
25
+ except ValueError:
26
+ return None
27
+
28
+
29
+ def _composite_overlays(
30
+ rgba: np.ndarray,
31
+ overlay_sid_str: str | None,
32
+ overlay_colors_str: str | None,
33
+ overlay_alpha: float,
34
+ overlay_alphas_str: str | None,
35
+ overlay_outline: bool,
36
+ dim_x: int,
37
+ dim_y: int,
38
+ idx_tuple: tuple[int, ...],
39
+ shape_hw: tuple[int, int],
40
+ base_shape: tuple[int, ...] | None = None,
41
+ ) -> np.ndarray:
42
+ """Composite one or more overlay masks onto RGBA pixels."""
43
+ if not overlay_sid_str:
44
+ return rgba
45
+ sids = [s.strip() for s in overlay_sid_str.split(",") if s.strip()]
46
+ colors_raw = (
47
+ [c.strip() for c in overlay_colors_str.split(",")] if overlay_colors_str else []
48
+ )
49
+ alphas_raw = (
50
+ [a.strip() for a in overlay_alphas_str.split(",")] if overlay_alphas_str else []
51
+ )
52
+ for i, sid in enumerate(sids):
53
+ color = _parse_hex_color(colors_raw[i]) if i < len(colors_raw) else None
54
+ alpha = overlay_alpha
55
+ if i < len(alphas_raw):
56
+ try:
57
+ alpha = float(alphas_raw[i])
58
+ except ValueError:
59
+ alpha = overlay_alpha
60
+ alpha = max(0.0, min(1.0, alpha))
61
+ ov_raw = _extract_overlay_mask(
62
+ sid,
63
+ dim_x,
64
+ dim_y,
65
+ idx_tuple,
66
+ expected_shape=shape_hw,
67
+ base_shape=base_shape,
68
+ )
69
+ rgba = _composite_overlay_mask(
70
+ rgba,
71
+ ov_raw,
72
+ alpha=alpha,
73
+ is_label=_overlay_is_label_map(sid, ov_raw),
74
+ override_color=color,
75
+ outline_only=overlay_outline,
76
+ )
77
+ return rgba
78
+
79
+
80
+ def _composite_mosaic_overlays(
81
+ rgba: np.ndarray,
82
+ overlay_sid_str: str | None,
83
+ overlay_colors_str: str | None,
84
+ overlay_alpha: float,
85
+ overlay_alphas_str: str | None,
86
+ overlay_outline: bool,
87
+ dim_x: int,
88
+ dim_y: int,
89
+ dim_z: int,
90
+ idx_tuple: tuple[int, ...],
91
+ base_shape: tuple[int, ...],
92
+ mosaic_cols: int | None = None,
93
+ ) -> np.ndarray:
94
+ """Composite each overlay as a mosaic using the base mosaic's frame indices.
95
+
96
+ Missing overlay axes are resolved per frame by ``_extract_overlay_mask``.
97
+ That lets a mask omit, for example, an echo axis without materialising a
98
+ repeated full-volume copy.
99
+ """
100
+ if not overlay_sid_str:
101
+ return rgba
102
+ sids = [sid.strip() for sid in overlay_sid_str.split(",") if sid.strip()]
103
+ colors_raw = (
104
+ [color.strip() for color in overlay_colors_str.split(",")]
105
+ if overlay_colors_str
106
+ else []
107
+ )
108
+ alphas_raw = (
109
+ [alpha.strip() for alpha in overlay_alphas_str.split(",")]
110
+ if overlay_alphas_str
111
+ else []
112
+ )
113
+ tile_shape = (int(base_shape[dim_y]), int(base_shape[dim_x]))
114
+ n_frames = int(base_shape[dim_z])
115
+
116
+ for i, sid in enumerate(sids):
117
+ color = _parse_hex_color(colors_raw[i]) if i < len(colors_raw) else None
118
+ try:
119
+ alpha = float(alphas_raw[i]) if i < len(alphas_raw) else overlay_alpha
120
+ except ValueError:
121
+ alpha = overlay_alpha
122
+ alpha = max(0.0, min(1.0, alpha))
123
+
124
+ frames = []
125
+ for frame in range(n_frames):
126
+ frame_idx = list(idx_tuple)
127
+ frame_idx[dim_z] = frame
128
+ ov_raw = _extract_overlay_mask(
129
+ sid,
130
+ dim_x,
131
+ dim_y,
132
+ tuple(frame_idx),
133
+ expected_shape=tile_shape,
134
+ base_shape=base_shape,
135
+ )
136
+ frames.append(
137
+ ov_raw if ov_raw is not None else np.zeros(tile_shape, dtype=np.float32)
138
+ )
139
+ grid, _, _ = _build_mosaic_grid(frames, n_frames, cols=mosaic_cols)
140
+ # Gaps are transparent, not NaN label values or heatmap samples.
141
+ grid = np.nan_to_num(grid, nan=0.0)
142
+ rgba = _composite_overlay_mask(
143
+ rgba,
144
+ grid,
145
+ alpha=alpha,
146
+ is_label=_overlay_is_label_map(sid, grid),
147
+ override_color=color,
148
+ outline_only=overlay_outline,
149
+ )
150
+ return rgba
@@ -6,7 +6,7 @@ from fastapi import Depends, Response
6
6
  from fastapi.responses import JSONResponse
7
7
 
8
8
  from arrayview._diff import _compute_diff, _diff_histogram, _render_diff_rgba
9
- from arrayview._overlays import _composite_overlays
9
+ from arrayview._overlays import _composite_mosaic_overlays, _composite_overlays
10
10
  from arrayview._render import (
11
11
  LUTS,
12
12
  _build_mosaic_grid,
@@ -178,6 +178,11 @@ def register_rendering_routes(app, *, get_session_or_404) -> None:
178
178
  vmin_override=vmin_override,
179
179
  vmax_override=vmax_override,
180
180
  )
181
+ rgba = _composite_mosaic_overlays(
182
+ rgba, overlay_sid, overlay_colors, overlay_alpha, overlay_alphas,
183
+ overlay_outline, dim_x, dim_y, dim_z, idx_tuple, session.shape,
184
+ mosaic_cols,
185
+ )
181
186
  if vmin_override is not None and vmax_override is not None:
182
187
  vmin, vmax = float(vmin_override), float(vmax_override)
183
188
  else:
@@ -264,6 +269,12 @@ def register_rendering_routes(app, *, get_session_or_404) -> None:
264
269
  )
265
270
  if qmri_role:
266
271
  vmin, vmax = _qmri_adjust_vmin_vmax(vmin, vmax, qmri_role)
272
+ if dim_z >= 0 and qmri_role:
273
+ rgba = _composite_mosaic_overlays(
274
+ rgba, overlay_sid, overlay_colors, overlay_alpha, overlay_alphas,
275
+ overlay_outline, dim_x, dim_y, dim_z, idx_tuple, session.shape,
276
+ mosaic_cols,
277
+ )
267
278
  render_ms = (time.perf_counter() - render_t0) * 1000.0
268
279
  encode_t0 = time.perf_counter()
269
280
  img = _pil_image().fromarray(rgba[:, :, :3], mode="RGB")
@@ -8,7 +8,7 @@ from starlette.websockets import WebSocketDisconnect
8
8
  import arrayview._session as _session_mod
9
9
  from arrayview._analysis import _build_metadata
10
10
  from arrayview._lifecycle import release_session
11
- from arrayview._overlays import _composite_overlays
11
+ from arrayview._overlays import _composite_mosaic_overlays, _composite_overlays
12
12
  from arrayview._render import (
13
13
  LUTS,
14
14
  _prepare_display,
@@ -232,6 +232,12 @@ def register_websocket_routes(app) -> None:
232
232
  vmax_override=vmax_override,
233
233
  ),
234
234
  )
235
+ rgba = _composite_mosaic_overlays(
236
+ rgba, msg.get("overlay_sid"), msg.get("overlay_colors"),
237
+ float(msg.get("overlay_alpha", 0.45)), msg.get("overlay_alphas"),
238
+ bool(msg.get("overlay_outline", False)), dim_x, dim_y, dim_z,
239
+ idx_tuple, session.shape, mosaic_cols,
240
+ )
235
241
  h, w = rgba.shape[:2]
236
242
  raw = extract_slice(session, dim_x, dim_y, list(idx_tuple))
237
243
  _, vmin, vmax = _prepare_display(
@@ -344,6 +350,14 @@ def register_websocket_routes(app) -> None:
344
350
  session.shape,
345
351
  )
346
352
 
353
+ if dim_z >= 0 and qmri_role:
354
+ rgba = _composite_mosaic_overlays(
355
+ rgba, msg.get("overlay_sid"), msg.get("overlay_colors"),
356
+ float(msg.get("overlay_alpha", 0.45)), msg.get("overlay_alphas"),
357
+ bool(msg.get("overlay_outline", False)), dim_x, dim_y, dim_z,
358
+ idx_tuple, session.shape, mosaic_cols,
359
+ )
360
+
347
361
  render_ms = (time.perf_counter() - render_t0) * 1000.0
348
362
  post_t0 = time.perf_counter()
349
363
  header = np.array([seq, w, h], dtype=np.uint32).tobytes()
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  import json
7
+ import platform
7
8
  import subprocess
8
9
  import sys
9
10
  import threading
@@ -219,7 +220,7 @@ def _open_browser(
219
220
  port_hint = int(url.split(":")[2].split("/")[0].split("?")[0])
220
221
  except Exception:
221
222
  port_hint = parsed_port
222
- hostname = os.uname().nodename or "<this-host>"
223
+ hostname = platform.node() or "<this-host>"
223
224
  print(
224
225
  f"[ArrayView] Plain SSH session detected.\n"
225
226
  f"\n"
@@ -4601,6 +4601,57 @@ class TestCropPersistence:
4601
4601
 
4602
4602
 
4603
4603
  class TestMultipleOverlays:
4604
+ def test_http_mosaic_repeats_overlay_across_missing_dimension(self, client, tmp_path):
4605
+ base_path = tmp_path / "mosaic-base.npy"
4606
+ np.save(base_path, np.zeros((4, 3, 6, 6), dtype=np.float32))
4607
+ base_sid = client.post("/load", json={"filepath": str(base_path)}).json()["sid"]
4608
+ overlay_data = np.zeros((4, 6, 6), dtype=np.uint8)
4609
+ overlay_data[2, 2:4, 2:4] = 1
4610
+ overlay_path = tmp_path / "mosaic-overlay.npy"
4611
+ np.save(overlay_path, overlay_data)
4612
+ overlay_sid = client.post("/load", json={"filepath": str(overlay_path)}).json()["sid"]
4613
+
4614
+ response = client.get(
4615
+ f"/slice/{base_sid}",
4616
+ params={
4617
+ "dim_x": 3,
4618
+ "dim_y": 2,
4619
+ "dim_z": 1,
4620
+ "indices": "2,0,3,3",
4621
+ "overlay_sid": overlay_sid,
4622
+ "overlay_colors": "ff0000",
4623
+ "overlay_alpha": 1.0,
4624
+ },
4625
+ )
4626
+ image = np.asarray(Image.open(io.BytesIO(response.content)))
4627
+ for x0 in (0, 8, 16):
4628
+ tile = image[:, x0 : x0 + 6]
4629
+ assert np.max(tile[:, :, 0].astype(int) - tile[:, :, 1].astype(int)) > 20
4630
+
4631
+ def test_mosaic_overlay_broadcasts_over_missing_mosaic_dimension(self):
4632
+ from arrayview._overlays import _composite_mosaic_overlays
4633
+ from arrayview._render import mosaic_shape
4634
+ from arrayview._session import SESSIONS, Session
4635
+
4636
+ base = Session(np.zeros((4, 3, 6, 6), dtype=np.float32))
4637
+ overlay_data = np.zeros((4, 6, 6), dtype=np.uint8)
4638
+ overlay_data[2, 3, 4] = 1
4639
+ overlay = Session(overlay_data)
4640
+ SESSIONS[overlay.sid] = overlay
4641
+ try:
4642
+ rows, cols = mosaic_shape(3)
4643
+ rgba = np.zeros((rows * 6 + (rows - 1) * 2, cols * 6 + (cols - 1) * 2, 4), dtype=np.uint8)
4644
+ result = _composite_mosaic_overlays(
4645
+ rgba, overlay.sid, "ff0000", 1.0, None, False,
4646
+ dim_x=3, dim_y=2, dim_z=1, idx_tuple=(2, 0, 3, 3),
4647
+ base_shape=base.shape,
4648
+ )
4649
+ for frame in range(3):
4650
+ row, col = divmod(frame, cols)
4651
+ assert result[row * 8 + 3, col * 8 + 4, 0] == 255
4652
+ finally:
4653
+ SESSIONS.pop(overlay.sid, None)
4654
+
4604
4655
  def test_overlay_broadcasts_over_missing_base_dimension(self):
4605
4656
  from arrayview._render import _extract_overlay_mask
4606
4657
  from arrayview._session import SESSIONS, Session
@@ -163,6 +163,7 @@ def test_vscode_tunnel_without_window_id_uses_focused_window_fallback(
163
163
  signal_dir = home / ".arrayview"
164
164
  signal_dir.mkdir(parents=True)
165
165
  monkeypatch.setenv("HOME", str(home))
166
+ monkeypatch.setenv("USERPROFILE", str(home))
166
167
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: True)
167
168
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: None)
168
169
  monkeypatch.setattr(signal, "_find_current_vscode_window_id", lambda: "100")
@@ -201,6 +202,7 @@ def test_vscode_tunnel_exact_window_id_is_not_redirected_to_newer_sibling(
201
202
  signal_dir = home / ".arrayview"
202
203
  signal_dir.mkdir(parents=True)
203
204
  monkeypatch.setenv("HOME", str(home))
205
+ monkeypatch.setenv("USERPROFILE", str(home))
204
206
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: True)
205
207
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "100")
206
208
 
@@ -231,6 +233,7 @@ def test_vscode_local_exact_window_id_is_not_redirected_to_newer_sibling(
231
233
  signal_dir = home / ".arrayview"
232
234
  signal_dir.mkdir(parents=True)
233
235
  monkeypatch.setenv("HOME", str(home))
236
+ monkeypatch.setenv("USERPROFILE", str(home))
234
237
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: False)
235
238
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "100")
236
239
 
@@ -261,6 +264,7 @@ def test_vscode_local_stale_window_id_with_multiple_windows_fails_closed(
261
264
  signal_dir = home / ".arrayview"
262
265
  signal_dir.mkdir(parents=True)
263
266
  monkeypatch.setenv("HOME", str(home))
267
+ monkeypatch.setenv("USERPROFILE", str(home))
264
268
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: False)
265
269
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "stale")
266
270
  monkeypatch.setattr(signal, "_find_current_vscode_window_id", lambda: None)
@@ -290,6 +294,7 @@ def test_vscode_local_missing_window_match_uses_focused_window_fallback(
290
294
  signal_dir = home / ".arrayview"
291
295
  signal_dir.mkdir(parents=True)
292
296
  monkeypatch.setenv("HOME", str(home))
297
+ monkeypatch.setenv("USERPROFILE", str(home))
293
298
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: False)
294
299
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: None)
295
300
  monkeypatch.setattr(signal, "_find_current_vscode_window_id", lambda: None)
@@ -331,6 +336,7 @@ def test_vscode_local_missing_window_match_with_local_windows_fails_closed(
331
336
  signal_dir = home / ".arrayview"
332
337
  signal_dir.mkdir(parents=True)
333
338
  monkeypatch.setenv("HOME", str(home))
339
+ monkeypatch.setenv("USERPROFILE", str(home))
334
340
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: False)
335
341
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: None)
336
342
  monkeypatch.setattr(signal, "_find_current_vscode_window_id", lambda: None)
@@ -19,6 +19,7 @@ def _request(tmp_path, **overrides):
19
19
 
20
20
  def test_open_request_includes_versioned_ack_metadata(monkeypatch, tmp_path):
21
21
  monkeypatch.setenv("HOME", str(tmp_path))
22
+ monkeypatch.setenv("USERPROFILE", str(tmp_path))
22
23
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "window-1")
23
24
  captured = []
24
25
  monkeypatch.setattr(
@@ -51,6 +52,7 @@ def test_open_request_includes_versioned_ack_metadata(monkeypatch, tmp_path):
51
52
 
52
53
  def test_open_request_reports_failed_legacy_write(monkeypatch, tmp_path):
53
54
  monkeypatch.setenv("HOME", str(tmp_path))
55
+ monkeypatch.setenv("USERPROFILE", str(tmp_path))
54
56
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: None)
55
57
  monkeypatch.setattr(signal, "_write_vscode_signal", lambda *args, **kwargs: False)
56
58
 
@@ -62,6 +64,7 @@ def test_open_request_reports_failed_legacy_write(monkeypatch, tmp_path):
62
64
 
63
65
  def test_open_request_correlates_ack_to_recovered_live_window(monkeypatch, tmp_path):
64
66
  monkeypatch.setenv("HOME", str(tmp_path))
67
+ monkeypatch.setenv("USERPROFILE", str(tmp_path))
65
68
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "stale-window")
66
69
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: False)
67
70
  signal_dir = tmp_path / ".arrayview"
@@ -86,6 +89,7 @@ def test_open_request_correlates_ack_to_recovered_live_window(monkeypatch, tmp_p
86
89
 
87
90
  def test_open_request_leaves_broadcast_window_to_claiming_extension(monkeypatch, tmp_path):
88
91
  monkeypatch.setenv("HOME", str(tmp_path))
92
+ monkeypatch.setenv("USERPROFILE", str(tmp_path))
89
93
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "stale-window")
90
94
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: True)
91
95
  signal_dir = tmp_path / ".arrayview"
@@ -112,6 +116,7 @@ def test_open_request_leaves_broadcast_window_to_claiming_extension(monkeypatch,
112
116
 
113
117
  def test_protocol_requests_get_distinct_queue_files(monkeypatch, tmp_path):
114
118
  monkeypatch.setenv("HOME", str(tmp_path))
119
+ monkeypatch.setenv("USERPROFILE", str(tmp_path))
115
120
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: True)
116
121
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "window-1")
117
122
  signal_dir = tmp_path / ".arrayview"
@@ -144,6 +149,7 @@ def test_protocol_requests_get_distinct_queue_files(monkeypatch, tmp_path):
144
149
 
145
150
  def test_protocol_uses_fixed_filename_for_running_legacy_extension(monkeypatch, tmp_path):
146
151
  monkeypatch.setenv("HOME", str(tmp_path))
152
+ monkeypatch.setenv("USERPROFILE", str(tmp_path))
147
153
  monkeypatch.setattr(signal, "_is_vscode_remote", lambda: True)
148
154
  monkeypatch.setattr(signal, "_find_arrayview_window_id", lambda: "window-1")
149
155
  signal_dir = tmp_path / ".arrayview"
@@ -240,6 +246,7 @@ def test_wait_rejects_malformed_or_unknown_ack(tmp_path):
240
246
 
241
247
  def test_cleanup_removes_only_stale_ack_files(monkeypatch, tmp_path):
242
248
  monkeypatch.setenv("HOME", str(tmp_path))
249
+ monkeypatch.setenv("USERPROFILE", str(tmp_path))
243
250
  signal_dir = tmp_path / ".arrayview"
244
251
  signal_dir.mkdir()
245
252
  stale = signal_dir / "open-ack-v0100-stale.json"
@@ -198,7 +198,7 @@ wheels = [
198
198
 
199
199
  [[package]]
200
200
  name = "arrayview"
201
- version = "0.31.1"
201
+ version = "0.31.2"
202
202
  source = { editable = "." }
203
203
  dependencies = [
204
204
  { name = "fastapi" },
@@ -1,4 +1,5 @@
1
1
  const assert = require('assert');
2
+ const path = require('path');
2
3
  const {
3
4
  collectReleaseSidsFromUrl,
4
5
  pingUrlFromViewerUrl,
@@ -54,18 +55,19 @@ assert.strictEqual(shouldDeferBroadcast(false, true, { broadcast: true }), false
54
55
  assert.strictEqual(shouldDeferBroadcast(true, false, { broadcast: true }), false);
55
56
  assert.strictEqual(shouldDeferBroadcast(false, false, { broadcast: false }), false);
56
57
 
57
- const home = '/home/tester';
58
+ const home = path.join(path.parse(process.cwd()).root, 'home', 'tester');
59
+ const ackPath = path.join(home, '.arrayview', 'open-ack-v0100-req-1.json');
58
60
  assert.strictEqual(
59
- validatedAckPath('/home/tester/.arrayview/open-ack-v0100-req-1.json', 'req-1', home),
60
- '/home/tester/.arrayview/open-ack-v0100-req-1.json'
61
+ validatedAckPath(ackPath, 'req-1', home),
62
+ path.resolve(ackPath)
61
63
  );
62
- assert.strictEqual(validatedAckPath('/tmp/open-ack-v0100-req-1.json', 'req-1', home), null);
64
+ assert.strictEqual(validatedAckPath(path.join(path.parse(process.cwd()).root, 'tmp', 'open-ack-v0100-req-1.json'), 'req-1', home), null);
63
65
  assert.strictEqual(
64
- validatedAckPath('/home/tester/.arrayview/open-ack-v0100-other.json', 'req-1', home),
66
+ validatedAckPath(path.join(home, '.arrayview', 'open-ack-v0100-other.json'), 'req-1', home),
65
67
  null
66
68
  );
67
69
  assert.strictEqual(
68
- validatedAckPath('/home/tester/.arrayview/sub/open-ack-v0100-req-1.json', 'req-1', home),
70
+ validatedAckPath(path.join(home, '.arrayview', 'sub', 'open-ack-v0100-req-1.json'), 'req-1', home),
69
71
  null
70
72
  );
71
73
 
@@ -1,76 +0,0 @@
1
- """Shared overlay compositing helpers."""
2
-
3
- from __future__ import annotations
4
-
5
- import numpy as np
6
-
7
- from arrayview._render import (
8
- _composite_overlay_mask,
9
- _extract_overlay_mask,
10
- _overlay_is_label_map,
11
- )
12
-
13
-
14
- def _parse_hex_color(hex_str: str) -> np.ndarray | None:
15
- """Parse a 6-char hex RGB color."""
16
- h = hex_str.strip().lstrip("#")
17
- if len(h) != 6:
18
- return None
19
- try:
20
- return np.array(
21
- [int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)],
22
- dtype=np.uint8,
23
- )
24
- except ValueError:
25
- return None
26
-
27
-
28
- def _composite_overlays(
29
- rgba: np.ndarray,
30
- overlay_sid_str: str | None,
31
- overlay_colors_str: str | None,
32
- overlay_alpha: float,
33
- overlay_alphas_str: str | None,
34
- overlay_outline: bool,
35
- dim_x: int,
36
- dim_y: int,
37
- idx_tuple: tuple[int, ...],
38
- shape_hw: tuple[int, int],
39
- base_shape: tuple[int, ...] | None = None,
40
- ) -> np.ndarray:
41
- """Composite one or more overlay masks onto RGBA pixels."""
42
- if not overlay_sid_str:
43
- return rgba
44
- sids = [s.strip() for s in overlay_sid_str.split(",") if s.strip()]
45
- colors_raw = (
46
- [c.strip() for c in overlay_colors_str.split(",")] if overlay_colors_str else []
47
- )
48
- alphas_raw = (
49
- [a.strip() for a in overlay_alphas_str.split(",")] if overlay_alphas_str else []
50
- )
51
- for i, sid in enumerate(sids):
52
- color = _parse_hex_color(colors_raw[i]) if i < len(colors_raw) else None
53
- alpha = overlay_alpha
54
- if i < len(alphas_raw):
55
- try:
56
- alpha = float(alphas_raw[i])
57
- except ValueError:
58
- alpha = overlay_alpha
59
- alpha = max(0.0, min(1.0, alpha))
60
- ov_raw = _extract_overlay_mask(
61
- sid,
62
- dim_x,
63
- dim_y,
64
- idx_tuple,
65
- expected_shape=shape_hw,
66
- base_shape=base_shape,
67
- )
68
- rgba = _composite_overlay_mask(
69
- rgba,
70
- ov_raw,
71
- alpha=alpha,
72
- is_label=_overlay_is_label_map(sid, ov_raw),
73
- override_color=color,
74
- outline_only=overlay_outline,
75
- )
76
- return rgba
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes