lean-runtime 4.26.0__tar.gz → 4.27.0__tar.gz

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 (198) hide show
  1. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/CHANGELOG.md +16 -0
  2. {lean_runtime-4.26.0/lean_runtime.egg-info → lean_runtime-4.27.0}/PKG-INFO +1 -1
  3. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/reference/python-api.md +5 -2
  4. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/project_execution.py +24 -4
  5. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/projects.py +107 -11
  6. {lean_runtime-4.26.0 → lean_runtime-4.27.0/lean_runtime.egg-info}/PKG-INFO +1 -1
  7. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/pyproject.toml +1 -1
  8. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_header_cache.py +1 -0
  9. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_projects.py +114 -0
  10. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/LICENSE +0 -0
  11. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/MANIFEST.in +0 -0
  12. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/README.md +0 -0
  13. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/environments.toml +0 -0
  14. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/core-v4.32.2.lock.json +0 -0
  15. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/leancert-v4.30.0.5.lock.json +0 -0
  16. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/leancert-v4.31.0.lock.json +0 -0
  17. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/leancert-v4.32.2.4.lock.json +0 -0
  18. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/leancert-v4.33.0.lock.json +0 -0
  19. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
  20. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
  21. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
  22. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/mathlib-v4.33.0.lock.json +0 -0
  23. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/catalog/locks/mathlib-v4.33.1.lock.json +0 -0
  24. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/compatibility/README.md +0 -0
  25. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/compatibility/lake-artifact-cache-4.33.0.json +0 -0
  26. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/compatibility/mathlib-4.32.2.json +0 -0
  27. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/compatibility/mathlib-4.32.2.toml +0 -0
  28. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/compatibility/mathlib-4.33.0.json +0 -0
  29. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/compatibility/mathlib-4.33.0.toml +0 -0
  30. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/concepts/context-selection.md +0 -0
  31. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/index.md +0 -0
  32. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/reference/commands.md +0 -0
  33. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/reference/python-advanced.md +0 -0
  34. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/reference/storage.md +0 -0
  35. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/trust.md +0 -0
  36. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/tutorial.md +0 -0
  37. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/workflows/check-files.md +0 -0
  38. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/docs/workflows/lake-projects.md +0 -0
  39. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/examples/mathlib.toml +0 -0
  40. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/__init__.py +0 -0
  41. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/__main__.py +0 -0
  42. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/_git.py +0 -0
  43. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/_paths.py +0 -0
  44. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/backends.py +0 -0
  45. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/bundles.py +0 -0
  46. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/capsules.py +0 -0
  47. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/cli.py +0 -0
  48. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/comparison.py +0 -0
  49. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/console.py +0 -0
  50. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/context_resolution.py +0 -0
  51. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/decisions.py +0 -0
  52. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/declaration_index.py +0 -0
  53. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/declaration_index_build.py +0 -0
  54. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/declaration_index_oci.py +0 -0
  55. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/diagnostics.py +0 -0
  56. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/__init__.py +0 -0
  57. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/analyzer.py +0 -0
  58. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/api.py +0 -0
  59. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/candidate.py +0 -0
  60. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/catalog.py +0 -0
  61. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/catalog_build.py +0 -0
  62. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/catalog_cli.py +0 -0
  63. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/catalog_manifest.py +0 -0
  64. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/data/catalog.json +0 -0
  65. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/defaults.py +0 -0
  66. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/engine.py +0 -0
  67. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/errors.py +0 -0
  68. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/history.py +0 -0
  69. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/memo.py +0 -0
  70. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/module_inventory.py +0 -0
  71. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/planner.py +0 -0
  72. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/policy.py +0 -0
  73. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/probe.py +0 -0
  74. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/py.typed +0 -0
  75. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/result.py +0 -0
  76. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/schema_resources.py +0 -0
  77. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
  78. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
  79. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
  80. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/environments.py +0 -0
  81. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/errors.py +0 -0
  82. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/events.py +0 -0
  83. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/facade.py +0 -0
  84. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/frontmatter.py +0 -0
  85. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/header_cache.py +0 -0
  86. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/health.py +0 -0
  87. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/identifier_resolver.py +0 -0
  88. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/import_syntax.py +0 -0
  89. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/lake.py +0 -0
  90. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/lake_cache.py +0 -0
  91. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/lockfiles.py +0 -0
  92. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/locking.py +0 -0
  93. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/matrix.py +0 -0
  94. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/models.py +0 -0
  95. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/oci.py +0 -0
  96. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/oci_protocol.py +0 -0
  97. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/packs.py +0 -0
  98. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/policies.py +0 -0
  99. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/profiling.py +0 -0
  100. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/programs.py +0 -0
  101. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/project_sharing.py +0 -0
  102. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/publisher_verification.py +0 -0
  103. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/py.typed +0 -0
  104. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/references.py +0 -0
  105. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/resolver.py +0 -0
  106. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/run_cli.py +0 -0
  107. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/runtime.py +0 -0
  108. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/schema_resources.py +0 -0
  109. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/serialization.py +0 -0
  110. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/shared_projects.py +0 -0
  111. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/specs.py +0 -0
  112. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/store.py +0 -0
  113. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/timings.py +0 -0
  114. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/toolchain_oci.py +0 -0
  115. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/toolchain_slim.py +0 -0
  116. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/toolchains.py +0 -0
  117. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/verification.py +0 -0
  118. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime/wire.py +0 -0
  119. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime.egg-info/SOURCES.txt +0 -0
  120. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime.egg-info/dependency_links.txt +0 -0
  121. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime.egg-info/entry_points.txt +0 -0
  122. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime.egg-info/requires.txt +0 -0
  123. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/lean_runtime.egg-info/top_level.txt +0 -0
  124. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/mkdocs.yml +0 -0
  125. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/attestation-v1.schema.json +0 -0
  126. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/check-batch-v1.schema.json +0 -0
  127. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/cleanup-v1.schema.json +0 -0
  128. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/comparison-v1.schema.json +0 -0
  129. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/execution-v1.schema.json +0 -0
  130. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/inspect-v1.schema.json +0 -0
  131. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/matrix-v1.schema.json +0 -0
  132. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/plan-v1.schema.json +0 -0
  133. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/profile-v1.schema.json +0 -0
  134. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/publication-v1.schema.json +0 -0
  135. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/status-v1.schema.json +0 -0
  136. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/schemas/verify-v1.schema.json +0 -0
  137. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/announcement_gate.py +0 -0
  138. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/catalog_update.py +0 -0
  139. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/lake_cache_gate.py +0 -0
  140. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/prepare_declaration_index.py +0 -0
  141. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/publish_declaration_index.py +0 -0
  142. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/registry_preflight.py +0 -0
  143. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/run_compatibility.py +0 -0
  144. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/run_v1_case_study.py +0 -0
  145. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/scripts/smoke_wheel.py +0 -0
  146. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/setup.cfg +0 -0
  147. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/conftest.py +0 -0
  148. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/e2e/test_real_discovery.py +0 -0
  149. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_analyzer.py +0 -0
  150. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_catalog.py +0 -0
  151. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_catalog_build.py +0 -0
  152. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_discovery_schema_resources.py +0 -0
  153. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_engine.py +0 -0
  154. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_memo.py +0 -0
  155. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_planner.py +0 -0
  156. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/discovery/test_policy.py +0 -0
  157. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_announcement_gate.py +0 -0
  158. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_backend.py +0 -0
  159. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_bundles.py +0 -0
  160. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_capsules.py +0 -0
  161. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_cli.py +0 -0
  162. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_console.py +0 -0
  163. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_context_resolution.py +0 -0
  164. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_declaration_index.py +0 -0
  165. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_diagnostics.py +0 -0
  166. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_environment_integration.py +0 -0
  167. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_events_health.py +0 -0
  168. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_facade.py +0 -0
  169. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_frontmatter.py +0 -0
  170. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_git.py +0 -0
  171. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_identifier_resolver.py +0 -0
  172. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_interactive.py +0 -0
  173. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_lake_cache.py +0 -0
  174. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_lockfiles.py +0 -0
  175. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_locking.py +0 -0
  176. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_models.py +0 -0
  177. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_multifile.py +0 -0
  178. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_oci_protocol.py +0 -0
  179. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_packs.py +0 -0
  180. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_paths.py +0 -0
  181. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_prebuilt_policy.py +0 -0
  182. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_programs.py +0 -0
  183. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_project_bootstrap.py +0 -0
  184. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_project_publish.py +0 -0
  185. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_references.py +0 -0
  186. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_run_cli.py +0 -0
  187. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_runtime.py +0 -0
  188. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_schema_resources.py +0 -0
  189. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_schemas.py +0 -0
  190. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_signatures.py +0 -0
  191. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_specs.py +0 -0
  192. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_store.py +0 -0
  193. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_toolchain_oci.py +0 -0
  194. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_toolchain_slim.py +0 -0
  195. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_toolchains.py +0 -0
  196. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_v1_precision.py +0 -0
  197. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_verification_inventory.py +0 -0
  198. {lean_runtime-4.26.0 → lean_runtime-4.27.0}/tests/test_verification_probe.py +0 -0
