pycat-napari 1.6.332__tar.gz → 1.6.333__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 (324) hide show
  1. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/CHANGELOG.md +23 -0
  2. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/PKG-INFO +1 -1
  3. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/pyproject.toml +1 -1
  4. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/central_manager.py +1 -1
  5. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/executor.py +16 -3
  6. pycat_napari-1.6.333/src/pycat/navigator/parameters.py +192 -0
  7. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/navigator_dock.py +84 -5
  8. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/.gitignore +0 -0
  9. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/CONTRIBUTING.md +0 -0
  10. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/LICENSE +0 -0
  11. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/README.md +0 -0
  12. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/THIRD_PARTY_LICENSES.txt +0 -0
  13. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/benchmarks/README.md +0 -0
  14. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/config/README.md +0 -0
  15. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/config/requirements-arm-mac.txt +0 -0
  16. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/config/requirements-base.txt +0 -0
  17. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/config/requirements-devbio-napari-arm-mac.txt +0 -0
  18. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/config/requirements-devbio-napari.txt +0 -0
  19. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/__init__.py +0 -0
  20. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/__init__.py +0 -0
  21. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/__init__.py +0 -0
  22. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/_common.py +0 -0
  23. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/analysis_steps.py +0 -0
  24. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/brightfield_steps.py +0 -0
  25. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/invitro_steps.py +0 -0
  26. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/io_steps.py +0 -0
  27. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/preprocessing_steps.py +0 -0
  28. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch/steps/segmentation_steps.py +0 -0
  29. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch_processor.py +0 -0
  30. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/batch_step_registry.py +0 -0
  31. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/data/__init__.py +0 -0
  32. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/data/data_modules.py +0 -0
  33. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/__init__.py +0 -0
  34. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/czi_seam.py +0 -0
  35. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/dialogs.py +0 -0
  36. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/file_io.py +0 -0
  37. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/frap_io.py +0 -0
  38. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/image_reader.py +0 -0
  39. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/image_source.py +0 -0
  40. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/image_structure.py +0 -0
  41. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/lazy_guard.py +0 -0
  42. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/lazy_sources.py +0 -0
  43. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/load_channel_identity.py +0 -0
  44. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/local_cache.py +0 -0
  45. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/metadata_extract.py +0 -0
  46. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/multidim_io.py +0 -0
  47. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/naming.py +0 -0
  48. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/napari_adapter.py +0 -0
  49. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/readers/__init__.py +0 -0
  50. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/readers/czi_bioformats.py +0 -0
  51. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/readers/image_reader_2d.py +0 -0
  52. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/readers/ims_reader.py +0 -0
  53. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/readers/mask_reader.py +0 -0
  54. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/readers/stack_layer_builders.py +0 -0
  55. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/readers/stack_metadata.py +0 -0
  56. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/routing.py +0 -0
  57. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/scenes.py +0 -0
  58. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/session.py +0 -0
  59. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/session_loader.py +0 -0
  60. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/session_manifest.py +0 -0
  61. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/sidecar_discovery.py +0 -0
  62. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/stack_access.py +0 -0
  63. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/stack_load.py +0 -0
  64. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/stack_openers.py +0 -0
  65. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/storage_probe.py +0 -0
  66. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/tagging.py +0 -0
  67. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/tiff_planes.py +0 -0
  68. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/tifffile_zarr_shim.py +0 -0
  69. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/viewer_load.py +0 -0
  70. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/writers.py +0 -0
  71. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/file_io/zarr_compat.py +0 -0
  72. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/fix_tifffile.py +0 -0
  73. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/icons/pycat_logo_512.png +0 -0
  74. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/icons/pycat_mark.png +0 -0
  75. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/__init__.py +0 -0
  76. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/adapters.py +0 -0
  77. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/canonical.py +0 -0
  78. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/capabilities.py +0 -0
  79. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/context.py +0 -0
  80. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/contracts.py +0 -0
  81. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/data/PyCAT_layer_tag_hierarchy_and_module_flow.xlsx +0 -0
  82. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/data/PyCAT_module_information_contracts.xlsx +0 -0
  83. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/data/PyCAT_question_tree_and_method_mapping.xlsx +0 -0
  84. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/data/operation_catalog.json +0 -0
  85. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/execution.py +0 -0
  86. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/gates.py +0 -0
  87. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/loader.py +0 -0
  88. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/modules.py +0 -0
  89. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/op_catalog.py +0 -0
  90. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/operation_spec.py +0 -0
  91. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/planner.py +0 -0
  92. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/quality_gates.py +0 -0
  93. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/question_engine.py +0 -0
  94. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/registry.py +0 -0
  95. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/scientific_tree.py +0 -0
  96. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/session.py +0 -0
  97. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/tags.py +0 -0
  98. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/navigator/templates.py +0 -0
  99. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/run_pycat.py +0 -0
  100. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/__init__.py +0 -0
  101. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/advanced_analysis_ui.py +0 -0
  102. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/analysis_plots.py +0 -0
  103. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/batch_roi_tools.py +0 -0
  104. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/benchmark_tools.py +0 -0
  105. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/biological_qc_tools.py +0 -0
  106. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/brightfield_tools.py +0 -0
  107. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/brightfield_ui.py +0 -0
  108. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/clean_spot_detection_tools.py +0 -0
  109. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_modes.py +0 -0
  110. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/__init__.py +0 -0
  111. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/coarsening.py +0 -0
  112. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/frame_quality.py +0 -0
  113. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/intensity.py +0 -0
  114. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/moduli.py +0 -0
  115. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/msd.py +0 -0
  116. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/photobleaching.py +0 -0
  117. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/relaxation.py +0 -0
  118. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics/survival.py +0 -0
  119. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics_tools.py +0 -0
  120. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/condensate_physics_ui.py +0 -0
  121. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/contrast_cascade_tools.py +0 -0
  122. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/contrast_cascade_ui.py +0 -0
  123. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/control_validation.py +0 -0
  124. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/correlation_func_analysis_tools.py +0 -0
  125. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/data_qc_tools.py +0 -0
  126. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/data_qc_ui.py +0 -0
  127. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/data_viz_tools.py +0 -0
  128. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/drawing_layers.py +0 -0
  129. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/dynamic_spatial_tools.py +0 -0
  130. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/fd_curve_tools.py +0 -0
  131. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/fd_curve_ui.py +0 -0
  132. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/feature_analysis_tools.py +0 -0
  133. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/feature_redundancy.py +0 -0
  134. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/fft_bandpass_tools.py +0 -0
  135. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/fibril_tools.py +0 -0
  136. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/fibril_ui.py +0 -0
  137. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/frap_tools.py +0 -0
  138. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/frap_ui.py +0 -0
  139. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/fusion_tools.py +0 -0
  140. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/fusion_ui.py +0 -0
  141. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/gaussian_localization_tools.py +0 -0
  142. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/general_image_tools.py +0 -0
  143. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/gpu_utils.py +0 -0
  144. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/__init__.py +0 -0
  145. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/_base.py +0 -0
  146. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/background.py +0 -0
  147. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/deblur.py +0 -0
  148. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/filters.py +0 -0
  149. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/preprocessing.py +0 -0
  150. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/size_estimation.py +0 -0
  151. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing/upscaling.py +0 -0
  152. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/image_processing_tools.py +0 -0
  153. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/intensity_profile_tools.py +0 -0
  154. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro/__init__.py +0 -0
  155. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro/analysis.py +0 -0
  156. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro/field_summary.py +0 -0
  157. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro/partition.py +0 -0
  158. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro/size_distribution.py +0 -0
  159. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro_bf_ui.py +0 -0
  160. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro_fluor_ui.py +0 -0
  161. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/invitro_tools.py +0 -0
  162. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/kymograph_tools.py +0 -0
  163. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/label_and_mask_tools.py +0 -0
  164. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/layer_tools.py +0 -0
  165. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/measurement_stability.py +0 -0
  166. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/molecular_counting_tools.py +0 -0
  167. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/morphological_complexity_tools.py +0 -0
  168. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/nb_tools.py +0 -0
  169. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/nb_ui.py +0 -0
  170. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/numba_utils.py +0 -0
  171. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/obj_based_coloc_analysis_tools.py +0 -0
  172. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/organizational_metrics_tools.py +0 -0
  173. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/partial_volume_tools.py +0 -0
  174. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/partition_enrichment_tools.py +0 -0
  175. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/pipeline_diagnostic_tools.py +0 -0
  176. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/pipeline_snr_tools.py +0 -0
  177. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/pixel_wise_corr_analysis_tools.py +0 -0
  178. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/qc_gallery.py +0 -0
  179. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/qc_gallery_ui.py +0 -0
  180. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/ratiometric_tools.py +0 -0
  181. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/scan_qc_tools.py +0 -0
  182. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/__init__.py +0 -0
  183. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/_common.py +0 -0
  184. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/cellpose.py +0 -0
  185. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/fz.py +0 -0
  186. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/intensity.py +0 -0
  187. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/local_thresholding.py +0 -0
  188. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/morphology.py +0 -0
  189. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/puncta_refinement.py +0 -0
  190. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/subcellular.py +0 -0
  191. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation/watershed.py +0 -0
  192. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation_scale_advisor.py +0 -0
  193. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/segmentation_tools.py +0 -0
  194. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/smlm_tools.py +0 -0
  195. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/spatial_acf_tools.py +0 -0
  196. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/spatial_metrology_tools.py +0 -0
  197. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/spatial_metrology_ui.py +0 -0
  198. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/spatial_randomness_tools.py +0 -0
  199. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/spida_tools.py +0 -0
  200. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/spida_ui.py +0 -0
  201. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/temperature_tools.py +0 -0
  202. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/temperature_ui.py +0 -0
  203. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/temporal_enhancement_tools.py +0 -0
  204. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries/__init__.py +0 -0
  205. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries/analysis.py +0 -0
  206. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries/correlation.py +0 -0
  207. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries/execution.py +0 -0
  208. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries/frame_access.py +0 -0
  209. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries/preprocessing.py +0 -0
  210. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries/ui.py +0 -0
  211. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries_condensate_tools.py +0 -0
  212. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries_invitro_fluor_ui.py +0 -0
  213. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/timeseries_invitro_tools.py +0 -0
  214. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/topology_tools.py +0 -0
  215. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/trackmate_bridge.py +0 -0
  216. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/ts_cache_manager.py +0 -0
  217. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/ts_cellpose_tools.py +0 -0
  218. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/two_channel_coloc_tools.py +0 -0
  219. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/unmixing_tools.py +0 -0
  220. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/video_export_tools.py +0 -0
  221. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/__init__.py +0 -0
  222. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/analysis.py +0 -0
  223. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/detection.py +0 -0
  224. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/drift.py +0 -0
  225. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/host.py +0 -0
  226. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/msd_adapter.py +0 -0
  227. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/napari_adapter.py +0 -0
  228. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/panels.py +0 -0
  229. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/populations.py +0 -0
  230. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/results_dock.py +0 -0
  231. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/table_adapter.py +0 -0
  232. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt/viscosity.py +0 -0
  233. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt_tools.py +0 -0
  234. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/vpt_ui.py +0 -0
  235. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/zstack_segmentation_tools.py +0 -0
  236. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/toolbox/zstack_segmentation_ui.py +0 -0
  237. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/__init__.py +0 -0
  238. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/brushable_table.py +0 -0
  239. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/brushable_workspace.py +0 -0
  240. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/channel_identity_dialog.py +0 -0
  241. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/comparative_figures_ui.py +0 -0
  242. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/coordinate_readout.py +0 -0
  243. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/feature_explorer_dock.py +0 -0
  244. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/field_status.py +0 -0
  245. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/home_dock.py +0 -0
  246. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/linked_selection_dock.py +0 -0
  247. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/menu_manager.py +0 -0
  248. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/metadata_contradiction_panel.py +0 -0
  249. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/operation_gating.py +0 -0
  250. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/preferences_dialog.py +0 -0
  251. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/preset_picker.py +0 -0
  252. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/scene_switcher.py +0 -0
  253. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_analysis_mixin.py +0 -0
  254. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_diagnostics_mixin.py +0 -0
  255. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_filtering_mixin.py +0 -0
  256. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_imageops_mixin.py +0 -0
  257. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_labels_mixin.py +0 -0
  258. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_modules.py +0 -0
  259. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_segmentation_mixin.py +0 -0
  260. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/ui_utils.py +0 -0
  261. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/ui/workflow_checklist.py +0 -0
  262. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/__init__.py +0 -0
  263. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/analysis_presets.py +0 -0
  264. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/app_mode.py +0 -0
  265. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/batch_brushing.py +0 -0
  266. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/brushing.py +0 -0
  267. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/calibration.py +0 -0
  268. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/channel_designations.py +0 -0
  269. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/channel_modality.py +0 -0
  270. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/channel_naming.py +0 -0
  271. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/cohort_targets.py +0 -0
  272. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/comparative_figures.py +0 -0
  273. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/comparative_stats.py +0 -0
  274. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/consolidated_table.py +0 -0
  275. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/dataset_identity.py +0 -0
  276. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/dock_space.py +0 -0
  277. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/entity_ref.py +0 -0
  278. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/entity_registry.py +0 -0
  279. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/environment_check.py +0 -0
  280. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/errors.py +0 -0
  281. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/feature_cards.py +0 -0
  282. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/feature_explorer.py +0 -0
  283. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/feature_families.py +0 -0
  284. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/feature_provenance.py +0 -0
  285. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/feature_registry.py +0 -0
  286. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/field_registry_hub.py +0 -0
  287. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/figure_refine.py +0 -0
  288. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/figure_spec.py +0 -0
  289. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/filter_store.py +0 -0
  290. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/fit_quality.py +0 -0
  291. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/frame_interval.py +0 -0
  292. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/general_utils.py +0 -0
  293. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/intensity_semantics.py +0 -0
  294. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/layer_bindings.json +0 -0
  295. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/layer_tag_hook.py +0 -0
  296. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/layer_tags.py +0 -0
  297. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/logging_utils.py +0 -0
  298. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/marker_logic.py +0 -0
  299. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/math_utils.py +0 -0
  300. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/measurement.py +0 -0
  301. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/measurement_ontology.py +0 -0
  302. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/metadata_contradictions.py +0 -0
  303. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/metadata_validity.py +0 -0
  304. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/notify.py +0 -0
  305. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/object_graph.py +0 -0
  306. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/object_ref.py +0 -0
  307. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/operation_runner.py +0 -0
  308. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/pixel_size.py +0 -0
  309. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/plot_backend_pyqtgraph.py +0 -0
  310. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/plot_backend_selection.py +0 -0
  311. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/plot_backends.py +0 -0
  312. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/preferences.py +0 -0
  313. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/qt_worker.py +0 -0
  314. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/quality_gate.py +0 -0
  315. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/reliability.py +0 -0
  316. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/result_models.py +0 -0
  317. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/results_store.py +0 -0
  318. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/sample_metadata.py +0 -0
  319. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/selection_overlay.py +0 -0
  320. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/selection_service.py +0 -0
  321. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/tag_registry.py +0 -0
  322. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/tag_resolver.py +0 -0
  323. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/src/pycat/utils/user_settings.py +0 -0
  324. {pycat_napari-1.6.332 → pycat_napari-1.6.333}/tests/README.md +0 -0
