reader-workbench 1.0.0__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.
- reader_workbench-1.0.0/CITATION.cff +10 -0
- reader_workbench-1.0.0/LICENSE +21 -0
- reader_workbench-1.0.0/MANIFEST.in +2 -0
- reader_workbench-1.0.0/PKG-INFO +91 -0
- reader_workbench-1.0.0/README.md +55 -0
- reader_workbench-1.0.0/assets/reader-banner.png +0 -0
- reader_workbench-1.0.0/pyproject.toml +128 -0
- reader_workbench-1.0.0/setup.cfg +4 -0
- reader_workbench-1.0.0/src/reader_workbench/__init__.py +22 -0
- reader_workbench-1.0.0/src/reader_workbench/__main__.py +4 -0
- reader_workbench-1.0.0/src/reader_workbench/_version.py +17 -0
- reader_workbench-1.0.0/src/reader_workbench/api/__init__.py +74 -0
- reader_workbench-1.0.0/src/reader_workbench/api/_record_reads.py +75 -0
- reader_workbench-1.0.0/src/reader_workbench/api/artifacts.py +79 -0
- reader_workbench-1.0.0/src/reader_workbench/api/facade.py +538 -0
- reader_workbench-1.0.0/src/reader_workbench/api/models.py +285 -0
- reader_workbench-1.0.0/src/reader_workbench/api/notebooks.py +63 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/__init__.py +18 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/builtins/__init__.py +36 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/builtins/cytometry.py +140 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/builtins/four_state_event_window.py +214 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/builtins/generic.py +21 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/builtins/logic.py +149 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/builtins/plate_reader.py +47 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/catalog.py +257 -0
- reader_workbench-1.0.0/src/reader_workbench/contracts/model.py +109 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/__init__.py +1 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/__init__.py +3 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/analysis/__init__.py +29 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/analysis/events.py +182 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/analysis/gating.py +175 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/analysis/workflow.py +248 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/io/__init__.py +3 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/io/fcs.py +135 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/plots/__init__.py +5 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/cytometry/plots/diagnostic.py +155 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/__init__.py +3 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/crosstalk/__init__.py +3 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/crosstalk/pairs.py +661 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/__init__.py +7 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/builder.py +321 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/collection/__init__.py +20 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/collection/checks.py +49 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/collection/constants.py +29 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/collection/model.py +19 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/collection/render.py +383 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/collection/sources.py +185 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/config.py +214 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/diagnostic.py +361 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/heatmap.py +86 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/math.py +191 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/reference.py +85 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/selection.py +228 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/treatment_semantics.py +51 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/four_state_vector/validation.py +19 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/__init__.py +3 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/encodings.py +93 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/extract_corners.py +192 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/main.py +236 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/metrics.py +96 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/overlay.py +129 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/prep.py +138 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/logic_symmetry/render.py +356 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/logic/treatment_columns.py +42 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/__init__.py +1 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/__init__.py +14 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/fold_change.py +474 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/__init__.py +21 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/aggregation.py +191 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/contract_fields.py +50 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/contracts.py +320 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/design_dispositions.py +54 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/disposition_records.py +140 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/event_sensitivity.py +27 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/materialize.py +274 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/observation_resampling.py +97 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/reduction.py +62 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/seeds.py +15 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/sources.py +308 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/well_exclusion_validation.py +94 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/four_state_event_window/well_exclusions.py +54 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/analysis/timepoints.py +76 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/io/__init__.py +6 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/io/sample_map.py +65 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/io/synergy_h1/__init__.py +6 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/io/synergy_h1/_kinetic.py +141 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/io/synergy_h1/_parser.py +295 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/io/synergy_h1/_shared.py +195 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/io/synergy_h1/_snapshot.py +130 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/ordering.py +59 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/__init__.py +15 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/_data.py +29 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/common.py +346 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/distributions.py +324 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/dual_reporter_triptych.py +525 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/dual_reporter_triptych_render.py +195 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/four_state_event_window/__init__.py +26 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic.py +295 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic_components.py +149 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic_render.py +308 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic_style.py +51 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/four_state_event_window/schema.py +8 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/four_state_event_window/summary.py +140 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/grouping.py +53 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/panels/__init__.py +12 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/panels/snapshot.py +161 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/panels/snapshot_data.py +91 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/panels/time_series.py +296 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/single_reporter_diagnostic.py +435 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/single_reporter_diagnostic_render.py +300 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/snapshot_barplot/__init__.py +315 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/snapshot_barplot/planning.py +168 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/snapshot_heatmap/__init__.py +205 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/snapshot_heatmap/inputs.py +103 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/time_series.py +317 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/ts_and_snap/__init__.py +479 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/plate_reader/plots/ts_and_snap/planning.py +283 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/time_series/__init__.py +29 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/time_series/aggregation.py +60 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/time_series/contracts.py +368 -0
- reader_workbench-1.0.0/src/reader_workbench/domains/time_series/reduction.py +395 -0
- reader_workbench-1.0.0/src/reader_workbench/errors.py +55 -0
- reader_workbench-1.0.0/src/reader_workbench/maintenance/__init__.py +6 -0
- reader_workbench-1.0.0/src/reader_workbench/maintenance/docs.py +335 -0
- reader_workbench-1.0.0/src/reader_workbench/maintenance/model.py +28 -0
- reader_workbench-1.0.0/src/reader_workbench/maintenance/release.py +39 -0
- reader_workbench-1.0.0/src/reader_workbench/maintenance/skills.py +124 -0
- reader_workbench-1.0.0/src/reader_workbench/plotting/__init__.py +20 -0
- reader_workbench-1.0.0/src/reader_workbench/plotting/mpl.py +56 -0
- reader_workbench-1.0.0/src/reader_workbench/plotting/sinks.py +69 -0
- reader_workbench-1.0.0/src/reader_workbench/plotting/style.py +175 -0
- reader_workbench-1.0.0/src/reader_workbench/plotting/utils.py +27 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/__init__.py +1 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/catalog.py +33 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/export/__init__.py +0 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/export/_paths.py +21 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/export/csv.py +41 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/export/xlsx.py +44 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/ingest/__init__.py +0 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/ingest/_discovery.py +58 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/ingest/discovery_policy.py +66 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/ingest/flow_cytometer.py +139 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/ingest/synergy_h1.py +234 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/manifests/__init__.py +1 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/manifests/export.py +29 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/manifests/ingest.py +29 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/manifests/plot.py +161 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/manifests/transform.py +172 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/manifests/validator.py +18 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/__init__.py +0 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/_shared.py +55 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/cytometry_diagnostic.py +54 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/distributions.py +58 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/dual_reporter_triptych.py +224 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/four_state_event_window_diagnostic.py +133 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/four_state_event_window_summary.py +53 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/four_state_vector_collection.py +45 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/four_state_vector_diagnostic.py +105 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/four_state_vector_heatmap.py +63 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/logic_symmetry.py +56 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/single_reporter_diagnostic.py +279 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/snapshot_barplot.py +65 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/snapshot_heatmap.py +104 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/time_series.py +114 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/plot/ts_and_snap.py +210 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/__init__.py +0 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/_four_state_vector.py +204 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/_labeling.py +109 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/alias.py +70 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/assay_labels.py +62 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/blank.py +79 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/crosstalk_pairs.py +180 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/cytometry_gating.py +120 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/fold_change.py +79 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/four_state_event_window.py +93 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/four_state_vector.py +62 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/four_state_vector_collection.py +41 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/logic_symmetry.py +67 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/outlier_filter.py +60 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/overflow.py +197 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/ratio.py +237 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/sample_map.py +170 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/transform/sample_metadata.py +94 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/validator/__init__.py +1 -0
- reader_workbench-1.0.0/src/reader_workbench/plugins/validator/to_tidy_plus_map.py +155 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/__init__.py +80 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/_builtins_plate_reader_growth.py +179 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/_builtins_plate_reader_variants.py +274 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/builtins.py +1656 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compiler.py +22 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compilers/__init__.py +1 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compilers/common.py +100 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compilers/cytometry.py +87 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compilers/generic.py +14 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compilers/logic.py +245 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compilers/plate_reader.py +937 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/compilers/plate_reader_pipeline.py +197 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/model.py +1486 -0
- reader_workbench-1.0.0/src/reader_workbench/protocols/semantic_coverage.py +234 -0
- reader_workbench-1.0.0/src/reader_workbench/runtime/__init__.py +12 -0
- reader_workbench-1.0.0/src/reader_workbench/runtime/builtin.py +23 -0
- reader_workbench-1.0.0/src/reader_workbench/runtime/model.py +42 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/__init__.py +60 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/assets/__init__.py +22 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/assets/types.py +118 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/audit/__init__.py +5 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/audit/experiments.py +307 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/audit/staging.py +187 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/__init__.py +51 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/_lazy.py +9 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/_records_view.py +150 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/_surface_execution.py +443 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/audit.py +95 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/automation.py +229 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/demo.py +46 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/dop.py +91 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/experiments.py +635 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/helpers.py +232 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/main.py +59 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/maintenance.py +82 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/notebooks.py +260 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/pagination.py +117 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/protocols.py +336 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/shared.py +309 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/surfaces.py +534 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/cli/verification.py +128 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/commands.py +10 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/config/__init__.py +47 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/config/identity.py +13 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/config/load.py +405 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/config/model.py +274 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/context.py +26 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/decl/__init__.py +31 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/decl/build.py +190 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/decl/model.py +81 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/dop/__init__.py +12 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/dop/builtins.py +261 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/dop/model.py +209 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/__init__.py +42 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/_shared.py +76 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/contracts.py +283 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/execution.py +326 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/file_outputs.py +260 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/inputs.py +161 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/invocations.py +507 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/planning.py +72 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/runtime.py +464 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/setup.py +149 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/engine/validation.py +684 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/experiment/__init__.py +47 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/experiment/model.py +381 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/experiments.py +133 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/graph/__init__.py +47 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/graph/nodes.py +102 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/graph/normalize.py +177 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/graph/refs.py +148 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/input_discovery.py +19 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/__init__.py +3 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/catalogs.py +128 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/common.py +92 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/dop.py +64 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/experiments.py +449 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/inventory.py +68 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/protocols.py +368 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/readiness.py +333 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/reports.py +367 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/results.py +166 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/runtime.py +287 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/semantics.py +192 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/inspection/validation.py +30 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/__init__.py +17 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/_launch_registry.py +112 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/_launch_runtime.py +104 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/components/__init__.py +21 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/components/deliverables.py +403 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/components/overview.py +119 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/eda.marimo.py.txt +153 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/launch.py +274 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/presentation.py +136 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/notebooks/scaffold.py +60 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/ontology.py +78 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/paths.py +44 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/ports/__init__.py +31 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/ports/model.py +168 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/__init__.py +44 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/epoch.py +329 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/evidence.py +247 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/identity.py +87 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/locking.py +185 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/model.py +711 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/sources.py +73 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/store.py +1022 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/records/verification.py +998 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/registry.py +333 -0
- reader_workbench-1.0.0/src/reader_workbench/workbench/spec_overrides.py +215 -0
- reader_workbench-1.0.0/src/reader_workbench.egg-info/PKG-INFO +91 -0
- reader_workbench-1.0.0/src/reader_workbench.egg-info/SOURCES.txt +299 -0
- reader_workbench-1.0.0/src/reader_workbench.egg-info/dependency_links.txt +1 -0
- reader_workbench-1.0.0/src/reader_workbench.egg-info/entry_points.txt +2 -0
- reader_workbench-1.0.0/src/reader_workbench.egg-info/requires.txt +15 -0
- reader_workbench-1.0.0/src/reader_workbench.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "Cite Reader and record the exact version, source revision and artifact checksum used."
|
|
3
|
+
type: software
|
|
4
|
+
title: "Reader: validated, traceable analysis of experimental instrument data"
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: South
|
|
7
|
+
given-names: Eric J.
|
|
8
|
+
repository-code: "https://github.com/e-south/reader"
|
|
9
|
+
license: MIT
|
|
10
|
+
# pyproject.toml owns the version; the release workflow adds it to the bundle citation.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Eric South
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reader-workbench
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Validated, traceable analysis workflows for experimental instrument data
|
|
5
|
+
Author: Eric J. South
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://github.com/e-south/reader/tree/main/docs
|
|
8
|
+
Project-URL: Issues, https://github.com/e-south/reader/issues
|
|
9
|
+
Project-URL: Repository, https://github.com/e-south/reader
|
|
10
|
+
Keywords: data-analysis,data-pipelines,scientific-computing,workbench
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering
|
|
17
|
+
Requires-Python: <3.13,>=3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: numpy>=1.26
|
|
21
|
+
Requires-Dist: matplotlib>=3.8
|
|
22
|
+
Requires-Dist: pandas>=2.1
|
|
23
|
+
Requires-Dist: pydantic>=2.6
|
|
24
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
25
|
+
Requires-Dist: typer>=0.16.0
|
|
26
|
+
Requires-Dist: click>=8.3.3
|
|
27
|
+
Requires-Dist: rich>=13.7
|
|
28
|
+
Requires-Dist: pyarrow>=23.0.1
|
|
29
|
+
Requires-Dist: openpyxl>=3.1
|
|
30
|
+
Requires-Dist: seaborn>=0.13
|
|
31
|
+
Requires-Dist: pillow>=12.3.0
|
|
32
|
+
Requires-Dist: polars>=1.36.1
|
|
33
|
+
Requires-Dist: flowio>=1.4.0
|
|
34
|
+
Requires-Dist: filelock<4,>=3.20.3
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# 
|
|
38
|
+
|
|
39
|
+
[](https://github.com/e-south/reader/actions/workflows/checks.yaml)
|
|
40
|
+
[](https://www.python.org/downloads/release/python-3120/)
|
|
41
|
+
[](https://github.com/e-south/reader/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
Reader ingests instrument files and experiment metadata, applies declared
|
|
44
|
+
transformations, and writes validated records, plots, exports, and notebooks.
|
|
45
|
+
Every unit of work—including a cross-experiment aggregate—has an owned directory
|
|
46
|
+
beneath `experiments/`, with source material in `inputs/`, a `reader/v8`
|
|
47
|
+
contract in `config.yaml`, and generated artifacts in `outputs/`.
|
|
48
|
+
The distribution and import package are named `reader-workbench` and
|
|
49
|
+
`reader_workbench`; the installed command remains `reader`.
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
Install Reader as a command-line tool:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv tool install reader-workbench
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For development, install from a checkout:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
git clone https://github.com/e-south/reader.git
|
|
63
|
+
cd reader
|
|
64
|
+
uv sync --locked --group dev
|
|
65
|
+
uv run reader demo
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The installed command is `reader`:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
reader demo
|
|
72
|
+
reader protocols
|
|
73
|
+
reader init ./experiments/my_experiment --protocol plate_reader/single_reporter_screen
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The demo prints a guided command tour. It does not execute a pipeline or write
|
|
77
|
+
files. Every generated starter can be inspected and validated before data is
|
|
78
|
+
added.
|
|
79
|
+
|
|
80
|
+
## Learn more
|
|
81
|
+
|
|
82
|
+
- [Getting started](https://github.com/e-south/reader/blob/main/docs/guides/getting_started.md) — install Reader, run the
|
|
83
|
+
demo, and scaffold a first experiment.
|
|
84
|
+
- [Common tasks](https://github.com/e-south/reader/blob/main/docs/guides/common_routes.md) — shortest commands for
|
|
85
|
+
discovery, validation, execution, and automation.
|
|
86
|
+
- [Python API](https://github.com/e-south/reader/blob/main/docs/core/python_api.md) — typed, task-oriented experiment and
|
|
87
|
+
plugin interfaces for integrations.
|
|
88
|
+
- [Documentation index](https://github.com/e-south/reader/blob/main/docs/README.md) — complete user, reference, and
|
|
89
|
+
maintainer documentation.
|
|
90
|
+
|
|
91
|
+
Reader is available under the [MIT license](https://github.com/e-south/reader/blob/main/LICENSE).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# 
|
|
2
|
+
|
|
3
|
+
[](https://github.com/e-south/reader/actions/workflows/checks.yaml)
|
|
4
|
+
[](https://www.python.org/downloads/release/python-3120/)
|
|
5
|
+
[](https://github.com/e-south/reader/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
Reader ingests instrument files and experiment metadata, applies declared
|
|
8
|
+
transformations, and writes validated records, plots, exports, and notebooks.
|
|
9
|
+
Every unit of work—including a cross-experiment aggregate—has an owned directory
|
|
10
|
+
beneath `experiments/`, with source material in `inputs/`, a `reader/v8`
|
|
11
|
+
contract in `config.yaml`, and generated artifacts in `outputs/`.
|
|
12
|
+
The distribution and import package are named `reader-workbench` and
|
|
13
|
+
`reader_workbench`; the installed command remains `reader`.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
Install Reader as a command-line tool:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uv tool install reader-workbench
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For development, install from a checkout:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone https://github.com/e-south/reader.git
|
|
27
|
+
cd reader
|
|
28
|
+
uv sync --locked --group dev
|
|
29
|
+
uv run reader demo
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The installed command is `reader`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
reader demo
|
|
36
|
+
reader protocols
|
|
37
|
+
reader init ./experiments/my_experiment --protocol plate_reader/single_reporter_screen
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The demo prints a guided command tour. It does not execute a pipeline or write
|
|
41
|
+
files. Every generated starter can be inspected and validated before data is
|
|
42
|
+
added.
|
|
43
|
+
|
|
44
|
+
## Learn more
|
|
45
|
+
|
|
46
|
+
- [Getting started](https://github.com/e-south/reader/blob/main/docs/guides/getting_started.md) — install Reader, run the
|
|
47
|
+
demo, and scaffold a first experiment.
|
|
48
|
+
- [Common tasks](https://github.com/e-south/reader/blob/main/docs/guides/common_routes.md) — shortest commands for
|
|
49
|
+
discovery, validation, execution, and automation.
|
|
50
|
+
- [Python API](https://github.com/e-south/reader/blob/main/docs/core/python_api.md) — typed, task-oriented experiment and
|
|
51
|
+
plugin interfaces for integrations.
|
|
52
|
+
- [Documentation index](https://github.com/e-south/reader/blob/main/docs/README.md) — complete user, reference, and
|
|
53
|
+
maintainer documentation.
|
|
54
|
+
|
|
55
|
+
Reader is available under the [MIT license](https://github.com/e-south/reader/blob/main/LICENSE).
|
|
Binary file
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "reader-workbench"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Validated, traceable analysis workflows for experimental instrument data"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12,<3.13"
|
|
11
|
+
authors = [{ name = "Eric J. South" }]
|
|
12
|
+
keywords = ["data-analysis", "data-pipelines", "scientific-computing", "workbench"]
|
|
13
|
+
license = "MIT"
|
|
14
|
+
license-files = ["LICENSE"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Topic :: Scientific/Engineering",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
dependencies = [
|
|
26
|
+
"numpy>=1.26",
|
|
27
|
+
"matplotlib>=3.8",
|
|
28
|
+
"pandas>=2.1",
|
|
29
|
+
"pydantic>=2.6",
|
|
30
|
+
"pyyaml>=6.0.2",
|
|
31
|
+
"typer>=0.16.0",
|
|
32
|
+
"click>=8.3.3",
|
|
33
|
+
"rich>=13.7",
|
|
34
|
+
"pyarrow>=23.0.1",
|
|
35
|
+
"openpyxl>=3.1",
|
|
36
|
+
"seaborn>=0.13",
|
|
37
|
+
"pillow>=12.3.0",
|
|
38
|
+
"polars>=1.36.1",
|
|
39
|
+
"flowio>=1.4.0",
|
|
40
|
+
"filelock>=3.20.3,<4",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
reader = "reader_workbench.workbench.cli:main"
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Documentation = "https://github.com/e-south/reader/tree/main/docs"
|
|
48
|
+
Issues = "https://github.com/e-south/reader/issues"
|
|
49
|
+
Repository = "https://github.com/e-south/reader"
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-dir]
|
|
52
|
+
"" = "src"
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.packages.find]
|
|
55
|
+
where = ["src"]
|
|
56
|
+
include = ["reader_workbench*"]
|
|
57
|
+
exclude = ["reader_workbench.tests", "reader_workbench.tests.*"]
|
|
58
|
+
namespaces = false
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.package-data]
|
|
61
|
+
"reader_workbench.workbench.notebooks" = ["*.marimo.py.txt"]
|
|
62
|
+
|
|
63
|
+
[dependency-groups]
|
|
64
|
+
dev = [
|
|
65
|
+
"pytest>=8.2",
|
|
66
|
+
"pytest-cov>=7.0",
|
|
67
|
+
"pip-audit>=2.10.1,<3",
|
|
68
|
+
"twine>=7,<8",
|
|
69
|
+
"ruff>=0.4",
|
|
70
|
+
"pre-commit>=3.7",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.uv]
|
|
74
|
+
required-version = ">=0.12.3,<0.13"
|
|
75
|
+
|
|
76
|
+
[tool.ruff]
|
|
77
|
+
target-version = "py312"
|
|
78
|
+
line-length = 120
|
|
79
|
+
src = ["src"]
|
|
80
|
+
extend-exclude = [".venv", "build", "dist", ".eggs", "*.egg-info"]
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint]
|
|
83
|
+
select = ["E","F","W","I","UP","B","SIM","C4","PLC","PLE"]
|
|
84
|
+
ignore = ["E501"]
|
|
85
|
+
|
|
86
|
+
[tool.ruff.lint.per-file-ignores]
|
|
87
|
+
"tests/**" = ["S101","PLR2004","B011"]
|
|
88
|
+
"**/*.ipynb" = ["E402"]
|
|
89
|
+
|
|
90
|
+
[tool.ruff.format]
|
|
91
|
+
quote-style = "double"
|
|
92
|
+
indent-style = "space"
|
|
93
|
+
line-ending = "auto"
|
|
94
|
+
skip-magic-trailing-comma = false
|
|
95
|
+
docstring-code-format = true
|
|
96
|
+
|
|
97
|
+
[tool.pytest.ini_options]
|
|
98
|
+
testpaths = [
|
|
99
|
+
"src/reader_workbench/tests",
|
|
100
|
+
"tests"
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
python_files = ["test_*.py", "*_test.py"]
|
|
104
|
+
python_classes = ["Test*", "*Tests"]
|
|
105
|
+
python_functions = ["test_*"]
|
|
106
|
+
|
|
107
|
+
addopts = [
|
|
108
|
+
"--strict-config",
|
|
109
|
+
"--strict-markers",
|
|
110
|
+
"-ra",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
markers = [
|
|
114
|
+
"integration: cross-surface integration coverage",
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
norecursedirs = [
|
|
118
|
+
".venv", "build", "dist", ".eggs", "*.egg-info",
|
|
119
|
+
"outputs", "raw_data", "_scratch", ".tmp"
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
[tool.coverage.run]
|
|
123
|
+
branch = true
|
|
124
|
+
source = ["reader_workbench"]
|
|
125
|
+
|
|
126
|
+
[tool.coverage.report]
|
|
127
|
+
show_missing = true
|
|
128
|
+
skip_covered = true
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Reader's narrow, task-oriented public entrypoint."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from importlib import import_module
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from reader_workbench.api import Experiment, open_experiment
|
|
10
|
+
|
|
11
|
+
__all__ = ["Experiment", "__version__", "open_experiment"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def __getattr__(name: str) -> Any:
|
|
15
|
+
if name == "__version__":
|
|
16
|
+
from reader_workbench._version import package_version # noqa: PLC0415
|
|
17
|
+
|
|
18
|
+
return package_version()
|
|
19
|
+
if name not in __all__:
|
|
20
|
+
raise AttributeError(f"module 'reader_workbench' has no attribute {name!r}")
|
|
21
|
+
api = import_module("reader_workbench.api")
|
|
22
|
+
return getattr(api, name)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
_DISTRIBUTION_NAME = "reader-workbench"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def package_version() -> str:
|
|
9
|
+
"""Return the installed Reader distribution version."""
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
return version(_DISTRIBUTION_NAME)
|
|
13
|
+
except PackageNotFoundError:
|
|
14
|
+
return "0+uninstalled"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = ["package_version"]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Stable, task-oriented interfaces for Reader experiments and plugins."""
|
|
2
|
+
|
|
3
|
+
from .artifacts import ArtifactFileResult, read_artifact
|
|
4
|
+
from .facade import (
|
|
5
|
+
describe_plugin,
|
|
6
|
+
inspect,
|
|
7
|
+
notebook,
|
|
8
|
+
open_experiment,
|
|
9
|
+
plan,
|
|
10
|
+
plots,
|
|
11
|
+
plugins,
|
|
12
|
+
read_dataframe,
|
|
13
|
+
records,
|
|
14
|
+
run,
|
|
15
|
+
validate,
|
|
16
|
+
verify,
|
|
17
|
+
)
|
|
18
|
+
from .models import (
|
|
19
|
+
ApiResult,
|
|
20
|
+
DataFrameRecordResult,
|
|
21
|
+
Experiment,
|
|
22
|
+
ExperimentEvidence,
|
|
23
|
+
ExperimentIdentity,
|
|
24
|
+
InspectionResult,
|
|
25
|
+
NotebookResult,
|
|
26
|
+
PlanResult,
|
|
27
|
+
PluginCatalogResult,
|
|
28
|
+
PluginDescriptorResult,
|
|
29
|
+
PluginPort,
|
|
30
|
+
PluginSummary,
|
|
31
|
+
RecordCatalogResult,
|
|
32
|
+
RecordRevision,
|
|
33
|
+
RunResult,
|
|
34
|
+
SelectedSteps,
|
|
35
|
+
SurfaceCatalogResult,
|
|
36
|
+
ValidationResult,
|
|
37
|
+
VerificationResult,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"ApiResult",
|
|
42
|
+
"ArtifactFileResult",
|
|
43
|
+
"DataFrameRecordResult",
|
|
44
|
+
"Experiment",
|
|
45
|
+
"ExperimentEvidence",
|
|
46
|
+
"ExperimentIdentity",
|
|
47
|
+
"InspectionResult",
|
|
48
|
+
"NotebookResult",
|
|
49
|
+
"PlanResult",
|
|
50
|
+
"PluginCatalogResult",
|
|
51
|
+
"PluginDescriptorResult",
|
|
52
|
+
"PluginPort",
|
|
53
|
+
"PluginSummary",
|
|
54
|
+
"RecordCatalogResult",
|
|
55
|
+
"RecordRevision",
|
|
56
|
+
"RunResult",
|
|
57
|
+
"SelectedSteps",
|
|
58
|
+
"SurfaceCatalogResult",
|
|
59
|
+
"ValidationResult",
|
|
60
|
+
"VerificationResult",
|
|
61
|
+
"describe_plugin",
|
|
62
|
+
"inspect",
|
|
63
|
+
"notebook",
|
|
64
|
+
"open_experiment",
|
|
65
|
+
"plan",
|
|
66
|
+
"plots",
|
|
67
|
+
"plugins",
|
|
68
|
+
"read_artifact",
|
|
69
|
+
"read_dataframe",
|
|
70
|
+
"records",
|
|
71
|
+
"run",
|
|
72
|
+
"validate",
|
|
73
|
+
"verify",
|
|
74
|
+
]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from reader_workbench.errors import RecordError
|
|
4
|
+
from reader_workbench.workbench.records import (
|
|
5
|
+
DataFrameArtifactRecord,
|
|
6
|
+
FileBundleRecord,
|
|
7
|
+
RecordStore,
|
|
8
|
+
record_revision_digest,
|
|
9
|
+
)
|
|
10
|
+
from reader_workbench.workbench.records.identity import is_sha256_digest
|
|
11
|
+
|
|
12
|
+
from .models import Experiment, RecordRevision
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolve_record_revision(
|
|
16
|
+
experiment: Experiment,
|
|
17
|
+
record_id: str,
|
|
18
|
+
*,
|
|
19
|
+
revision: int | None,
|
|
20
|
+
revision_digest: str | None,
|
|
21
|
+
missing_label: str = "Record",
|
|
22
|
+
) -> tuple[RecordStore, DataFrameArtifactRecord | FileBundleRecord, RecordRevision]:
|
|
23
|
+
"""Resolve one catalog revision and prove its caller-supplied identity."""
|
|
24
|
+
|
|
25
|
+
if not isinstance(record_id, str) or not record_id.strip():
|
|
26
|
+
raise RecordError("record_id must be a non-empty string")
|
|
27
|
+
if record_id != record_id.strip():
|
|
28
|
+
raise RecordError("record_id must not contain leading or trailing whitespace")
|
|
29
|
+
if (revision is None) != (revision_digest is None):
|
|
30
|
+
raise RecordError("revision and revision_digest must be provided together")
|
|
31
|
+
if revision is not None and (isinstance(revision, bool) or not isinstance(revision, int) or revision < 1):
|
|
32
|
+
raise RecordError("revision must be a positive integer")
|
|
33
|
+
if revision_digest is not None and not is_sha256_digest(revision_digest):
|
|
34
|
+
raise RecordError("revision_digest must be a sha256 digest")
|
|
35
|
+
|
|
36
|
+
declaration = experiment._declaration
|
|
37
|
+
layout = declaration.experiment_semantics.layout
|
|
38
|
+
store = experiment._runtime.record_store(
|
|
39
|
+
layout.outputs_dir,
|
|
40
|
+
plots_subdir=layout.plots_subdir,
|
|
41
|
+
exports_subdir=layout.exports_subdir,
|
|
42
|
+
experiment_root=declaration.experiment.root,
|
|
43
|
+
create=False,
|
|
44
|
+
)
|
|
45
|
+
if not store.catalog_exists():
|
|
46
|
+
raise RecordError(
|
|
47
|
+
f"Record catalog is missing for experiment {declaration.experiment.id!r}: {store.records_path}"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
history = store.record_history(record_id)
|
|
51
|
+
if not history:
|
|
52
|
+
raise RecordError(f"{missing_label} {record_id!r} is missing; produce it in an earlier step.")
|
|
53
|
+
resolved_revision = len(history) if revision is None else revision
|
|
54
|
+
if resolved_revision > len(history):
|
|
55
|
+
raise RecordError(
|
|
56
|
+
f"Record {record_id!r} revision {resolved_revision} is unavailable; refresh the record catalog."
|
|
57
|
+
)
|
|
58
|
+
record = history[resolved_revision - 1]
|
|
59
|
+
actual_revision_digest = record_revision_digest(record, outputs_dir=store.root)
|
|
60
|
+
if revision_digest is not None and actual_revision_digest != revision_digest:
|
|
61
|
+
raise RecordError(
|
|
62
|
+
f"Record {record_id!r} revision digest mismatch; refresh the record catalog before reading it."
|
|
63
|
+
)
|
|
64
|
+
return (
|
|
65
|
+
store,
|
|
66
|
+
record,
|
|
67
|
+
RecordRevision(
|
|
68
|
+
record_id=record.record_id,
|
|
69
|
+
revision=resolved_revision,
|
|
70
|
+
revision_digest=actual_revision_digest,
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
__all__ = ["resolve_record_revision"]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
from mimetypes import guess_type
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from reader_workbench.errors import RecordError
|
|
8
|
+
from reader_workbench.workbench.records import (
|
|
9
|
+
FileBundleRecord,
|
|
10
|
+
record_to_dict,
|
|
11
|
+
verify_record_artifact_integrity,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from ._record_reads import resolve_record_revision
|
|
15
|
+
from .models import ArtifactFileResult, Experiment
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def read_artifact(
|
|
19
|
+
experiment: Experiment,
|
|
20
|
+
record_id: str,
|
|
21
|
+
*,
|
|
22
|
+
revision: int,
|
|
23
|
+
revision_digest: str,
|
|
24
|
+
path: str,
|
|
25
|
+
) -> ArtifactFileResult:
|
|
26
|
+
"""Read verified bytes for one file in an exact file-bundle record revision."""
|
|
27
|
+
|
|
28
|
+
if revision is None or revision_digest is None:
|
|
29
|
+
raise RecordError("read_artifact requires both revision and revision_digest")
|
|
30
|
+
if not isinstance(path, str) or not path.strip() or path != path.strip():
|
|
31
|
+
raise RecordError("path must be one non-empty outputs-relative artifact path")
|
|
32
|
+
requested_path = Path(path)
|
|
33
|
+
if requested_path.is_absolute() or ".." in requested_path.parts or requested_path == Path("."):
|
|
34
|
+
raise RecordError("path must be one confined outputs-relative artifact path")
|
|
35
|
+
normalized_path = requested_path.as_posix()
|
|
36
|
+
if normalized_path != path:
|
|
37
|
+
raise RecordError("path must use the canonical outputs-relative artifact path from records()")
|
|
38
|
+
|
|
39
|
+
store, record, bound_revision = resolve_record_revision(
|
|
40
|
+
experiment,
|
|
41
|
+
record_id,
|
|
42
|
+
revision=revision,
|
|
43
|
+
revision_digest=revision_digest,
|
|
44
|
+
missing_label="File-bundle record",
|
|
45
|
+
)
|
|
46
|
+
if not isinstance(record, FileBundleRecord):
|
|
47
|
+
raise RecordError(f"Record {record_id!r} exists but is not a file bundle")
|
|
48
|
+
payload = record_to_dict(record, outputs_dir=store.root)
|
|
49
|
+
raw_files = payload.get("files")
|
|
50
|
+
encoded_files = raw_files if isinstance(raw_files, list) else []
|
|
51
|
+
try:
|
|
52
|
+
file_index = encoded_files.index(normalized_path)
|
|
53
|
+
except ValueError as exc:
|
|
54
|
+
raise RecordError(
|
|
55
|
+
f"Artifact {normalized_path!r} is not part of record {record_id!r} revision {revision}."
|
|
56
|
+
) from exc
|
|
57
|
+
|
|
58
|
+
verify_record_artifact_integrity(record, outputs_dir=store.root)
|
|
59
|
+
evidence_by_path = {item.relative_path.as_posix(): item for item in record.file_evidence}
|
|
60
|
+
evidence = evidence_by_path[normalized_path]
|
|
61
|
+
try:
|
|
62
|
+
content = record.files[file_index].read_bytes()
|
|
63
|
+
except OSError as exc:
|
|
64
|
+
raise RecordError(f"Artifact {normalized_path!r} could not be read after verification.") from exc
|
|
65
|
+
actual_digest = "sha256:" + hashlib.sha256(content).hexdigest()
|
|
66
|
+
if len(content) != evidence.size_bytes or actual_digest != evidence.content_digest:
|
|
67
|
+
raise RecordError(f"Artifact {normalized_path!r} changed while it was being read; refresh and retry.")
|
|
68
|
+
return ArtifactFileResult(
|
|
69
|
+
experiment=experiment.identity,
|
|
70
|
+
record=bound_revision,
|
|
71
|
+
relative_path=normalized_path,
|
|
72
|
+
media_type=guess_type(normalized_path)[0] or "application/octet-stream",
|
|
73
|
+
content_digest=evidence.content_digest,
|
|
74
|
+
size_bytes=evidence.size_bytes,
|
|
75
|
+
content=content,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
__all__ = ["ArtifactFileResult", "read_artifact"]
|