@@ -2,6 +2,22 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 4.27.0 - 2026-08-26
6
+
7
+ - Fingerprint a project by what Lake compiles, not by everything beside the
8
+ lakefile. The workspace digest that keys header snapshots and provenance now
9
+ hashes `lakefile.toml`/`lakefile.lean`, `lean-toolchain`, `lake-manifest.json`,
10
+ and the `.lean` files under each declared target's module roots (the whole
11
+ tree, minus `.git` and `.lake`, when the lakefile is not declarative).
12
+ Previously every byte under the project root was read on each `check` and
13
+ `build`, so a lakefile above a data directory, a virtual environment, or an
14
+ unrelated monorepo made the first step of a check run for minutes with no
15
+ output. Digests change value once because of this.
16
+ - Announce project fingerprinting as `project.fingerprint_started` and
17
+ `project.fingerprint_finished` events (phase `fingerprint`, with
18
+ `elapsed_ms`), so `--verbose` never goes silent between `check.started` and
19
+ the first Lake invocation.
20
+
5
21
  ## 4.26.0 - 2026-08-26
6
22
 
7
23
  - Stop `status` claiming a download is required for core-only files. A lock
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-runtime
3
- Version: 4.26.0
3
+ Version: 4.27.0
4
4
  Summary: Run Lean 4 proofs from Python or standalone files