@@ -1,3 +1,26 @@
1
+ ## [1.6.333] - 2026-07-24
2
+ ### Added — **Navigator execution-adapter layer, Phase 2: an honest parameter review — seeded, editable, provenance-recorded.**
3
+ The navigator asks *what* to do, not *with which parameters* — but a guided run that silently picks a
4
+ rolling-ball radius (or a segmentation method) the user never saw is worse than asking. Phase 2 adds the
5
+ minimal parameter review, Qt-free at its core:
6
+ - New **`navigator/parameters.py`**: each adapter-covered step declares its **material** parameters (the handful
7
+ the science turns on, not every argument). `build_param_review(plan, ctx)` seeds them by a declared
8
+ precedence — **a matching preset → a session value → the grounded function default** — never an invented one.
9
+ `ReviewedStep` generalises the preset `populate-but-never-lock` contract to the no-preset case too: the user
10
+ may edit any value, and the edit is tracked as **provenance in the exact `PresetApplication.record()` shape**
11
+ (`preset_key`, `modified_parameters`, `is_modified`, `parameters`), `preset_key=None` when no preset seeded it.
12
+ - **The reviewed values drive the run.** `run_plan(…, params_by_step=, provenance_by_step=)` merges the reviewed
13
+ values over the adapter's derived params (routing keys like `active_layer` still come from the adapter) and
14
+ records the provenance onto each ran step's `StepOutcome`. `tests/navigator/test_navigator_parameters.py`
15
+ (`base`, 9) pins it: an edited rolling-ball radius makes the guided result equal the **manual operation at
16
+ that radius** — and *not* at the default — so the edit provably reaches the computation.
17
+ - **The dock surfaces it**: the plan view renders an editable "Review parameters" form (a spin/combo per
18
+ material parameter, seeded, tooltip-documented) above Run; the Run passes the `ParamReview` through
19
+ `run_plan_via_central_manager`, which also reports which steps ran with modified parameters. A programmatic
20
+ run with no form still builds a default-seeded review, so provenance is recorded either way.
21
+ - **Later phases** (per the `navigator_execution_adapters` spec): more adapters one workflow at a time (each
22
+ behind its route-equivalence test), then dock progress + cancel.
23
+
1
24
  ## [1.6.332] - 2026-07-24
