mostlyright-data 0.9.0__py3-none-any.whl
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.
- mostlyright/data_harness/__init__.py +158 -0
- mostlyright/data_harness/acquisition/__init__.py +55 -0
- mostlyright/data_harness/acquisition/http.py +2773 -0
- mostlyright/data_harness/acquisition/parsing.py +809 -0
- mostlyright/data_harness/acquisition/ranges.py +495 -0
- mostlyright/data_harness/acquisition/result_download.py +360 -0
- mostlyright/data_harness/acquisition/retention_admission.py +248 -0
- mostlyright/data_harness/acquisition/sandbox.py +4888 -0
- mostlyright/data_harness/acquisition/url_policy.py +530 -0
- mostlyright/data_harness/agent_runtime.py +2743 -0
- mostlyright/data_harness/assets/logo-ink.svg +31 -0
- mostlyright/data_harness/backends/__init__.py +28 -0
- mostlyright/data_harness/backends/pandas_backend.py +350 -0
- mostlyright/data_harness/backends/polars_backend.py +366 -0
- mostlyright/data_harness/backends/protocol.py +124 -0
- mostlyright/data_harness/backends/reference.py +83 -0
- mostlyright/data_harness/backends/registry.py +55 -0
- mostlyright/data_harness/backends/restrictions.py +126 -0
- mostlyright/data_harness/canonical.py +333 -0
- mostlyright/data_harness/catalog_job.py +625 -0
- mostlyright/data_harness/cli.py +5398 -0
- mostlyright/data_harness/contracts.py +53 -0
- mostlyright/data_harness/coordinator.py +1307 -0
- mostlyright/data_harness/deploy.py +924 -0
- mostlyright/data_harness/deploy_target.py +312 -0
- mostlyright/data_harness/deployment_evidence.py +1067 -0
- mostlyright/data_harness/event_presentation.py +576 -0
- mostlyright/data_harness/events.py +2152 -0
- mostlyright/data_harness/fast_delimited.py +239 -0
- mostlyright/data_harness/fleet.py +237 -0
- mostlyright/data_harness/formats.py +236 -0
- mostlyright/data_harness/governors.py +1163 -0
- mostlyright/data_harness/hosted_bootstrap.py +972 -0
- mostlyright/data_harness/hosted_crawler.py +1115 -0
- mostlyright/data_harness/hosted_crawler_container_smoke.py +351 -0
- mostlyright/data_harness/hosted_crawler_fetch.py +423 -0
- mostlyright/data_harness/hosted_crawler_job.py +1277 -0
- mostlyright/data_harness/hosted_crawler_protocol.py +676 -0
- mostlyright/data_harness/hosted_dataset.py +1500 -0
- mostlyright/data_harness/hosted_deploy.py +3037 -0
- mostlyright/data_harness/hosted_handoff.py +62 -0
- mostlyright/data_harness/hosted_ingestion_contract.py +504 -0
- mostlyright/data_harness/hosted_ingestion_job.py +356 -0
- mostlyright/data_harness/hosted_ingestion_job_smoke.py +40 -0
- mostlyright/data_harness/hosted_session_container_smoke.py +194 -0
- mostlyright/data_harness/hosted_session_worker.py +3554 -0
- mostlyright/data_harness/hosted_session_worker_job_smoke.py +46 -0
- mostlyright/data_harness/hosted_worker.py +6784 -0
- mostlyright/data_harness/ingestion/__init__.py +56 -0
- mostlyright/data_harness/ingestion/contracts.py +461 -0
- mostlyright/data_harness/ingestion/faults.py +42 -0
- mostlyright/data_harness/ingestion/gcs_store.py +1162 -0
- mostlyright/data_harness/ingestion/spool.py +130 -0
- mostlyright/data_harness/ingestion/store.py +885 -0
- mostlyright/data_harness/key_seam.py +434 -0
- mostlyright/data_harness/linux_process_boundary.py +262 -0
- mostlyright/data_harness/local_contracts.py +2880 -0
- mostlyright/data_harness/local_search/__init__.py +5 -0
- mostlyright/data_harness/local_search/build_index.py +1087 -0
- mostlyright/data_harness/local_search/contracts.py +920 -0
- mostlyright/data_harness/local_search/query_trace.py +266 -0
- mostlyright/data_harness/local_search/retrieval.py +700 -0
- mostlyright/data_harness/local_search/sealed.py +474 -0
- mostlyright/data_harness/local_search/service.py +784 -0
- mostlyright/data_harness/nbrender/CONTRACT.md +212 -0
- mostlyright/data_harness/nbrender/__init__.py +12 -0
- mostlyright/data_harness/nbrender/chrome.py +359 -0
- mostlyright/data_harness/nbrender/code_body.py +266 -0
- mostlyright/data_harness/nbrender/document.py +407 -0
- mostlyright/data_harness/nbrender/frame.py +275 -0
- mostlyright/data_harness/nbrender/interactive.py +337 -0
- mostlyright/data_harness/nbrender/markdown_body.py +477 -0
- mostlyright/data_harness/nbrender/mr_components.py +134 -0
- mostlyright/data_harness/nbrender/outputs_data.py +595 -0
- mostlyright/data_harness/nbrender/outputs_rich.py +906 -0
- mostlyright/data_harness/nbrender/outputs_source.py +260 -0
- mostlyright/data_harness/nbrender/outputs_stage.py +176 -0
- mostlyright/data_harness/nbrender/outputs_text.py +400 -0
- mostlyright/data_harness/nbrender/parse.py +394 -0
- mostlyright/data_harness/nbrender/status.py +40 -0
- mostlyright/data_harness/nbrender/tokens.py +1295 -0
- mostlyright/data_harness/notebook.py +1710 -0
- mostlyright/data_harness/offline.py +2049 -0
- mostlyright/data_harness/operation_registry.py +1007 -0
- mostlyright/data_harness/operator_setup.py +239 -0
- mostlyright/data_harness/pipeline.py +6428 -0
- mostlyright/data_harness/plan_graph.py +2026 -0
- mostlyright/data_harness/preparation/__init__.py +104 -0
- mostlyright/data_harness/preparation/contracts.py +1017 -0
- mostlyright/data_harness/preparation/engine.py +221 -0
- mostlyright/data_harness/preparation/errors.py +14 -0
- mostlyright/data_harness/preparation/gates.py +751 -0
- mostlyright/data_harness/preparation/joins.py +574 -0
- mostlyright/data_harness/preparation/profile.py +384 -0
- mostlyright/data_harness/preparation/table.py +217 -0
- mostlyright/data_harness/preparation/transforms.py +568 -0
- mostlyright/data_harness/progress_events.py +534 -0
- mostlyright/data_harness/readers/__init__.py +46 -0
- mostlyright/data_harness/readers/containers.py +963 -0
- mostlyright/data_harness/readers/contracts.py +542 -0
- mostlyright/data_harness/readers/delimited.py +257 -0
- mostlyright/data_harness/readers/grib2/__init__.py +33 -0
- mostlyright/data_harness/readers/grib2/admission.py +722 -0
- mostlyright/data_harness/readers/grib2/decode.py +1009 -0
- mostlyright/data_harness/readers/grib2/geometry.py +1133 -0
- mostlyright/data_harness/readers/grib2/portable_math.py +501 -0
- mostlyright/data_harness/readers/json_tabular.py +485 -0
- mostlyright/data_harness/readers/registry.py +514 -0
- mostlyright/data_harness/readers/samples/README.md +110 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +25 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +25 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +25 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +3 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +23 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +5 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +25 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +30 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +5 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +44 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +1 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +48 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +4 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +24 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +27 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +27 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +20 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +55 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +54 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +54 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +54 -0
- mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
- mostlyright/data_harness/readers/samples.py +582 -0
- mostlyright/data_harness/readers/spreadsheet.py +803 -0
- mostlyright/data_harness/readers/tabular.py +510 -0
- mostlyright/data_harness/recipe.py +5321 -0
- mostlyright/data_harness/repair/__init__.py +78 -0
- mostlyright/data_harness/repair/adapters.py +274 -0
- mostlyright/data_harness/repair/contracts.py +872 -0
- mostlyright/data_harness/repair/coordinator.py +1099 -0
- mostlyright/data_harness/repair/errors.py +16 -0
- mostlyright/data_harness/review.py +2533 -0
- mostlyright/data_harness/rowset.py +283 -0
- mostlyright/data_harness/serving.py +1975 -0
- mostlyright/data_harness/serving_edge.py +590 -0
- mostlyright/data_harness/serving_http.py +1031 -0
- mostlyright/data_harness/session_probes.py +759 -0
- mostlyright/data_harness/signing.py +101 -0
- mostlyright/data_harness/source_discovery.py +898 -0
- mostlyright/data_harness/sources/__init__.py +209 -0
- mostlyright/data_harness/sources/_adapter_steps.py +213 -0
- mostlyright/data_harness/sources/adapters.py +1214 -0
- mostlyright/data_harness/sources/cadence.py +1428 -0
- mostlyright/data_harness/sources/cadence_emission.py +453 -0
- mostlyright/data_harness/sources/cadence_history.py +546 -0
- mostlyright/data_harness/sources/catalog/__init__.py +17 -0
- mostlyright/data_harness/sources/catalog/admission.py +477 -0
- mostlyright/data_harness/sources/catalog/authoring.py +1701 -0
- mostlyright/data_harness/sources/catalog/authoring_policy.py +701 -0
- mostlyright/data_harness/sources/catalog/authoring_shards.py +1217 -0
- mostlyright/data_harness/sources/catalog/bounded_io.py +231 -0
- mostlyright/data_harness/sources/catalog/channel.py +523 -0
- mostlyright/data_harness/sources/catalog/channel_client.py +296 -0
- mostlyright/data_harness/sources/catalog/contracts.py +825 -0
- mostlyright/data_harness/sources/catalog/coverage.py +137 -0
- mostlyright/data_harness/sources/catalog/delta.py +1340 -0
- mostlyright/data_harness/sources/catalog/embedding.py +532 -0
- mostlyright/data_harness/sources/catalog/entry_v2.py +1182 -0
- mostlyright/data_harness/sources/catalog/fill.py +3889 -0
- mostlyright/data_harness/sources/catalog/fill_partitions.py +459 -0
- mostlyright/data_harness/sources/catalog/fill_staging.py +1105 -0
- mostlyright/data_harness/sources/catalog/gating.py +374 -0
- mostlyright/data_harness/sources/catalog/generation_receipt.py +1607 -0
- mostlyright/data_harness/sources/catalog/harvest/__init__.py +7 -0
- mostlyright/data_harness/sources/catalog/harvest/ckan.py +384 -0
- mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +798 -0
- mostlyright/data_harness/sources/catalog/harvest/protocol.py +964 -0
- mostlyright/data_harness/sources/catalog/harvest/sdmx.py +445 -0
- mostlyright/data_harness/sources/catalog/harvest/stac.py +384 -0
- mostlyright/data_harness/sources/catalog/health.py +447 -0
- mostlyright/data_harness/sources/catalog/hosted_catalog.py +105 -0
- mostlyright/data_harness/sources/catalog/identity_history.py +1549 -0
- mostlyright/data_harness/sources/catalog/neural.py +1618 -0
- mostlyright/data_harness/sources/catalog/packed_catalog.py +2345 -0
- mostlyright/data_harness/sources/catalog/packed_retrieval.py +1517 -0
- mostlyright/data_harness/sources/catalog/packed_writer.py +2802 -0
- mostlyright/data_harness/sources/catalog/query_trace.py +1037 -0
- mostlyright/data_harness/sources/catalog/recommend.py +171 -0
- mostlyright/data_harness/sources/catalog/retrieval.py +230 -0
- mostlyright/data_harness/sources/catalog/retrieval_manifest.py +995 -0
- mostlyright/data_harness/sources/catalog/rights_decisions.py +254 -0
- mostlyright/data_harness/sources/catalog/sealed.py +560 -0
- mostlyright/data_harness/sources/catalog/search.py +230 -0
- mostlyright/data_harness/sources/catalog/streaming_delta.py +1097 -0
- mostlyright/data_harness/sources/catalog/update.py +891 -0
- mostlyright/data_harness/sources/collections.py +815 -0
- mostlyright/data_harness/sources/contracts.py +2223 -0
- mostlyright/data_harness/sources/deletion.py +761 -0
- mostlyright/data_harness/sources/fitness.py +162 -0
- mostlyright/data_harness/sources/governance.py +163 -0
- mostlyright/data_harness/sources/hosted.py +173 -0
- mostlyright/data_harness/sources/integration.py +218 -0
- mostlyright/data_harness/sources/range_reader.py +418 -0
- mostlyright/data_harness/sources/registry.py +514 -0
- mostlyright/data_harness/sources/rights_rule.py +59 -0
- mostlyright/data_harness/sources/source_cadence_vectors.v1.json +1 -0
- mostlyright/data_harness/sources/sports.py +521 -0
- mostlyright/data_harness/sources/stream.py +524 -0
- mostlyright/data_harness/sources/stream_connector.py +418 -0
- mostlyright/data_harness/sources/stream_recorder.py +1404 -0
- mostlyright/data_harness/studio_boundary.py +2019 -0
- mostlyright/data_harness/thin/__init__.py +37 -0
- mostlyright/data_harness/thin/acquire.py +1137 -0
- mostlyright/data_harness/thin/acquire_cancel.py +579 -0
- mostlyright/data_harness/thin/approvals.py +617 -0
- mostlyright/data_harness/thin/commands.py +406 -0
- mostlyright/data_harness/thin/download.py +194 -0
- mostlyright/data_harness/thin/narrative.py +589 -0
- mostlyright/data_harness/thin/parity.py +1070 -0
- mostlyright/data_harness/thin/propose.py +2759 -0
- mostlyright/data_harness/thin/research.py +1663 -0
- mostlyright/data_harness/thin/router.py +924 -0
- mostlyright/data_harness/thin/runs.py +519 -0
- mostlyright/data_harness/thin/session.py +281 -0
- mostlyright/data_harness/thin/stream.py +501 -0
- mostlyright/data_harness/thin/transport.py +187 -0
- mostlyright/data_harness/thin/vocabulary.py +368 -0
- mostlyright/data_harness/thin/workers.py +164 -0
- mostlyright/data_harness/ucum/TABLE-PIN.json +40 -0
- mostlyright/data_harness/ucum/ucum-subset.v1.json +632 -0
- mostlyright/data_harness/unit_flow.py +927 -0
- mostlyright/data_harness/units.py +572 -0
- mostlyright/data_harness/ux/__init__.py +9 -0
- mostlyright/data_harness/ux/approve.py +485 -0
- mostlyright/data_harness/ux/author_yaml.py +597 -0
- mostlyright/data_harness/ux/cloud_auth.py +447 -0
- mostlyright/data_harness/ux/commands/__init__.py +260 -0
- mostlyright/data_harness/ux/commands/approve.py +136 -0
- mostlyright/data_harness/ux/commands/auth.py +744 -0
- mostlyright/data_harness/ux/commands/author.py +79 -0
- mostlyright/data_harness/ux/commands/catalog_author.py +403 -0
- mostlyright/data_harness/ux/commands/catalog_fill.py +523 -0
- mostlyright/data_harness/ux/commands/catalog_harvest.py +545 -0
- mostlyright/data_harness/ux/commands/catalog_publish.py +1838 -0
- mostlyright/data_harness/ux/commands/catalog_search.py +71 -0
- mostlyright/data_harness/ux/commands/catalog_update.py +437 -0
- mostlyright/data_harness/ux/commands/deploy.py +134 -0
- mostlyright/data_harness/ux/commands/deploy_dataset.py +98 -0
- mostlyright/data_harness/ux/commands/deploy_plan.py +105 -0
- mostlyright/data_harness/ux/commands/deploy_status.py +104 -0
- mostlyright/data_harness/ux/commands/diff.py +74 -0
- mostlyright/data_harness/ux/commands/index.py +84 -0
- mostlyright/data_harness/ux/commands/inventory.py +47 -0
- mostlyright/data_harness/ux/commands/list_builds.py +143 -0
- mostlyright/data_harness/ux/commands/login.py +63 -0
- mostlyright/data_harness/ux/commands/peek.py +236 -0
- mostlyright/data_harness/ux/commands/plan_check.py +90 -0
- mostlyright/data_harness/ux/commands/preflight.py +97 -0
- mostlyright/data_harness/ux/commands/record.py +107 -0
- mostlyright/data_harness/ux/commands/review_setup.py +47 -0
- mostlyright/data_harness/ux/commands/search.py +440 -0
- mostlyright/data_harness/ux/commands/show.py +61 -0
- mostlyright/data_harness/ux/commands/whoami.py +37 -0
- mostlyright/data_harness/ux/credential_native.py +551 -0
- mostlyright/data_harness/ux/credential_store.py +1055 -0
- mostlyright/data_harness/ux/credentials.py +631 -0
- mostlyright/data_harness/ux/diffing.py +444 -0
- mostlyright/data_harness/ux/headline.py +671 -0
- mostlyright/data_harness/ux/hosted_acquisition.py +974 -0
- mostlyright/data_harness/ux/hosted_run_status.py +619 -0
- mostlyright/data_harness/ux/inventory.py +427 -0
- mostlyright/data_harness/ux/local_review.py +375 -0
- mostlyright/data_harness/ux/login.py +691 -0
- mostlyright/data_harness/ux/path_kind.py +147 -0
- mostlyright/data_harness/ux/peek.py +1000 -0
- mostlyright/data_harness/ux/plain_file.py +178 -0
- mostlyright/data_harness/ux/plan_check.py +311 -0
- mostlyright/data_harness/ux/preflight.py +918 -0
- mostlyright/data_harness/ux/readers.py +1124 -0
- mostlyright/data_harness/ux/remediation.py +2195 -0
- mostlyright/data_harness/ux/render.py +657 -0
- mostlyright/data_harness/ux/workload.py +1077 -0
- mostlyright/data_harness/viewer.py +3713 -0
- mostlyright/data_harness/visual_run/__init__.py +83 -0
- mostlyright/data_harness/visual_run/authoring.py +235 -0
- mostlyright/data_harness/visual_run/contracts.py +673 -0
- mostlyright/data_harness/visual_run/materialize.py +486 -0
- mostlyright/data_harness/visual_run/observations.py +874 -0
- mostlyright/data_harness/visual_run/query.py +259 -0
- mostlyright/data_harness/visual_run/reducer.py +280 -0
- mostlyright/data_harness/visual_run/sdk.py +892 -0
- mostlyright/data_harness/visual_run/store.py +584 -0
- mostlyright/data_harness/visual_run/transport.py +239 -0
- mostlyright/data_harness/watch.py +2999 -0
- mostlyright_data-0.9.0.dist-info/METADATA +607 -0
- mostlyright_data-0.9.0.dist-info/RECORD +314 -0
- mostlyright_data-0.9.0.dist-info/WHEEL +4 -0
- mostlyright_data-0.9.0.dist-info/entry_points.txt +12 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
"""``mr-data search`` over already-published exact local stores.
|
|
2
|
+
|
|
3
|
+
A v1/v2 public catalog uses its sealed lookup contract. A range-local packed generation is larger
|
|
4
|
+
than any one answer should be allowed to read, so it is searched only under a work budget the
|
|
5
|
+
caller states in full -- eight caps, none of which has a default here or anywhere below here --
|
|
6
|
+
together with the composite generation receipt that describes the generation being asked. Those
|
|
7
|
+
ten values are handed to the service unchanged; this module chooses none of them.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import re
|
|
14
|
+
from collections.abc import Mapping, Sequence
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from mostlyright.data_harness.local_search.contracts import (
|
|
19
|
+
_RIGHTS_STATUSES,
|
|
20
|
+
BuildField,
|
|
21
|
+
BuildTimeCoverage,
|
|
22
|
+
LocalSearchContractError,
|
|
23
|
+
)
|
|
24
|
+
from mostlyright.data_harness.local_search.retrieval import (
|
|
25
|
+
MAX_QUERY_CHARS,
|
|
26
|
+
MAX_RETRIEVAL_LIMIT,
|
|
27
|
+
BuildFilters,
|
|
28
|
+
ExactDigestFilter,
|
|
29
|
+
RecipeIdentityFilter,
|
|
30
|
+
SourceIdentityFilter,
|
|
31
|
+
)
|
|
32
|
+
from mostlyright.data_harness.local_search.service import capture_local_search
|
|
33
|
+
from mostlyright.data_harness.sources.catalog.gating import CatalogRequirement
|
|
34
|
+
from mostlyright.data_harness.sources.contracts import (
|
|
35
|
+
DATA_FORMATS,
|
|
36
|
+
OBLIGATION_LIFECYCLES,
|
|
37
|
+
SourceContractError,
|
|
38
|
+
)
|
|
39
|
+
from mostlyright.data_harness.ux.commands import CommandSpec
|
|
40
|
+
|
|
41
|
+
_DIGEST = re.compile(r"^[0-9a-f]{64}$")
|
|
42
|
+
_DIGEST_KINDS = ("candidate", "dataset", "facts", "lineage", "requirements", "validation_policy")
|
|
43
|
+
_LOGICAL_TYPES = ("date", "float64", "int64", "string")
|
|
44
|
+
_FORBIDDEN_PAYLOAD_KEYS = frozenset({"locator", "relative_path", "score", "scores"})
|
|
45
|
+
|
|
46
|
+
#: Every cap one packed search may spend, in the order the work contract states them. There is no
|
|
47
|
+
#: default for any of them here: a default would be an answer to "how much may this question cost"
|
|
48
|
+
#: given by whoever forgot to ask rather than by the caller who has to live with it.
|
|
49
|
+
_WORK_BUDGET = (
|
|
50
|
+
"max_ranges",
|
|
51
|
+
"max_packs",
|
|
52
|
+
"max_member_bytes",
|
|
53
|
+
"max_posting_terms",
|
|
54
|
+
"max_candidates",
|
|
55
|
+
"max_open_files",
|
|
56
|
+
"max_query_encodes",
|
|
57
|
+
"max_elapsed_seconds",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
#: The composite receipt that describes the packed generation being asked, and its exact bytes.
|
|
61
|
+
_PACKED_COORDINATES = ("public_generation_receipt", "public_generation_receipt_sha256")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def add_arguments(parser: argparse.ArgumentParser) -> None:
|
|
65
|
+
parser.add_argument(
|
|
66
|
+
"--public-index-root", type=Path, required=True, help="the sealed public catalog root"
|
|
67
|
+
)
|
|
68
|
+
parser.add_argument(
|
|
69
|
+
"--public-manifest-sha256",
|
|
70
|
+
type=_sha256,
|
|
71
|
+
required=True,
|
|
72
|
+
help="the exact public retrieval-manifest fingerprint",
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"--private-index-root", type=Path, required=True, help="the sealed private index root"
|
|
76
|
+
)
|
|
77
|
+
parser.add_argument(
|
|
78
|
+
"--private-manifest-sha256",
|
|
79
|
+
type=_sha256,
|
|
80
|
+
required=True,
|
|
81
|
+
help="the exact private index-manifest fingerprint",
|
|
82
|
+
)
|
|
83
|
+
parser.add_argument(
|
|
84
|
+
"--build-root", type=Path, required=True, help="the root for selected Build replay"
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--question", type=_question, required=True, help="the bounded search question"
|
|
88
|
+
)
|
|
89
|
+
parser.add_argument(
|
|
90
|
+
"--limit",
|
|
91
|
+
type=int,
|
|
92
|
+
choices=range(1, MAX_RETRIEVAL_LIMIT + 1),
|
|
93
|
+
required=True,
|
|
94
|
+
help="the maximum matches considered from each store",
|
|
95
|
+
)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"--public-backend",
|
|
98
|
+
choices=("lexical", "neural"),
|
|
99
|
+
required=True,
|
|
100
|
+
help="the closed public retrieval backend",
|
|
101
|
+
)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"--private-backend",
|
|
104
|
+
choices=("lexical", "neural"),
|
|
105
|
+
required=True,
|
|
106
|
+
help="the closed private retrieval backend",
|
|
107
|
+
)
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"--neural-model-root",
|
|
110
|
+
type=Path,
|
|
111
|
+
help="the explicit governed sidecar root when neural is selected",
|
|
112
|
+
)
|
|
113
|
+
parser.add_argument(
|
|
114
|
+
"--allow-lexical-fallback",
|
|
115
|
+
action="store_true",
|
|
116
|
+
help=(
|
|
117
|
+
"allow an explicitly requested unavailable public neural representation to use lexical"
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
parser.add_argument(
|
|
122
|
+
"--source-format",
|
|
123
|
+
dest="source_formats",
|
|
124
|
+
action="append",
|
|
125
|
+
choices=tuple(sorted(DATA_FORMATS)),
|
|
126
|
+
required=True,
|
|
127
|
+
help="an acceptable public source format; repeat to allow more",
|
|
128
|
+
)
|
|
129
|
+
parser.add_argument(
|
|
130
|
+
"--source-max-update-seconds",
|
|
131
|
+
type=int,
|
|
132
|
+
required=True,
|
|
133
|
+
help="the slowest acceptable public source update interval",
|
|
134
|
+
)
|
|
135
|
+
parser.add_argument(
|
|
136
|
+
"--source-intended-use", required=True, help="the declared use for source rights checks"
|
|
137
|
+
)
|
|
138
|
+
parser.add_argument(
|
|
139
|
+
"--source-lifecycle",
|
|
140
|
+
choices=tuple(sorted(OBLIGATION_LIFECYCLES)),
|
|
141
|
+
required=True,
|
|
142
|
+
help="the lifecycle used for source obligation checks",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
parser.add_argument(
|
|
146
|
+
"--grain", action="append", help="one exact required grain field; repeat for more"
|
|
147
|
+
)
|
|
148
|
+
parser.add_argument(
|
|
149
|
+
"--time-start-inclusive", help="first included date for the required overlap"
|
|
150
|
+
)
|
|
151
|
+
parser.add_argument("--time-end-exclusive", help="first excluded date for the required overlap")
|
|
152
|
+
parser.add_argument(
|
|
153
|
+
"--required-field",
|
|
154
|
+
dest="required_fields",
|
|
155
|
+
action="append",
|
|
156
|
+
type=_field,
|
|
157
|
+
help="required NAME:LOGICAL_TYPE; repeat for more fields",
|
|
158
|
+
)
|
|
159
|
+
parser.add_argument(
|
|
160
|
+
"--source-identity",
|
|
161
|
+
dest="source_identities",
|
|
162
|
+
action="append",
|
|
163
|
+
type=_source_identity,
|
|
164
|
+
help="required SOURCE_ID:CONTENT_SHA256; repeat for more sources",
|
|
165
|
+
)
|
|
166
|
+
parser.add_argument(
|
|
167
|
+
"--rights-status",
|
|
168
|
+
dest="rights_statuses",
|
|
169
|
+
action="append",
|
|
170
|
+
choices=tuple(sorted(_RIGHTS_STATUSES)),
|
|
171
|
+
help="one acceptable sealed rights status; repeat for more",
|
|
172
|
+
)
|
|
173
|
+
parser.add_argument("--recipe-id", help="the exact required recipe identifier")
|
|
174
|
+
parser.add_argument("--recipe-version", type=int, help="the exact required recipe version")
|
|
175
|
+
parser.add_argument(
|
|
176
|
+
"--recipe-sha256", type=_sha256, help="the exact required recipe fingerprint"
|
|
177
|
+
)
|
|
178
|
+
parser.add_argument(
|
|
179
|
+
"--digest-kind", choices=_DIGEST_KINDS, help="the kind of exact Build digest required"
|
|
180
|
+
)
|
|
181
|
+
parser.add_argument("--digest-sha256", type=_sha256, help="the exact required Build digest")
|
|
182
|
+
|
|
183
|
+
parser.add_argument(
|
|
184
|
+
"--public-generation-receipt",
|
|
185
|
+
type=Path,
|
|
186
|
+
help="the composite receipt of the packed public catalog being asked",
|
|
187
|
+
)
|
|
188
|
+
parser.add_argument(
|
|
189
|
+
"--public-generation-receipt-sha256",
|
|
190
|
+
type=_sha256,
|
|
191
|
+
help="the exact composite receipt fingerprint",
|
|
192
|
+
)
|
|
193
|
+
parser.add_argument(
|
|
194
|
+
"--max-ranges", type=int, help="most key ranges this packed search may consider"
|
|
195
|
+
)
|
|
196
|
+
parser.add_argument("--max-packs", type=int, help="most packs this packed search may open")
|
|
197
|
+
parser.add_argument(
|
|
198
|
+
"--max-member-bytes", type=int, help="most bytes this packed search may read"
|
|
199
|
+
)
|
|
200
|
+
parser.add_argument(
|
|
201
|
+
"--max-posting-terms", type=int, help="most posting terms this packed search may read"
|
|
202
|
+
)
|
|
203
|
+
parser.add_argument(
|
|
204
|
+
"--max-candidates", type=int, help="most entries this packed search may examine"
|
|
205
|
+
)
|
|
206
|
+
parser.add_argument(
|
|
207
|
+
"--max-open-files", type=int, help="most files this packed search may hold open at once"
|
|
208
|
+
)
|
|
209
|
+
parser.add_argument(
|
|
210
|
+
"--max-query-encodes", type=int, help="most times the question itself may be encoded"
|
|
211
|
+
)
|
|
212
|
+
parser.add_argument(
|
|
213
|
+
"--max-elapsed-seconds", type=int, help="longest this packed search may take"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
218
|
+
time_overlap = _time_filter(args.time_start_inclusive, args.time_end_exclusive)
|
|
219
|
+
recipe = _recipe_filter(args.recipe_id, args.recipe_version, args.recipe_sha256)
|
|
220
|
+
exact_digest = _digest_filter(args.digest_kind, args.digest_sha256)
|
|
221
|
+
try:
|
|
222
|
+
filters = BuildFilters(
|
|
223
|
+
grain=None if args.grain is None else tuple(args.grain),
|
|
224
|
+
time_overlap=time_overlap,
|
|
225
|
+
required_fields=tuple(args.required_fields or ()),
|
|
226
|
+
sources=tuple(sorted(args.source_identities or (), key=lambda item: item.source_id)),
|
|
227
|
+
rights_statuses=tuple(sorted(args.rights_statuses or ())),
|
|
228
|
+
recipe=recipe,
|
|
229
|
+
exact_digest=exact_digest,
|
|
230
|
+
)
|
|
231
|
+
except LocalSearchContractError as error:
|
|
232
|
+
raise SourceContractError(error.code, error.path, error.detail) from error
|
|
233
|
+
requirement = CatalogRequirement(
|
|
234
|
+
intended_use=args.source_intended_use,
|
|
235
|
+
lifecycle=args.source_lifecycle,
|
|
236
|
+
required_data_formats=tuple(sorted(set(args.source_formats))),
|
|
237
|
+
max_update_frequency_seconds=args.source_max_update_seconds,
|
|
238
|
+
require_open_access=True,
|
|
239
|
+
require_live=True,
|
|
240
|
+
)
|
|
241
|
+
packed_receipt, work_limits = _packed_contract(args)
|
|
242
|
+
try:
|
|
243
|
+
captured = capture_local_search(
|
|
244
|
+
public_index_root=args.public_index_root,
|
|
245
|
+
expected_public_manifest_sha256=args.public_manifest_sha256,
|
|
246
|
+
private_index_root=args.private_index_root,
|
|
247
|
+
expected_private_manifest_sha256=args.private_manifest_sha256,
|
|
248
|
+
build_root=args.build_root,
|
|
249
|
+
question=args.question,
|
|
250
|
+
source_requirement=requirement,
|
|
251
|
+
build_filters=filters,
|
|
252
|
+
public_backend=args.public_backend,
|
|
253
|
+
allow_lexical_fallback=args.allow_lexical_fallback,
|
|
254
|
+
private_backend=args.private_backend,
|
|
255
|
+
neural_model_root=args.neural_model_root,
|
|
256
|
+
public_packed_receipt=packed_receipt,
|
|
257
|
+
catalog_work_limits=work_limits,
|
|
258
|
+
limit=args.limit,
|
|
259
|
+
)
|
|
260
|
+
except LocalSearchContractError as error:
|
|
261
|
+
raise SourceContractError(error.code, error.path, error.detail) from error
|
|
262
|
+
_assert_closed_payload(captured.payload)
|
|
263
|
+
return captured.payload
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _packed_contract(args: argparse.Namespace) -> tuple[Any | None, Any | None]:
|
|
267
|
+
"""The packed generation's receipt and its work budget, stated in full or not at all.
|
|
268
|
+
|
|
269
|
+
Ten values decide whether this is a packed search: the composite receipt, its fingerprint, and
|
|
270
|
+
the eight caps. Stating some of them is not a smaller question -- it is a question nobody has
|
|
271
|
+
said the cost of -- so a partial set is refused here rather than completed with a guess.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
stated = [name for name in (*_PACKED_COORDINATES, *_WORK_BUDGET) if _stated(args, name)]
|
|
275
|
+
if not stated:
|
|
276
|
+
return None, None
|
|
277
|
+
missing = [name for name in (*_PACKED_COORDINATES, *_WORK_BUDGET) if not _stated(args, name)]
|
|
278
|
+
if missing:
|
|
279
|
+
raise SourceContractError(
|
|
280
|
+
"LOCAL_SEARCH_WORK_BUDGET",
|
|
281
|
+
missing[0],
|
|
282
|
+
"a packed catalog is searched under its composite receipt and all eight work caps, "
|
|
283
|
+
"or it is not searched at all",
|
|
284
|
+
)
|
|
285
|
+
from mostlyright.data_harness.sources.catalog.generation_receipt import (
|
|
286
|
+
MAX_COMPOSITE_ARRAY_ITEMS,
|
|
287
|
+
MAX_COMPOSITE_RECEIPT_BYTES,
|
|
288
|
+
MAX_COMPOSITE_RECEIPT_DEPTH,
|
|
289
|
+
load_bounded_json,
|
|
290
|
+
verify_generation_receipt,
|
|
291
|
+
)
|
|
292
|
+
from mostlyright.data_harness.sources.catalog.packed_retrieval import CatalogSearchWorkLimits
|
|
293
|
+
|
|
294
|
+
_raw, receipt = load_bounded_json(
|
|
295
|
+
args.public_generation_receipt,
|
|
296
|
+
label="public_generation_receipt",
|
|
297
|
+
maximum=MAX_COMPOSITE_RECEIPT_BYTES,
|
|
298
|
+
max_depth=MAX_COMPOSITE_RECEIPT_DEPTH,
|
|
299
|
+
max_members=MAX_COMPOSITE_ARRAY_ITEMS,
|
|
300
|
+
max_items=MAX_COMPOSITE_ARRAY_ITEMS,
|
|
301
|
+
expected_sha256=args.public_generation_receipt_sha256,
|
|
302
|
+
)
|
|
303
|
+
verify_generation_receipt(receipt)
|
|
304
|
+
publication = receipt["publication"]
|
|
305
|
+
if publication.get("expected_head_sha256") != args.public_manifest_sha256:
|
|
306
|
+
raise SourceContractError(
|
|
307
|
+
"LOCAL_SEARCH_WORK_BUDGET",
|
|
308
|
+
"public_manifest_sha256",
|
|
309
|
+
"this composite receipt describes another packed generation",
|
|
310
|
+
)
|
|
311
|
+
return publication["packed_receipt"], CatalogSearchWorkLimits(
|
|
312
|
+
**{name: getattr(args, name) for name in _WORK_BUDGET}
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _stated(args: argparse.Namespace, name: str) -> bool:
|
|
317
|
+
return getattr(args, name, None) is not None
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _time_filter(start: str | None, end: str | None) -> BuildTimeCoverage | None:
|
|
321
|
+
if (start is None) != (end is None):
|
|
322
|
+
raise SourceContractError(
|
|
323
|
+
"LOCAL_SEARCH_FILTER_PAIR",
|
|
324
|
+
"time_overlap",
|
|
325
|
+
"time start and end must be supplied together",
|
|
326
|
+
)
|
|
327
|
+
if start is None:
|
|
328
|
+
return None
|
|
329
|
+
try:
|
|
330
|
+
return BuildTimeCoverage(start, end) # type: ignore[arg-type]
|
|
331
|
+
except LocalSearchContractError as error:
|
|
332
|
+
raise SourceContractError(error.code, error.path, error.detail) from error
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _recipe_filter(
|
|
336
|
+
recipe_id: str | None, recipe_version: int | None, recipe_sha256: str | None
|
|
337
|
+
) -> RecipeIdentityFilter | None:
|
|
338
|
+
supplied = (recipe_id, recipe_version, recipe_sha256)
|
|
339
|
+
if any(value is not None for value in supplied) and not all(
|
|
340
|
+
value is not None for value in supplied
|
|
341
|
+
):
|
|
342
|
+
raise SourceContractError(
|
|
343
|
+
"LOCAL_SEARCH_FILTER_PAIR",
|
|
344
|
+
"recipe",
|
|
345
|
+
"recipe id, version, and digest must be supplied together",
|
|
346
|
+
)
|
|
347
|
+
if recipe_id is None:
|
|
348
|
+
return None
|
|
349
|
+
try:
|
|
350
|
+
return RecipeIdentityFilter(
|
|
351
|
+
recipe_id,
|
|
352
|
+
recipe_version,
|
|
353
|
+
recipe_sha256, # type: ignore[arg-type]
|
|
354
|
+
)
|
|
355
|
+
except LocalSearchContractError as error:
|
|
356
|
+
raise SourceContractError(error.code, error.path, error.detail) from error
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _digest_filter(kind: str | None, digest: str | None) -> ExactDigestFilter | None:
|
|
360
|
+
if (kind is None) != (digest is None):
|
|
361
|
+
raise SourceContractError(
|
|
362
|
+
"LOCAL_SEARCH_FILTER_PAIR",
|
|
363
|
+
"exact_digest",
|
|
364
|
+
"digest kind and digest must be supplied together",
|
|
365
|
+
)
|
|
366
|
+
if kind is None:
|
|
367
|
+
return None
|
|
368
|
+
try:
|
|
369
|
+
return ExactDigestFilter(kind, digest) # type: ignore[arg-type]
|
|
370
|
+
except LocalSearchContractError as error:
|
|
371
|
+
raise SourceContractError(error.code, error.path, error.detail) from error
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def _field(value: str) -> BuildField:
|
|
375
|
+
name, separator, logical_type = value.rpartition(":")
|
|
376
|
+
if not separator or not name or logical_type not in _LOGICAL_TYPES:
|
|
377
|
+
raise argparse.ArgumentTypeError(
|
|
378
|
+
f"must be NAME:LOGICAL_TYPE where type is one of {list(_LOGICAL_TYPES)}"
|
|
379
|
+
)
|
|
380
|
+
try:
|
|
381
|
+
return BuildField(name, logical_type)
|
|
382
|
+
except LocalSearchContractError as error:
|
|
383
|
+
raise argparse.ArgumentTypeError(error.detail) from error
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _source_identity(value: str) -> SourceIdentityFilter:
|
|
387
|
+
source_id, separator, digest = value.rpartition(":")
|
|
388
|
+
if not separator or not source_id or _DIGEST.fullmatch(digest) is None:
|
|
389
|
+
raise argparse.ArgumentTypeError("must be SOURCE_ID:CONTENT_SHA256")
|
|
390
|
+
try:
|
|
391
|
+
return SourceIdentityFilter(source_id, digest)
|
|
392
|
+
except LocalSearchContractError as error:
|
|
393
|
+
raise argparse.ArgumentTypeError(error.detail) from error
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _sha256(value: str) -> str:
|
|
397
|
+
if _DIGEST.fullmatch(value) is None:
|
|
398
|
+
raise argparse.ArgumentTypeError("must be a lowercase SHA-256 digest")
|
|
399
|
+
return value
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def _question(value: str) -> str:
|
|
403
|
+
if not 1 <= len(value) <= MAX_QUERY_CHARS:
|
|
404
|
+
raise argparse.ArgumentTypeError(f"must contain 1 to {MAX_QUERY_CHARS} characters")
|
|
405
|
+
return value
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _assert_closed_payload(value: Any) -> None:
|
|
409
|
+
if isinstance(value, Mapping):
|
|
410
|
+
for key, member in value.items():
|
|
411
|
+
normalized = str(key).lower()
|
|
412
|
+
if normalized in _FORBIDDEN_PAYLOAD_KEYS or normalized.endswith("_score"):
|
|
413
|
+
raise SourceContractError(
|
|
414
|
+
"LOCAL_SEARCH_OUTPUT_BOUNDARY",
|
|
415
|
+
"search.payload",
|
|
416
|
+
"service payload exposed a private score or mutable locator",
|
|
417
|
+
)
|
|
418
|
+
_assert_closed_payload(member)
|
|
419
|
+
elif isinstance(value, Sequence) and not isinstance(value, str | bytes | bytearray):
|
|
420
|
+
for member in value:
|
|
421
|
+
_assert_closed_payload(member)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _exit_code(payload: Mapping[str, Any]) -> int:
|
|
425
|
+
"""A search that stopped before it finished is not an answer, so it does not exit zero.
|
|
426
|
+
|
|
427
|
+
Nothing was ruled out: the budget closed. A script that treated that as "no fitting source"
|
|
428
|
+
would draw the one conclusion the result cannot support, so the exit code says so as well.
|
|
429
|
+
"""
|
|
430
|
+
|
|
431
|
+
return 0 if payload.get("status") == "local_search_complete" else 1
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
SPEC = CommandSpec(
|
|
435
|
+
name="search",
|
|
436
|
+
help="search exact published public and private local stores without changing them",
|
|
437
|
+
add_arguments=add_arguments,
|
|
438
|
+
run=run,
|
|
439
|
+
exit_code=_exit_code,
|
|
440
|
+
)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""``mr-data show`` -- read one build back: what it answers, what a row is, and how it checked out.
|
|
2
|
+
|
|
3
|
+
This module is the command and nothing else: its arguments, and the one call that turns them into
|
|
4
|
+
the payload both renderings are built from. The reading itself lives in
|
|
5
|
+
:mod:`mostlyright.data_harness.ux.readers`, so the same facts are available to a browser page
|
|
6
|
+
without going through argparse.
|
|
7
|
+
|
|
8
|
+
Nothing here prints, and nothing here catches: a refusal is a typed error, and the command line
|
|
9
|
+
renders it with the sentences the remediation map supplies.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from mostlyright.data_harness.ux.commands import CommandSpec
|
|
19
|
+
from mostlyright.data_harness.ux.readers import build_facts, plain_card
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def add_arguments(parser: argparse.ArgumentParser) -> None:
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"run_dir",
|
|
25
|
+
type=Path,
|
|
26
|
+
help="a build folder, or the Workbench folder that holds one",
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"--card",
|
|
30
|
+
action="store_true",
|
|
31
|
+
help="print the plain-language summary of the data and nothing else",
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--members",
|
|
35
|
+
action="store_true",
|
|
36
|
+
help="also list every file the Receipt covers",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
41
|
+
# Imported here, not at the top: this package is loaded while the command line is still being
|
|
42
|
+
# set up. Calling the command line's own helper rather than restating its rule is what stops
|
|
43
|
+
# show and verify ever disagreeing about which folder a Workbench folder's run lives in.
|
|
44
|
+
from mostlyright.data_harness.cli import _candidate_run_target
|
|
45
|
+
|
|
46
|
+
target = _candidate_run_target(args.run_dir)
|
|
47
|
+
facts = build_facts(target)
|
|
48
|
+
card = plain_card(facts)
|
|
49
|
+
if args.card:
|
|
50
|
+
return {"status": "build_shown", "run_dir": str(facts.run_dir), "card": card}
|
|
51
|
+
payload = facts.to_dict(members=args.members)
|
|
52
|
+
payload["card"] = card
|
|
53
|
+
return payload
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
SPEC = CommandSpec(
|
|
57
|
+
name="show",
|
|
58
|
+
help="show one build: what it answers, what a row is, its columns, checks, and fingerprints",
|
|
59
|
+
add_arguments=add_arguments,
|
|
60
|
+
run=run,
|
|
61
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""``mr-data whoami`` -- compatibility spelling for remotely truthful ``auth status``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from mostlyright.data_harness.ux.commands import CommandSpec, auth
|
|
9
|
+
|
|
10
|
+
DESCRIPTION = (
|
|
11
|
+
"Compatibility alias for mr-data auth status. Validates the effective device credential with "
|
|
12
|
+
"Cloud and reports stored metadata separately; it never prints a credential."
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def add_arguments(parser: argparse.ArgumentParser) -> None:
|
|
17
|
+
parser.description = DESCRIPTION
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--credential-store",
|
|
20
|
+
choices=("secure-file",),
|
|
21
|
+
help="explicitly use the secure-file fallback for first credential migration",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
26
|
+
payload = dict(auth.status_payload(credential_store=args.credential_store))
|
|
27
|
+
payload["compatibility_alias"] = "whoami"
|
|
28
|
+
return payload
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
SPEC = CommandSpec(
|
|
32
|
+
name="whoami",
|
|
33
|
+
help="compatibility alias for auth status",
|
|
34
|
+
add_arguments=add_arguments,
|
|
35
|
+
run=run,
|
|
36
|
+
exit_code=auth.exit_code,
|
|
37
|
+
)
|