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.
Files changed (314) hide show
  1. mostlyright/data_harness/__init__.py +158 -0
  2. mostlyright/data_harness/acquisition/__init__.py +55 -0
  3. mostlyright/data_harness/acquisition/http.py +2773 -0
  4. mostlyright/data_harness/acquisition/parsing.py +809 -0
  5. mostlyright/data_harness/acquisition/ranges.py +495 -0
  6. mostlyright/data_harness/acquisition/result_download.py +360 -0
  7. mostlyright/data_harness/acquisition/retention_admission.py +248 -0
  8. mostlyright/data_harness/acquisition/sandbox.py +4888 -0
  9. mostlyright/data_harness/acquisition/url_policy.py +530 -0
  10. mostlyright/data_harness/agent_runtime.py +2743 -0
  11. mostlyright/data_harness/assets/logo-ink.svg +31 -0
  12. mostlyright/data_harness/backends/__init__.py +28 -0
  13. mostlyright/data_harness/backends/pandas_backend.py +350 -0
  14. mostlyright/data_harness/backends/polars_backend.py +366 -0
  15. mostlyright/data_harness/backends/protocol.py +124 -0
  16. mostlyright/data_harness/backends/reference.py +83 -0
  17. mostlyright/data_harness/backends/registry.py +55 -0
  18. mostlyright/data_harness/backends/restrictions.py +126 -0
  19. mostlyright/data_harness/canonical.py +333 -0
  20. mostlyright/data_harness/catalog_job.py +625 -0
  21. mostlyright/data_harness/cli.py +5398 -0
  22. mostlyright/data_harness/contracts.py +53 -0
  23. mostlyright/data_harness/coordinator.py +1307 -0
  24. mostlyright/data_harness/deploy.py +924 -0
  25. mostlyright/data_harness/deploy_target.py +312 -0
  26. mostlyright/data_harness/deployment_evidence.py +1067 -0
  27. mostlyright/data_harness/event_presentation.py +576 -0
  28. mostlyright/data_harness/events.py +2152 -0
  29. mostlyright/data_harness/fast_delimited.py +239 -0
  30. mostlyright/data_harness/fleet.py +237 -0
  31. mostlyright/data_harness/formats.py +236 -0
  32. mostlyright/data_harness/governors.py +1163 -0
  33. mostlyright/data_harness/hosted_bootstrap.py +972 -0
  34. mostlyright/data_harness/hosted_crawler.py +1115 -0
  35. mostlyright/data_harness/hosted_crawler_container_smoke.py +351 -0
  36. mostlyright/data_harness/hosted_crawler_fetch.py +423 -0
  37. mostlyright/data_harness/hosted_crawler_job.py +1277 -0
  38. mostlyright/data_harness/hosted_crawler_protocol.py +676 -0
  39. mostlyright/data_harness/hosted_dataset.py +1500 -0
  40. mostlyright/data_harness/hosted_deploy.py +3037 -0
  41. mostlyright/data_harness/hosted_handoff.py +62 -0
  42. mostlyright/data_harness/hosted_ingestion_contract.py +504 -0
  43. mostlyright/data_harness/hosted_ingestion_job.py +356 -0
  44. mostlyright/data_harness/hosted_ingestion_job_smoke.py +40 -0
  45. mostlyright/data_harness/hosted_session_container_smoke.py +194 -0
  46. mostlyright/data_harness/hosted_session_worker.py +3554 -0
  47. mostlyright/data_harness/hosted_session_worker_job_smoke.py +46 -0
  48. mostlyright/data_harness/hosted_worker.py +6784 -0
  49. mostlyright/data_harness/ingestion/__init__.py +56 -0
  50. mostlyright/data_harness/ingestion/contracts.py +461 -0
  51. mostlyright/data_harness/ingestion/faults.py +42 -0
  52. mostlyright/data_harness/ingestion/gcs_store.py +1162 -0
  53. mostlyright/data_harness/ingestion/spool.py +130 -0
  54. mostlyright/data_harness/ingestion/store.py +885 -0
  55. mostlyright/data_harness/key_seam.py +434 -0
  56. mostlyright/data_harness/linux_process_boundary.py +262 -0
  57. mostlyright/data_harness/local_contracts.py +2880 -0
  58. mostlyright/data_harness/local_search/__init__.py +5 -0
  59. mostlyright/data_harness/local_search/build_index.py +1087 -0
  60. mostlyright/data_harness/local_search/contracts.py +920 -0
  61. mostlyright/data_harness/local_search/query_trace.py +266 -0
  62. mostlyright/data_harness/local_search/retrieval.py +700 -0
  63. mostlyright/data_harness/local_search/sealed.py +474 -0
  64. mostlyright/data_harness/local_search/service.py +784 -0
  65. mostlyright/data_harness/nbrender/CONTRACT.md +212 -0
  66. mostlyright/data_harness/nbrender/__init__.py +12 -0
  67. mostlyright/data_harness/nbrender/chrome.py +359 -0
  68. mostlyright/data_harness/nbrender/code_body.py +266 -0
  69. mostlyright/data_harness/nbrender/document.py +407 -0
  70. mostlyright/data_harness/nbrender/frame.py +275 -0
  71. mostlyright/data_harness/nbrender/interactive.py +337 -0
  72. mostlyright/data_harness/nbrender/markdown_body.py +477 -0
  73. mostlyright/data_harness/nbrender/mr_components.py +134 -0
  74. mostlyright/data_harness/nbrender/outputs_data.py +595 -0
  75. mostlyright/data_harness/nbrender/outputs_rich.py +906 -0
  76. mostlyright/data_harness/nbrender/outputs_source.py +260 -0
  77. mostlyright/data_harness/nbrender/outputs_stage.py +176 -0
  78. mostlyright/data_harness/nbrender/outputs_text.py +400 -0
  79. mostlyright/data_harness/nbrender/parse.py +394 -0
  80. mostlyright/data_harness/nbrender/status.py +40 -0
  81. mostlyright/data_harness/nbrender/tokens.py +1295 -0
  82. mostlyright/data_harness/notebook.py +1710 -0
  83. mostlyright/data_harness/offline.py +2049 -0
  84. mostlyright/data_harness/operation_registry.py +1007 -0
  85. mostlyright/data_harness/operator_setup.py +239 -0
  86. mostlyright/data_harness/pipeline.py +6428 -0
  87. mostlyright/data_harness/plan_graph.py +2026 -0
  88. mostlyright/data_harness/preparation/__init__.py +104 -0
  89. mostlyright/data_harness/preparation/contracts.py +1017 -0
  90. mostlyright/data_harness/preparation/engine.py +221 -0
  91. mostlyright/data_harness/preparation/errors.py +14 -0
  92. mostlyright/data_harness/preparation/gates.py +751 -0
  93. mostlyright/data_harness/preparation/joins.py +574 -0
  94. mostlyright/data_harness/preparation/profile.py +384 -0
  95. mostlyright/data_harness/preparation/table.py +217 -0
  96. mostlyright/data_harness/preparation/transforms.py +568 -0
  97. mostlyright/data_harness/progress_events.py +534 -0
  98. mostlyright/data_harness/readers/__init__.py +46 -0
  99. mostlyright/data_harness/readers/containers.py +963 -0
  100. mostlyright/data_harness/readers/contracts.py +542 -0
  101. mostlyright/data_harness/readers/delimited.py +257 -0
  102. mostlyright/data_harness/readers/grib2/__init__.py +33 -0
  103. mostlyright/data_harness/readers/grib2/admission.py +722 -0
  104. mostlyright/data_harness/readers/grib2/decode.py +1009 -0
  105. mostlyright/data_harness/readers/grib2/geometry.py +1133 -0
  106. mostlyright/data_harness/readers/grib2/portable_math.py +501 -0
  107. mostlyright/data_harness/readers/json_tabular.py +485 -0
  108. mostlyright/data_harness/readers/registry.py +514 -0
  109. mostlyright/data_harness/readers/samples/README.md +110 -0
  110. mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
  111. mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +24 -0
  112. mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
  113. mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +24 -0
  114. mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
  115. mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +24 -0
  116. mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
  117. mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +24 -0
  118. mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
  119. mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +25 -0
  120. mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  121. mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +25 -0
  122. mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  123. mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +25 -0
  124. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +3 -0
  125. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +23 -0
  126. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +5 -0
  127. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +25 -0
  128. mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +30 -0
  129. mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +5 -0
  130. mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +44 -0
  131. mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +1 -0
  132. mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +48 -0
  133. mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +4 -0
  134. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
  135. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +24 -0
  136. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +27 -0
  137. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  138. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +27 -0
  139. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  140. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +20 -0
  141. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +55 -0
  142. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
  143. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +54 -0
  144. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  145. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +54 -0
  146. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
  147. mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +54 -0
  148. mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  149. mostlyright/data_harness/readers/samples.py +582 -0
  150. mostlyright/data_harness/readers/spreadsheet.py +803 -0
  151. mostlyright/data_harness/readers/tabular.py +510 -0
  152. mostlyright/data_harness/recipe.py +5321 -0
  153. mostlyright/data_harness/repair/__init__.py +78 -0
  154. mostlyright/data_harness/repair/adapters.py +274 -0
  155. mostlyright/data_harness/repair/contracts.py +872 -0
  156. mostlyright/data_harness/repair/coordinator.py +1099 -0
  157. mostlyright/data_harness/repair/errors.py +16 -0
  158. mostlyright/data_harness/review.py +2533 -0
  159. mostlyright/data_harness/rowset.py +283 -0
  160. mostlyright/data_harness/serving.py +1975 -0
  161. mostlyright/data_harness/serving_edge.py +590 -0
  162. mostlyright/data_harness/serving_http.py +1031 -0
  163. mostlyright/data_harness/session_probes.py +759 -0
  164. mostlyright/data_harness/signing.py +101 -0
  165. mostlyright/data_harness/source_discovery.py +898 -0
  166. mostlyright/data_harness/sources/__init__.py +209 -0
  167. mostlyright/data_harness/sources/_adapter_steps.py +213 -0
  168. mostlyright/data_harness/sources/adapters.py +1214 -0
  169. mostlyright/data_harness/sources/cadence.py +1428 -0
  170. mostlyright/data_harness/sources/cadence_emission.py +453 -0
  171. mostlyright/data_harness/sources/cadence_history.py +546 -0
  172. mostlyright/data_harness/sources/catalog/__init__.py +17 -0
  173. mostlyright/data_harness/sources/catalog/admission.py +477 -0
  174. mostlyright/data_harness/sources/catalog/authoring.py +1701 -0
  175. mostlyright/data_harness/sources/catalog/authoring_policy.py +701 -0
  176. mostlyright/data_harness/sources/catalog/authoring_shards.py +1217 -0
  177. mostlyright/data_harness/sources/catalog/bounded_io.py +231 -0
  178. mostlyright/data_harness/sources/catalog/channel.py +523 -0
  179. mostlyright/data_harness/sources/catalog/channel_client.py +296 -0
  180. mostlyright/data_harness/sources/catalog/contracts.py +825 -0
  181. mostlyright/data_harness/sources/catalog/coverage.py +137 -0
  182. mostlyright/data_harness/sources/catalog/delta.py +1340 -0
  183. mostlyright/data_harness/sources/catalog/embedding.py +532 -0
  184. mostlyright/data_harness/sources/catalog/entry_v2.py +1182 -0
  185. mostlyright/data_harness/sources/catalog/fill.py +3889 -0
  186. mostlyright/data_harness/sources/catalog/fill_partitions.py +459 -0
  187. mostlyright/data_harness/sources/catalog/fill_staging.py +1105 -0
  188. mostlyright/data_harness/sources/catalog/gating.py +374 -0
  189. mostlyright/data_harness/sources/catalog/generation_receipt.py +1607 -0
  190. mostlyright/data_harness/sources/catalog/harvest/__init__.py +7 -0
  191. mostlyright/data_harness/sources/catalog/harvest/ckan.py +384 -0
  192. mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +798 -0
  193. mostlyright/data_harness/sources/catalog/harvest/protocol.py +964 -0
  194. mostlyright/data_harness/sources/catalog/harvest/sdmx.py +445 -0
  195. mostlyright/data_harness/sources/catalog/harvest/stac.py +384 -0
  196. mostlyright/data_harness/sources/catalog/health.py +447 -0
  197. mostlyright/data_harness/sources/catalog/hosted_catalog.py +105 -0
  198. mostlyright/data_harness/sources/catalog/identity_history.py +1549 -0
  199. mostlyright/data_harness/sources/catalog/neural.py +1618 -0
  200. mostlyright/data_harness/sources/catalog/packed_catalog.py +2345 -0
  201. mostlyright/data_harness/sources/catalog/packed_retrieval.py +1517 -0
  202. mostlyright/data_harness/sources/catalog/packed_writer.py +2802 -0
  203. mostlyright/data_harness/sources/catalog/query_trace.py +1037 -0
  204. mostlyright/data_harness/sources/catalog/recommend.py +171 -0
  205. mostlyright/data_harness/sources/catalog/retrieval.py +230 -0
  206. mostlyright/data_harness/sources/catalog/retrieval_manifest.py +995 -0
  207. mostlyright/data_harness/sources/catalog/rights_decisions.py +254 -0
  208. mostlyright/data_harness/sources/catalog/sealed.py +560 -0
  209. mostlyright/data_harness/sources/catalog/search.py +230 -0
  210. mostlyright/data_harness/sources/catalog/streaming_delta.py +1097 -0
  211. mostlyright/data_harness/sources/catalog/update.py +891 -0
  212. mostlyright/data_harness/sources/collections.py +815 -0
  213. mostlyright/data_harness/sources/contracts.py +2223 -0
  214. mostlyright/data_harness/sources/deletion.py +761 -0
  215. mostlyright/data_harness/sources/fitness.py +162 -0
  216. mostlyright/data_harness/sources/governance.py +163 -0
  217. mostlyright/data_harness/sources/hosted.py +173 -0
  218. mostlyright/data_harness/sources/integration.py +218 -0
  219. mostlyright/data_harness/sources/range_reader.py +418 -0
  220. mostlyright/data_harness/sources/registry.py +514 -0
  221. mostlyright/data_harness/sources/rights_rule.py +59 -0
  222. mostlyright/data_harness/sources/source_cadence_vectors.v1.json +1 -0
  223. mostlyright/data_harness/sources/sports.py +521 -0
  224. mostlyright/data_harness/sources/stream.py +524 -0
  225. mostlyright/data_harness/sources/stream_connector.py +418 -0
  226. mostlyright/data_harness/sources/stream_recorder.py +1404 -0
  227. mostlyright/data_harness/studio_boundary.py +2019 -0
  228. mostlyright/data_harness/thin/__init__.py +37 -0
  229. mostlyright/data_harness/thin/acquire.py +1137 -0
  230. mostlyright/data_harness/thin/acquire_cancel.py +579 -0
  231. mostlyright/data_harness/thin/approvals.py +617 -0
  232. mostlyright/data_harness/thin/commands.py +406 -0
  233. mostlyright/data_harness/thin/download.py +194 -0
  234. mostlyright/data_harness/thin/narrative.py +589 -0
  235. mostlyright/data_harness/thin/parity.py +1070 -0
  236. mostlyright/data_harness/thin/propose.py +2759 -0
  237. mostlyright/data_harness/thin/research.py +1663 -0
  238. mostlyright/data_harness/thin/router.py +924 -0
  239. mostlyright/data_harness/thin/runs.py +519 -0
  240. mostlyright/data_harness/thin/session.py +281 -0
  241. mostlyright/data_harness/thin/stream.py +501 -0
  242. mostlyright/data_harness/thin/transport.py +187 -0
  243. mostlyright/data_harness/thin/vocabulary.py +368 -0
  244. mostlyright/data_harness/thin/workers.py +164 -0
  245. mostlyright/data_harness/ucum/TABLE-PIN.json +40 -0
  246. mostlyright/data_harness/ucum/ucum-subset.v1.json +632 -0
  247. mostlyright/data_harness/unit_flow.py +927 -0
  248. mostlyright/data_harness/units.py +572 -0
  249. mostlyright/data_harness/ux/__init__.py +9 -0
  250. mostlyright/data_harness/ux/approve.py +485 -0
  251. mostlyright/data_harness/ux/author_yaml.py +597 -0
  252. mostlyright/data_harness/ux/cloud_auth.py +447 -0
  253. mostlyright/data_harness/ux/commands/__init__.py +260 -0
  254. mostlyright/data_harness/ux/commands/approve.py +136 -0
  255. mostlyright/data_harness/ux/commands/auth.py +744 -0
  256. mostlyright/data_harness/ux/commands/author.py +79 -0
  257. mostlyright/data_harness/ux/commands/catalog_author.py +403 -0
  258. mostlyright/data_harness/ux/commands/catalog_fill.py +523 -0
  259. mostlyright/data_harness/ux/commands/catalog_harvest.py +545 -0
  260. mostlyright/data_harness/ux/commands/catalog_publish.py +1838 -0
  261. mostlyright/data_harness/ux/commands/catalog_search.py +71 -0
  262. mostlyright/data_harness/ux/commands/catalog_update.py +437 -0
  263. mostlyright/data_harness/ux/commands/deploy.py +134 -0
  264. mostlyright/data_harness/ux/commands/deploy_dataset.py +98 -0
  265. mostlyright/data_harness/ux/commands/deploy_plan.py +105 -0
  266. mostlyright/data_harness/ux/commands/deploy_status.py +104 -0
  267. mostlyright/data_harness/ux/commands/diff.py +74 -0
  268. mostlyright/data_harness/ux/commands/index.py +84 -0
  269. mostlyright/data_harness/ux/commands/inventory.py +47 -0
  270. mostlyright/data_harness/ux/commands/list_builds.py +143 -0
  271. mostlyright/data_harness/ux/commands/login.py +63 -0
  272. mostlyright/data_harness/ux/commands/peek.py +236 -0
  273. mostlyright/data_harness/ux/commands/plan_check.py +90 -0
  274. mostlyright/data_harness/ux/commands/preflight.py +97 -0
  275. mostlyright/data_harness/ux/commands/record.py +107 -0
  276. mostlyright/data_harness/ux/commands/review_setup.py +47 -0
  277. mostlyright/data_harness/ux/commands/search.py +440 -0
  278. mostlyright/data_harness/ux/commands/show.py +61 -0
  279. mostlyright/data_harness/ux/commands/whoami.py +37 -0
  280. mostlyright/data_harness/ux/credential_native.py +551 -0
  281. mostlyright/data_harness/ux/credential_store.py +1055 -0
  282. mostlyright/data_harness/ux/credentials.py +631 -0
  283. mostlyright/data_harness/ux/diffing.py +444 -0
  284. mostlyright/data_harness/ux/headline.py +671 -0
  285. mostlyright/data_harness/ux/hosted_acquisition.py +974 -0
  286. mostlyright/data_harness/ux/hosted_run_status.py +619 -0
  287. mostlyright/data_harness/ux/inventory.py +427 -0
  288. mostlyright/data_harness/ux/local_review.py +375 -0
  289. mostlyright/data_harness/ux/login.py +691 -0
  290. mostlyright/data_harness/ux/path_kind.py +147 -0
  291. mostlyright/data_harness/ux/peek.py +1000 -0
  292. mostlyright/data_harness/ux/plain_file.py +178 -0
  293. mostlyright/data_harness/ux/plan_check.py +311 -0
  294. mostlyright/data_harness/ux/preflight.py +918 -0
  295. mostlyright/data_harness/ux/readers.py +1124 -0
  296. mostlyright/data_harness/ux/remediation.py +2195 -0
  297. mostlyright/data_harness/ux/render.py +657 -0
  298. mostlyright/data_harness/ux/workload.py +1077 -0
  299. mostlyright/data_harness/viewer.py +3713 -0
  300. mostlyright/data_harness/visual_run/__init__.py +83 -0
  301. mostlyright/data_harness/visual_run/authoring.py +235 -0
  302. mostlyright/data_harness/visual_run/contracts.py +673 -0
  303. mostlyright/data_harness/visual_run/materialize.py +486 -0
  304. mostlyright/data_harness/visual_run/observations.py +874 -0
  305. mostlyright/data_harness/visual_run/query.py +259 -0
  306. mostlyright/data_harness/visual_run/reducer.py +280 -0
  307. mostlyright/data_harness/visual_run/sdk.py +892 -0
  308. mostlyright/data_harness/visual_run/store.py +584 -0
  309. mostlyright/data_harness/visual_run/transport.py +239 -0
  310. mostlyright/data_harness/watch.py +2999 -0
  311. mostlyright_data-0.9.0.dist-info/METADATA +607 -0
  312. mostlyright_data-0.9.0.dist-info/RECORD +314 -0
  313. mostlyright_data-0.9.0.dist-info/WHEEL +4 -0
  314. mostlyright_data-0.9.0.dist-info/entry_points.txt +12 -0