2
25
  ### Added — **Navigator execution-adapter layer, Phase 1: "Run analysis" computes a plan through the batch handlers, gate-respecting (guided == batch == manual).**
3
26
  `selection_scale` Part 2 established there is no uniform "run this op" — but the batch `_STEP_MAP` handlers ARE
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycat-napari
3
- Version: 1.6.332
3
+ Version: 1.6.333
4
4
  Summary: Python Condensate Analysis Toolbox - A napari-based tool for biomolecular condensate analysis
5
5
  Project-URL: Homepage, https://github.com/BanerjeeLab-repertoire/pycat-napari
6
6
  Project-URL: Repository, https://github.com/BanerjeeLab-repertoire/pycat-napari
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pycat-napari"
7
- version = "1.6.332"
7
+ version = "1.6.333"
8
8
  description = "Python Condensate Analysis Toolbox - A napari-based tool for biomolecular condensate analysis"
9
9
  readme = "README.md"
10
10
  # 3.13 is BLOCKED UPSTREAM, not by PyCAT's own code (which compiles and passes core on 3.13).
@@ -124,7 +124,7 @@ class CentralManager:
124
124
  from pycat.ui.navigator_dock import install_navigator_action, run_plan_via_central_manager
125
125
  self._navigator_action = install_navigator_action(
126
126
  self.viewer, central_manager=self,
127
- on_run=lambda plan: run_plan_via_central_manager(self, plan))
127
+ on_run=lambda plan, review=None: run_plan_via_central_manager(self, plan, review))
128
128
  # Populate the feature registry so any consumer (the beginner home dock, a capability query) sees
