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,260 @@
1
+ """Native passive component for deterministic source-observation evidence."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from typing import Any
7
+
8
+ from mostlyright.data_harness.nbrender.parse import Output, RenderContext, esc
9
+ from mostlyright.data_harness.visual_run.observations import (
10
+ safe_column_for_display,
11
+ safe_for_display,
12
+ )
13
+
14
+ MIME = "application/vnd.mostlyright.source-observation+json"
15
+ FIELDS = frozenset(
16
+ {
17
+ "schema_version",
18
+ "source_id",
19
+ "content_sha256",
20
+ "bytes",
21
+ "format",
22
+ "rights",
23
+ "classification",
24
+ "row_count",
25
+ "typed_schema",
26
+ "missingness",
27
+ "sample",
28
+ "warnings",
29
+ "fitness",
30
+ }
31
+ )
32
+ FORMAT_FIELDS = frozenset({"name", "media_type", "encoding"})
33
+ RIGHTS_FIELDS = frozenset({"status", "evidence", "permissions"})
34
+ SCHEMA_FIELDS = frozenset({"name", "logical_type", "nullable"})
35
+ WARNING_FIELDS = frozenset({"code", "message"})
36
+ FITNESS_FIELDS = frozenset({"parseable", "has_columns", "has_rows", "sample_values_permitted"})
37
+ CLASSIFICATIONS = frozenset({"public", "internal", "confidential", "restricted"})
38
+ RIGHTS_STATUSES = frozenset(
39
+ {
40
+ "public_domain",
41
+ "permissive_license",
42
+ "project_owned",
43
+ "authorized_internal",
44
+ "user_authorized",
45
+ }
46
+ )
47
+ PERMISSIONS = frozenset({"local_use", "redistribute", "host"})
48
+ LOGICAL_TYPES = frozenset(
49
+ {
50
+ "null",
51
+ "boolean",
52
+ "int64",
53
+ "float64",
54
+ "decimal",
55
+ "date",
56
+ "timestamp",
57
+ "timestamp_utc",
58
+ "string",
59
+ "mixed",
60
+ }
61
+ )
62
+ _IDENTIFIER = re.compile(r"\A[A-Za-z0-9](?:[A-Za-z0-9._:-]{0,127})\Z")
63
+ _WARNING_CODE = re.compile(r"\A[A-Z][A-Z0-9_]{0,63}\Z")
64
+ _DIGEST = re.compile(r"\A[0-9a-f]{64}\Z")
65
+ MAX_COLUMNS = 512
66
+ MAX_SAMPLE_ROWS = 5
67
+ MAX_WARNINGS = 128
68
+ MAX_TEXT = 16_384
69
+
70
+
71
+ def _text(value: Any, *, maximum: int = MAX_TEXT) -> bool:
72
+ return isinstance(value, str) and bool(value) and len(value) <= maximum
73
+
74
+
75
+ def _nonnegative_integer(value: Any, *, maximum: int = 2**63 - 1) -> bool:
76
+ return type(value) is int and 0 <= value <= maximum
77
+
78
+
79
+ def valid_payload(value: Any) -> bool:
80
+ """Validate the exact closed payload emitted by ``_visual_source_summary``."""
81
+
82
+ if not isinstance(value, dict) or set(value) != FIELDS:
83
+ return False
84
+ if (
85
+ value.get("schema_version") != "mostlyright.source-observation.v1"
86
+ or not isinstance(value.get("source_id"), str)
87
+ or _IDENTIFIER.fullmatch(value["source_id"]) is None
88
+ or not isinstance(value.get("content_sha256"), str)
89
+ or _DIGEST.fullmatch(value["content_sha256"]) is None
90
+ or not _nonnegative_integer(value.get("bytes"))
91
+ or not _nonnegative_integer(value.get("row_count"))
92
+ or value.get("classification") not in CLASSIFICATIONS
93
+ ):
94
+ return False
95
+
96
+ format_value = value.get("format")
97
+ if (
98
+ not isinstance(format_value, dict)
99
+ or set(format_value) != FORMAT_FIELDS
100
+ or not _text(format_value.get("name"), maximum=64)
101
+ or format_value.get("media_type") != "text/csv"
102
+ or format_value.get("encoding") != "utf-8"
103
+ ):
104
+ return False
105
+
106
+ rights = value.get("rights")
107
+ if not isinstance(rights, dict) or set(rights) != RIGHTS_FIELDS:
108
+ return False
109
+ permissions = rights.get("permissions")
110
+ if (
111
+ rights.get("status") not in RIGHTS_STATUSES
112
+ or not _text(rights.get("evidence"))
113
+ or not safe_for_display(rights["evidence"])
114
+ or not isinstance(permissions, list)
115
+ or not permissions
116
+ or len(permissions) != len(set(permissions))
117
+ or any(permission not in PERMISSIONS for permission in permissions)
118
+ ):
119
+ return False
120
+
121
+ typed_schema = value.get("typed_schema")
122
+ if (
123
+ not isinstance(typed_schema, list)
124
+ or not 1 <= len(typed_schema) <= MAX_COLUMNS
125
+ or any(not isinstance(item, dict) or set(item) != SCHEMA_FIELDS for item in typed_schema)
126
+ ):
127
+ return False
128
+ columns = [item["name"] for item in typed_schema]
129
+ if (
130
+ len(columns) != len(set(columns))
131
+ or any(not safe_column_for_display(column) for column in columns)
132
+ or any(item["logical_type"] not in LOGICAL_TYPES for item in typed_schema)
133
+ or any(type(item["nullable"]) is not bool for item in typed_schema)
134
+ ):
135
+ return False
136
+
137
+ missingness = value.get("missingness")
138
+ if (
139
+ not isinstance(missingness, dict)
140
+ or set(missingness) != set(columns)
141
+ or any(
142
+ not _nonnegative_integer(count, maximum=value["row_count"])
143
+ for count in missingness.values()
144
+ )
145
+ or any(item["nullable"] != (missingness[item["name"]] > 0) for item in typed_schema)
146
+ ):
147
+ return False
148
+
149
+ fitness = value.get("fitness")
150
+ if (
151
+ not isinstance(fitness, dict)
152
+ or set(fitness) != FITNESS_FIELDS
153
+ or any(type(fitness[field]) is not bool for field in FITNESS_FIELDS)
154
+ or fitness["parseable"] is not True
155
+ or fitness["has_columns"] != bool(columns)
156
+ or fitness["has_rows"] != (value["row_count"] > 0)
157
+ ):
158
+ return False
159
+ public_values = (
160
+ rights["status"] in {"public_domain", "permissive_license"}
161
+ and value["classification"] == "public"
162
+ )
163
+ if fitness["sample_values_permitted"] != public_values:
164
+ return False
165
+
166
+ sample = value.get("sample")
167
+ if not isinstance(sample, list) or len(sample) > MAX_SAMPLE_ROWS:
168
+ return False
169
+ if (not public_values and sample) or any(
170
+ not isinstance(row, dict)
171
+ or list(row) != columns
172
+ or any(
173
+ type(cell) not in {bool, int, str, type(None)}
174
+ or (isinstance(cell, str) and (len(cell) > 512 or not safe_for_display(cell)))
175
+ for cell in row.values()
176
+ )
177
+ for row in sample
178
+ ):
179
+ return False
180
+
181
+ warnings = value.get("warnings")
182
+ return bool(
183
+ isinstance(warnings, list)
184
+ and len(warnings) <= MAX_WARNINGS
185
+ and all(
186
+ isinstance(item, dict)
187
+ and set(item) == WARNING_FIELDS
188
+ and isinstance(item.get("code"), str)
189
+ and _WARNING_CODE.fullmatch(item["code"]) is not None
190
+ and _text(item.get("message"))
191
+ and safe_for_display(item["message"])
192
+ for item in warnings
193
+ )
194
+ )
195
+
196
+
197
+ def _sample_table(columns: list[str], rows: list[dict[str, Any]]) -> str:
198
+ if not rows:
199
+ return '<p class="nb-stage-policy">Source values withheld by display policy.</p>'
200
+ head = "".join(f'<th scope="col">{esc(column)}</th>' for column in columns)
201
+ body = "".join(
202
+ "<tr>" + "".join(f"<td>{esc(row[column])}</td>" for column in columns) + "</tr>"
203
+ for row in rows
204
+ )
205
+ return (
206
+ '<div class="nb-stage-table" tabindex="0" aria-label="Bounded source sample"><table>'
207
+ f"<thead><tr>{head}</tr></thead><tbody>{body}</tbody></table></div>"
208
+ )
209
+
210
+
211
+ def render_source_observation(out: Output, _ctx: RenderContext) -> str:
212
+ value = out.data.get(MIME)
213
+ if not valid_payload(value):
214
+ raise ValueError("invalid source-observation MIME payload")
215
+ assert isinstance(value, dict)
216
+ schema = "".join(
217
+ "<li><code>"
218
+ + esc(item["name"])
219
+ + "</code><span>"
220
+ + esc(item["logical_type"])
221
+ + (" · nullable" if item["nullable"] else "")
222
+ + f" · {esc(value['missingness'][item['name']])} missing</span></li>"
223
+ for item in value["typed_schema"]
224
+ )
225
+ warnings = (
226
+ "".join(
227
+ f'<li class="is-warning"><strong>{esc(item["code"])}</strong>'
228
+ f"<span>{esc(item['message'])}</span></li>"
229
+ for item in value["warnings"]
230
+ )
231
+ or '<li class="is-info"><strong>source</strong><span>No source warnings</span></li>'
232
+ )
233
+ fitness = value["fitness"]
234
+ return (
235
+ '<section class="nb-source-observation" aria-label="Source evidence">'
236
+ "<header><span>Source evidence</span>"
237
+ f"<strong>{esc(value['source_id'])}</strong>"
238
+ f"<small>{esc(value['classification'])}</small></header>"
239
+ "<dl><div><dt>Rows</dt><dd>"
240
+ f"{esc(value['row_count'])}</dd></div><div><dt>Bytes</dt>"
241
+ f"<dd>{esc(value['bytes'])}</dd></div><div><dt>Format</dt>"
242
+ f"<dd>{esc(value['format']['name'])}</dd></div></dl>"
243
+ '<div class="nb-stage-evidence">'
244
+ "<section><h4>Rights & classification</h4>"
245
+ f"<p><strong>{esc(value['rights']['status'])}</strong> · "
246
+ f"{esc(', '.join(value['rights']['permissions']))}</p>"
247
+ f"<p>{esc(value['rights']['evidence'])}</p></section>"
248
+ "<section><h4>Schema & missingness</h4>"
249
+ f'<ul class="nb-stage-schema">{schema}</ul></section>'
250
+ "<section><h4>Fitness</h4>"
251
+ f"<p>parseable: {esc(fitness['parseable'])} · columns: {esc(fitness['has_columns'])} · "
252
+ f"rows: {esc(fitness['has_rows'])}</p></section>"
253
+ "<section><h4>Warnings</h4>"
254
+ f'<ul class="nb-stage-findings">{warnings}</ul></section></div>'
255
+ + _sample_table([item["name"] for item in value["typed_schema"]], value["sample"])
256
+ + f"<footer><code>{esc(value['content_sha256'])}</code></footer></section>"
257
+ )
258
+
259
+
260
+ __all__ = ["MIME", "render_source_observation", "valid_payload"]
@@ -0,0 +1,176 @@
1
+ """Passive native component for bounded stage-observation MIME data."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import Any
7
+
8
+ from mostlyright.data_harness.nbrender.parse import Output, RenderContext, esc
9
+ from mostlyright.data_harness.visual_run.observations import validate_stage_observation
10
+
11
+ MIME = "application/vnd.mostlyright.stage-observation.v1+json"
12
+ MIME_CURRENT = "application/vnd.mostlyright.stage-observation+json"
13
+ MIMES = (MIME_CURRENT, MIME)
14
+ _OPERATION_COMPONENTS = {
15
+ "union": ("union", "Union compatibility"),
16
+ "join": ("join", "Join contract"),
17
+ "aggregate": ("aggregate", "Aggregation"),
18
+ "resample": ("resample", "Temporal resampling"),
19
+ "normalize": ("normalization", "Normalization"),
20
+ "cast": ("normalization", "Type normalization"),
21
+ "rename": ("normalization", "Schema normalization"),
22
+ }
23
+
24
+
25
+ def valid_payload(value: Any) -> bool:
26
+ try:
27
+ validate_stage_observation(value)
28
+ except (TypeError, ValueError):
29
+ return False
30
+ return True
31
+
32
+
33
+ def _table(columns: list[str], rows: list[dict[str, Any]], *, label: str) -> str:
34
+ if not rows:
35
+ return '<p class="nb-stage-policy">Values withheld by display policy.</p>'
36
+ head = "".join(f'<th scope="col">{esc(column)}</th>' for column in columns)
37
+ body = "".join(
38
+ "<tr>"
39
+ + "".join(
40
+ f"<td>{esc(json.dumps(row.get(column), ensure_ascii=False, sort_keys=True))}</td>"
41
+ for column in columns
42
+ )
43
+ + "</tr>"
44
+ for row in rows
45
+ )
46
+ return (
47
+ f'<div class="nb-stage-table" tabindex="0" aria-label="{esc(label)}"><table>'
48
+ f"<thead><tr>{head}</tr></thead><tbody>{body}</tbody></table></div>"
49
+ )
50
+
51
+
52
+ def _facts(value: dict[str, Any]) -> str:
53
+ facts = (
54
+ ("Input rows", value["input_rows"]),
55
+ ("Output rows", value["output_rows"]),
56
+ ("Rejected", value["rejected_rows"]),
57
+ ("Duplicates", value["duplicate_rows"]),
58
+ )
59
+ return (
60
+ "<dl>"
61
+ + "".join(
62
+ f"<div><dt>{esc(label)}</dt><dd>{esc(number)}</dd></div>" for label, number in facts
63
+ )
64
+ + "</dl>"
65
+ )
66
+
67
+
68
+ def _v2_evidence(value: dict[str, Any]) -> str:
69
+ if value.get("schema_version") != "stage-observation.v2":
70
+ return ""
71
+ audit = value["audit"]
72
+ schemas = "".join(
73
+ "<li><strong data-semantic-label>"
74
+ f"{esc(column['name'])}</strong><span>{esc(column['logical_type'])}"
75
+ f"{' · nullable' if column['nullable'] else ''}</span></li>"
76
+ for column in value["output_schema"]
77
+ )
78
+ profiles = _table(
79
+ ["column", "rows_examined", "null_count", "distinct_count"],
80
+ value["profiles"],
81
+ label="Column profiles",
82
+ )
83
+ lineage = "".join(
84
+ "<li><strong>"
85
+ + esc(item["column"])
86
+ + "</strong><span>"
87
+ + esc(
88
+ ", ".join(f"{source['coordinate']}.{source['column']}" for source in item["sources"])
89
+ or "derived"
90
+ )
91
+ + "</span><small>"
92
+ + esc(" → ".join(item["operations"]) or "identity")
93
+ + "</small></li>"
94
+ for item in value["lineage"]
95
+ )
96
+ findings = (
97
+ "".join(
98
+ f'<li class="is-{esc(item["severity"])}"><strong>{esc(item["code"])}</strong>'
99
+ f"<span>{esc(item['message'])}</span>"
100
+ f"<small>{esc(item['column'] or 'dataset')}</small></li>"
101
+ for item in value["findings"]
102
+ )
103
+ or '<li class="is-info"><strong>checks</strong><span>No quality findings</span></li>'
104
+ )
105
+ sources = ", ".join(value["source_coordinates"]) or "derived inputs"
106
+ operation_component = ""
107
+ component = _OPERATION_COMPONENTS.get(value["operation"])
108
+ if component is not None:
109
+ kind, label = component
110
+ parameters = json.dumps(
111
+ value["operation_parameters"], ensure_ascii=False, sort_keys=True, separators=(",", ":")
112
+ )
113
+ operation_component = (
114
+ f'<section class="nb-stage-operation nb-stage-operation--{kind}">'
115
+ f"<h4>{esc(label)}</h4><p>{esc(len(value['inputs']))} input coordinate(s) → "
116
+ f"{esc(value['output_rows'])} rows</p><code>{esc(parameters)}</code></section>"
117
+ )
118
+ representative_component = ""
119
+ representative = (
120
+ value["coverage"].get("representative_window") if value["display"] == "full" else None
121
+ )
122
+ if representative is not None:
123
+ input_rows = [row for item in representative["inputs"] for row in item["rows"]]
124
+ input_columns = list(input_rows[0]) if input_rows else []
125
+ representative_component = (
126
+ '<details class="nb-stage-window"><summary>Representative sealed window</summary>'
127
+ f"<p>{esc(representative['start'])} → {esc(representative['end'])}</p>"
128
+ + _table(input_columns, input_rows, label="Representative input rows")
129
+ + _table(
130
+ list(representative["output"]),
131
+ [representative["output"]] if representative["output"] else [],
132
+ label="Representative resample output",
133
+ )
134
+ + "</details>"
135
+ )
136
+ return (
137
+ '<div class="nb-stage-evidence">'
138
+ + operation_component
139
+ + representative_component
140
+ + '<section><h4>Schema & semantic labels</h4><ul class="nb-stage-schema">'
141
+ + schemas
142
+ + "</ul></section>"
143
+ "<section><h4>Profiles</h4>" + profiles + "</section>"
144
+ '<section><h4>Quality examples</h4><ul class="nb-stage-findings">'
145
+ + findings
146
+ + "</ul></section>"
147
+ '<section><h4>Column lineage</h4><ul class="nb-stage-lineage">'
148
+ + lineage
149
+ + "</ul></section>"
150
+ '<section class="nb-stage-audit"><h4>Sealed evidence</h4>'
151
+ f"<p><strong>{esc(audit['engine'])}</strong> · {esc(audit['order_contract'])}</p>"
152
+ f"<p>{esc(sources)}</p><code>{esc(value['output_digest'])}</code></section></div>"
153
+ )
154
+
155
+
156
+ def render_stage_observation(
157
+ out: Output, _ctx: RenderContext, *, mimetype: str | None = None
158
+ ) -> str:
159
+ selected = mimetype or next((name for name in MIMES if name in out.data), MIME)
160
+ value = out.data.get(selected)
161
+ if not valid_payload(value):
162
+ raise ValueError("invalid stage-observation MIME payload")
163
+ assert isinstance(value, dict)
164
+ truncation = " · bounded sample" if value["truncated"] else ""
165
+ return (
166
+ '<section class="nb-stage-observation" aria-label="Data operation evidence">'
167
+ "<header><span>Data operation</span>"
168
+ f"<strong>{esc(value['operation'])}</strong><small>{esc(value['node_id'])}</small></header>"
169
+ + _facts(value)
170
+ + _v2_evidence(value)
171
+ + _table(value["columns"], value["sample"], label="Bounded stage sample")
172
+ + f"<footer>{esc(value['display'])}{esc(truncation)}</footer></section>"
173
+ )
174
+
175
+
176
+ __all__ = ["MIME", "MIMES", "MIME_CURRENT", "render_stage_observation", "valid_payload"]