pycat-napari 1.6.330__tar.gz → 1.6.332__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.
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/CHANGELOG.md +46 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/PKG-INFO +1 -1
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/pyproject.toml +1 -1
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/central_manager.py +6 -3
- pycat_napari-1.6.332/src/pycat/navigator/executor.py +163 -0
- pycat_napari-1.6.332/src/pycat/navigator/templates.py +135 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/navigator_dock.py +56 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/.gitignore +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/CONTRIBUTING.md +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/LICENSE +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/README.md +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/THIRD_PARTY_LICENSES.txt +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/benchmarks/README.md +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/config/README.md +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/config/requirements-arm-mac.txt +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/config/requirements-base.txt +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/config/requirements-devbio-napari-arm-mac.txt +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/config/requirements-devbio-napari.txt +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/_common.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/analysis_steps.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/brightfield_steps.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/invitro_steps.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/io_steps.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/preprocessing_steps.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch/steps/segmentation_steps.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch_processor.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/batch_step_registry.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/data/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/data/data_modules.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/czi_seam.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/dialogs.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/file_io.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/frap_io.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/image_reader.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/image_source.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/image_structure.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/lazy_guard.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/lazy_sources.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/load_channel_identity.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/local_cache.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/metadata_extract.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/multidim_io.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/naming.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/napari_adapter.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/czi_bioformats.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/image_reader_2d.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/ims_reader.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/mask_reader.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/stack_layer_builders.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/stack_metadata.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/routing.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/scenes.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/session.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/session_loader.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/session_manifest.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/sidecar_discovery.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/stack_access.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/stack_load.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/stack_openers.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/storage_probe.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/tagging.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/tiff_planes.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/tifffile_zarr_shim.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/viewer_load.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/writers.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/zarr_compat.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/fix_tifffile.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/icons/pycat_logo_512.png +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/icons/pycat_mark.png +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/adapters.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/canonical.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/capabilities.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/context.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/contracts.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/data/PyCAT_layer_tag_hierarchy_and_module_flow.xlsx +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/data/PyCAT_module_information_contracts.xlsx +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/data/PyCAT_question_tree_and_method_mapping.xlsx +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/data/operation_catalog.json +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/execution.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/gates.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/loader.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/modules.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/op_catalog.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/operation_spec.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/planner.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/quality_gates.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/question_engine.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/registry.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/scientific_tree.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/session.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/navigator/tags.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/run_pycat.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/advanced_analysis_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/analysis_plots.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/batch_roi_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/benchmark_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/biological_qc_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/brightfield_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/brightfield_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/clean_spot_detection_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_modes.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/coarsening.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/frame_quality.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/intensity.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/moduli.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/msd.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/photobleaching.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/relaxation.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics/survival.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/condensate_physics_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/contrast_cascade_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/contrast_cascade_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/control_validation.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/correlation_func_analysis_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/data_qc_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/data_qc_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/data_viz_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/drawing_layers.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/dynamic_spatial_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/fd_curve_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/fd_curve_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/feature_analysis_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/feature_redundancy.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/fft_bandpass_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/fibril_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/fibril_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/frap_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/frap_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/fusion_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/fusion_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/gaussian_localization_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/general_image_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/gpu_utils.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/_base.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/background.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/deblur.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/filters.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/preprocessing.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/size_estimation.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing/upscaling.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/image_processing_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/intensity_profile_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro/analysis.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro/field_summary.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro/partition.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro/size_distribution.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro_bf_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro_fluor_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/invitro_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/kymograph_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/label_and_mask_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/layer_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/measurement_stability.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/molecular_counting_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/morphological_complexity_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/nb_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/nb_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/numba_utils.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/obj_based_coloc_analysis_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/organizational_metrics_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/partial_volume_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/partition_enrichment_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/pipeline_diagnostic_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/pipeline_snr_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/pixel_wise_corr_analysis_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/qc_gallery.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/qc_gallery_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/ratiometric_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/scan_qc_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/_common.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/cellpose.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/fz.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/intensity.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/local_thresholding.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/morphology.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/puncta_refinement.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/subcellular.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation/watershed.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation_scale_advisor.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/segmentation_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/smlm_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/spatial_acf_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/spatial_metrology_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/spatial_metrology_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/spatial_randomness_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/spida_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/spida_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/temperature_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/temperature_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/temporal_enhancement_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries/analysis.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries/correlation.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries/execution.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries/frame_access.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries/preprocessing.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries/ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries_condensate_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries_invitro_fluor_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/timeseries_invitro_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/topology_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/trackmate_bridge.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/ts_cache_manager.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/ts_cellpose_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/two_channel_coloc_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/unmixing_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/video_export_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/analysis.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/detection.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/drift.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/host.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/msd_adapter.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/napari_adapter.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/panels.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/populations.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/results_dock.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/table_adapter.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt/viscosity.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/vpt_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/zstack_segmentation_tools.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/toolbox/zstack_segmentation_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/brushable_table.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/brushable_workspace.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/channel_identity_dialog.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/comparative_figures_ui.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/coordinate_readout.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/feature_explorer_dock.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/field_status.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/home_dock.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/linked_selection_dock.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/menu_manager.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/metadata_contradiction_panel.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/operation_gating.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/preferences_dialog.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/preset_picker.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/scene_switcher.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_analysis_mixin.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_diagnostics_mixin.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_filtering_mixin.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_imageops_mixin.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_labels_mixin.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_modules.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_segmentation_mixin.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/ui_utils.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/ui/workflow_checklist.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/__init__.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/analysis_presets.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/app_mode.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/batch_brushing.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/brushing.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/calibration.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/channel_designations.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/channel_modality.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/channel_naming.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/cohort_targets.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/comparative_figures.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/comparative_stats.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/consolidated_table.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/dataset_identity.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/dock_space.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/entity_ref.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/entity_registry.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/environment_check.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/errors.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/feature_cards.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/feature_explorer.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/feature_families.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/feature_provenance.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/feature_registry.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/field_registry_hub.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/figure_refine.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/figure_spec.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/filter_store.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/fit_quality.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/frame_interval.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/general_utils.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/intensity_semantics.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/layer_bindings.json +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/layer_tag_hook.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/layer_tags.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/logging_utils.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/marker_logic.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/math_utils.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/measurement.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/measurement_ontology.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/metadata_contradictions.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/metadata_validity.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/notify.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/object_graph.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/object_ref.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/operation_runner.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/pixel_size.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/plot_backend_pyqtgraph.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/plot_backend_selection.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/plot_backends.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/preferences.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/qt_worker.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/quality_gate.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/reliability.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/result_models.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/results_store.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/sample_metadata.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/selection_overlay.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/selection_service.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/tag_registry.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/tag_resolver.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/utils/user_settings.py +0 -0
- {pycat_napari-1.6.330 → pycat_napari-1.6.332}/tests/README.md +0 -0
|
@@ -1,3 +1,49 @@
|
|
|
1
|
+
## [1.6.332] - 2026-07-24
|
|
2
|
+
### Added — **Navigator execution-adapter layer, Phase 1: "Run analysis" computes a plan through the batch handlers, gate-respecting (guided == batch == manual).**
|
|
3
|
+
`selection_scale` Part 2 established there is no uniform "run this op" — but the batch `_STEP_MAP` handlers ARE
|
|
4
|
+
the proven "same computation" route (uniform `(state, image_path, params, output_dir)`; `test_route_equivalence`
|
|
5
|
+
asserts batch == manual). This ships the executor that drives them:
|
|
6
|
+
- New Qt-free **`navigator/executor.py`**: `run_plan(plan, state, …)` executes a compiled plan by driving the
|
|
7
|
+
batch handlers in the gate-respecting order (`execution.execution_order`), threading each step's output
|
|
8
|
+
through a shared `state` as a batch replay does. An `ExecAdapter` maps a plan step to a batch handler and
|
|
9
|
+
derives its params; **a step with no adapter is reported ('needs_panel'), never invoked with guessed
|
|
10
|
+
arguments** — the whole point of an adapter layer over a generic `fn(image)` (which would produce wrong
|
|
11
|
+
science silently). Gate semantics are READ from `execution_order`: a blocker halts the run (state untouched),
|
|
12
|
+
a caveat runs with its reason, probes first.
|
|
13
|
+
- **One proven adapter (`background_removal`)** — the shortest chain `test_route_equivalence` covers — so the
|
|
14
|
+
acceptance gate is pinned: `tests/navigator/test_navigator_executor.py` (`base`, 5) asserts **guided == batch
|
|
15
|
+
== manual, bit for bit**, plus a blocker halts + leaves state untouched, a caveat runs, and an uncovered step
|
|
16
|
+
is reported not invoked.
|
|
17
|
+
- **The Run button is wired** (`run_plan_via_central_manager`, passed as `on_run` from `central_manager`):
|
|
18
|
+
adapter-covered steps run through the batch handlers; uncovered steps are reported "run these from their
|
|
19
|
+
method panels, in order". Safe on an uncovered plan (nothing runs); best-effort.
|
|
20
|
+
- **Later phases** (per the `navigator_execution_adapters` spec): a parameter-review panel, more adapters one
|
|
21
|
+
workflow at a time (each behind its own route-equivalence test), and dock progress/cancel.
|
|
22
|
+
|
|
23
|
+
## [1.6.331] - 2026-07-24
|
|
24
|
+
### Added — **Save an answered guided plan as a reusable method template (selection_scale Part 3).**
|
|
25
|
+
The navigator's payoff: a plan the user likes should be reusable on other data without re-answering. A guided
|
|
26
|
+
template IS a preset with provenance about how it was authored — so it follows the `analysis_presets`
|
|
27
|
+
discipline (it records the ANSWERS that produced it) but, being a user-level artefact that survives sessions,
|
|
28
|
+
lives in the general `user_settings` service rather than the hardcoded, sensitivity-validated preset registry.
|
|
29
|
+
- New Qt-free **`navigator/templates.py`**: `GuidedTemplate` (name, observables, target, the question trail,
|
|
30
|
+
step names, parameters) + `template_from_plan` / `save_template` / `list_templates` / `load_template` /
|
|
31
|
+
`delete_template` / `rename_template` (never overwrites), persisted under `user_settings` key
|
|
32
|
+
`navigator.templates`.
|
|
33
|
+
- **The verdicts are deliberately NOT stored.** A quality-gate verdict is a property of the DATA, not the
|
|
34
|
+
plan — a template runnable on one dataset may be blocked on another — so applying a template
|
|
35
|
+
(`intent_from_template` → recompile against the new context) **re-evaluates every gate**. Carrying a verdict
|
|
36
|
+
over would assert quality never checked on this data. A corrupt template entry degrades to "not available"
|
|
37
|
+
(skipped), never a crash.
|
|
38
|
+
- **Reachable**: a '💾 Save as template…' button in the navigator plan view persists the current answers under
|
|
39
|
+
a user-supplied name.
|
|
40
|
+
- Tests: `tests/navigator/test_navigator_templates.py` (`base`, 7 — save+reload carries steps and answers,
|
|
41
|
+
applying to a different dataset re-evaluates the gates, verdicts absent, persistence across sessions,
|
|
42
|
+
delete/rename-never-overwrites, corrupt-degrades) + a dock integration test for the Save button. Full
|
|
43
|
+
core-or-base green.
|
|
44
|
+
- **Follow-on:** the template-picker UI (start a new analysis FROM a saved template — the apply half's UI; the
|
|
45
|
+
mechanism is done and tested).
|
|
46
|
+
|
|
1
47
|
## [1.6.330] - 2026-07-24
|
|
2
48
|
### Added — **Gate-respecting execution model for a guided plan, and an actionable run order in the dock (selection_scale Part 2).**
|
|
3
49
|
Part 2 asked to wire the navigator's Run button to execute the compiled plan "through the existing execution
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycat-napari
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.332
|
|
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.
|
|
7
|
+
version = "1.6.332"
|
|
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).
|
|
@@ -119,9 +119,12 @@ class CentralManager:
|
|
|
119
119
|
getattr(self.menu_manager, 'file_menu', None),
|
|
120
120
|
getattr(getattr(self.viewer, 'window', None), '_qt_window', None))
|
|
121
121
|
# Navigator: guided-analysis dock (question flow -> quality-gated, editable plan). Entry point here,
|
|
122
|
-
# not the line-capped menu god-file.
|
|
123
|
-
from
|
|
124
|
-
|
|
122
|
+
# not the line-capped menu god-file. Run analysis is wired through the execution-adapter layer (Phase
|
|
123
|
+
# 1): adapter-covered steps run via the batch handlers, the rest are reported "run from your panel".
|
|
124
|
+
from pycat.ui.navigator_dock import install_navigator_action, run_plan_via_central_manager
|
|
125
|
+
self._navigator_action = install_navigator_action(
|
|
126
|
+
self.viewer, central_manager=self,
|
|
127
|
+
on_run=lambda plan: run_plan_via_central_manager(self, plan))
|
|
125
128
|
# Populate the feature registry so any consumer (the beginner home dock, a capability query) sees
|
|
126
129
|
# every surfaced-but-otherwise-hidden feature (navigator inc 4). Guarded: a registration hiccup must
|
|
127
130
|
# never break startup, and the cards' openers import Qt/toolbox lazily so this stays cheap.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""**Execute a compiled navigator plan by driving the BATCH step handlers** (execution-adapter layer, Phase 1).
|
|
2
|
+
|
|
3
|
+
`selection_scale` Part 2 established there is no uniform "run this op" — PyCAT operations have bespoke,
|
|
4
|
+
panel-collected signatures. But the **batch `_STEP_MAP` handlers** are the proven "same computation" route:
|
|
5
|
+
they share one signature — ``(state, image_path, params, output_dir)`` — and `test_route_equivalence` already
|
|
6
|
+
asserts they compute byte-identically to the manual GUI route. So the executor drives *those* handlers, in the
|
|
7
|
+
gate-respecting order (`execution.execution_order`), threading each step's output through a shared ``state``
|
|
8
|
+
dict exactly as a batch replay does.
|
|
9
|
+
|
|
10
|
+
The narrow bridge is per-step: an :class:`ExecAdapter` maps a plan step to a batch handler and derives that
|
|
11
|
+
handler's ``params`` from the answers. A plan step with **no adapter is reported** ("run it from its method
|
|
12
|
+
panel"), never invoked with guessed arguments — a `fn(image)` fallback would pass wrong args and produce wrong
|
|
13
|
+
science silently, which is the whole reason this is an adapter layer and not a loop over ``resolve_operation``.
|
|
14
|
+
|
|
15
|
+
Phase 1 ships the executor + registry + ONE proven adapter (``background_removal`` — the shortest chain
|
|
16
|
+
`test_route_equivalence` already covers), so `guided == batch == manual` is pinned; later phases add adapters
|
|
17
|
+
one workflow at a time, each earning its place with a route-equivalence test. Qt-free; a runner is optional
|
|
18
|
+
(off-thread when given, synchronous otherwise)."""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import dataclasses
|
|
22
|
+
import pathlib
|
|
23
|
+
import tempfile
|
|
24
|
+
from typing import Callable, Optional
|
|
25
|
+
|
|
26
|
+
from .execution import execution_order
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclasses.dataclass(frozen=True)
|
|
30
|
+
class ExecAdapter:
|
|
31
|
+
"""Bridges ONE plan step to the batch handler that computes it. ``params_from(intent, ctx, state)`` derives
|
|
32
|
+
the handler's ``params`` from the answers (Phase 1: grounded defaults; a preset seed lands in Phase 2)."""
|
|
33
|
+
plan_step: str
|
|
34
|
+
batch_step: str
|
|
35
|
+
params_from: Callable
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _background_removal_params(intent, ctx, state):
|
|
39
|
+
radius = None
|
|
40
|
+
try:
|
|
41
|
+
radius = ctx.get("ball_radius") if ctx is not None else None
|
|
42
|
+
except Exception: # broad-ok: optional_probe — a context miss falls back to the grounded default
|
|
43
|
+
radius = None
|
|
44
|
+
return {"ball_radius": int(radius) if radius else 50, "active_layer": "segmentation image"}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
#: The declared adapters. The ONLY place a plan step is tied to a computation — a step absent here is reported
|
|
48
|
+
#: as "run from its panel", never guessed at. Grows one workflow per phase (each behind a route-equivalence test).
|
|
49
|
+
_ADAPTERS: dict = {
|
|
50
|
+
"background_removal": ExecAdapter("background_removal", "background_removal", _background_removal_params),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def has_adapter(step_name: str) -> bool:
|
|
55
|
+
return step_name in _ADAPTERS
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclasses.dataclass(frozen=True)
|
|
59
|
+
class StepOutcome:
|
|
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'``."""
|
|
62
|
+
name: str
|
|
63
|
+
outcome: str
|
|
64
|
+
detail: str = ""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclasses.dataclass
|
|
68
|
+
class ExecReport:
|
|
69
|
+
steps: list = dataclasses.field(default_factory=list)
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def ran(self) -> list:
|
|
73
|
+
return [s for s in self.steps if s.outcome.startswith("ran")]
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def stopped(self) -> bool:
|
|
77
|
+
return any(s.outcome in ("blocked", "error") for s in self.steps)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def needs_panel(self) -> list:
|
|
81
|
+
return [s for s in self.steps if s.outcome == "needs_panel"]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _build_step_registry() -> dict:
|
|
85
|
+
"""The production batch step registry (name → replay handler), built the way `BatchProcessor` does. Only
|
|
86
|
+
the import-clean `batch_step_registry` is touched (no Qt)."""
|
|
87
|
+
registry: dict = {}
|
|
88
|
+
|
|
89
|
+
class _Recorder:
|
|
90
|
+
def register_step(self, name, fn):
|
|
91
|
+
registry[name] = fn
|
|
92
|
+
|
|
93
|
+
from pycat.batch_step_registry import register_all_steps
|
|
94
|
+
register_all_steps(_Recorder())
|
|
95
|
+
return registry
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def run_plan(plan, state, *, intent=None, ctx=None, image_path=None, output_dir=None, runner=None,
|
|
99
|
+
on_step: Optional[Callable] = None) -> ExecReport:
|
|
100
|
+
"""Execute ``plan``'s steps in gate order by driving the batch handlers, threading ``state`` (a dict the
|
|
101
|
+
handlers read/write, exactly as a batch replay). Returns an :class:`ExecReport`.
|
|
102
|
+
|
|
103
|
+
Gate semantics are READ from :func:`execution.execution_order`, never re-decided: a **blocker** stops the
|
|
104
|
+
run at that step (nothing after it runs); a **caveat** runs with the caveat recorded; **probes** run first.
|
|
105
|
+
A step with no :class:`ExecAdapter` is reported ``'needs_panel'`` — never invoked with guessed arguments.
|
|
106
|
+
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)."""
|
|
108
|
+
intent = intent if intent is not None else getattr(plan, "intent", None)
|
|
109
|
+
registry = _build_step_registry()
|
|
110
|
+
report = ExecReport()
|
|
111
|
+
|
|
112
|
+
tmp = None
|
|
113
|
+
if output_dir is None:
|
|
114
|
+
tmp = tempfile.TemporaryDirectory()
|
|
115
|
+
output_dir = pathlib.Path(tmp.name)
|
|
116
|
+
if image_path is None:
|
|
117
|
+
image_path = pathlib.Path(output_dir) / "sample.tif"
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
halted = False
|
|
121
|
+
for es in execution_order(plan):
|
|
122
|
+
if halted or es.status == "skipped":
|
|
123
|
+
report.steps.append(StepOutcome(es.name, "skipped", es.reason))
|
|
124
|
+
continue
|
|
125
|
+
if es.status == "blocked":
|
|
126
|
+
report.steps.append(StepOutcome(es.name, "blocked", es.reason))
|
|
127
|
+
halted = True
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
adapter = _ADAPTERS.get(es.name)
|
|
131
|
+
if adapter is None:
|
|
132
|
+
report.steps.append(StepOutcome(
|
|
133
|
+
es.name, "needs_panel", "no execution adapter yet — run this step from its method panel"))
|
|
134
|
+
if on_step:
|
|
135
|
+
on_step(report.steps[-1])
|
|
136
|
+
continue
|
|
137
|
+
|
|
138
|
+
fn = registry.get(adapter.batch_step)
|
|
139
|
+
if fn is None:
|
|
140
|
+
report.steps.append(StepOutcome(es.name, "error",
|
|
141
|
+
f"batch step {adapter.batch_step!r} is not registered"))
|
|
142
|
+
halted = True
|
|
143
|
+
continue
|
|
144
|
+
|
|
145
|
+
params = adapter.params_from(intent, ctx, state)
|
|
146
|
+
try:
|
|
147
|
+
if runner is not None:
|
|
148
|
+
runner.execute(fn, state, image_path, params, output_dir)
|
|
149
|
+
else:
|
|
150
|
+
fn(state, image_path, params, output_dir)
|
|
151
|
+
except Exception as exc: # broad-ok: scientific_result — a failed step halts; report it, never silently continue on stale state
|
|
152
|
+
report.steps.append(StepOutcome(es.name, "error", f"{type(exc).__name__}: {exc}"))
|
|
153
|
+
halted = True
|
|
154
|
+
continue
|
|
155
|
+
|
|
156
|
+
report.steps.append(StepOutcome(
|
|
157
|
+
es.name, "ran_with_caveat" if es.status == "caveat" else "ran", es.reason))
|
|
158
|
+
if on_step:
|
|
159
|
+
on_step(report.steps[-1])
|
|
160
|
+
finally:
|
|
161
|
+
if tmp is not None:
|
|
162
|
+
tmp.cleanup()
|
|
163
|
+
return report
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""**Save an answered guided plan as a reusable method template** (selection_scale Part 3).
|
|
2
|
+
|
|
3
|
+
The navigator's payoff: the questionnaire produces a plan, and a plan the user likes should be reusable on
|
|
4
|
+
other data without re-answering. A guided template *is* a preset with provenance about how it was authored —
|
|
5
|
+
so it follows the ``analysis_presets`` discipline (it records WHERE it came from: the answers that produced
|
|
6
|
+
it) but is a **user-level, per-session-surviving** artefact, so it lives in the general ``user_settings``
|
|
7
|
+
service rather than the hardcoded, sensitivity-validated ``ANALYSIS_PRESETS`` registry.
|
|
8
|
+
|
|
9
|
+
**What is stored, and what is deliberately NOT.** A template stores the ANSWERS (the intent: observables,
|
|
10
|
+
target, and the question trail) plus the step names the plan produced and any parameters the user set. It does
|
|
11
|
+
**not** store the quality-gate verdicts. Those are a property of the DATA, not the plan — a template runnable
|
|
12
|
+
on one dataset may be blocked on another — so applying a template re-compiles the intent against the new
|
|
13
|
+
data's context, which re-evaluates every gate. Carrying a verdict over would assert quality that was never
|
|
14
|
+
checked here. A corrupt template entry degrades to "not available" (skipped), never a crash.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import dataclasses
|
|
19
|
+
|
|
20
|
+
from .contracts import AnalysisIntent
|
|
21
|
+
|
|
22
|
+
#: user_settings key holding ``{name: serialized_template}``.
|
|
23
|
+
_STORE_KEY = "navigator.templates"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclasses.dataclass(frozen=True)
|
|
27
|
+
class GuidedTemplate:
|
|
28
|
+
"""A saved guided plan. ``question`` is the answer trail that produced it — its provenance, so a user
|
|
29
|
+
revisiting the template can see WHY the steps are there and edit the answers to regenerate rather than
|
|
30
|
+
hand-edit steps. ``steps`` is the ordered step names the plan produced (for display / provenance);
|
|
31
|
+
``parameters`` are any values the user adjusted. Gate verdicts are intentionally absent — they are
|
|
32
|
+
re-evaluated against the data a template is applied to."""
|
|
33
|
+
name: str
|
|
34
|
+
observables: tuple = ()
|
|
35
|
+
target: str = None
|
|
36
|
+
question: str = ""
|
|
37
|
+
steps: tuple = ()
|
|
38
|
+
parameters: dict = dataclasses.field(default_factory=dict)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def template_from_plan(name, intent, plan, *, parameters=None) -> GuidedTemplate:
|
|
42
|
+
"""Build a template from an answered ``intent`` and the ``plan`` it compiled to (the answers + the ordered
|
|
43
|
+
step names). No verdicts are captured — see the module docstring."""
|
|
44
|
+
return GuidedTemplate(
|
|
45
|
+
name=str(name),
|
|
46
|
+
observables=tuple(getattr(intent, "observables", ()) or ()),
|
|
47
|
+
target=getattr(intent, "target", None),
|
|
48
|
+
question=getattr(intent, "question", "") or "",
|
|
49
|
+
steps=tuple(s.name for s in getattr(plan, "steps", ())),
|
|
50
|
+
parameters=dict(parameters or {}))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def intent_from_template(template) -> AnalysisIntent:
|
|
54
|
+
"""Reconstruct the answers as a fresh :class:`AnalysisIntent`. Compile this against the CURRENT data's
|
|
55
|
+
context to re-run every quality gate — a template blocked on the new data reports it, because the verdicts
|
|
56
|
+
were never stored."""
|
|
57
|
+
return AnalysisIntent(target=template.target, observables=list(template.observables),
|
|
58
|
+
question=template.question)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# ── persistence via user_settings (survives sessions, applies across datasets) ───────────────────────
|
|
62
|
+
|
|
63
|
+
def _store(store):
|
|
64
|
+
if store is not None:
|
|
65
|
+
return store
|
|
66
|
+
from pycat.utils.user_settings import settings
|
|
67
|
+
return settings()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _serialize(t: GuidedTemplate) -> dict:
|
|
71
|
+
return {"name": t.name, "observables": list(t.observables), "target": t.target,
|
|
72
|
+
"question": t.question, "steps": list(t.steps), "parameters": dict(t.parameters)}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _deserialize(d) -> "GuidedTemplate | None":
|
|
76
|
+
try:
|
|
77
|
+
return GuidedTemplate(
|
|
78
|
+
name=str(d["name"]),
|
|
79
|
+
observables=tuple(d.get("observables") or ()),
|
|
80
|
+
target=d.get("target"),
|
|
81
|
+
question=str(d.get("question") or ""),
|
|
82
|
+
steps=tuple(d.get("steps") or ()),
|
|
83
|
+
parameters=dict(d.get("parameters") or {}))
|
|
84
|
+
except Exception: # broad-ok: optional_probe — a corrupt entry degrades to "not available", not a crash
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _read_all(store) -> dict:
|
|
89
|
+
raw = _store(store).get(_STORE_KEY, {}) or {}
|
|
90
|
+
return raw if isinstance(raw, dict) else {}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def save_template(template: GuidedTemplate, *, store=None) -> GuidedTemplate:
|
|
94
|
+
"""Persist ``template`` under its name (overwriting a same-named one). Returns it."""
|
|
95
|
+
s = _store(store)
|
|
96
|
+
all_ = _read_all(s)
|
|
97
|
+
all_[template.name] = _serialize(template)
|
|
98
|
+
s.set(_STORE_KEY, all_)
|
|
99
|
+
return template
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def list_templates(*, store=None) -> list:
|
|
103
|
+
"""Every saved template, name-sorted; corrupt entries are skipped (degrade to 'not available')."""
|
|
104
|
+
out = [_deserialize(v) for v in _read_all(store).values()]
|
|
105
|
+
return sorted((t for t in out if t is not None), key=lambda t: t.name.lower())
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def load_template(name, *, store=None):
|
|
109
|
+
"""The named template, or ``None`` if absent or corrupt."""
|
|
110
|
+
return _deserialize(_read_all(store).get(name))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def delete_template(name, *, store=None) -> bool:
|
|
114
|
+
"""Remove the named template. Returns True if it existed."""
|
|
115
|
+
s = _store(store)
|
|
116
|
+
all_ = _read_all(s)
|
|
117
|
+
if name not in all_:
|
|
118
|
+
return False
|
|
119
|
+
del all_[name]
|
|
120
|
+
s.set(_STORE_KEY, all_)
|
|
121
|
+
return True
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def rename_template(old_name, new_name, *, store=None) -> bool:
|
|
125
|
+
"""Rename ``old_name`` to ``new_name``. No-op (False) if the source is absent or the target already
|
|
126
|
+
exists — renaming must never silently overwrite another template."""
|
|
127
|
+
s = _store(store)
|
|
128
|
+
all_ = _read_all(s)
|
|
129
|
+
if old_name not in all_ or new_name in all_ or not str(new_name).strip():
|
|
130
|
+
return False
|
|
131
|
+
entry = dict(all_.pop(old_name))
|
|
132
|
+
entry["name"] = str(new_name)
|
|
133
|
+
all_[str(new_name)] = entry
|
|
134
|
+
s.set(_STORE_KEY, all_)
|
|
135
|
+
return True
|
|
@@ -128,6 +128,34 @@ 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):
|
|
132
|
+
"""Execute a compiled plan against the session's data through the execution-adapter layer, and report
|
|
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``."""
|
|
136
|
+
try:
|
|
137
|
+
from pycat.navigator.executor import run_plan
|
|
138
|
+
dr = getattr(getattr(central_manager, "active_data_class", None), "data_repository", None)
|
|
139
|
+
if dr is None:
|
|
140
|
+
return
|
|
141
|
+
report = run_plan(plan, dr, ctx=dr)
|
|
142
|
+
ran = [s.name for s in report.ran]
|
|
143
|
+
panel = [s.name for s in report.needs_panel]
|
|
144
|
+
blocked = [s for s in report.steps if s.outcome == "blocked"]
|
|
145
|
+
parts = []
|
|
146
|
+
if ran:
|
|
147
|
+
parts.append("Ran: " + ", ".join(ran) + ".")
|
|
148
|
+
if blocked:
|
|
149
|
+
parts.append(f"Stopped at {blocked[0].name} — {blocked[0].detail}")
|
|
150
|
+
if panel:
|
|
151
|
+
parts.append("Run these from their method panels, in order: " + ", ".join(panel) + ".")
|
|
152
|
+
from napari.utils.notifications import show_info
|
|
153
|
+
show_info(" ".join(parts) or "Nothing to run.")
|
|
154
|
+
except Exception as exc: # broad-ok: ui_cleanup — a run attempt must never crash the guided panel
|
|
155
|
+
from pycat.utils.general_utils import debug_log
|
|
156
|
+
debug_log("navigator: run_plan_via_central_manager failed", exc)
|
|
157
|
+
|
|
158
|
+
|
|
131
159
|
def _guided_run_note(plan):
|
|
132
160
|
"""The honest guided-run message, made ACTIONABLE with the gate-respecting run ORDER. Auto-running the
|
|
133
161
|
whole plan needs a per-operation execution adapter (PyCAT ops have bespoke, panel-collected signatures —
|
|
@@ -144,6 +172,33 @@ def _guided_run_note(plan):
|
|
|
144
172
|
return msg + (f", in this order:\n{order}." if order else ".")
|
|
145
173
|
|
|
146
174
|
|
|
175
|
+
def _add_template_save(widget, body_layout):
|
|
176
|
+
"""Add a 'Save as template…' button that persists the answered plan under a user-supplied name (the answers
|
|
177
|
+
+ step names, NOT the gate verdicts — see navigator.templates). Reusable on other data without
|
|
178
|
+
re-answering. Best-effort: a save failure never breaks the plan view."""
|
|
179
|
+
from PyQt5.QtWidgets import QPushButton, QInputDialog
|
|
180
|
+
|
|
181
|
+
def _save():
|
|
182
|
+
try:
|
|
183
|
+
name, ok = QInputDialog.getText(widget, "Save guided template", "Template name:")
|
|
184
|
+
if not ok or not str(name).strip():
|
|
185
|
+
return
|
|
186
|
+
from pycat.navigator.templates import template_from_plan, save_template
|
|
187
|
+
plan = widget._session.compile_plan()
|
|
188
|
+
save_template(template_from_plan(str(name).strip(), widget._session.intent, plan))
|
|
189
|
+
from napari.utils.notifications import show_info
|
|
190
|
+
show_info(f"Saved guided template '{str(name).strip()}' — reuse it on other data from Home.")
|
|
191
|
+
except Exception as exc: # broad-ok: ui_cleanup — a save failure must not break the plan view
|
|
192
|
+
from pycat.utils.general_utils import debug_log
|
|
193
|
+
debug_log("navigator: could not save the template", exc)
|
|
194
|
+
|
|
195
|
+
btn = QPushButton("\U0001f4be Save as template…") # 💾
|
|
196
|
+
btn.setToolTip("Save these answers as a reusable method template — apply it to other data without "
|
|
197
|
+
"re-answering (the quality gates re-evaluate on the new data).")
|
|
198
|
+
btn.clicked.connect(_save)
|
|
199
|
+
body_layout.addWidget(btn)
|
|
200
|
+
|
|
201
|
+
|
|
147
202
|
def build_navigator_widget(session, *, on_run=None, central_manager=None, parent=None):
|
|
148
203
|
"""Build (do not mount) the Navigator widget over ``session``, or return ``None`` if Qt is unavailable
|
|
149
204
|
(headless). ``on_run(plan)`` is called when the user runs the compiled plan. When ``central_manager`` is
|
|
@@ -226,6 +281,7 @@ def build_navigator_widget(session, *, on_run=None, central_manager=None, parent
|
|
|
226
281
|
over = QPushButton("↺ Start over")
|
|
227
282
|
over.clicked.connect(_restart)
|
|
228
283
|
body_layout.addWidget(over)
|
|
284
|
+
_add_template_save(widget, body_layout)
|
|
229
285
|
|
|
230
286
|
def _answer(spec, value):
|
|
231
287
|
widget._session.answer(spec, value)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pycat_napari-1.6.330 → pycat_napari-1.6.332}/src/pycat/file_io/readers/stack_layer_builders.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|