129
129
  # every surfaced-but-otherwise-hidden feature (navigator inc 4). Guarded: a registration hiccup must
130
130
  # never break startup, and the cards' openers import Qt/toolbox lazily so this stays cheap.
@@ -58,10 +58,13 @@ def has_adapter(step_name: str) -> bool:
58
58
  @dataclasses.dataclass(frozen=True)
59
59
  class StepOutcome:
60
60
  """What happened to one step. ``outcome`` is ``'ran'`` / ``'ran_with_caveat'`` / ``'blocked'`` (the run
61
- stops here) / ``'skipped'`` (after a blocker) / ``'needs_panel'`` (no adapter yet) / ``'error'``."""
61
+ stops here) / ``'skipped'`` (after a blocker) / ``'needs_panel'`` (no adapter yet) / ``'error'``.
62
+ ``provenance`` (Phase 2) records how the step was parameterised — the ``PresetApplication.record()`` shape
63
+ (which preset, if any, seeded it and what the user changed) — empty when the step carried no review."""
62
64
  name: str
63
65
  outcome: str
64
66
  detail: str = ""
67
+ provenance: dict = dataclasses.field(default_factory=dict)
65
68
 
66
69
 
67
70
  @dataclasses.dataclass
@@ -96,6 +99,7 @@ def _build_step_registry() -> dict:
96
99
 
97
100
 
98
101
  def run_plan(plan, state, *, intent=None, ctx=None, image_path=None, output_dir=None, runner=None,
102
+ params_by_step: Optional[dict] = None, provenance_by_step: Optional[dict] = None,
99
103
  on_step: Optional[Callable] = None) -> ExecReport:
100
104
  """Execute ``plan``'s steps in gate order by driving the batch handlers, threading ``state`` (a dict the
