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,374 @@
1
+ """The facts gate: decide whether a catalog entry may be used, on facts alone.
2
+
3
+ Every decision here is a function of structured facts -- the rights status and its obligations,
4
+ whether the source needs authentication, which payload formats it publishes, how often it updates,
5
+ and whether it is answering. None of those is a matter of degree, and none of them is negotiable
6
+ by how well a source matched a question.
7
+
8
+ This module has no way to consult a similarity number. It does not import the module that
9
+ computes one, or any module that touches a sealed embedding; its inputs cannot represent one; and
10
+ its own function signatures have no parameter that could carry one. That is a structural property
11
+ rather than a convention, and a test proves it by reading the import closure and the syntax tree
12
+ rather than by reading this paragraph.
13
+
14
+ Rights are not re-adjudicated here either. ``sources.rights_rule.rights_disposition`` is the one
15
+ authority for what a rights status means, and ``evaluate_obligations`` is the one obligation
16
+ evaluator. A second copy could disagree with the first, and the disagreement
17
+ would be about whether someone may lawfully use a dataset.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from dataclasses import dataclass
23
+ from typing import Any
24
+
25
+ from mostlyright.data_harness.sources.catalog.contracts import CatalogEntry
26
+ from mostlyright.data_harness.sources.contracts import (
27
+ DATA_FORMATS,
28
+ OBLIGATION_LIFECYCLES,
29
+ SourceContractError,
30
+ _CanonicalContract,
31
+ evaluate_obligations,
32
+ )
33
+ from mostlyright.data_harness.sources.rights_rule import rights_disposition
34
+
35
+ CATALOG_REQUIREMENT_CONTRACT_VERSION = "harness-source-catalog-requirement.v1"
36
+ CATALOG_VERDICT_CONTRACT_VERSION = "harness-source-catalog-verdict.v1"
37
+
38
+ # Ordered. A verdict's check list is digested, so its order must be fixed.
39
+ CATALOG_CHECKS = (
40
+ "rights",
41
+ "obligations",
42
+ "authentication",
43
+ "data_format",
44
+ "cadence",
45
+ "liveness",
46
+ )
47
+
48
+ CATALOG_DISPOSITIONS = ("admitted", "refused", "human_escalation_required")
49
+
50
+ MAX_DETAIL = 500
51
+ MAX_REQUIRED_FORMATS = 16
52
+ MAX_ATTACHED_DIGESTS = 32
53
+ MAX_FREQUENCY_SECONDS = 10 * 365 * 24 * 60 * 60
54
+
55
+
56
+ @dataclass(frozen=True)
57
+ class CatalogRequirement(_CanonicalContract):
58
+ """What a caller needs from a source, expressed entirely as facts.
59
+
60
+ There is deliberately no threshold field. A threshold would be an admission decision taken by
61
+ degree of textual match, which is the one thing this gate exists to make impossible.
62
+ """
63
+
64
+ intended_use: str
65
+ lifecycle: str
66
+ required_data_formats: tuple[str, ...]
67
+ max_update_frequency_seconds: int
68
+ require_open_access: bool = True
69
+ require_live: bool = True
70
+ attached_license_artifact_digests: tuple[str, ...] = ()
71
+ schema_version: str = CATALOG_REQUIREMENT_CONTRACT_VERSION
72
+
73
+ def __post_init__(self) -> None:
74
+ _constant(
75
+ self.schema_version,
76
+ CATALOG_REQUIREMENT_CONTRACT_VERSION,
77
+ "requirement.schema_version",
78
+ )
79
+ _text(self.intended_use, "requirement.intended_use", maximum=200)
80
+ _choice(self.lifecycle, OBLIGATION_LIFECYCLES, "requirement.lifecycle")
81
+ _choices(
82
+ self.required_data_formats,
83
+ DATA_FORMATS,
84
+ "requirement.required_data_formats",
85
+ maximum=MAX_REQUIRED_FORMATS,
86
+ )
87
+ _integer(
88
+ self.max_update_frequency_seconds,
89
+ "requirement.max_update_frequency_seconds",
90
+ minimum=0,
91
+ maximum=MAX_FREQUENCY_SECONDS,
92
+ )
93
+ _boolean(self.require_open_access, "requirement.require_open_access")
94
+ _boolean(self.require_live, "requirement.require_live")
95
+ _digests(
96
+ self.attached_license_artifact_digests,
97
+ "requirement.attached_license_artifact_digests",
98
+ maximum=MAX_ATTACHED_DIGESTS,
99
+ )
100
+
101
+ def to_dict(self) -> dict[str, Any]:
102
+ return {
103
+ "schema_version": self.schema_version,
104
+ "intended_use": self.intended_use,
105
+ "lifecycle": self.lifecycle,
106
+ "required_data_formats": list(self.required_data_formats),
107
+ "max_update_frequency_seconds": self.max_update_frequency_seconds,
108
+ "require_open_access": self.require_open_access,
109
+ "require_live": self.require_live,
110
+ "attached_license_artifact_digests": list(self.attached_license_artifact_digests),
111
+ }
112
+
113
+
114
+ @dataclass(frozen=True)
115
+ class CatalogCheck(_CanonicalContract):
116
+ """One named fact check and how it came out."""
117
+
118
+ check: str
119
+ outcome: str
120
+ detail: str
121
+
122
+ def __post_init__(self) -> None:
123
+ _choice(self.check, frozenset(CATALOG_CHECKS), "check.check")
124
+ _choice(self.outcome, frozenset({"pass", "fail"}), "check.outcome")
125
+ _text(self.detail, "check.detail", maximum=MAX_DETAIL)
126
+
127
+ def to_dict(self) -> dict[str, str]:
128
+ return {"check": self.check, "outcome": self.outcome, "detail": self.detail}
129
+
130
+
131
+ @dataclass(frozen=True)
132
+ class CatalogGateVerdict(_CanonicalContract):
133
+ """One entry's decision, with the citations that make it checkable later.
134
+
135
+ Three digests, because a decision has three inputs and citing two of them makes the record
136
+ ambiguous. ``entry_digest`` and ``rights_digest`` cite what was decided about;
137
+ ``requirement_digest`` cites what it was decided against, which supplies the other half of
138
+ every check here -- the lifecycle, the intended use, the required formats, the cadence ceiling
139
+ and the open-access and liveness switches. Without it the same entry yields ``admitted`` under
140
+ one requirement and ``refused`` under another and the two stored verdicts are indistinguishable
141
+ in their citations. ``registry.acquire``'s ``REQUEST_BINDING`` check is the same idea one layer
142
+ down.
143
+ """
144
+
145
+ entry_coordinate: str
146
+ disposition: str
147
+ reason: str
148
+ checks: tuple[CatalogCheck, ...]
149
+ entry_digest: str
150
+ rights_digest: str
151
+ requirement_digest: str
152
+ schema_version: str = CATALOG_VERDICT_CONTRACT_VERSION
153
+
154
+ def __post_init__(self) -> None:
155
+ _constant(
156
+ self.schema_version,
157
+ CATALOG_VERDICT_CONTRACT_VERSION,
158
+ "verdict.schema_version",
159
+ )
160
+ _text(self.entry_coordinate, "verdict.entry_coordinate", maximum=200)
161
+ _choice(self.disposition, frozenset(CATALOG_DISPOSITIONS), "verdict.disposition")
162
+ _text(self.reason, "verdict.reason", maximum=MAX_DETAIL)
163
+ if not isinstance(self.checks, tuple):
164
+ raise SourceContractError("TYPE", "verdict.checks", "must be an immutable tuple")
165
+ if tuple(item.check for item in self.checks) != CATALOG_CHECKS:
166
+ raise SourceContractError(
167
+ "CATALOG_CHECK_SET",
168
+ "verdict.checks",
169
+ f"must contain each of {list(CATALOG_CHECKS)} exactly once, in order",
170
+ )
171
+ _digest(self.entry_digest, "verdict.entry_digest")
172
+ _digest(self.rights_digest, "verdict.rights_digest")
173
+ _digest(self.requirement_digest, "verdict.requirement_digest")
174
+
175
+ def to_dict(self) -> dict[str, Any]:
176
+ return {
177
+ "schema_version": self.schema_version,
178
+ "entry_coordinate": self.entry_coordinate,
179
+ "disposition": self.disposition,
180
+ "reason": self.reason,
181
+ "checks": [item.to_dict() for item in self.checks],
182
+ "entry_digest": self.entry_digest,
183
+ "rights_digest": self.rights_digest,
184
+ "requirement_digest": self.requirement_digest,
185
+ }
186
+
187
+
188
+ def gate_entries(
189
+ entries: tuple[CatalogEntry, ...],
190
+ *,
191
+ requirement: CatalogRequirement,
192
+ ) -> tuple[CatalogGateVerdict, ...]:
193
+ """Decide each entry against the requirement. A pure function of facts.
194
+
195
+ Note what this signature cannot express: there is no argument through which a degree of
196
+ textual match could arrive, and neither ``CatalogEntry`` nor ``CatalogRequirement`` has a
197
+ field able to carry one.
198
+ """
199
+
200
+ if not isinstance(entries, tuple):
201
+ raise SourceContractError("TYPE", "entries", "must be an immutable tuple")
202
+ if not isinstance(requirement, CatalogRequirement):
203
+ raise SourceContractError("TYPE", "requirement", "must be a CatalogRequirement")
204
+ verdicts: list[CatalogGateVerdict] = []
205
+ for position, entry in enumerate(entries):
206
+ if not isinstance(entry, CatalogEntry):
207
+ raise SourceContractError(
208
+ "TYPE",
209
+ f"entries[{position}]",
210
+ "must be a CatalogEntry",
211
+ )
212
+ verdicts.append(_gate_one(entry, requirement))
213
+ return tuple(verdicts)
214
+
215
+
216
+ def _gate_one(entry: CatalogEntry, requirement: CatalogRequirement) -> CatalogGateVerdict:
217
+ disposition_of_rights = rights_disposition(entry.rights.status)
218
+ outcomes: dict[str, tuple[bool, str]] = {}
219
+
220
+ outcomes["rights"] = (
221
+ disposition_of_rights == "admit",
222
+ f"rights status {entry.rights.status!r} is {disposition_of_rights}",
223
+ )
224
+
225
+ if disposition_of_rights == "admit":
226
+ try:
227
+ applicable = evaluate_obligations(
228
+ rights=entry.rights,
229
+ lifecycle=requirement.lifecycle,
230
+ intended_use=requirement.intended_use,
231
+ attached_artifact_digests=requirement.attached_license_artifact_digests,
232
+ )
233
+ except SourceContractError as error:
234
+ outcomes["obligations"] = (
235
+ False,
236
+ f"licence obligations are not satisfied: {error.detail}"[:MAX_DETAIL],
237
+ )
238
+ else:
239
+ outcomes["obligations"] = (
240
+ True,
241
+ f"{len(applicable)} licence obligation(s) apply and are satisfied",
242
+ )
243
+ else:
244
+ outcomes["obligations"] = (
245
+ True,
246
+ "not evaluated: the rights check already decided this entry",
247
+ )
248
+
249
+ needs_login = requirement.require_open_access and entry.authentication_required
250
+ outcomes["authentication"] = (
251
+ not needs_login,
252
+ "the source requires authentication and open access was required"
253
+ if needs_login
254
+ else "no authentication is required",
255
+ )
256
+
257
+ shared_formats = sorted(set(entry.data_formats) & set(requirement.required_data_formats))
258
+ outcomes["data_format"] = (
259
+ bool(shared_formats),
260
+ f"published formats {sorted(entry.data_formats)} "
261
+ f"{'include' if shared_formats else 'do not include'} "
262
+ f"a required format from {sorted(requirement.required_data_formats)}",
263
+ )
264
+
265
+ observed_frequency = entry.observation.update_frequency_seconds
266
+ outcomes["cadence"] = (
267
+ observed_frequency <= requirement.max_update_frequency_seconds,
268
+ f"the source updates every {observed_frequency}s against a required "
269
+ f"{requirement.max_update_frequency_seconds}s",
270
+ )
271
+
272
+ live_status = entry.observation.live_status
273
+ outcomes["liveness"] = (
274
+ not (requirement.require_live and live_status != "live"),
275
+ f"the last probe found the source {live_status!r}",
276
+ )
277
+
278
+ checks = tuple(
279
+ CatalogCheck(
280
+ check=name,
281
+ outcome="pass" if outcomes[name][0] else "fail",
282
+ detail=outcomes[name][1],
283
+ )
284
+ for name in CATALOG_CHECKS
285
+ )
286
+ failed = [item.check for item in checks if item.outcome != "pass"]
287
+
288
+ # Precedence mirrors the fitness adjudicator exactly: escalation first, then any failure.
289
+ if disposition_of_rights == "escalate":
290
+ disposition = "human_escalation_required"
291
+ reason = "rights are unclear and require human legal/product escalation"
292
+ elif failed:
293
+ disposition = "refused"
294
+ reason = f"failed checks: {', '.join(failed)}"
295
+ else:
296
+ disposition = "admitted"
297
+ reason = "every required fact check passes"
298
+
299
+ return CatalogGateVerdict(
300
+ entry_coordinate=entry.coordinate,
301
+ disposition=disposition,
302
+ reason=reason,
303
+ checks=checks,
304
+ entry_digest=entry.digest,
305
+ rights_digest=entry.rights.digest,
306
+ requirement_digest=requirement.digest,
307
+ )
308
+
309
+
310
+ def _text(value: Any, path: str, *, maximum: int) -> str:
311
+ if not isinstance(value, str) or not value or len(value) > maximum:
312
+ raise SourceContractError(
313
+ "TEXT",
314
+ path,
315
+ f"must be a non-empty string no longer than {maximum} characters",
316
+ )
317
+ return value
318
+
319
+
320
+ def _constant(value: Any, expected: str, path: str) -> None:
321
+ if value != expected:
322
+ raise SourceContractError("VERSION", path, f"must equal {expected!r}")
323
+
324
+
325
+ def _choice(value: Any, allowed: frozenset[str] | set[str], path: str) -> str:
326
+ text = _text(value, path, maximum=128)
327
+ if text not in allowed:
328
+ raise SourceContractError("ENUM", path, f"must be one of {sorted(allowed)}")
329
+ return text
330
+
331
+
332
+ def _choices(values: Any, allowed: frozenset[str], path: str, *, maximum: int) -> None:
333
+ if not isinstance(values, tuple):
334
+ raise SourceContractError("TYPE", path, "must be an immutable tuple")
335
+ if not values:
336
+ raise SourceContractError("EMPTY", path, "must not be empty")
337
+ if len(values) > maximum:
338
+ raise SourceContractError("LIMIT", path, f"must contain at most {maximum} values")
339
+ for position, value in enumerate(values):
340
+ _choice(value, allowed, f"{path}[{position}]")
341
+ if len(set(values)) != len(values):
342
+ raise SourceContractError("DUPLICATE", path, "values must be unique")
343
+
344
+
345
+ def _digest(value: Any, path: str) -> str:
346
+ text = _text(value, path, maximum=64)
347
+ if len(text) != 64 or any(char not in "0123456789abcdef" for char in text):
348
+ raise SourceContractError("SHA256", path, "must be a lowercase 64-character SHA-256")
349
+ return text
350
+
351
+
352
+ def _digests(values: Any, path: str, *, maximum: int) -> None:
353
+ if not isinstance(values, tuple):
354
+ raise SourceContractError("TYPE", path, "must be an immutable tuple")
355
+ if len(values) > maximum:
356
+ raise SourceContractError("LIMIT", path, f"must contain at most {maximum} values")
357
+ for position, value in enumerate(values):
358
+ _digest(value, f"{path}[{position}]")
359
+
360
+
361
+ def _integer(value: Any, path: str, *, minimum: int, maximum: int) -> int:
362
+ if type(value) is not int or not minimum <= value <= maximum:
363
+ raise SourceContractError(
364
+ "INTEGER",
365
+ path,
366
+ f"must be an integer in [{minimum}, {maximum}]",
367
+ )
368
+ return value
369
+
370
+
371
+ def _boolean(value: Any, path: str) -> bool:
372
+ if type(value) is not bool:
373
+ raise SourceContractError("BOOLEAN", path, "must be a boolean")
374
+ return value