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,283 @@
1
+ """The ONE cross-runtime value domain for a cell of a sealed dataset.
2
+
3
+ Two callers need to turn sealed Parquet bytes into a canonical JSON payload: the hosted
4
+ worker's table preview and the serving surface. They face the same two hard facts.
5
+ ``canonical.canonical_json_bytes`` refuses every float, so a numeric cell has to reach the
6
+ encoder as text; and ``canonical.MAX_CANONICAL_MEMBERS`` is exactly the pipeline's
7
+ ``MAX_ROWS``, so a whole-dataset payload cannot be canonicalized at all and has to be fitted
8
+ to a byte budget.
9
+
10
+ Both problems are solved here once. A second renderer would be a second value domain, and
11
+ two restatements of a value domain stay mutually consistent right up until one of them is
12
+ edited -- which is the failure ``docs/CONTRACTS.md`` records for restated format tables: the
13
+ copy keeps agreeing with itself while the real gate rots.
14
+
15
+ This module is deliberately a LEAF. Its only in-package import is ``canonical``; the bounds
16
+ it enforces arrive as arguments rather than being read from ``pipeline``. A caller that must
17
+ prove a small call graph -- that no request path can reach an origin fetch or an unsealed
18
+ draft -- can then start from a small named set instead of from the pipeline's whole import
19
+ closure.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import math
25
+ import re
26
+ from collections.abc import Callable, Sequence
27
+
28
+ import pyarrow as pa
29
+ import pyarrow.parquet as pq
30
+
31
+ from mostlyright.data_harness.canonical import CanonicalJSONError
32
+
33
+ __all__ = [
34
+ "COLUMN_NAME",
35
+ "RowsetError",
36
+ "fit_canonical_payload",
37
+ "inspect_sealed_parquet",
38
+ "open_sealed_parquet",
39
+ "render_cell",
40
+ "render_filtered_window",
41
+ "render_rows",
42
+ ]
43
+
44
+ # The one refusal code this module raises. A caller that needs a different error identity
45
+ # translates at its own boundary rather than teaching this module about that identity.
46
+ ROWS_INVALID = "DATASET_ROWS_INVALID"
47
+
48
+ # The frozen column-name shape a sealed dataset may present to either reader.
49
+ COLUMN_NAME = re.compile(r"^[A-Za-z_][A-Za-z0-9_.:-]{0,127}$")
50
+
51
+
52
+ class RowsetError(RuntimeError):
53
+ """A deterministic rowset gate refused a sealed dataset read.
54
+
55
+ Shaped like ``pipeline.BuildError``: a typed refusal carrying a greppable ``code``,
56
+ whose ``str()`` is exactly the message, so a caller can re-raise it under its own error
57
+ type without the message text changing.
58
+ """
59
+
60
+ def __init__(self, code: str, message: str) -> None:
61
+ super().__init__(message)
62
+ self.code = code
63
+
64
+
65
+ def render_cell(scalar: pa.Scalar) -> bool | str | None:
66
+ """Render one Arrow scalar into the cross-runtime value domain.
67
+
68
+ The domain is exactly ``bool | str | None``. Every number leaves as text because the
69
+ canonical encoder refuses non-integer JSON numbers outright, and rendering an integer as
70
+ text too keeps one rule for all numerics instead of a width-dependent one.
71
+ """
72
+
73
+ if not scalar.is_valid:
74
+ return None
75
+ value = scalar.as_py()
76
+ data_type = scalar.type
77
+ if pa.types.is_boolean(data_type):
78
+ if type(value) is not bool: # pragma: no cover - Arrow type invariant
79
+ raise RowsetError(ROWS_INVALID, "boolean scalar is invalid")
80
+ return value
81
+ if pa.types.is_string(data_type) or pa.types.is_large_string(data_type):
82
+ if not isinstance(value, str): # pragma: no cover - Arrow type invariant
83
+ raise RowsetError(ROWS_INVALID, "string scalar is invalid")
84
+ return value
85
+ if pa.types.is_integer(data_type):
86
+ return str(value)
87
+ if pa.types.is_floating(data_type):
88
+ if not isinstance(value, float) or not math.isfinite(value):
89
+ raise RowsetError(
90
+ ROWS_INVALID,
91
+ "floating preview values must be finite",
92
+ )
93
+ return format(value, ".17g")
94
+ if pa.types.is_decimal(data_type):
95
+ return format(value, "f")
96
+ if pa.types.is_date(data_type):
97
+ return value.isoformat()
98
+ if pa.types.is_timestamp(data_type):
99
+ rendered = value.isoformat(timespec="microseconds")
100
+ return rendered.removesuffix("+00:00") + "Z" if rendered.endswith("+00:00") else rendered
101
+ raise RowsetError(
102
+ ROWS_INVALID,
103
+ f"unsupported preview column type: {data_type}",
104
+ )
105
+
106
+
107
+ def render_rows(
108
+ source: pa.RecordBatch | pa.Table,
109
+ columns: Sequence[str],
110
+ ) -> list[dict[str, bool | str | None]]:
111
+ """Render every row of one batch or table as an ordered mapping of rendered cells.
112
+
113
+ Columns are addressed positionally, in the order the caller read them off the sealed
114
+ schema, so a duplicate or reordered name in the mapping cannot silently pick a different
115
+ Arrow column than the one the guards inspected.
116
+ """
117
+
118
+ return [
119
+ {
120
+ column: render_cell(source.column(column_index)[row_index])
121
+ for column_index, column in enumerate(columns)
122
+ }
123
+ for row_index in range(source.num_rows)
124
+ ]
125
+
126
+
127
+ def render_filtered_window(
128
+ parquet: pq.ParquetFile,
129
+ columns: Sequence[str],
130
+ *,
131
+ select: Callable[[pa.RecordBatch], pa.RecordBatch | pa.Table],
132
+ offset: int,
133
+ limit: int,
134
+ batch_size: int = 1_024,
135
+ exact_match_count: int | None = None,
136
+ ) -> tuple[int, list[dict[str, bool | str | None]]]:
137
+ """Retain one bounded window and count only when no exact metadata count exists.
138
+
139
+ Sealed file order remains the order: batches are visited in Parquet order and rows are
140
+ appended in their order inside each batch. Unfiltered serving supplies the exact Parquet
141
+ metadata count, so scanning stops as soon as the requested window is full. A filtered read has
142
+ no trustworthy metadata count and continues only to keep ``matched_row_count`` exact. Live
143
+ Arrow state is one fixed-size batch plus at most ``limit`` rendered rows, never the table.
144
+ """
145
+
146
+ if exact_match_count is not None and (
147
+ type(exact_match_count) is not int or exact_match_count < 0
148
+ ):
149
+ raise RowsetError(ROWS_INVALID, "exact match count is invalid")
150
+ matched_row_count = 0
151
+ rendered: list[dict[str, bool | str | None]] = []
152
+ for row_group in range(parquet.metadata.num_row_groups):
153
+ row_group_rows = parquet.metadata.row_group(row_group).num_rows
154
+ if exact_match_count is not None and matched_row_count + row_group_rows <= offset:
155
+ matched_row_count += row_group_rows
156
+ continue
157
+ for batch in parquet.iter_batches(batch_size=batch_size, row_groups=[row_group]):
158
+ selected = select(batch)
159
+ selected_count = selected.num_rows
160
+ start = max(offset - matched_row_count, 0)
161
+ remaining = limit - len(rendered)
162
+ if remaining > 0 and start < selected_count:
163
+ retained = selected.slice(start, min(remaining, selected_count - start))
164
+ rendered.extend(render_rows(retained, columns))
165
+ matched_row_count += selected_count
166
+ if exact_match_count is not None and len(rendered) == limit:
167
+ return exact_match_count, rendered
168
+ return exact_match_count if exact_match_count is not None else matched_row_count, rendered
169
+
170
+
171
+ def inspect_sealed_parquet(
172
+ parquet: pq.ParquetFile,
173
+ *,
174
+ max_columns: int,
175
+ max_rows: int,
176
+ max_uncompressed_bytes: int,
177
+ ) -> tuple[list[str], int]:
178
+ """Validate one already-open sealed Parquet file entirely from its metadata."""
179
+
180
+ columns = list(parquet.schema_arrow.names)
181
+ total_row_count = parquet.metadata.num_rows
182
+ if (
183
+ not 1 <= len(columns) <= max_columns
184
+ or len(columns) != len(set(columns))
185
+ or any(not COLUMN_NAME.fullmatch(column) for column in columns)
186
+ ):
187
+ raise RowsetError(
188
+ ROWS_INVALID,
189
+ "preview columns violate the frozen table-preview contract",
190
+ )
191
+ if type(total_row_count) is not int or not 0 <= total_row_count <= max_rows:
192
+ raise RowsetError(
193
+ ROWS_INVALID,
194
+ "preview row count exceeds the candidate row budget",
195
+ )
196
+ declared_uncompressed_bytes = sum(
197
+ parquet.metadata.row_group(index).total_byte_size
198
+ for index in range(parquet.metadata.num_row_groups)
199
+ )
200
+ if (
201
+ type(declared_uncompressed_bytes) is not int
202
+ or not 0 <= declared_uncompressed_bytes <= max_uncompressed_bytes
203
+ ):
204
+ raise RowsetError(
205
+ ROWS_INVALID,
206
+ "preview Parquet exceeds the candidate decompression budget",
207
+ )
208
+ return columns, total_row_count
209
+
210
+
211
+ def open_sealed_parquet(
212
+ parquet_raw: bytes,
213
+ *,
214
+ max_columns: int,
215
+ max_rows: int,
216
+ max_uncompressed_bytes: int,
217
+ ) -> tuple[pq.ParquetFile, list[str], int]:
218
+ """Open sealed Parquet bytes and refuse anything outside the declared bounds.
219
+
220
+ Every guard reads only Parquet metadata, so an oversized or malformed file is refused
221
+ before a single row group is decompressed. The bounds arrive as arguments: this module
222
+ does not decide what a dataset's limits are, it only enforces the ones it is handed.
223
+ """
224
+
225
+ try:
226
+ parquet = pq.ParquetFile(pa.BufferReader(parquet_raw))
227
+ columns, total_row_count = inspect_sealed_parquet(
228
+ parquet,
229
+ max_columns=max_columns,
230
+ max_rows=max_rows,
231
+ max_uncompressed_bytes=max_uncompressed_bytes,
232
+ )
233
+ except RowsetError:
234
+ raise
235
+ except Exception as error:
236
+ raise RowsetError(
237
+ ROWS_INVALID,
238
+ f"sealed Parquet preview derivation failed: {type(error).__name__}",
239
+ ) from error
240
+ return parquet, columns, total_row_count
241
+
242
+
243
+ def fit_canonical_payload(
244
+ encode: Callable[[int], bytes],
245
+ row_count: int,
246
+ *,
247
+ max_bytes: int,
248
+ ) -> bytes:
249
+ """Return the encoding of the longest row prefix that fits ``max_bytes``.
250
+
251
+ The loop searches rather than estimates because the canonical encoding of a row is not a
252
+ function of its Python size: escaping, key ordering and the shared envelope all move the
253
+ encoded length, and ``MAX_CANONICAL_MEMBERS`` bounds a member COUNT rather than a byte
254
+ count. The only honest bound on a candidate prefix is the length of that prefix once
255
+ encoded, so the prefix length is what gets bisected. A ``CanonicalJSONError`` from the
256
+ encoder is read as "this prefix is too large" and shrinks the search, which is what keeps
257
+ the member ceiling a bound on the payload rather than an error propagated to the caller.
258
+
259
+ A payload is always shrunk by whole rows from the end. A cell value is never truncated,
260
+ so every row that is served is the row that was sealed.
261
+ """
262
+
263
+ low = 0
264
+ high = row_count
265
+ selected = b""
266
+ while low <= high:
267
+ middle = (low + high) // 2
268
+ try:
269
+ encoded = encode(middle)
270
+ except CanonicalJSONError:
271
+ high = middle - 1
272
+ continue
273
+ if len(encoded) <= max_bytes:
274
+ selected = encoded
275
+ low = middle + 1
276
+ else:
277
+ high = middle - 1
278
+ if not selected:
279
+ raise RowsetError(
280
+ ROWS_INVALID,
281
+ "preview metadata alone exceeds the artifact byte budget",
282
+ )
283
+ return selected