101
105
  handlers read/write, exactly as a batch replay). Returns an :class:`ExecReport`.
@@ -104,7 +108,11 @@ def run_plan(plan, state, *, intent=None, ctx=None, image_path=None, output_dir=
104
108
  run at that step (nothing after it runs); a **caveat** runs with the caveat recorded; **probes** run first.
105
109
  A step with no :class:`ExecAdapter` is reported ``'needs_panel'`` — never invoked with guessed arguments.
106
110
  A step that raises halts the run (downstream depends on its output). ``runner`` (an ``OperationRunner``)
107
- runs each handler off the Qt thread when given; otherwise handlers run synchronously (headless / tests)."""
111
+ runs each handler off the Qt thread when given; otherwise handlers run synchronously (headless / tests).
112
+
113
+ ``params_by_step`` (Phase 2) overrides the adapter's derived params per step with the user-reviewed values
114
+ (:mod:`pycat.navigator.parameters`); ``provenance_by_step`` records how each ran step was parameterised
115
+ (the ``PresetApplication.record()`` shape) onto its :class:`StepOutcome`."""
108
116
  intent = intent if intent is not None else getattr(plan, "intent", None)
109
117
  registry = _build_step_registry()
110
118
  report = ExecReport()
@@ -143,6 +151,10 @@ def run_plan(plan, state, *, intent=None, ctx=None, image_path=None, output_dir=
143
151
  continue
144
152
 
145
153
  params = adapter.params_from(intent, ctx, state)
154
+ if params_by_step and es.name in params_by_step:
155
+ # Reviewed values override the adapter's derived params, but the adapter still supplies the
156
+ # non-reviewed routing keys (e.g. active_layer) — merge, don't replace.
157
+ params = {**params, **params_by_step[es.name]}
146
158
  try:
147
159
  if runner is not None:
148
160
  runner.execute(fn, state, image_path, params, output_dir)
@@ -153,8 +165,9 @@ def run_plan(plan, state, *, intent=None, ctx=None, image_path=None, output_dir=
153
165
  halted = True
154
166
  continue
155
167
 
168
+ prov = (provenance_by_step or {}).get(es.name, {})
156
169
  report.steps.append(StepOutcome(
157
- es.name, "ran_with_caveat" if es.status == "caveat" else "ran", es.reason))
170
+ es.name, "ran_with_caveat" if es.status == "caveat" else "ran", es.reason, prov))
158
171
  if on_step:
159
172
  on_step(report.steps[-1])
160
173
  finally:
@@ -0,0 +1,192 @@
1
+ """**The minimal parameter review — surface the handful of parameters that change the result, seeded honestly.**
2
+
3
+ Execution-adapter layer, Phase 2. The navigator asks *what* to do, not *with which parameters* — but a guided
4
+ run that silently picks a rolling-ball radius (or a segmentation method) the user never saw is worse than
5
+ asking. So before a run, each adapter-covered step surfaces its **material** parameters — the handful that
6
+ materially change the result — in a small editable set, seeded by a declared precedence:
7
+
8
+ 1. **A matching preset** (:mod:`pycat.utils.analysis_presets`) — if one ``applies_to`` this step's workflow,
9
+ its parameters seed the values (the populate-but-never-lock contract).
10
+ 2. **A session value** — a measured/derived value already in the context (e.g. a ``ball_radius`` the user
11
+ measured on their data) seeds an un-preset parameter.
12
+ 3. **The grounded function default** — the same default the batch handler falls back to; never an invented one.
13
+
14
+ The user may edit any value; the edit is tracked so the run records **which preset (if any) seeded each step
15
+ and what the user changed** — the exact ``PresetApplication.record()`` shape, so a guided result states how it
16
+ was parameterised and a saved template can carry those params. Qt-free: this is the model the dock's editable
17
+ form and :func:`pycat.navigator.executor.run_plan` both read; the dock only builds widgets over it.
18
+
19
+ Phase 2 ships the model + the one shipped adapter's material set (``background_removal`` → ``ball_radius``);
20
+ later adapters declare their material params here as they land, each still behind a route-equivalence test."""
21
+ from __future__ import annotations
22
+
23
+ import dataclasses
24
+ from typing import Optional
25
+
26
+ from .execution import execution_order
27
+ from .executor import has_adapter
28
+
29
+
30
+ @dataclasses.dataclass(frozen=True)
31
+ class StepParam:
32
+ """One material parameter of a step — declared, so the review shows the same handful the science turns on
33
+ (not every argument the function takes). ``kind`` is ``'int'`` / ``'float'`` / ``'choice'``; ``default`` is
34
+ the grounded function default (what the batch handler falls back to), never an invented value."""
35
+ name: str
36
+ label: str
37
+ kind: str
38
+ default: object
39
+ choices: tuple = ()
40
+ help: str = ""
41
+ minimum: object = None
42
+ maximum: object = None
43
+
44
+
45
+ #: The material parameters per plan step — the ONLY place a step declares which of its arguments are surfaced
46
+ #: for review. Grows one adapter at a time (each behind its route-equivalence test), mirroring ``executor._ADAPTERS``.
47
+ _MATERIAL: dict = {
48
+ "background_removal": (
49
+ StepParam("ball_radius", "Rolling-ball radius (px)", "int", 50, minimum=1,
50
+ help="The rolling-ball structuring radius for background estimation. Larger keeps more "
51
+ "low-frequency structure; too small eats real signal. Default 50 px."),
52
+ ),
53
+ }
54
+
55
+
56
+ #: Plan step → the ``analysis_presets`` workflow id whose presets seed it (preset precedence, source 1). Empty
57
+ #: for the shipped adapter (no preset applies to ``background_removal``); entries land with the adapters that a
58
+ #: preset actually configures (e.g. ``condensate_puncta_refinement``), one per phase.
59
+ _PRESET_WORKFLOW: dict = {}
60
+
61
+
62
+ def material_params(step_name: str) -> tuple:
63
+ """The declared material parameters of ``step_name`` (empty if none/unknown)."""
64
+ return _MATERIAL.get(step_name, ())
65
+
66
+
67
+ def _coerce(param: StepParam, value):
68
+ """Coerce a value to the parameter's kind, falling back to the default on a bad value (never raise into a
69
+ run) — an int param must not carry a float that changes ``ceil`` downstream."""
70
+ try:
71
+ if param.kind == "int":
72
+ return int(round(float(value)))
73
+ if param.kind == "float":
74
+ return float(value)
75
+ except (TypeError, ValueError):
76
+ return param.default
77
+ return value
78
+
79
+
80
+ def _applicable_preset(step_name: str):
81
+ """The single preset that applies to this step's workflow, or ``None``. If more than one applies we return
82
+ ``None`` (picking one silently would be dishonest — that is a preset-picker choice, not a default)."""
83
+ workflow = _PRESET_WORKFLOW.get(step_name)
84
+ if not workflow:
85
+ return None
86
+ try:
87
+ from pycat.utils.analysis_presets import presets_for
88
+ applicable = presets_for(workflow)
89
+ except Exception: # broad-ok: optional_probe — no preset registry → seed from defaults, not a crash
90
+ return None
91
+ return applicable[0] if len(applicable) == 1 else None
92
+
93
+
94
+ def _seed_value(param: StepParam, preset, ctx):
95
+ """Seed one parameter by the declared precedence: preset → session value → grounded default."""
96
+ if preset is not None and param.name in getattr(preset, "parameters", {}):
97
+ return _coerce(param, preset.parameters[param.name])
98
+ if ctx is not None:
99
+ try:
100
+ cv = ctx.get(param.name)
101
+ except Exception: # broad-ok: optional_probe — a non-mapping context just means no session value
102
+ cv = None
103
+ if cv is not None:
104
+ return _coerce(param, cv)
105
+ return param.default
106
+
107
+
108
+ class ReviewedStep:
109
+ """One step's reviewable parameters: seeded honestly, editable, tracking the deviation from the seed. The
110
+ populate-but-never-lock contract of :class:`PresetApplication`, generalised to also cover the no-preset
111
+ case (``preset_key`` is ``None`` then) — because provenance is owed whether or not a preset seeded it."""
112
+
113
+ def __init__(self, step_name: str, params, *, preset=None, ctx=None):
114
+ self.step_name = step_name
115
+ self.params = tuple(params)
116
+ self.preset = preset
117
+ self._seed = {p.name: _seed_value(p, preset, ctx) for p in self.params}
118
+ self.values = dict(self._seed)
119
+ self._modified: set = set()
120
+
121
+ def _param(self, name) -> Optional[StepParam]:
122
+ return next((p for p in self.params if p.name == name), None)
123
+
124
+ def set(self, name, value):
125
+ """Set a value (coerced to its kind); mark it modified iff it differs from the seed. Setting it back to
126
+ the seeded value clears the modification — a result that matches the seed was not 'modified'."""
127
+ param = self._param(name)
128
+ if param is None:
129
+ return self
130
+ v = _coerce(param, value)
131
+ if self._seed.get(name) != v:
132
+ self._modified.add(name)
133
+ else:
134
+ self._modified.discard(name)
135
+ self.values[name] = v
136
+ return self
137
+
138
+ @property
139
+ def is_modified(self) -> bool:
140
+ return bool(self._modified)
141
+
142
+ def provenance(self) -> dict:
143
+ """The recorded provenance — the exact :meth:`PresetApplication.record` shape, with ``preset_key``
144
+ ``None`` when no preset seeded the step. Travels into the run report and a saved template."""
145
+ return {"preset_key": self.preset.key if self.preset is not None else None,
146
+ "modified_parameters": sorted(self._modified),
147
+ "is_modified": self.is_modified,
148
+ "parameters": dict(self.values)}
149
+
150
+
151
+ class ParamReview:
152
+ """The reviewable parameter set for a whole plan — the adapter-covered, runnable steps that declare
153
+ material params, each a :class:`ReviewedStep`. The dock renders an editable form over it; the executor
154
+ reads :meth:`params_by_step` / :meth:`provenance_by_step`."""
155
+
156
+ def __init__(self, steps):
157
+ self.steps = list(steps)
158
+
159
+ @property
160
+ def is_empty(self) -> bool:
161
+ return not self.steps
162
+
163
+ def step(self, name) -> Optional[ReviewedStep]:
164
+ return next((s for s in self.steps if s.step_name == name), None)
165
+
166
+ def params_by_step(self) -> dict:
167
+ return {s.step_name: dict(s.values) for s in self.steps}
168
+
169
+ def provenance_by_step(self) -> dict:
170
+ return {s.step_name: s.provenance() for s in self.steps}
171
+
172
+
173
+ def build_param_review(plan, ctx=None) -> ParamReview:
174
+ """Build the reviewable parameter set for ``plan``: one :class:`ReviewedStep` per adapter-covered step that
175
+ will actually run (``run`` / ``caveat`` in :func:`execution_order`) and declares material params, seeded by
176
+ the declared precedence. Blocked/skipped steps carry no review (they will not run). Never invents a
177
+ parameter — a step with no declared material params contributes nothing to review."""
178
+ reviewed = []
179
+ try:
180
+ order = execution_order(plan)
181
+ except Exception: # broad-ok: optional_probe — an un-orderable plan yields an empty review, not a crash
182
+ order = []
183
+ for es in order:
184
+ if es.status not in ("run", "caveat"):
185
+ continue
186
+ if not has_adapter(es.name):
187
+ continue
188
+ params = material_params(es.name)
189
+ if not params:
190
+ continue
191
+ reviewed.append(ReviewedStep(es.name, params, preset=_applicable_preset(es.name), ctx=ctx))
192
+ return ParamReview(reviewed)
@@ -128,17 +128,25 @@ def _render_observations(widget, body_layout):
128
128
  "color: gray; font-size: 10px; margin-bottom: 4px;"))