5
5
  Author: Alejandro Radisic
6
6
  License-Expression: Apache-2.0
@@ -137,8 +137,11 @@ and lock identities, exact package commits and Git tree hashes, toolchain,
137
137
  platform, backend, policy, source digest, and start time.
138
138
 
139
139
  Mutable project results have no environment or lock identity. Their provenance
140
- instead records the canonical root, a workspace digest excluding `.git` and
141
- `.lake`, Lake configuration and manifest digests, and Git revision state.
140
+ instead records the canonical root, a workspace digest of what Lake compiles
141
+ (the lakefile, toolchain pin, manifest, and the `.lean` files under each
142
+ declared target's module roots; the whole tree minus `.git` and `.lake` when the
143
+ lakefile is not declarative), Lake configuration and manifest digests, and Git
144
+ revision state.
142
145
 
143
146
  ## Work with Lake projects
144
147
 
@@ -31,7 +31,7 @@ else: # pragma: no cover - exercised by the Python 3.10 CI job
31
31
  from .errors import ProjectError
32
32
  from .import_syntax import IMPORT_STATEMENT
33
33
  from .locking import FileLock
34
- from .models import ExecutionResult, PhaseTiming
34
+ from .models import ExecutionResult, PhaseTiming, ProjectProvenance
35
35
  from .policies import ExecutionPolicy
36
36
  from .project_sharing import project_sharing_enabled
37
37
  from .projects import ProjectContext
@@ -94,6 +94,26 @@ class ProjectExecutor:
94
94
  def __init__(self, runtime: Runtime) -> None:
95
95
  self.runtime = runtime
96
96
 
