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,368 @@
|
|
|
1
|
+
"""Every ``mr-data`` name, the lane it runs in, and the written reason it runs there.
|
|
2
|
+
|
|
3
|
+
WHY A REASON AND NOT JUST A LANE. PR #308 landed one hosted lane and one word for everything
|
|
4
|
+
else: forty-five commands were ``local``, which is true and says nothing. It cannot distinguish
|
|
5
|
+
``mr-data show`` -- which a person types about a hosted run every day and which had no hosted
|
|
6
|
+
answer -- from ``mr-data init``, which makes a folder on this computer and is meaningless without
|
|
7
|
+
one, from ``mr-data export-hosted-candidate``, which exists only to hand a locally built table to
|
|
8
|
+
the backend and is not part of anybody's hosted day. Those three want three different sentences
|
|
9
|
+
when they refuse, and a table with one column cannot give them.
|
|
10
|
+
|
|
11
|
+
So each name below carries a lane AND the sentence that justifies it. The sentence is not
|
|
12
|
+
decoration: :mod:`mostlyright.data_harness.thin.router` prints it in the refusal, the thin help
|
|
13
|
+
groups by lane, and ``docs/HOSTED-PARITY.md`` is generated from nothing else -- there is one
|
|
14
|
+
statement of why a command is where it is, and every surface reads it from here.
|
|
15
|
+
|
|
16
|
+
THE FIVE LANES.
|
|
17
|
+
|
|
18
|
+
``HOSTED``
|
|
19
|
+
Implemented against Studio V3 and reachable on a bare interpreter. The command means the same
|
|
20
|
+
thing it means locally, takes the same flags, and prints the same receipt.
|
|
21
|
+
|
|
22
|
+
``PORTABLE``
|
|
23
|
+
Already pure Python before ADR 0021. The thin profile runs the SAME implementation the local
|
|
24
|
+
profile runs, not a copy of it.
|
|
25
|
+
|
|
26
|
+
``HOSTED_PENDING``
|
|
27
|
+
User-facing, and it should be hosted. It is not, and the reason names the exact missing
|
|
28
|
+
capability rather than saying "later". Each of these is blocked on something outside this
|
|
29
|
+
repository, and the sentence says what would unblock it. A gap that is written down is a gap
|
|
30
|
+
somebody can close; one recorded as "local" is a gap nobody can see.
|
|
31
|
+
|
|
32
|
+
``WORKER``
|
|
33
|
+
An operator or worker surface. It runs inside the backend's own execution environment, never
|
|
34
|
+
on a person's laptop, so it has no thin lane by construction and never will. What it needs is
|
|
35
|
+
a sentence instead of a traceback.
|
|
36
|
+
|
|
37
|
+
``LOCAL``
|
|
38
|
+
Local tooling, behind the ``[local]`` extra by design. Either it is about files on this
|
|
39
|
+
computer -- and there are none in a hosted build -- or the hosted lane already answers the
|
|
40
|
+
same question under a different name, which the reason says.
|
|
41
|
+
|
|
42
|
+
⚠ THE SET OF NAMES IS THE COMMAND LINE'S, NOT THIS FILE'S. ``tests/test_thin_client.py`` asserts
|
|
43
|
+
:data:`VOCABULARY` equals the live parser's subcommands, so a command cannot be added to one and
|
|
44
|
+
forgotten in the other.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
from __future__ import annotations
|
|
48
|
+
|
|
49
|
+
from dataclasses import dataclass
|
|
50
|
+
|
|
51
|
+
#: Implemented by the thin lane against Studio.
|
|
52
|
+
HOSTED = "hosted"
|
|
53
|
+
|
|
54
|
+
#: Pure Python already, and identical in both profiles.
|
|
55
|
+
PORTABLE = "portable"
|
|
56
|
+
|
|
57
|
+
#: User-facing, not hosted yet, and blocked on a named capability outside this repository.
|
|
58
|
+
HOSTED_PENDING = "hosted-pending"
|
|
59
|
+
|
|
60
|
+
#: A backend operator surface, which is never a thin-client concern.
|
|
61
|
+
WORKER = "worker"
|
|
62
|
+
|
|
63
|
+
#: Needs the ``[local]`` extra, by design.
|
|
64
|
+
LOCAL = "local"
|
|
65
|
+
|
|
66
|
+
#: Every lane, in the order a reader should meet them.
|
|
67
|
+
LANES: tuple[str, ...] = (HOSTED, PORTABLE, HOSTED_PENDING, WORKER, LOCAL)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(frozen=True)
|
|
71
|
+
class Lane:
|
|
72
|
+
"""One command's lane and the written reason it is in that lane.
|
|
73
|
+
|
|
74
|
+
``reason`` is one sentence, in the second person where it addresses somebody at a terminal,
|
|
75
|
+
and it must survive being printed on its own: it is what a refusal says after the command
|
|
76
|
+
name, with no surrounding paragraph to lean on.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
lane: str
|
|
80
|
+
reason: str
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# --------------------------------------------------------------------------------------------
|
|
84
|
+
# The table
|
|
85
|
+
# --------------------------------------------------------------------------------------------
|
|
86
|
+
#
|
|
87
|
+
# Sorted by name. Read it as the answer to one question asked fifty-eight times: if somebody types
|
|
88
|
+
# this on a machine that has no local execution lane, what should happen?
|
|
89
|
+
|
|
90
|
+
CLASSIFICATION: dict[str, Lane] = {
|
|
91
|
+
"acquire": Lane(
|
|
92
|
+
HOSTED,
|
|
93
|
+
"it fetches one public address in Studio's clean room and prints the Receipt Studio "
|
|
94
|
+
"bound, naming which party resolved the pinned Reader",
|
|
95
|
+
),
|
|
96
|
+
"acquire-cancel": Lane(
|
|
97
|
+
HOSTED,
|
|
98
|
+
"it cancels one active public acquisition by the workspace and session coordinate its "
|
|
99
|
+
"Receipt printed, reusing a durable idempotency journal if the response was lost",
|
|
100
|
+
),
|
|
101
|
+
"acquire-slices": Lane(
|
|
102
|
+
HOSTED_PENDING,
|
|
103
|
+
"the hosted request contract admits one URL and a slice order needs two origin-bound "
|
|
104
|
+
"locators plus an ordered plan, and its safety rests on those N+2 requests sharing one "
|
|
105
|
+
"DNS epoch -- which fanning them out as one hosted session each would silently lose",
|
|
106
|
+
),
|
|
107
|
+
"adapters": Lane(
|
|
108
|
+
LOCAL,
|
|
109
|
+
"it lists what the source adapters an acquisition document registers can do here, which "
|
|
110
|
+
"is a fact about this installation and not about the backend",
|
|
111
|
+
),
|
|
112
|
+
"agent-request-validate": Lane(
|
|
113
|
+
LOCAL,
|
|
114
|
+
"it checks a request document against the contracts compiled into this installation, and "
|
|
115
|
+
"reaches no network at all",
|
|
116
|
+
),
|
|
117
|
+
"approve": Lane(
|
|
118
|
+
HOSTED,
|
|
119
|
+
"it records the decision you are asking for, prints where the person who must grant it "
|
|
120
|
+
"does so, and reads back what they decided; it never decides",
|
|
121
|
+
),
|
|
122
|
+
"author": Lane(
|
|
123
|
+
LOCAL,
|
|
124
|
+
"it turns a YAML file on this computer into a Recipe file on this computer; the hosted "
|
|
125
|
+
"lane answers recipe authoring with `propose`, which drives Studio's own authoring routes",
|
|
126
|
+
),
|
|
127
|
+
"auth": Lane(
|
|
128
|
+
PORTABLE,
|
|
129
|
+
"it validates the effective device key with Cloud and explains the token boundary without "
|
|
130
|
+
"requiring the local execution lane",
|
|
131
|
+
),
|
|
132
|
+
"build": Lane(HOSTED, "it queues one hosted build and says where to watch it"),
|
|
133
|
+
"catalog-author": Lane(LOCAL, "it writes one public catalog generation to a folder here"),
|
|
134
|
+
"catalog-fill": Lane(LOCAL, "it stages and publishes one public catalog successor here"),
|
|
135
|
+
"catalog-harvest": Lane(LOCAL, "it sweeps a provider into a folder here, under a key file"),
|
|
136
|
+
"catalog-publish": Lane(LOCAL, "it publishes one authored generation from a folder here"),
|
|
137
|
+
"catalog-search": Lane(LOCAL, "it searches a catalog installed on this computer"),
|
|
138
|
+
"catalog-update": Lane(LOCAL, "it installs a catalog release onto this computer"),
|
|
139
|
+
"deploy": Lane(
|
|
140
|
+
LOCAL,
|
|
141
|
+
"it stages a Build made on this computer and activates it; the hosted lane answers this "
|
|
142
|
+
"with `propose`, which opens the recipe proposal a hosted build activates, so there is "
|
|
143
|
+
"nothing here to stage",
|
|
144
|
+
),
|
|
145
|
+
"deploy-dataset": Lane(HOSTED, "it downloads one hosted run's dataset and verifies its digest"),
|
|
146
|
+
"deploy-plan": Lane(
|
|
147
|
+
LOCAL,
|
|
148
|
+
"it writes the request document for deploying a Build made on this computer, and contacts "
|
|
149
|
+
"nothing; the hosted lane answers this with `propose`, which drives the deployment routes "
|
|
150
|
+
"directly from an authored bundle",
|
|
151
|
+
),
|
|
152
|
+
"deploy-status": Lane(
|
|
153
|
+
HOSTED, "it reports what Studio says about the run one deployment queued"
|
|
154
|
+
),
|
|
155
|
+
"diff": Lane(HOSTED, "it compares two hosted runs and says what changed"),
|
|
156
|
+
"export-hosted-candidate": Lane(
|
|
157
|
+
WORKER,
|
|
158
|
+
"it packages a Build made on this computer for the backend to ingest, which is the local "
|
|
159
|
+
"build lane's own handoff step and not part of any hosted day",
|
|
160
|
+
),
|
|
161
|
+
"fleet": Lane(HOSTED, "it says which hosted runs are waiting for a person"),
|
|
162
|
+
"index": Lane(LOCAL, "it builds a private search index over Builds on this computer"),
|
|
163
|
+
"init": Lane(LOCAL, "it makes a workbench folder on this computer"),
|
|
164
|
+
"inspect": Lane(HOSTED, "it shows the sealed evidence Studio holds for one hosted run"),
|
|
165
|
+
"inventory": Lane(
|
|
166
|
+
LOCAL,
|
|
167
|
+
"it lists the operations, types, joins and engines this installation can run, and a "
|
|
168
|
+
"hosted profile runs none of them",
|
|
169
|
+
),
|
|
170
|
+
"list": Lane(HOSTED, "it lists the hosted runs in this workspace"),
|
|
171
|
+
"login": Lane(PORTABLE, "sign in and store a device credential"),
|
|
172
|
+
"note": Lane(
|
|
173
|
+
HOSTED,
|
|
174
|
+
"it writes one cell of the operator-facing decision record into the hosted run's own "
|
|
175
|
+
"log, where the notebook and the live view both read it; it is prose, not evidence",
|
|
176
|
+
),
|
|
177
|
+
"notebook": Lane(HOSTED, "it brings back the notebook Studio rendered for one hosted run"),
|
|
178
|
+
"peek": Lane(HOSTED, "it shows the columns, types and first rows of one hosted table version"),
|
|
179
|
+
"plan": Lane(
|
|
180
|
+
LOCAL,
|
|
181
|
+
"it checks and locks the plan in a workbench folder on this computer; the hosted lane "
|
|
182
|
+
"answers this with `propose`, whose table plan is created against Studio directly",
|
|
183
|
+
),
|
|
184
|
+
"plan-check": Lane(
|
|
185
|
+
LOCAL,
|
|
186
|
+
"it builds a plan into a throwaway folder on this computer to see whether it works",
|
|
187
|
+
),
|
|
188
|
+
"preflight": Lane(
|
|
189
|
+
LOCAL,
|
|
190
|
+
"it reports what would stop a build on this computer, which is the one question a hosted "
|
|
191
|
+
"profile never has to ask",
|
|
192
|
+
),
|
|
193
|
+
"propose": Lane(
|
|
194
|
+
HOSTED,
|
|
195
|
+
"it authors one hosted recipe proposal from a bundle of documents -- the Dataset, "
|
|
196
|
+
"question, sources, table plan and the recipe -- and opens the approval a person settles, "
|
|
197
|
+
"so a hosted build has a proposal to name; it asks and never grants",
|
|
198
|
+
),
|
|
199
|
+
"recipe-approve": Lane(
|
|
200
|
+
HOSTED,
|
|
201
|
+
"it is the same ask about one Table recipe approval, which a signed-in editor confirms in "
|
|
202
|
+
"the dashboard rather than under a step-up; the hosted lane asks and never grants",
|
|
203
|
+
),
|
|
204
|
+
"recipe-export": Lane(LOCAL, "it writes a checked Recipe to a file on this computer"),
|
|
205
|
+
"recipe-run": Lane(
|
|
206
|
+
LOCAL,
|
|
207
|
+
"it executes a Recipe on this computer; `mr-data run --hosted` is the hosted lane's answer "
|
|
208
|
+
"to the same question and it is already here",
|
|
209
|
+
),
|
|
210
|
+
"recipe-validate": Lane(
|
|
211
|
+
LOCAL, "it checks and fingerprints a Recipe file on this computer, reaching nothing"
|
|
212
|
+
),
|
|
213
|
+
"recipe-verify": Lane(
|
|
214
|
+
LOCAL, "it re-checks a Recipe version against inputs pinned on this computer"
|
|
215
|
+
),
|
|
216
|
+
"record": Lane(LOCAL, "it seals messages already recorded on this computer into batches"),
|
|
217
|
+
"research-close": Lane(
|
|
218
|
+
HOSTED,
|
|
219
|
+
"it closes one hosted research session, cancelling the probes still queued, so its "
|
|
220
|
+
"worker exits and the service behind it scales back to zero",
|
|
221
|
+
),
|
|
222
|
+
"research-open": Lane(
|
|
223
|
+
HOSTED,
|
|
224
|
+
"it opens one hosted research session against a Dataset and a question, and shows the "
|
|
225
|
+
"worker warming up rather than hiding the cold start",
|
|
226
|
+
),
|
|
227
|
+
"research-probe": Lane(
|
|
228
|
+
HOSTED,
|
|
229
|
+
"it asks a research session's warm worker one question about a source, follows the "
|
|
230
|
+
"session's own event stream until the probe settles, and prints the answer; the answer is "
|
|
231
|
+
"exploration, never evidence",
|
|
232
|
+
),
|
|
233
|
+
"research-status": Lane(
|
|
234
|
+
HOSTED,
|
|
235
|
+
"it reports Studio's own reading of one research session, and of one probe with its "
|
|
236
|
+
"answer when asked",
|
|
237
|
+
),
|
|
238
|
+
"resume": Lane(LOCAL, "it picks up an interrupted build in a folder on this computer"),
|
|
239
|
+
"review": Lane(
|
|
240
|
+
LOCAL,
|
|
241
|
+
"it seals a review decision from reports on this computer; hosted review decisions are "
|
|
242
|
+
"Studio's approvals surface and carry its step-up requirement",
|
|
243
|
+
),
|
|
244
|
+
"review-setup": Lane(LOCAL, "it creates protected review material on this computer"),
|
|
245
|
+
"run": Lane(HOSTED, "it queues one hosted build and says where to watch it"),
|
|
246
|
+
"search": Lane(LOCAL, "it searches stores published or indexed on this computer"),
|
|
247
|
+
"serve": Lane(LOCAL, "it serves a dataset from this computer on a local address"),
|
|
248
|
+
"show": Lane(HOSTED, "it shows what one hosted run holds"),
|
|
249
|
+
"sign-review": Lane(LOCAL, "it signs a reviewer report with a key held on this computer"),
|
|
250
|
+
"source-audit": Lane(
|
|
251
|
+
LOCAL, "it checks proposed sources against the contracts compiled into this installation"
|
|
252
|
+
),
|
|
253
|
+
"status": Lane(HOSTED, "it reports Studio's own reading of one hosted run, with its receipts"),
|
|
254
|
+
"verify": Lane(HOSTED, "it re-checks one hosted run against the evidence Studio sealed"),
|
|
255
|
+
"view": Lane(HOSTED, "it opens the notebook Studio rendered for one hosted run"),
|
|
256
|
+
"watch": Lane(HOSTED, "it streams one hosted run's live progress, resuming across stream cuts"),
|
|
257
|
+
"whoami": Lane(PORTABLE, "it is the compatibility alias for remotely truthful `auth status`"),
|
|
258
|
+
"workflow": Lane(
|
|
259
|
+
LOCAL,
|
|
260
|
+
"it prints the local build workflow and who decides at each step; the hosted workflow is "
|
|
261
|
+
"the dashboard's",
|
|
262
|
+
),
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
#: Every command name and its lane. The half of :data:`CLASSIFICATION` the router branches on,
|
|
266
|
+
#: derived rather than restated so the two can never disagree.
|
|
267
|
+
VOCABULARY: dict[str, str] = {name: item.lane for name, item in CLASSIFICATION.items()}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def names_in(lane: str) -> tuple[str, ...]:
|
|
271
|
+
"""Every command in one lane, sorted."""
|
|
272
|
+
|
|
273
|
+
return tuple(sorted(name for name, item in CLASSIFICATION.items() if item.lane == lane))
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def reason_for(command: str) -> str:
|
|
277
|
+
"""The written reason one command runs where it runs."""
|
|
278
|
+
|
|
279
|
+
return CLASSIFICATION[command].reason
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# --------------------------------------------------------------------------------------------
|
|
283
|
+
# The other six executables
|
|
284
|
+
# --------------------------------------------------------------------------------------------
|
|
285
|
+
#
|
|
286
|
+
# `mr-data` is not the only console script this distribution installs. The six below are the
|
|
287
|
+
# backend's own executables: they are started by the worker image with a job descriptor and a
|
|
288
|
+
# capability descriptor, they speak the fenced internal protocol, and none of them has any meaning
|
|
289
|
+
# on a laptop. On a thin install every one of them used to end in a traceback out of `pyarrow` or
|
|
290
|
+
# `cryptography` before its first line ran, because the module holding the entry point imports
|
|
291
|
+
# both at module scope.
|
|
292
|
+
#
|
|
293
|
+
# ⚠ THE GUARD CANNOT LIVE IN THOSE MODULES. A check inside `hosted_worker.producer_main` is
|
|
294
|
+
# unreachable on a thin install: the import that fails is the one that loads the module the
|
|
295
|
+
# function is defined in. So the console script points at a shim that imports nothing until it has
|
|
296
|
+
# decided, and `hosted_worker.py` is not touched at all -- which is also what keeps this out of the
|
|
297
|
+
# way of the lane editing that file this run.
|
|
298
|
+
|
|
299
|
+
#: Console script name -> (module, attribute) it delegates to once the local lane is present, and
|
|
300
|
+
#: the sentence that says what the executable is for.
|
|
301
|
+
WORKER_ENTRY_POINTS: dict[str, tuple[str, str, str]] = {
|
|
302
|
+
"mr-data-bootstrap": (
|
|
303
|
+
"mostlyright.data_harness.hosted_bootstrap",
|
|
304
|
+
"main",
|
|
305
|
+
"prepares a hosted worker's execution environment before a job runs",
|
|
306
|
+
),
|
|
307
|
+
"mr-data-catalog-job": (
|
|
308
|
+
"mostlyright.data_harness.catalog_job",
|
|
309
|
+
"catalog_job_main",
|
|
310
|
+
"runs one stage of the sealed source catalogue's harvest, author and publish pipeline",
|
|
311
|
+
),
|
|
312
|
+
"mr-data-coordinator": (
|
|
313
|
+
"mostlyright.data_harness.coordinator",
|
|
314
|
+
"coordinator_main",
|
|
315
|
+
"runs the hosted work loop that claims and executes attempts",
|
|
316
|
+
),
|
|
317
|
+
"mr-data-crawler": (
|
|
318
|
+
"mostlyright.data_harness.hosted_crawler",
|
|
319
|
+
"crawler_main",
|
|
320
|
+
"runs the isolated hosted fetcher that holds no credential",
|
|
321
|
+
),
|
|
322
|
+
"mr-data-crawler-job": (
|
|
323
|
+
"mostlyright.data_harness.hosted_crawler_job",
|
|
324
|
+
"crawler_job_main",
|
|
325
|
+
"runs one isolated hosted fetch job to completion",
|
|
326
|
+
),
|
|
327
|
+
"mr-data-producer": (
|
|
328
|
+
"mostlyright.data_harness.hosted_worker",
|
|
329
|
+
"producer_main",
|
|
330
|
+
"runs one hosted build attempt inside the backend's worker image",
|
|
331
|
+
),
|
|
332
|
+
"mr-data-verifier": (
|
|
333
|
+
"mostlyright.data_harness.hosted_worker",
|
|
334
|
+
"verifier_main",
|
|
335
|
+
"independently re-checks one hosted build attempt inside the backend's worker image",
|
|
336
|
+
),
|
|
337
|
+
"mr-data-session-worker": (
|
|
338
|
+
"mostlyright.data_harness.hosted_session_worker",
|
|
339
|
+
"session_worker_main",
|
|
340
|
+
"serves one warm research session inside the backend's Cloud Run session-worker service",
|
|
341
|
+
),
|
|
342
|
+
"mr-data-session-worker-job": (
|
|
343
|
+
"mostlyright.data_harness.hosted_session_worker",
|
|
344
|
+
"session_worker_job_main",
|
|
345
|
+
"runs one research session to terminal state inside a backend Cloud Run Job task",
|
|
346
|
+
),
|
|
347
|
+
"mr-data-ingestion-job": (
|
|
348
|
+
"mostlyright.data_harness.hosted_ingestion_job",
|
|
349
|
+
"ingestion_job_main",
|
|
350
|
+
"runs one fenced resumable-ingestion delivery inside a backend Cloud Run Job task",
|
|
351
|
+
),
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
__all__ = [
|
|
356
|
+
"CLASSIFICATION",
|
|
357
|
+
"HOSTED",
|
|
358
|
+
"HOSTED_PENDING",
|
|
359
|
+
"LANES",
|
|
360
|
+
"LOCAL",
|
|
361
|
+
"PORTABLE",
|
|
362
|
+
"VOCABULARY",
|
|
363
|
+
"WORKER",
|
|
364
|
+
"WORKER_ENTRY_POINTS",
|
|
365
|
+
"Lane",
|
|
366
|
+
"names_in",
|
|
367
|
+
"reason_for",
|
|
368
|
+
]
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""The backend executables' front doors, so a thin install answers instead of crashing.
|
|
2
|
+
|
|
3
|
+
``mr-data-producer``, ``mr-data-verifier``, ``mr-data-coordinator``, ``mr-data-bootstrap``,
|
|
4
|
+
``mr-data-crawler``, ``mr-data-crawler-job``, ``mr-data-catalog-job``,
|
|
5
|
+
``mr-data-session-worker``, ``mr-data-session-worker-job`` and ``mr-data-ingestion-job`` are the
|
|
6
|
+
backend's own executables.
|
|
7
|
+
Most are started by the worker image with a job descriptor and a capability descriptor on numbered
|
|
8
|
+
file descriptors. The session-worker Job instead receives only an opaque dispatch identifier and
|
|
9
|
+
Studio exchange coordinates, then obtains its fenced lease through the authenticated exchange;
|
|
10
|
+
it receives no capability descriptor. Nothing about either form makes sense on a laptop, and ADR
|
|
11
|
+
0021 does not give them a hosted lane because they ARE the hosted lane.
|
|
12
|
+
|
|
13
|
+
What they should not do is end in a traceback. Every one of those entry points is defined in a
|
|
14
|
+
module that imports ``pyarrow`` or ``cryptography`` at module scope, so on a thin install the
|
|
15
|
+
failure happened during the import that loaded the entry point itself -- before any code of ours
|
|
16
|
+
could say anything. PR #308 recorded that as a known gap and left it, because closing it looked
|
|
17
|
+
like it meant editing ``hosted_worker.py``.
|
|
18
|
+
|
|
19
|
+
It does not. The console script points HERE instead, and this module imports nothing at all until
|
|
20
|
+
it has decided which of the two answers it owes:
|
|
21
|
+
|
|
22
|
+
* with the ``[local]`` extra present, it resolves the real entry point and hands the arguments
|
|
23
|
+
over unchanged -- byte-identical behaviour, one extra function call in the path;
|
|
24
|
+
* without it, it prints one typed sentence naming the executable and what it is for, on stderr,
|
|
25
|
+
through the same error map every other ``mr-data`` refusal goes through, and exits 2.
|
|
26
|
+
|
|
27
|
+
``hosted_worker.py`` is not touched by any of this, which is what a reviewer should check first.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import importlib
|
|
33
|
+
import json
|
|
34
|
+
import sys
|
|
35
|
+
from collections.abc import Sequence
|
|
36
|
+
|
|
37
|
+
from mostlyright.data_harness.thin.vocabulary import WORKER_ENTRY_POINTS
|
|
38
|
+
|
|
39
|
+
#: The code every one of these refusals carries. One code, not six: the answer is the same answer
|
|
40
|
+
#: -- this executable belongs to the backend -- and six codes would be six ways to say it.
|
|
41
|
+
WORKER_ENTRY_POINT_CODE = "THIN_WORKER_ENTRY_POINT_IS_LOCAL"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _refuse(executable: str, purpose: str, argv: Sequence[str]) -> int:
|
|
45
|
+
"""Say what this executable is, where it runs, and what to install to run it here."""
|
|
46
|
+
|
|
47
|
+
from mostlyright.data_harness.thin.router import LOCAL_INSTALL_HINT
|
|
48
|
+
from mostlyright.data_harness.ux.remediation import remediation_for
|
|
49
|
+
from mostlyright.data_harness.ux.render import render_error
|
|
50
|
+
|
|
51
|
+
detail = (
|
|
52
|
+
f"{executable} is a backend executable -- it {purpose} -- and this installation is the "
|
|
53
|
+
f"hosted profile, which carries no execution lane; {LOCAL_INSTALL_HINT}"
|
|
54
|
+
)
|
|
55
|
+
remediation = remediation_for(WORKER_ENTRY_POINT_CODE)
|
|
56
|
+
if "--json" in argv:
|
|
57
|
+
print(
|
|
58
|
+
json.dumps(
|
|
59
|
+
{
|
|
60
|
+
"schema_version": "mr-data-error.v1",
|
|
61
|
+
"code": WORKER_ENTRY_POINT_CODE,
|
|
62
|
+
"error": detail,
|
|
63
|
+
"headline": detail,
|
|
64
|
+
"remediation": list(remediation),
|
|
65
|
+
},
|
|
66
|
+
ensure_ascii=False,
|
|
67
|
+
sort_keys=True,
|
|
68
|
+
),
|
|
69
|
+
file=sys.stderr,
|
|
70
|
+
flush=True,
|
|
71
|
+
)
|
|
72
|
+
else:
|
|
73
|
+
print(
|
|
74
|
+
render_error(detail, code=WORKER_ENTRY_POINT_CODE, remediation=remediation),
|
|
75
|
+
file=sys.stderr,
|
|
76
|
+
flush=True,
|
|
77
|
+
)
|
|
78
|
+
return 2
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _dispatch(executable: str, argv: Sequence[str] | None) -> int:
|
|
82
|
+
"""Hand one backend executable's arguments to its real entry point, or refuse by name."""
|
|
83
|
+
|
|
84
|
+
from mostlyright.data_harness.thin.router import local_lane_available
|
|
85
|
+
|
|
86
|
+
module_name, attribute, purpose = WORKER_ENTRY_POINTS[executable]
|
|
87
|
+
arguments = list(sys.argv[1:] if argv is None else argv)
|
|
88
|
+
if not local_lane_available():
|
|
89
|
+
return _refuse(executable, purpose, arguments)
|
|
90
|
+
entry_point = getattr(importlib.import_module(module_name), attribute)
|
|
91
|
+
return int(entry_point(arguments))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def bootstrap_main(argv: Sequence[str] | None = None) -> int:
|
|
95
|
+
return _dispatch("mr-data-bootstrap", argv)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def catalog_job_main(argv: Sequence[str] | None = None) -> int:
|
|
99
|
+
return _dispatch("mr-data-catalog-job", argv)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def coordinator_main(argv: Sequence[str] | None = None) -> int:
|
|
103
|
+
return _dispatch("mr-data-coordinator", argv)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def crawler_main(argv: Sequence[str] | None = None) -> int:
|
|
107
|
+
return _dispatch("mr-data-crawler", argv)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def crawler_job_main(argv: Sequence[str] | None = None) -> int:
|
|
111
|
+
return _dispatch("mr-data-crawler-job", argv)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def producer_main(argv: Sequence[str] | None = None) -> int:
|
|
115
|
+
return _dispatch("mr-data-producer", argv)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def verifier_main(argv: Sequence[str] | None = None) -> int:
|
|
119
|
+
return _dispatch("mr-data-verifier", argv)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def session_worker_main(argv: Sequence[str] | None = None) -> int:
|
|
123
|
+
return _dispatch("mr-data-session-worker", argv)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def session_worker_job_main(argv: Sequence[str] | None = None) -> int:
|
|
127
|
+
return _dispatch("mr-data-session-worker-job", argv)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def ingestion_job_main(argv: Sequence[str] | None = None) -> int:
|
|
131
|
+
return _dispatch("mr-data-ingestion-job", argv)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
#: Console script name -> the function in this module that backs it. Held equal to
|
|
135
|
+
#: ``pyproject.toml``'s ``[project.scripts]`` by ``tests/test_thin_client.py``, so a backend
|
|
136
|
+
#: executable cannot be added on one side alone.
|
|
137
|
+
SHIMS = {
|
|
138
|
+
"mr-data-bootstrap": bootstrap_main,
|
|
139
|
+
"mr-data-catalog-job": catalog_job_main,
|
|
140
|
+
"mr-data-coordinator": coordinator_main,
|
|
141
|
+
"mr-data-crawler": crawler_main,
|
|
142
|
+
"mr-data-crawler-job": crawler_job_main,
|
|
143
|
+
"mr-data-producer": producer_main,
|
|
144
|
+
"mr-data-verifier": verifier_main,
|
|
145
|
+
"mr-data-session-worker": session_worker_main,
|
|
146
|
+
"mr-data-session-worker-job": session_worker_job_main,
|
|
147
|
+
"mr-data-ingestion-job": ingestion_job_main,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
__all__ = [
|
|
152
|
+
"SHIMS",
|
|
153
|
+
"WORKER_ENTRY_POINT_CODE",
|
|
154
|
+
"bootstrap_main",
|
|
155
|
+
"catalog_job_main",
|
|
156
|
+
"coordinator_main",
|
|
157
|
+
"crawler_job_main",
|
|
158
|
+
"crawler_main",
|
|
159
|
+
"ingestion_job_main",
|
|
160
|
+
"producer_main",
|
|
161
|
+
"session_worker_job_main",
|
|
162
|
+
"session_worker_main",
|
|
163
|
+
"verifier_main",
|
|
164
|
+
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "ucum-pin.v1",
|
|
3
|
+
"covers": "src/mostlyright/data_harness/ucum",
|
|
4
|
+
"standard": "UCUM",
|
|
5
|
+
"standard_version": "2.2",
|
|
6
|
+
"standard_release": "2024-06-28",
|
|
7
|
+
"specification": "https://ucum.org/ucum",
|
|
8
|
+
"subset": "docs/UNITS.md",
|
|
9
|
+
"canonical_tree_digest": {
|
|
10
|
+
"algorithm": "sha256",
|
|
11
|
+
"rule": [
|
|
12
|
+
"Collect every regular file under the covered path except this one.",
|
|
13
|
+
"Order them by their path relative to that root, compared as a tuple of path components.",
|
|
14
|
+
"Fold each file into one running sha256: the relative POSIX path as UTF-8, one NUL byte, then the sha256 digest of the file's bytes.",
|
|
15
|
+
"The hexadecimal digest of the running sha256 is the tree digest."
|
|
16
|
+
],
|
|
17
|
+
"note": "The same rule vendor/VENDOR.lock.json states, and TABLE-PIN.json is outside it because a digest cannot cover the file recording it."
|
|
18
|
+
},
|
|
19
|
+
"artifacts": [
|
|
20
|
+
{
|
|
21
|
+
"path": "ucum-subset.v1.json",
|
|
22
|
+
"sha256": "24caf113858cd4fb58dfb800e1b0a04236d5718e68073607d3fba30227e35d23",
|
|
23
|
+
"bytes": 14237
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"tree_sha256": "4e3301c3f46ee162bfd006e92d2bdaa89e74cafe6228064d0b0871d702365a12",
|
|
27
|
+
"file_count": 1,
|
|
28
|
+
"consumers": [
|
|
29
|
+
{
|
|
30
|
+
"name": "mostlyright.data_harness.units",
|
|
31
|
+
"note": "Reads the table once per process and resolves every declared unit against it. Nothing else opens these files at run time."
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"update_procedure": [
|
|
35
|
+
"State the change in docs/UNITS.md first: the subset is a documented contract, not whatever the table happens to hold.",
|
|
36
|
+
"Add or amend the atom with both its recorded definition and its recorded factor, so the two can be checked against each other.",
|
|
37
|
+
"Recompute the digests here, and the file count with them. Do not update one alone.",
|
|
38
|
+
"Run `uv run --extra dev python -m pytest -q tests/test_units_table.py tests/test_units.py`."
|
|
39
|
+
]
|
|
40
|
+
}
|