129
129
 
130
130
 
131
- def run_plan_via_central_manager(central_manager, plan):
131
+ def run_plan_via_central_manager(central_manager, plan, review=None):
132
132
  """Execute a compiled plan against the session's data through the execution-adapter layer, and report
133
133
  per-step outcomes. Adapter-covered steps run through the batch handlers (the proven 'same computation'
134
- route); a step with no adapter yet is reported as 'run from its panel' — never invoked with guessed args.
135
- Safe on an uncovered plan (nothing runs); best-effort, never crashes the UI. This is the wired ``on_run``."""
134
+ route) with the user-reviewed parameters (Phase 2); a step with no adapter yet is reported as 'run from its
135
+ panel' — never invoked with guessed args. ``review`` is the :class:`ParamReview` the dock built from its
136
+ editable form; when ``None`` (a programmatic run), one is built from the plan so parameters are still
137
+ preset/default-seeded and provenance is still recorded. Safe on an uncovered plan (nothing runs);
138
+ best-effort, never crashes the UI. This is the wired ``on_run``."""
136
139
  try:
137
140
  from pycat.navigator.executor import run_plan
138
141
  dr = getattr(getattr(central_manager, "active_data_class", None), "data_repository", None)
139
142
  if dr is None:
140
143
  return
141
- report = run_plan(plan, dr, ctx=dr)
144
+ if review is None:
145
+ from pycat.navigator.parameters import build_param_review
146
+ review = build_param_review(plan, ctx=dr)
147
+ report = run_plan(plan, dr, ctx=dr,
148
+ params_by_step=review.params_by_step(),
149
+ provenance_by_step=review.provenance_by_step())
142
150
  ran = [s.name for s in report.ran]
143
151
  panel = [s.name for s in report.needs_panel]
144
152
  blocked = [s for s in report.steps if s.outcome == "blocked"]
@@ -149,6 +157,9 @@ def run_plan_via_central_manager(central_manager, plan):
149
157
  parts.append(f"Stopped at {blocked[0].name} — {blocked[0].detail}")
150
158
  if panel:
151
159
  parts.append("Run these from their method panels, in order: " + ", ".join(panel) + ".")
160
+ modified = [s.name for s in report.ran if s.provenance.get("is_modified")]
161
+ if modified:
162
+ parts.append("Parameters modified for: " + ", ".join(modified) + ".")
152
163
  from napari.utils.notifications import show_info
153
164
  show_info(" ".join(parts) or "Nothing to run.")
154
165
  except Exception as exc: # broad-ok: ui_cleanup — a run attempt must never crash the guided panel
@@ -199,6 +210,68 @@ def _add_template_save(widget, body_layout):
199
210
  body_layout.addWidget(btn)
200
211
 
201
212
 
213
+ def _param_input(param, value, on_change):
214
+ """One editable control for a material parameter, seeded at ``value``; ``on_change(new_value)`` fires on
215
+ edit. int → spin box, float → double spin, choice → combo. Returns the widget (or ``None`` on an odd kind)."""
216
+ from PyQt5.QtWidgets import QSpinBox, QDoubleSpinBox, QComboBox
217
+ if param.kind == "int":
218
+ w = QSpinBox()
219
+ w.setMinimum(int(param.minimum) if param.minimum is not None else 0)
220
+ w.setMaximum(int(param.maximum) if param.maximum is not None else 100000)
221
+ w.setValue(int(value))
222
+ w.valueChanged.connect(lambda v: on_change(v))
223
+ return w
224
+ if param.kind == "float":
225
+ w = QDoubleSpinBox()
226
+ w.setDecimals(3)
227
+ w.setMinimum(float(param.minimum) if param.minimum is not None else 0.0)
228
+ w.setMaximum(float(param.maximum) if param.maximum is not None else 1e9)
229
+ w.setValue(float(value))
230
+ w.valueChanged.connect(lambda v: on_change(v))
231
+ return w
232
+ if param.kind == "choice":
233
+ w = QComboBox()
234
+ w.addItems([str(c) for c in param.choices])
235
+ if str(value) in [str(c) for c in param.choices]:
236
+ w.setCurrentText(str(value))
237
+ w.currentTextChanged.connect(lambda v: on_change(v))
238
+ return w
239
+ return None
240
+
241
+
242
+ def _add_param_review(widget, body_layout, plan):
243
+ """Render the editable parameter-review form (Phase 2) and stash the :class:`ParamReview` on the widget as
244
+ ``_review`` for the run. Surfaces the handful of material parameters per adapter-covered step, seeded from a
245
+ preset/session value/grounded default (never invented); an edit is tracked so the run records provenance.
246
+ Renders nothing when no adapter-covered step has material params — the honest 'nothing to review' case."""
247
+ from PyQt5.QtWidgets import QFrame, QVBoxLayout, QHBoxLayout
248
+ from pycat.navigator.parameters import build_param_review, material_params
249
+ try:
250
+ review = build_param_review(plan, ctx=widget._session.ctx)
251
+ except Exception: # broad-ok: ui_cleanup — a review failure must not break the plan view
252
+ review = None
253
+ widget._review = review
254
+ if review is None or review.is_empty:
255
+ return
256
+ body_layout.addWidget(_label("⚙ Review parameters", "font-weight: bold; font-size: 12px; margin-top: 6px;"))
257
+ body_layout.addWidget(_label("Seeded from your data and grounded defaults — edit before running.",
258
+ "color: gray; font-size: 10px;"))
259
+ for step in review.steps:
260
+ body_layout.addWidget(_label(step.step_name, "font-weight: bold; font-size: 11px; color: #2a7ab0;"))
261
+ for param in material_params(step.step_name):
262
+ frame = QFrame()
263
+ row = QHBoxLayout(frame)
264
+ row.setContentsMargins(0, 0, 0, 0)
265
+ row.addWidget(_label(param.label, "font-size: 11px;"))
266
+ inp = _param_input(param, step.values.get(param.name, param.default),
267
+ lambda v, s=step, n=param.name: s.set(n, v))
268
+ if inp is not None:
269
+ if param.help:
270
+ inp.setToolTip(param.help)
271
+ row.addWidget(inp)
272
+ body_layout.addWidget(frame)
273
+
274
+
202
275
  def build_navigator_widget(session, *, on_run=None, central_manager=None, parent=None):
203
276
  """Build (do not mount) the Navigator widget over ``session``, or return ``None`` if Qt is unavailable