97
+ def _provenance(self, context: ProjectContext) -> ProjectProvenance:
98
+ """Fingerprint the project, announcing the work so large trees never look hung."""
99
+ self.runtime.events.emit(
100
+ "project.fingerprint_started",
101
+ f"Fingerprinting project sources: {context.root}",
102
+ phase="fingerprint",
103
+ root=str(context.root),
104
+ )
105
+ started = time.monotonic()
106
+ provenance = context.provenance()
107
+ elapsed = time.monotonic() - started
108
+ self.runtime.events.emit(
109
+ "project.fingerprint_finished",
110
+ f"Fingerprinted project sources in {elapsed:.2f}s",
111
+ phase="fingerprint",
112
+ root=str(context.root),
113
+ elapsed_ms=round(elapsed * 1000),
114
+ )
115
+ return provenance
116
+
97
117
  @staticmethod
98
118
  def _declares_dependencies(context: ProjectContext) -> bool:
99
119
  """Whether the lakefile requires packages Lake would have to fetch."""
@@ -202,7 +222,7 @@ class ProjectExecutor:
202
222
  context.toolchain, "lake", "env", "lean", relative
203
223
  )
204
224
  text = source.read_text(encoding="utf-8")
205
- provenance = context.provenance()
225
+ provenance = self._provenance(context)
206
226
 
207
227
  def execute(selected_command: list[str]) -> ExecutionResult:
