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,79 @@
|
|
|
1
|
+
"""``mr-data author`` -- write the Recipe in YAML, get the Recipe you can approve.
|
|
2
|
+
|
|
3
|
+
Three gates stand between the file a person writes and the fingerprint `mr-data approve` binds:
|
|
4
|
+
the reader refuses rather than guesses, `parse_fresh_recipe` checks the result against the
|
|
5
|
+
contract field by field and resolves every Reader pin, and the written file is created without
|
|
6
|
+
overwriting anything.
|
|
7
|
+
|
|
8
|
+
This module is the command and nothing else. The reading lives in
|
|
9
|
+
:mod:`mostlyright.data_harness.ux.author_yaml`, so the same step is available to a browser page
|
|
10
|
+
without going through argparse. Nothing here prints, and nothing here catches a refusal: the
|
|
11
|
+
command line renders it with the sentences the remediation map supplies.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from mostlyright.data_harness.canonical import canonical_json_bytes
|
|
21
|
+
from mostlyright.data_harness.recipe import RecipeError, parse_fresh_recipe
|
|
22
|
+
from mostlyright.data_harness.ux.author_yaml import parse_author_yaml, read_author_source
|
|
23
|
+
from mostlyright.data_harness.ux.commands import CommandSpec
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def add_arguments(parser: argparse.ArgumentParser) -> None:
|
|
27
|
+
# The flag names match recipe-export deliberately: a person who knows one knows the other.
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"--recipe",
|
|
30
|
+
type=Path,
|
|
31
|
+
required=True,
|
|
32
|
+
help="the YAML file you wrote the Recipe in",
|
|
33
|
+
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--output",
|
|
36
|
+
type=Path,
|
|
37
|
+
required=True,
|
|
38
|
+
help="where to write the Recipe; nothing is ever overwritten",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
43
|
+
# Imported here, not at the top: this package is loaded while the command line is still being
|
|
44
|
+
# set up. Reusing the command line's own writer is what keeps this file's publication receipt
|
|
45
|
+
# identical to the one every other written output carries.
|
|
46
|
+
from mostlyright.data_harness import cli
|
|
47
|
+
|
|
48
|
+
recipe = parse_fresh_recipe(parse_author_yaml(read_author_source(args.recipe)))
|
|
49
|
+
raw = canonical_json_bytes(recipe.to_dict())
|
|
50
|
+
try:
|
|
51
|
+
publication = cli._write_output_exclusive(
|
|
52
|
+
args.output,
|
|
53
|
+
raw,
|
|
54
|
+
purpose="recipe",
|
|
55
|
+
authority="stdout_recipe_receipt",
|
|
56
|
+
)
|
|
57
|
+
except FileExistsError as exc:
|
|
58
|
+
raise RecipeError(
|
|
59
|
+
"RECIPE_OUTPUT_EXISTS",
|
|
60
|
+
"output",
|
|
61
|
+
"recipe output already exists",
|
|
62
|
+
) from exc
|
|
63
|
+
return {
|
|
64
|
+
"status": "recipe_authored",
|
|
65
|
+
"output": str(args.output),
|
|
66
|
+
"recipe_id": recipe.recipe_id,
|
|
67
|
+
"recipe_version": recipe.recipe_version,
|
|
68
|
+
"recipe_digest": recipe.digest,
|
|
69
|
+
"expected_size_bytes": len(raw),
|
|
70
|
+
"publication": publication,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
SPEC = CommandSpec(
|
|
75
|
+
name="author",
|
|
76
|
+
help="turn a YAML recipe description into a recipe you can approve",
|
|
77
|
+
add_arguments=add_arguments,
|
|
78
|
+
run=run,
|
|
79
|
+
)
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"""``catalog-author``: stream one converged v4 generation into bounded authoring shards.
|
|
2
|
+
|
|
3
|
+
This module is the explicit second stage of the provider-scale harvest -> author -> publish
|
|
4
|
+
workflow. It reads a private staging root and an exact harvest receipt, and writes immutable
|
|
5
|
+
authoring shards behind one atomic manifest plus one secret-free receipt. It reaches no network,
|
|
6
|
+
accepts no key material, opens no predecessor catalog, and never loads a whole generation into
|
|
7
|
+
memory; every one of those properties is a structural consequence of what it imports.
|
|
8
|
+
|
|
9
|
+
A ``--resume`` may replace only the exact typed-incomplete receipt its interrupted run left at the
|
|
10
|
+
same path, after checking that the retained receipt belongs to this stage and describes this
|
|
11
|
+
output root. A fresh receipt path remains exclusive, and a complete receipt is never overwritten.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
from collections.abc import Mapping
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from mostlyright.data_harness.canonical import (
|
|
22
|
+
CanonicalJSONError,
|
|
23
|
+
parse_canonical_json,
|
|
24
|
+
sha256_bytes,
|
|
25
|
+
)
|
|
26
|
+
from mostlyright.data_harness.sources.catalog.authoring_shards import (
|
|
27
|
+
AUTHORING_RECEIPT_SCHEMA,
|
|
28
|
+
MAX_AUTHORING_SHARD_BYTES,
|
|
29
|
+
MAX_AUTHORING_SHARD_ENTRIES,
|
|
30
|
+
AuthoringLimits,
|
|
31
|
+
AuthoringSelection,
|
|
32
|
+
CatalogAuthoringRefused,
|
|
33
|
+
run_catalog_authoring,
|
|
34
|
+
)
|
|
35
|
+
from mostlyright.data_harness.sources.catalog.bounded_io import (
|
|
36
|
+
BoundedReadFailure,
|
|
37
|
+
read_bounded_path,
|
|
38
|
+
)
|
|
39
|
+
from mostlyright.data_harness.sources.catalog.coverage import (
|
|
40
|
+
COVERAGE_EXHAUSTIVE_RULE,
|
|
41
|
+
SELECTION_RULES,
|
|
42
|
+
)
|
|
43
|
+
from mostlyright.data_harness.sources.catalog.generation_receipt import (
|
|
44
|
+
ReceiptInstallation,
|
|
45
|
+
install_receipt,
|
|
46
|
+
load_execution_coordinate,
|
|
47
|
+
publication_output_lock,
|
|
48
|
+
receipt_installation_lock,
|
|
49
|
+
require_output_root_identity,
|
|
50
|
+
retained_incomplete_receipt,
|
|
51
|
+
root_coordinate,
|
|
52
|
+
)
|
|
53
|
+
from mostlyright.data_harness.ux.commands import CommandSpec
|
|
54
|
+
|
|
55
|
+
# The exact stage receipts this command will accept as the source of a fill checkpoint digest.
|
|
56
|
+
# A receipt is a coordinate carrier, never an authority: the live staging checkpoint decides
|
|
57
|
+
# whether the generation converged.
|
|
58
|
+
HARVEST_RECEIPT_SCHEMAS = frozenset({"mr-data-catalog-fill.v1", "mr-data-catalog-harvest.v1"})
|
|
59
|
+
MAX_HARVEST_RECEIPT_BYTES = 8_388_608
|
|
60
|
+
MAX_AUTHOR_RECEIPT_BYTES = 8_388_608
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def add_arguments(parser: argparse.ArgumentParser) -> None:
|
|
64
|
+
parser.add_argument(
|
|
65
|
+
"--staging-root",
|
|
66
|
+
type=Path,
|
|
67
|
+
required=True,
|
|
68
|
+
help="the private staging root holding one converged harvest generation",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"--harvest-receipt",
|
|
72
|
+
type=Path,
|
|
73
|
+
required=True,
|
|
74
|
+
help="the exact harvest receipt naming the staging checkpoint to author",
|
|
75
|
+
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--harvest-receipt-sha256", required=True, help="the exact harvest receipt fingerprint"
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--policy", required=True, help="the exact reviewed authoring policy coordinate"
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"--output-root", type=Path, required=True, help="the authoring shard output root"
|
|
84
|
+
)
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"--receipt-file", type=Path, required=True, help="where this stage's receipt is installed"
|
|
87
|
+
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--execution-manifest",
|
|
90
|
+
type=Path,
|
|
91
|
+
help="the committed source and installed-wheel coordinate document",
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument("--execution-commit", help="the exact commit that coordinate was cut at")
|
|
94
|
+
parser.add_argument(
|
|
95
|
+
"--max-records", type=int, required=True, help="maximum authored provider records"
|
|
96
|
+
)
|
|
97
|
+
parser.add_argument(
|
|
98
|
+
"--max-input-bytes", type=int, required=True, help="maximum normalized input bytes read"
|
|
99
|
+
)
|
|
100
|
+
parser.add_argument(
|
|
101
|
+
"--max-shard-entries",
|
|
102
|
+
type=int,
|
|
103
|
+
required=True,
|
|
104
|
+
help=f"entries per authoring shard, at most {MAX_AUTHORING_SHARD_ENTRIES}",
|
|
105
|
+
)
|
|
106
|
+
parser.add_argument(
|
|
107
|
+
"--max-shard-bytes",
|
|
108
|
+
type=int,
|
|
109
|
+
required=True,
|
|
110
|
+
help=f"bytes per authoring shard, at most {MAX_AUTHORING_SHARD_BYTES}",
|
|
111
|
+
)
|
|
112
|
+
parser.add_argument(
|
|
113
|
+
"--max-disk-bytes", type=int, required=True, help="maximum local working disk bytes"
|
|
114
|
+
)
|
|
115
|
+
parser.add_argument(
|
|
116
|
+
"--max-wall-seconds", type=int, required=True, help="maximum cumulative authoring seconds"
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"--coverage-rule",
|
|
120
|
+
choices=sorted(SELECTION_RULES),
|
|
121
|
+
default=None,
|
|
122
|
+
help=(
|
|
123
|
+
"the registered rule that selects a bounded part of the converged sweep; "
|
|
124
|
+
"omit both coverage flags to author every record the sweep found"
|
|
125
|
+
),
|
|
126
|
+
)
|
|
127
|
+
parser.add_argument(
|
|
128
|
+
"--coverage-bound",
|
|
129
|
+
type=int,
|
|
130
|
+
default=None,
|
|
131
|
+
help=(
|
|
132
|
+
"how many records that rule selects. This is not --max-records: --max-records is a "
|
|
133
|
+
"resource budget whose exhaustion still yields an incomplete generation, so set it "
|
|
134
|
+
"at least as large as this bound or the run stops at AUTHOR_RECORD_LIMIT"
|
|
135
|
+
),
|
|
136
|
+
)
|
|
137
|
+
parser.add_argument(
|
|
138
|
+
"--resume",
|
|
139
|
+
action="store_true",
|
|
140
|
+
help="continue the retained partial generation from its exact journal digest",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def run(args: argparse.Namespace) -> dict[str, Any]:
|
|
145
|
+
output_root = Path(args.output_root)
|
|
146
|
+
with publication_output_lock(
|
|
147
|
+
output_root,
|
|
148
|
+
label="output_root",
|
|
149
|
+
code_prefix="AUTHOR",
|
|
150
|
+
refusal=CatalogAuthoringRefused,
|
|
151
|
+
) as output_descriptor:
|
|
152
|
+
with receipt_installation_lock(
|
|
153
|
+
args.receipt_file,
|
|
154
|
+
label="receipt_file",
|
|
155
|
+
code_prefix="AUTHOR",
|
|
156
|
+
refusal=CatalogAuthoringRefused,
|
|
157
|
+
) as receipt_installation:
|
|
158
|
+
return _run_locked(
|
|
159
|
+
args,
|
|
160
|
+
output_root=output_root,
|
|
161
|
+
output_descriptor=output_descriptor,
|
|
162
|
+
receipt_installation=receipt_installation,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _run_locked(
|
|
167
|
+
args: argparse.Namespace,
|
|
168
|
+
*,
|
|
169
|
+
output_root: Path,
|
|
170
|
+
output_descriptor: int,
|
|
171
|
+
receipt_installation: ReceiptInstallation,
|
|
172
|
+
) -> dict[str, Any]:
|
|
173
|
+
manifest_path = getattr(args, "execution_manifest", None)
|
|
174
|
+
execution_commit = getattr(args, "execution_commit", None)
|
|
175
|
+
if (manifest_path is None) != (execution_commit is None):
|
|
176
|
+
raise CatalogAuthoringRefused(
|
|
177
|
+
"AUTHOR_EXECUTION_COORDINATE",
|
|
178
|
+
"execution_manifest",
|
|
179
|
+
"execution manifest and commit are supplied together",
|
|
180
|
+
)
|
|
181
|
+
execution = (
|
|
182
|
+
None
|
|
183
|
+
if manifest_path is None
|
|
184
|
+
else load_execution_coordinate(Path(manifest_path), execution_commit)
|
|
185
|
+
)
|
|
186
|
+
checkpoint_sha256, harvest_execution = _harvest_checkpoint(
|
|
187
|
+
args.harvest_receipt, args.harvest_receipt_sha256
|
|
188
|
+
)
|
|
189
|
+
if harvest_execution is not None and execution != harvest_execution:
|
|
190
|
+
raise CatalogAuthoringRefused(
|
|
191
|
+
"AUTHOR_EXECUTION_COORDINATE",
|
|
192
|
+
"execution_manifest",
|
|
193
|
+
"provider-scale authoring must execute the exact harvest coordinate",
|
|
194
|
+
)
|
|
195
|
+
selection = _selection(args)
|
|
196
|
+
replaces = _replaceable_receipt(
|
|
197
|
+
Path(args.receipt_file), output_root, resume=args.resume, execution=execution
|
|
198
|
+
)
|
|
199
|
+
expected_journal_sha256 = None
|
|
200
|
+
if args.resume:
|
|
201
|
+
expected_journal_sha256 = _retained_journal_sha256(output_root)
|
|
202
|
+
result = run_catalog_authoring(
|
|
203
|
+
staging_root=Path(args.staging_root),
|
|
204
|
+
expected_fill_checkpoint_sha256=checkpoint_sha256,
|
|
205
|
+
policy_id=args.policy,
|
|
206
|
+
output_root=output_root,
|
|
207
|
+
limits=AuthoringLimits(
|
|
208
|
+
max_records=args.max_records,
|
|
209
|
+
max_input_bytes=args.max_input_bytes,
|
|
210
|
+
max_shard_entries=args.max_shard_entries,
|
|
211
|
+
max_shard_bytes=args.max_shard_bytes,
|
|
212
|
+
max_disk_bytes=args.max_disk_bytes,
|
|
213
|
+
max_wall_seconds=args.max_wall_seconds,
|
|
214
|
+
),
|
|
215
|
+
selection=selection,
|
|
216
|
+
expected_journal_sha256=expected_journal_sha256,
|
|
217
|
+
output_descriptor=output_descriptor,
|
|
218
|
+
)
|
|
219
|
+
payload = {
|
|
220
|
+
**result.receipt,
|
|
221
|
+
"harvest_receipt_sha256": args.harvest_receipt_sha256,
|
|
222
|
+
"output_root_sha256": root_coordinate(output_root),
|
|
223
|
+
}
|
|
224
|
+
if execution is not None:
|
|
225
|
+
payload["execution"] = execution
|
|
226
|
+
|
|
227
|
+
def commit_guard() -> None:
|
|
228
|
+
require_output_root_identity(
|
|
229
|
+
output_root,
|
|
230
|
+
output_descriptor,
|
|
231
|
+
label="output_root",
|
|
232
|
+
code_prefix="AUTHOR",
|
|
233
|
+
refusal=CatalogAuthoringRefused,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
install_receipt(
|
|
237
|
+
Path(args.receipt_file),
|
|
238
|
+
payload,
|
|
239
|
+
maximum=MAX_AUTHOR_RECEIPT_BYTES,
|
|
240
|
+
label="receipt_file",
|
|
241
|
+
code_prefix="AUTHOR",
|
|
242
|
+
refusal=CatalogAuthoringRefused,
|
|
243
|
+
replaces=replaces,
|
|
244
|
+
installation=receipt_installation,
|
|
245
|
+
commit_guard=commit_guard,
|
|
246
|
+
)
|
|
247
|
+
return payload
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _selection(args: argparse.Namespace) -> AuthoringSelection:
|
|
251
|
+
"""The coverage this invocation was asked for, stated by two flags or by neither.
|
|
252
|
+
|
|
253
|
+
Both flags or neither: a rule without a bound does not say how much of the sweep to take,
|
|
254
|
+
and a bound without a rule does not say which records, so each alone is an instruction this
|
|
255
|
+
command cannot carry out. Refusing here rather than picking a default for the missing half
|
|
256
|
+
keeps an operator from discovering at publication that they published a catalogue nobody
|
|
257
|
+
asked for.
|
|
258
|
+
|
|
259
|
+
The default is exhaustive, which is what this command did before a bound could be stated.
|
|
260
|
+
That direction matters: forgetting a flag can only publish a whole catalogue, never a
|
|
261
|
+
silently partial one.
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
rule = getattr(args, "coverage_rule", None)
|
|
265
|
+
bound = getattr(args, "coverage_bound", None)
|
|
266
|
+
if rule is None and bound is None:
|
|
267
|
+
return AuthoringSelection()
|
|
268
|
+
if rule is None or bound is None:
|
|
269
|
+
raise CatalogAuthoringRefused(
|
|
270
|
+
"AUTHOR_COVERAGE",
|
|
271
|
+
"coverage_rule",
|
|
272
|
+
"a bounded coverage states its rule and its bound together",
|
|
273
|
+
)
|
|
274
|
+
if rule == COVERAGE_EXHAUSTIVE_RULE:
|
|
275
|
+
raise CatalogAuthoringRefused(
|
|
276
|
+
"AUTHOR_COVERAGE",
|
|
277
|
+
"coverage_rule",
|
|
278
|
+
"an exhaustive coverage is what omitting both flags asks for",
|
|
279
|
+
)
|
|
280
|
+
return AuthoringSelection(rule=rule, bound=bound)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _replaceable_receipt(
|
|
284
|
+
path: Path,
|
|
285
|
+
output_root: Path,
|
|
286
|
+
*,
|
|
287
|
+
resume: bool,
|
|
288
|
+
execution: Mapping[str, Any] | None = None,
|
|
289
|
+
) -> dict[str, Any] | None:
|
|
290
|
+
"""The typed-incomplete receipt this resume is allowed to replace, or nothing at all.
|
|
291
|
+
|
|
292
|
+
Installation is otherwise ``O_EXCL``: evidence is never overwritten. The one exception is the
|
|
293
|
+
receipt an interrupted invocation of *this* stage left at *this* destination for *this* output
|
|
294
|
+
root, which the resume that continues it replaces rather than leaving two documents describing
|
|
295
|
+
one generation.
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
if not resume:
|
|
299
|
+
return None
|
|
300
|
+
retained = retained_incomplete_receipt(
|
|
301
|
+
path,
|
|
302
|
+
maximum=MAX_AUTHOR_RECEIPT_BYTES,
|
|
303
|
+
label="receipt_file",
|
|
304
|
+
schema=AUTHORING_RECEIPT_SCHEMA,
|
|
305
|
+
incomplete_status="incomplete",
|
|
306
|
+
output_root=output_root,
|
|
307
|
+
code_prefix="AUTHOR",
|
|
308
|
+
refusal=CatalogAuthoringRefused,
|
|
309
|
+
)
|
|
310
|
+
if retained is not None and retained.get("execution") != execution:
|
|
311
|
+
raise CatalogAuthoringRefused(
|
|
312
|
+
"AUTHOR_RESUME_RECEIPT",
|
|
313
|
+
"execution_manifest",
|
|
314
|
+
"the retained authoring stage used another execution coordinate",
|
|
315
|
+
)
|
|
316
|
+
return retained
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def _harvest_checkpoint(path: Path, expected_sha256: Any) -> tuple[str, Mapping[str, Any] | None]:
|
|
320
|
+
if not _is_digest(expected_sha256):
|
|
321
|
+
raise CatalogAuthoringRefused(
|
|
322
|
+
"AUTHOR_HARVEST_RECEIPT_DIGEST",
|
|
323
|
+
"harvest_receipt_sha256",
|
|
324
|
+
"must be a lowercase SHA-256",
|
|
325
|
+
)
|
|
326
|
+
raw = _read_bounded_regular(path, maximum=MAX_HARVEST_RECEIPT_BYTES)
|
|
327
|
+
if sha256_bytes(raw) != expected_sha256:
|
|
328
|
+
raise CatalogAuthoringRefused(
|
|
329
|
+
"AUTHOR_HARVEST_RECEIPT_DIGEST",
|
|
330
|
+
"harvest_receipt",
|
|
331
|
+
"harvest receipt bytes differ from the required digest",
|
|
332
|
+
)
|
|
333
|
+
try:
|
|
334
|
+
payload = parse_canonical_json(raw)
|
|
335
|
+
except CanonicalJSONError as error:
|
|
336
|
+
raise CatalogAuthoringRefused(
|
|
337
|
+
"AUTHOR_HARVEST_RECEIPT_SCHEMA", "harvest_receipt", "receipt is not canonical JSON"
|
|
338
|
+
) from error
|
|
339
|
+
if (
|
|
340
|
+
not isinstance(payload, Mapping)
|
|
341
|
+
or payload.get("schema_version") not in HARVEST_RECEIPT_SCHEMAS
|
|
342
|
+
or not _is_digest(payload.get("checkpoint_sha256"))
|
|
343
|
+
):
|
|
344
|
+
raise CatalogAuthoringRefused(
|
|
345
|
+
"AUTHOR_HARVEST_RECEIPT_SCHEMA",
|
|
346
|
+
"harvest_receipt",
|
|
347
|
+
"receipt must name one accepted stage schema and an exact checkpoint digest",
|
|
348
|
+
)
|
|
349
|
+
execution = payload.get("execution")
|
|
350
|
+
if payload["schema_version"] == "mr-data-catalog-harvest.v1":
|
|
351
|
+
if not isinstance(execution, Mapping):
|
|
352
|
+
raise CatalogAuthoringRefused(
|
|
353
|
+
"AUTHOR_HARVEST_RECEIPT_SCHEMA",
|
|
354
|
+
"harvest_receipt",
|
|
355
|
+
"provider-scale harvest receipt must carry its execution coordinate",
|
|
356
|
+
)
|
|
357
|
+
return payload["checkpoint_sha256"], execution
|
|
358
|
+
return payload["checkpoint_sha256"], None
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _retained_journal_sha256(output_root: Path) -> str:
|
|
362
|
+
raw = _read_bounded_regular(output_root / "journal.json", maximum=MAX_AUTHOR_RECEIPT_BYTES)
|
|
363
|
+
return sha256_bytes(raw)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def _read_bounded_regular(path: Path, *, maximum: int) -> bytes:
|
|
367
|
+
try:
|
|
368
|
+
raw = read_bounded_path(path, maximum=maximum)
|
|
369
|
+
except (BoundedReadFailure, OSError) as error:
|
|
370
|
+
if isinstance(error, OSError):
|
|
371
|
+
raise CatalogAuthoringRefused(
|
|
372
|
+
"AUTHOR_INPUT_UNREADABLE", str(path.name), "cannot open the required document"
|
|
373
|
+
) from error
|
|
374
|
+
if error.reason not in {"limit", "type", "changed"}:
|
|
375
|
+
raise CatalogAuthoringRefused(
|
|
376
|
+
"AUTHOR_INPUT_UNREADABLE", str(path.name), "cannot open the required document"
|
|
377
|
+
) from error
|
|
378
|
+
raise CatalogAuthoringRefused(
|
|
379
|
+
"AUTHOR_INPUT_LIMIT",
|
|
380
|
+
str(path.name),
|
|
381
|
+
"must be a stable bounded single-link regular file",
|
|
382
|
+
) from error
|
|
383
|
+
assert raw is not None
|
|
384
|
+
return raw
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def _is_digest(value: Any) -> bool:
|
|
388
|
+
return (
|
|
389
|
+
isinstance(value, str) and len(value) == 64 and all(c in "0123456789abcdef" for c in value)
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def _exit_code(payload: Mapping[str, Any]) -> int:
|
|
394
|
+
return 0 if payload.get("status") == "complete" else 1
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
SPEC = CommandSpec(
|
|
398
|
+
name="catalog-author",
|
|
399
|
+
help="author one converged public catalog generation into bounded authoring shards",
|
|
400
|
+
add_arguments=add_arguments,
|
|
401
|
+
run=run,
|
|
402
|
+
exit_code=_exit_code,
|
|
403
|
+
)
|