204
277
  (headless). ``on_run(plan)`` is called when the user runs the compiled plan. When ``central_manager`` is
@@ -235,6 +308,7 @@ def build_navigator_widget(session, *, on_run=None, central_manager=None, parent
235
308
  widget._rows = []
236
309
  widget._choice_buttons = []
237
310
  widget._run_button = None
311
+ widget._review = None # Phase 2: the ParamReview built at plan render, passed to the run
238
312
  widget._regate_only = False # a viewer event re-gates; answering/restart recompiles
239
313
  widget._reeval_pending = False
240
314
 
@@ -267,6 +341,7 @@ def build_navigator_widget(session, *, on_run=None, central_manager=None, parent
267
341
  body_layout.addWidget(_label(_PLAN_LEGEND, "color: gray; font-size: 10px; margin-bottom: 4px;"))
268
342
  for row in widget._rows:
269
343
  body_layout.addWidget(_row_frame(row))
344
+ _add_param_review(widget, body_layout, plan) # Phase 2: the editable, seeded material params
270
345
  run = QPushButton("▶ Run analysis")
271
346
  reason = widget._session.run_blocked_reason()
272
347
  run.setEnabled(reason is None and callable(widget._on_run))
@@ -289,7 +364,11 @@ def build_navigator_widget(session, *, on_run=None, central_manager=None, parent
289
364
 
290
365
  def _run():
291
366
  if callable(widget._on_run) and widget._plan is not None:
292
- widget._on_run(widget._plan)
367
+ review = getattr(widget, "_review", None)
368
+ try:
369
+ widget._on_run(widget._plan, review) # Phase 2: pass the reviewed params
370
+ except TypeError:
371
+ widget._on_run(widget._plan) # a 1-arg on_run (older callers) still works
293
372
 
294
373
  def _restart():
295
374
  widget._session = NavigatorSession()
File without changes
File without changes