208
228
  return self.runtime._raw_result(
@@ -248,7 +268,7 @@ class ProjectExecutor:
248
268
  command = self.runtime.toolchains.command(
249
269
  context.toolchain, "lake", "env", "lean", relative
250
270
  )
251
- provenance = context.provenance()
271
+ provenance = self._provenance(context)
252
272
 
253
273
  def execute(selected_command: list[str]) -> ExecutionResult:
254
274
  return self.runtime._raw_result(
@@ -368,7 +388,7 @@ class ProjectExecutor:
368
388
  )
369
389
  command = self.runtime.toolchains.command(context.toolchain, "lake", *lake_arguments)
370
390
  environment = self.runtime.lake_cache.environment(context)
371
- project_provenance = context.provenance()
391
+ project_provenance = self._provenance(context)
372
392
  package_provenance = context.package_provenance()
373
393
  package_arguments = (
374
394
  (f"--packages={workspace.overrides_file}",) if workspace is not None else ()
@@ -27,7 +27,6 @@ from ._git import git_command
27
27
  from .errors import ProjectError, ProjectNotFoundError
28
28
  from .models import ExecutionResult, PackageProvenance, ProjectProvenance
29
29
  from .policies import ExecutionPolicy
30
- from .store import source_snapshot_digest
31
30
  from .toolchains import normalize_toolchain
32
31
 
33
32
  if TYPE_CHECKING:
@@ -363,6 +362,28 @@ class ProjectContext:
363
362
  selected = Path(path).expanduser().resolve()
364
363
  if selected.suffix != ".lean":
365
364
  return None
365
+ roots = self.source_roots()
366
+ if roots is None:
367
+ return None
368
+ for source_root, root_parts in roots:
369
+ try:
370
+ relative = selected.relative_to(source_root)
371
+ except ValueError:
372
+ continue
373
+ relative_module = relative.with_suffix("").parts
374
+ if relative_module[: len(root_parts)] == root_parts:
375
+ return True
376
+ return False
377
+
378
+ def source_roots(self) -> tuple[tuple[Path, tuple[str, ...]], ...] | None:
379
+ """Return the module prefixes Lake compiles for this project.
380
+
381
+ Each entry pairs a resolved source directory with a module-name prefix
382
+ (``("Foo", "Bar")`` for ``Foo.Bar``). Declarative Lake files can be
383
+ inspected exactly without executing Lake; ``None`` means the project
384
+ format is not safely understood and callers should fall back to the
385
+ whole project tree.
386
+ """
366
387
  if self.lakefile.name != "lakefile.toml":
367
388
  return None
368
389
  try:
@@ -377,6 +398,7 @@ class ProjectContext:
377
398
  targets.extend((key, item) for item in entries)
378
399
  if not targets:
379
400
  return None
401
+ result: list[tuple[Path, tuple[str, ...]]] = []
380
402
  for target_kind, target in targets:
381
403
  src_dir = target.get("srcDir", ".")
382
404
  if not isinstance(src_dir, str):
@@ -389,21 +411,95 @@ class ProjectContext:
389
411
  return None
390
412
  # `roots` selects library build roots; it does not restrict the
391
413
  # namespace of source modules belonging to a lean_lib target.
392
- # Include the library name so sibling modules are still recognized.
414
+ # Include the library name so sibling modules are still recognized,
415
+ # and the leading module of each glob so `Foo.*` style globs count.
393
416
  name = target.get("name")
394
417
  if target_kind == "lean_lib" and isinstance(name, str) and name not in roots:
395
418
  roots = [name, *roots]
419
+ globs = target.get("globs", [])
420
+ if not isinstance(globs, list) or not all(isinstance(glob, str) for glob in globs):
421
+ return None
422
+ for glob in globs:
423
+ prefix = glob.removesuffix(".*").removesuffix(".+")
424
+ if prefix and prefix not in roots:
425
+ roots.append(prefix)
396
426
  source_root = (self.root / src_dir).resolve()
397
- try:
398
- relative = selected.relative_to(source_root)
399
- except ValueError:
400
- continue
401
- relative_module = relative.with_suffix("").parts
402
427
  for root in roots:
403
428
  root_parts = tuple(part for part in root.replace("`", "").split(".") if part)
404
- if relative_module[: len(root_parts)] == root_parts:
405
- return True
406
- return False
429
+ if root_parts and (source_root, root_parts) not in result:
430
+ result.append((source_root, root_parts))
431
+ return tuple(result)
432
+
433
+ def source_digest(self) -> str:
434
+ """Hash only the content Lake compiles: configuration and module sources.
435
+
436
+ Unlike :func:`source_snapshot_digest`, which fingerprints a whole tree,
437
+ this ignores datasets, virtual environments, and anything else that
438
+ happens to live beside the lakefile. The digest still changes whenever
439
+ the lakefile, toolchain pin, manifest, or any owned ``.lean`` file
440
+ changes, which is what the header cache keys on.
441
+ """
442
+ digest = hashlib.sha256()
443
+
444
+ def add_file(path: Path) -> None:
445
+ try:
446
+ mode = path.stat().st_mode & 0o111
447
+ relative = path.relative_to(self.root).as_posix()
448
+ with path.open("rb") as handle:
449
+ digest.update(b"file\0" + relative.encode() + b"\0")
450
+ digest.update(str(mode).encode() + b"\0")
451
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
452
+ digest.update(chunk)
453
+ except OSError:
454
+ return
455
+
456
+ for name in ("lakefile.toml", "lakefile.lean", "lean-toolchain", "lake-manifest.json"):
457
+ candidate = self.root / name
458
+ if candidate.is_file() and not candidate.is_symlink():
459
+ add_file(candidate)
460
+ seen: set[Path] = set()
461
+ module_files, directories_to_walk = self._source_locations()
462
+ for path in module_files:
463
+ if path.is_file() and not path.is_symlink():
464
+ seen.add(path)
465
+ add_file(path)
466
+ for start in directories_to_walk:
467
+ for directory, directories, filenames in os.walk(start, followlinks=False):
468
+ current = Path(directory)
469
+ directories[:] = sorted(
470
+ name
471
+ for name in directories
472
+ if name not in {".git", ".lake"} and not (current / name).is_symlink()
473
+ )
474
+ for name in sorted(filenames):
475
+ if not name.endswith(".lean"):
476
+ continue
477
+ path = current / name
478
+ if path in seen or path.is_symlink():
479
+ continue
480
+ seen.add(path)
481
+ add_file(path)
482
+ return "sha256:" + digest.hexdigest()
483
+
484
+ def _source_locations(self) -> tuple[tuple[Path, ...], tuple[Path, ...]]:
485
+ """Split owned sources into root module files and directories to walk.
486
+
487
+ A module prefix ``Foo.Bar`` owns ``Foo/Bar.lean`` and everything under
488
+ ``Foo/Bar/``. Without declared targets the whole project tree is walked.
489
+ """
490
+ roots = self.source_roots()
491
+ if roots is None:
492
+ return ((), (self.root,))
493
+ files: list[Path] = []
494
+ directories: list[Path] = []
495
+ for source_root, root_parts in roots:
496
+ module = source_root.joinpath(*root_parts)
497
+ module_file = module.with_suffix(".lean")
498
+ if module_file not in files:
499
+ files.append(module_file)
500
+ if module not in directories:
501
+ directories.append(module)
502
+ return tuple(files), tuple(directories)
407
503
 
408
504
  def current_manifest(self) -> Path | None:
409
505
  path = self.root / "lake-manifest.json"
@@ -424,7 +520,7 @@ class ProjectContext:
424
520
  pass
425
521
  return ProjectProvenance(
426
522
  root=str(self.root),
427
- workspace_digest=source_snapshot_digest(self.root),
523
+ workspace_digest=self.source_digest(),
428
524
  lakefile_digest=_file_digest(self.lakefile) or "",
429
525
  manifest_digest=_file_digest(manifest) if manifest is not None else None,
430
526
  git_revision=revision,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-runtime
3
- Version: 4.26.0
3
+ Version: 4.27.0
4
4
  Summary: Run Lean 4 proofs from Python or standalone files
5
5
  Author: Alejandro Radisic
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lean-runtime"
7
- version = "4.26.0"
7
+ version = "4.27.0"
8
8
  description = "Run Lean 4 proofs from Python or standalone files"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -313,6 +313,7 @@ def test_shared_builds_record_workspace_lock_timing(tmp_path: Path) -> None:
313
313
  ),
314
314
  build_lock=build_lock,
315
315
  ),
316
+ events=SimpleNamespace(emit=lambda *_args, **_kwargs: None),
316
317
  _raw_result=lambda *_args, **_kwargs: _execution(True),
317
318
  )