@@ -0,0 +1,257 @@
1
+ """``delimited_text``: a tab-separated source, at the cost of one file and no table edit.
2
+
3
+ This family exists to make a point as much as to read a file, so the point is written here
4
+ where the next person to propose the alternative will find it.
5
+
6
+ A delimiter is a setting, not a wire format
7
+ -------------------------------------------
8
+ The sealed artifact is always canonical CSV -- ``formats.READER_OUTPUT_FORMATS`` has one
9
+ member and the reason is recorded there. So a tab-separated source is a Reader family whose
10
+ decode options name a delimiter, and the format tables do not move at all. Under the other
11
+ design, where the sealed artifact keeps the source's own encoding, ``tsv`` would have to
12
+ enter ``PARSER_FORMAT_ORDER`` -- which rotates the ``parse`` and ``retrieve_and_parse``
13
+ policy digests on both platform clauses, re-pins four literals, and widens the media-type
14
+ table, the suffix table, the snapshot-suffix pattern, the deletion regex, the plan-format
15
+ enum, and the parser dispatch. ``raw/{source_id}.csv`` would then be a lie. None of that
16
+ happens here, and ``tests/h3/test_readers_delimited.py`` asserts that none of it happened.
17
+
18
+ Thin on purpose
19
+ ---------------
20
+ Admission is "are these bytes valid UTF-8 text within budget", the decode is
21
+ ``tabular.decode_delimited``, and the emission is ``tabular.encode_canonical_csv``. The same
22
+ two functions decode a zip member, a gzip stream, and a tar member, which is what lets four
23
+ paths produce one answer. If this module ever grows a parsing rule of its own, that rule has
24
+ been duplicated out of ``tabular.py`` and the four paths have started to disagree.
25
+
26
+ Four decisions, each with its reason
27
+ ------------------------------------
28
+ Every one of these is a refusal, and a refusal is only defensible if the reason is written
29
+ next to it.
30
+
31
+ * **The delimiter set is closed** to the single characters in ``ADMITTED_DELIMITERS``: tab
32
+ and comma today. Every additional delimiter is a new parser surface and a new class of
33
+ ambiguity -- a semicolon file in a locale that uses the comma as a decimal separator reads
34
+ as a different table under each -- and no supported source needs one. Widening the
35
+ set is a source edit that goes through review, exactly like the format table.
36
+ * **The encoding is strict UTF-8**, spelled one way. A byte sequence that is not valid UTF-8
37
+ is refused rather than replaced, because a replacement character in sealed data is silent
38
+ corruption: the artifact verifies clean forever and the value it carries is not the value
39
+ the publisher wrote. ``UTF-8`` and ``utf-8-sig`` are refused as spellings too, since two
40
+ spellings of one setting seal to two different options digests for one decode.
41
+ * **A leading byte-order mark is consumed**, by ``decode_delimited``, before the header is
42
+ read. A mark that survives into the first column name produces a dataset whose first
43
+ column silently fails every join, and "whatever the standard library happens to do" is not
44
+ a rule anyone can check. A mark anywhere else in the text is a character and stays.
45
+ * **A headerless source is refused.** ``header: false`` would need the recipe to supply the
46
+ column names, and this family's closed option set has no way to state them; naming columns
47
+ by position instead would put names into a dataset that nobody wrote down and no recipe
48
+ describes. So the option is admitted only as ``true``, and reading a headerless source is
49
+ a reviewed widening -- a ``columns`` option -- rather than something a decoder invents.
50
+ The shared helper still names columns positionally for the container families, which pass
51
+ ``header`` through from their own settings; that is their decision to make, not this one's.
52
+
53
+ Import discipline: this module reads ``formats``, ``readers.contracts``, and
54
+ ``readers.tabular``. It reaches no filesystem and imports nothing from ``acquisition``.
55
+ """
56
+
57
+ from __future__ import annotations
58
+
59
+ from collections.abc import Iterator, Mapping
60
+ from dataclasses import dataclass, field
61
+ from typing import Any
62
+
63
+ from mostlyright.data_harness.formats import (
64
+ FORMAT_MEDIA_TYPES,
65
+ FORMAT_SUFFIXES,
66
+ READER_CONTRACT_VERSION,
67
+ READER_OUTPUT_FORMATS,
68
+ )
69
+ from mostlyright.data_harness.readers.contracts import (
70
+ ReaderBudgets,
71
+ ReaderError,
72
+ ReaderPin,
73
+ ReaderResult,
74
+ bulk_default_budgets,
75
+ )
76
+ from mostlyright.data_harness.readers.tabular import (
77
+ FALLBACK_STEM,
78
+ decode_delimited_stream,
79
+ encode_canonical_csv,
80
+ sealed_filename,
81
+ )
82
+
83
+ __all__ = ["ADMITTED_DELIMITERS", "ADMITTED_ENCODINGS", "DelimitedTextReader"]
84
+
85
+ # The one encoding a Reader may seal, unpacked rather than restated. A second member in the
86
+ # leaf's table makes this line raise at import, which is the loud failure that forces a family
87
+ # to choose its output encoding deliberately.
88
+ (_OUTPUT_FORMAT,) = READER_OUTPUT_FORMATS
89
+ _OUTPUT_MEDIA_TYPE = sorted(FORMAT_MEDIA_TYPES[_OUTPUT_FORMAT])[0]
90
+ _OUTPUT_SUFFIX = sorted(FORMAT_SUFFIXES[_OUTPUT_FORMAT])[0]
91
+
92
+ # The closed delimiter table. Two single characters, and the module docstring says why the
93
+ # set is closed rather than open. Adding one is a reviewed source edit.
94
+ ADMITTED_DELIMITERS: tuple[str, ...] = ("\t", ",")
95
+
96
+ # The closed encoding table, one spelling of one encoding. A tuple rather than a bare
97
+ # constant because the shape is the same shape the delimiter set has, and the next entry --
98
+ # if there is ever an honest one -- goes through the same review.
99
+ ADMITTED_ENCODINGS: tuple[str, ...] = ("utf-8",)
100
+
101
+ # The whole option vocabulary. ``delimiter`` is required because it is the whole of what
102
+ # this family decides; the other two have stated defaults, so an ordinary recipe names one
103
+ # setting and a strict recipe names three.
104
+ _REQUIRED_OPTION_KEYS = ("delimiter",)
105
+ _OPTIONAL_OPTION_KEYS = ("header", "encoding")
106
+ _OPTION_KEYS = (*_REQUIRED_OPTION_KEYS, *_OPTIONAL_OPTION_KEYS)
107
+
108
+
109
+ def _validate_options(options: Any, *, subject: str) -> dict[str, Any]:
110
+ """Admit this family's closed option set, refusing an unknown key by name.
111
+
112
+ Strict on purpose. The options digest is sealed into the recipe forever, so a key that
113
+ was accepted and ignored would be an unreviewable difference between two recipes that
114
+ look identical to everyone who reads them.
115
+ """
116
+
117
+ if not isinstance(options, Mapping):
118
+ raise ReaderError("READER_OPTIONS", subject, "must be an object")
119
+ unknown = sorted(str(key) for key in options if key not in _OPTION_KEYS)
120
+ if unknown:
121
+ raise ReaderError(
122
+ "READER_OPTIONS",
123
+ subject,
124
+ f"names no such setting: {', '.join(unknown)}; this family takes "
125
+ f"{', '.join(sorted(_OPTION_KEYS))}",
126
+ )
127
+
128
+ delimiter = options.get("delimiter")
129
+ if not isinstance(delimiter, str) or delimiter not in ADMITTED_DELIMITERS:
130
+ raise ReaderError(
131
+ "READER_OPTIONS",
132
+ f"{subject}.delimiter",
133
+ "must name one of the delimiters this family admits: a tab or a comma. The set "
134
+ "is closed because every additional delimiter is a new parser surface and a new "
135
+ "class of ambiguity; widening it is a reviewed source edit",
136
+ )
137
+
138
+ encoding = options.get("encoding", ADMITTED_ENCODINGS[0])
139
+ if not isinstance(encoding, str) or encoding not in ADMITTED_ENCODINGS:
140
+ raise ReaderError(
141
+ "READER_OPTIONS",
142
+ f"{subject}.encoding",
143
+ f"must be exactly {ADMITTED_ENCODINGS[0]!r}. Text that is not valid UTF-8 is "
144
+ "refused rather than decoded with replacement characters, because a replacement "
145
+ "character in sealed data is corruption that verifies clean forever",
146
+ )
147
+
148
+ header = options.get("header", True)
149
+ if not isinstance(header, bool):
150
+ raise ReaderError("READER_OPTIONS", f"{subject}.header", "must be true or false")
151
+ if not header:
152
+ raise ReaderError(
153
+ "READER_OPTIONS",
154
+ f"{subject}.header",
155
+ "must be true: a headerless source needs the recipe to supply its column names, "
156
+ "this family's settings have no way to state them, and naming columns by position "
157
+ "would put names into the dataset that nobody wrote down. Add a header row to the "
158
+ "source, or widen this family with a reviewed columns option",
159
+ )
160
+
161
+ return {"delimiter": delimiter, "header": header, "encoding": encoding}
162
+
163
+
164
+ @dataclass(frozen=True)
165
+ class DelimitedTextReader:
166
+ """``delimited_text``: delimited text read from bytes, sealed as canonical CSV.
167
+
168
+ The order of the work is options, decode, emit -- three steps, because the admission this
169
+ family performs *is* the decode: "is this valid UTF-8 text, within budget, whose rows are
170
+ the width its header states" is exactly what ``decode_delimited`` answers, and asking it
171
+ twice in two places is how two answers come to disagree.
172
+
173
+ ``accepted_media_types`` admits the two media types a delimited source arrives under.
174
+ That is an input-side declaration and it is not a format table: what may be *sealed* is
175
+ still ``csv`` alone, which is why ``text/tab-separated-values`` appears here and in no
176
+ table in ``formats``.
177
+ """
178
+
179
+ family_id: str = "delimited_text"
180
+ family_version: str = "1.0.0"
181
+ contract_version: str = READER_CONTRACT_VERSION
182
+ output_format: str = _OUTPUT_FORMAT
183
+ accepted_media_types: tuple[str, ...] = ("text/csv", "text/tab-separated-values")
184
+ default_budgets: ReaderBudgets = field(default_factory=bulk_default_budgets)
185
+
186
+ def validate_options(self, options: Mapping[str, Any]) -> Mapping[str, Any]:
187
+ return _validate_options(options, subject="reader.delimited_text.decode_options")
188
+
189
+ def decode(self, content: bytes, pin: ReaderPin, budgets: ReaderBudgets) -> ReaderResult:
190
+ options = self.validate_options(pin.decode_options)
191
+ # Parsed rows feed the canonical encoder one at a time rather than being drained
192
+ # into a table first. A year-scale source is millions of rows, and the table form
193
+ # would hold every cell as a live object at once -- the decode's memory ceiling is
194
+ # the row, not the file.
195
+ columns, rows = decode_delimited_stream(
196
+ content,
197
+ delimiter=str(options["delimiter"]),
198
+ header=bool(options["header"]),
199
+ budgets=budgets,
200
+ )
201
+ row_count = 0
202
+
203
+ def counted() -> Iterator[tuple[str, ...]]:
204
+ nonlocal row_count
205
+ for row in rows:
206
+ row_count += 1
207
+ yield row
208
+
209
+ payload = encode_canonical_csv(columns, counted(), budgets=budgets)
210
+ return ReaderResult(
211
+ content=payload,
212
+ data_format=_OUTPUT_FORMAT,
213
+ media_type=_OUTPUT_MEDIA_TYPE,
214
+ # Loose delimited text carries no name of its own: the bytes are the whole input,
215
+ # and the source's filename is not part of what was decoded. So the shared
216
+ # fallback stem is used deliberately, exactly as the gzip family uses it, rather
217
+ # than a name invented here or taken from somewhere the decode never looked.
218
+ filename=sealed_filename(FALLBACK_STEM, suffix=_OUTPUT_SUFFIX),
219
+ row_count=row_count,
220
+ column_names=columns,
221
+ declared_cell_count=row_count * len(columns),
222
+ )
223
+
224
+
225
+ @dataclass(frozen=True)
226
+ class DelimitedTextReaderV1_1(DelimitedTextReader):
227
+ """``delimited_text@1.1.0`` admits ``text/plain`` as a label, and decodes nothing new.
228
+
229
+ A publisher that serves comma-separated bytes under ``text/plain`` is not describing a
230
+ different file; it is declining to describe the file at all. ``acquisition/http.py``
231
+ already writes that rule down for the byte-stream spelling -- a weak label "says only
232
+ that a server declined to say anything", and the control is the structural check behind
233
+ the sandbox boundary, never the header. Version ``1.0.0`` admitted the two labels that
234
+ name the format outright, which refused whole archives that were never unfit: Iowa
235
+ Environmental Mesonet serves its ASOS/METAR CSV under ``text/plain``, and so does a large
236
+ share of public agency endpoints.
237
+
238
+ This is an admission change and not a decode change. ``decode`` is inherited untouched,
239
+ so the bytes a recipe seals under this coordinate are the bytes ``1.0.0`` would have
240
+ sealed; what moves is only which responses reach the decoder. It is a new coordinate for
241
+ the reason ``archive.zip@1.1.0`` is one: ``1.0.0`` stays closed to the weak label, so an
242
+ already-approved recipe cannot silently begin admitting responses its review never saw.
243
+
244
+ The label is the only thing widened. ``text/html`` remains outside every allowlist, which
245
+ is what keeps the bot-wall refusal intact, and the shared decoder's own refusals -- strict
246
+ UTF-8, a NUL byte, a repeated column name, a row whose width differs from its header --
247
+ are unchanged and remain the whole admission. Archive and executable bytes arriving under
248
+ this label are refused as invalid UTF-8 rather than by prefix: the magic table is enforced
249
+ in ``acquisition/parsing`` and in the container families, and this family imports neither.
250
+ """
251
+
252
+ family_version: str = "1.1.0"
253
+ accepted_media_types: tuple[str, ...] = (
254
+ "text/csv",
255
+ "text/plain",
256
+ "text/tab-separated-values",
257
+ )
@@ -0,0 +1,33 @@
1
+ """The weather-model Reader separates admission from decoding.
2
+
3
+ A weather model publishes its output as GRIB2 messages, and a GRIB2 message states its
4
+ geometry and its packing method in its headers, before any value appears. That is the whole
5
+ reason this package is split the way it is. ``admission`` reads those headers, decides
6
+ whether this product is willing to open the message at all, and returns the offsets of the
7
+ data section without reading it. The decoder requires that admission result.
8
+
9
+ ``MESSAGES_ROOT`` is the vendored evidence: three real messages, committed with their
10
+ provenance, from which every number in the allowlist was read. They are also the family's
11
+ known-good samples under ``readers/samples/weather.grib2/1.0.0``. Admission and sample checks read
12
+ the same files.
13
+
14
+ The path is spelled out rather than imported from ``readers.samples``, which would close an
15
+ import cycle: the sample loader reads the Toolbox, the Toolbox holds the weather family, and the
16
+ weather family is in this package.
17
+
18
+ Import discipline: this package reads ``readers.contracts`` and the standard library. Like
19
+ every module under ``readers/``, it must not import ``acquisition``, ``sources``, ``recipe``, or
20
+ ``pipeline``; those layers import this one and a back-edge would close an import cycle.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import pathlib
26
+
27
+ __all__ = ["MESSAGES_ROOT"]
28
+
29
+ # The vendored messages ship inside the package because that is where they are needed: the
30
+ # warm-up check runs in production and its file must be installed with the code that opens it.
31
+ MESSAGES_ROOT = (
32
+ pathlib.Path(__file__).resolve().parent.parent / "samples" / "weather.grib2" / "1.0.0"
33
+ )