318
319
  executor = ProjectExecutor(runtime) # type: ignore[arg-type]
@@ -1811,3 +1811,117 @@ def test_project_async_cancellation_waits_for_process_cleanup(tmp_path: Path) ->
1811
1811
  await task
1812
1812
 
1813
1813
  asyncio.run(cancel_check())
1814
+
1815
+
1816
+ def test_project_source_digest_ignores_unrelated_files(tmp_path: Path) -> None:
1817
+ from lean_runtime.projects import discover_project
1818
+
1819
+ source = _project(tmp_path / "project")
1820
+ (tmp_path / "project" / "lakefile.toml").write_text(
1821
+ 'name = "sample"\n[[lean_lib]]\nname = "Sample"\n'
1822
+ )
1823
+ context = discover_project(source)
1824
+ assert context.source_roots() == (((tmp_path / "project").resolve(), ("Sample",)),)
1825
+ original = context.provenance().workspace_digest
1826
+ assert original.startswith("sha256:")
1827
+
1828
+ # Data, tooling, and nested unrelated projects beside the lakefile are not sources.
1829
+ (tmp_path / "project" / "README.md").write_text("notes\n")
1830
+ (tmp_path / "project" / "data").mkdir()
1831
+ (tmp_path / "project" / "data" / "blob.bin").write_bytes(b"\0" * 4096)
1832
+ (tmp_path / "project" / "venv" / "lib").mkdir(parents=True)
1833
+ (tmp_path / "project" / "venv" / "lib" / "site.py").write_text("x = 1\n")
1834
+ (tmp_path / "project" / "Other").mkdir()
1835
+ (tmp_path / "project" / "Other" / "Unowned.lean").write_text("example : True := trivial\n")
1836
+ assert context.provenance().workspace_digest == original
1837
+
1838
+ # Owned modules, sibling modules, and configuration do change it.
1839
+ (tmp_path / "project" / "Sample" / "Extra.lean").write_text("example : True := trivial\n")
1840
+ with_module = context.provenance().workspace_digest
1841
+ assert with_module != original
1842
+ (tmp_path / "project" / "Sample.lean").write_text("import Sample.Main\n")
1843
+ with_root_module = context.provenance().workspace_digest
1844
+ assert with_root_module != with_module
1845
+ source.write_text("example : 1 = 1 := rfl\n")
1846
+ with_edit = context.provenance().workspace_digest
1847
+ assert with_edit != with_root_module
1848
+ (tmp_path / "project" / "lean-toolchain").write_text("leanprover/lean4:v4.33.0\n")
1849
+ with_toolchain = context.provenance().workspace_digest
1850
+ assert with_toolchain != with_edit
1851
+ (tmp_path / "project" / "lakefile.toml").write_text('name = "sample"\nversion = "0.2.0"\n')
1852
+ assert context.provenance().workspace_digest != with_toolchain
1853
+
1854
+
1855
+ def test_project_source_digest_walks_whole_tree_without_declared_targets(
1856
+ tmp_path: Path,
1857
+ ) -> None:
1858
+ from lean_runtime.projects import discover_project
1859
+
1860
+ root = tmp_path / "project"
1861
+ root.mkdir()
1862
+ (root / "lean-toolchain").write_text("leanprover/lean4:v4.32.0\n")
1863
+ (root / "lakefile.lean").write_text("import Lake\nopen Lake DSL\npackage sample\n")
1864
+ (root / "Sample").mkdir()
1865
+ (root / "Sample" / "Main.lean").write_text("example : True := trivial\n")
1866
+ context = discover_project(root / "Sample" / "Main.lean")
1867
+ assert context.source_roots() is None
1868
+ original = context.provenance().workspace_digest
1869
+
1870
+ (root / "data").mkdir()
1871
+ (root / "data" / "blob.bin").write_bytes(b"\0" * 4096)
1872
+ (root / ".lake").mkdir()
1873
+ (root / ".lake" / "Ignored.lean").write_text("example : True := trivial\n")
1874
+ assert context.provenance().workspace_digest == original
1875
+
1876
+ (root / "Anywhere").mkdir()
1877
+ (root / "Anywhere" / "Module.lean").write_text("example : True := trivial\n")
1878
+ assert context.provenance().workspace_digest != original
1879
+
1880
+
1881
+ def test_project_source_roots_include_globs_and_exe_roots(tmp_path: Path) -> None:
1882
+ from lean_runtime.projects import discover_project
1883
+
1884
+ root = tmp_path / "project"
1885
+ root.mkdir()
1886
+ (root / "lean-toolchain").write_text("leanprover/lean4:v4.32.0\n")
1887
+ (root / "lakefile.toml").write_text(
1888
+ 'name = "sample"\n'
1889
+ "[[lean_lib]]\n"
1890
+ 'name = "Sample"\n'
1891
+ 'srcDir = "src"\n'
1892
+ 'globs = ["Extra.*"]\n'
1893
+ "[[lean_exe]]\n"
1894
+ 'name = "tool"\n'
1895
+ 'root = "Tool.Main"\n'
1896
+ )
1897
+ (root / "src" / "Sample").mkdir(parents=True)
1898
+ (root / "src" / "Sample" / "Main.lean").write_text("example : True := trivial\n")
1899
+ context = discover_project(root / "src" / "Sample" / "Main.lean")
1900
+ roots = context.source_roots()
1901
+ assert roots is not None
1902
+ assert set(roots) == {
1903
+ ((root / "src").resolve(), ("Sample",)),
1904
+ ((root / "src").resolve(), ("Extra",)),
1905
+ (root.resolve(), ("Tool", "Main")),
1906
+ }
1907
+ assert context.owns_file(root / "src" / "Extra" / "Thing.lean") is True
1908
+ assert context.owns_file(root / "Tool" / "Main" / "Impl.lean") is True
1909
+ assert context.owns_file(root / "src" / "Stray.lean") is False
1910
+
1911
+
1912
+ def test_project_check_announces_fingerprinting(tmp_path: Path) -> None:
1913
+ source = _project(tmp_path / "project")
1914
+ events: list[RuntimeEvent] = []
1915
+ runtime = Runtime(
1916
+ toolchains=ProjectToolchains(tmp_path / "runtime"),
1917
+ libraries=[], # type: ignore[arg-type]
1918
+ on_event=events.append,
1919
+ )
1920
+ result = runtime.project(source).check_file(source)
1921
+ assert result.ok
1922
+ kinds = [event.kind for event in events]
1923
+ started = kinds.index("project.fingerprint_started")
1924
+ finished = kinds.index("project.fingerprint_finished")
1925
+ assert started < finished
1926
+ assert events[started].data["root"] == str(runtime.project(source).root)
1927
+ assert isinstance(events[finished].data["elapsed_ms"], int)
File without changes
File without changes
File without changes
File without changes
File without changes