lean-runtime 2.0.0__tar.gz → 2.0.1__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 (109) hide show
  1. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/CHANGELOG.md +7 -0
  2. {lean_runtime-2.0.0/lean_runtime.egg-info → lean_runtime-2.0.1}/PKG-INFO +1 -1
  3. lean_runtime-2.0.1/lean_runtime/_git.py +13 -0
  4. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/bundles.py +4 -4
  5. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/environments.py +7 -7
  6. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/projects.py +2 -1
  7. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/references.py +4 -3
  8. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/resolver.py +4 -3
  9. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/store.py +10 -8
  10. {lean_runtime-2.0.0 → lean_runtime-2.0.1/lean_runtime.egg-info}/PKG-INFO +1 -1
  11. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/SOURCES.txt +2 -0
  12. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/pyproject.toml +1 -1
  13. lean_runtime-2.0.1/tests/test_git.py +12 -0
  14. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_store.py +28 -0
  15. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/LICENSE +0 -0
  16. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/MANIFEST.in +0 -0
  17. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/README.md +0 -0
  18. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/compatibility/README.md +0 -0
  19. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/compatibility/mathlib-4.32.2.json +0 -0
  20. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/compatibility/mathlib-4.32.2.toml +0 -0
  21. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/architecture.md +0 -0
  22. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/captures.md +0 -0
  23. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/case-study-v1.md +0 -0
  24. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/cli.md +0 -0
  25. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/development.md +0 -0
  26. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/environments.md +0 -0
  27. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/getting-started.md +0 -0
  28. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/index.md +0 -0
  29. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/local-projects.md +0 -0
  30. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/portable-copies.md +0 -0
  31. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/python-api.md +0 -0
  32. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/ready-programs.md +0 -0
  33. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/standalone-files.md +0 -0
  34. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/trust-and-limitations.md +0 -0
  35. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/v1-precision.md +0 -0
  36. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/examples/mathlib.toml +0 -0
  37. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/__init__.py +0 -0
  38. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/__main__.py +0 -0
  39. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/backends.py +0 -0
  40. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/cli.py +0 -0
  41. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/comparison.py +0 -0
  42. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/decisions.py +0 -0
  43. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/diagnostics.py +0 -0
  44. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/errors.py +0 -0
  45. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/events.py +0 -0
  46. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/facade.py +0 -0
  47. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/frontmatter.py +0 -0
  48. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/health.py +0 -0
  49. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/lake.py +0 -0
  50. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/lockfiles.py +0 -0
  51. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/locking.py +0 -0
  52. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/matrix.py +0 -0
  53. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/models.py +0 -0
  54. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/oci.py +0 -0
  55. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/policies.py +0 -0
  56. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/profiling.py +0 -0
  57. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/programs.py +0 -0
  58. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/publisher_verification.py +0 -0
  59. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/py.typed +0 -0
  60. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/run_cli.py +0 -0
  61. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/runtime.py +0 -0
  62. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/schema_resources.py +0 -0
  63. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/serialization.py +0 -0
  64. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/specs.py +0 -0
  65. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/timings.py +0 -0
  66. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/toolchains.py +0 -0
  67. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/verification.py +0 -0
  68. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/wire.py +0 -0
  69. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/dependency_links.txt +0 -0
  70. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/entry_points.txt +0 -0
  71. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/requires.txt +0 -0
  72. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/top_level.txt +0 -0
  73. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/mkdocs.yml +0 -0
  74. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/cleanup-v1.schema.json +0 -0
  75. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/comparison-v1.schema.json +0 -0
  76. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/execution-v1.schema.json +0 -0
  77. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/inspect-v1.schema.json +0 -0
  78. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/matrix-v1.schema.json +0 -0
  79. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/profile-v1.schema.json +0 -0
  80. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/verify-v1.schema.json +0 -0
  81. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/scripts/run_compatibility.py +0 -0
  82. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/scripts/run_v1_case_study.py +0 -0
  83. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/scripts/smoke_wheel.py +0 -0
  84. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/setup.cfg +0 -0
  85. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/conftest.py +0 -0
  86. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_backend.py +0 -0
  87. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_bundles.py +0 -0
  88. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_cli.py +0 -0
  89. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_diagnostics.py +0 -0
  90. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_environment_integration.py +0 -0
  91. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_events_health.py +0 -0
  92. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_facade.py +0 -0
  93. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_frontmatter.py +0 -0
  94. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_interactive.py +0 -0
  95. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_lockfiles.py +0 -0
  96. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_multifile.py +0 -0
  97. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_prebuilt_policy.py +0 -0
  98. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_programs.py +0 -0
  99. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_projects.py +0 -0
  100. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_references.py +0 -0
  101. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_run_cli.py +0 -0
  102. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_runtime.py +0 -0
  103. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_schema_resources.py +0 -0
  104. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_schemas.py +0 -0
  105. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_signatures.py +0 -0
  106. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_specs.py +0 -0
  107. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_toolchains.py +0 -0
  108. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_v1_precision.py +0 -0
  109. {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_verification_inventory.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.1
4
+
5
+ - Enable Git's long-path support for every Runtime-managed source operation so
6
+ Mathlib environments can be prepared and materialized on Windows.
7
+ - Preserve the primary Git diagnostic when cleanup of a failed Windows source
8
+ checkout also encounters locked files.
9
+
3
10
  ## 2.0.0
4
11
 
5
12
  Version 2 gives the public interface the language used by Lean users rather
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-runtime
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: Run Lean 4 proofs from Python or standalone files
5
5
  Author: Alejandro Radisic
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1,13 @@
1
+ """Internal construction of portable Git commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ def git_command(*arguments: str) -> list[str]:
7
+ """Return a Git command that can materialize Lean's deep source trees.
8
+
9
+ ``core.longpaths`` is meaningful on Git for Windows and harmless on other
10
+ platforms. Supplying it per invocation avoids mutable global Git settings.
11
+ """
12
+
13
+ return ["git", "-c", "core.longpaths=true", *arguments]
@@ -19,6 +19,7 @@ from datetime import datetime, timezone
19
19
  from pathlib import Path, PurePosixPath
20
20
  from typing import Any
21
21
 
22
+ from ._git import git_command
22
23
  from .backends import Backend
23
24
  from .errors import EnvironmentError
24
25
  from .events import EventEmitter
@@ -281,7 +282,7 @@ def _verify_package(root: Path, package: LockedPackage) -> None:
281
282
  observed: list[str] = []
282
283
  for revision in ("HEAD", "HEAD^{tree}"):
283
284
  result = subprocess.run(
284
- ["git", "-C", str(root), "rev-parse", revision],
285
+ git_command("-C", str(root), "rev-parse", revision),
285
286
  text=True,
286
287
  capture_output=True,
287
288
  check=False,
@@ -292,15 +293,14 @@ def _verify_package(root: Path, package: LockedPackage) -> None:
292
293
  if observed != [package.revision.lower(), package.tree_hash.lower()]:
293
294
  raise EnvironmentError(f"bundled package source mismatch: {package.name}")
294
295
  status = subprocess.run(
295
- [
296
- "git",
296
+ git_command(
297
297
  "-C",
298
298
  str(root),
299
299
  "status",
300
300
  "--porcelain=v1",
301
301
  "--untracked-files=all",
302
302
  "--ignored=no",
303
- ],
303
+ ),
304
304
  text=True,
305
305
  capture_output=True,
306
306
  check=False,
@@ -20,6 +20,7 @@ from datetime import datetime, timezone
20
20
  from pathlib import Path, PurePosixPath
21
21
  from typing import Any, Generic, TextIO, TypeVar, cast
22
22
 
23
+ from ._git import git_command
23
24
  from .backends import Backend, BackendResult, InteractiveProcess, InteractiveTextReader
24
25
  from .diagnostics import error_diagnostic, parse_diagnostics
25
26
  from .errors import EnvironmentError, MaterializationError, PolicyError
@@ -1138,18 +1139,17 @@ class EnvironmentManager:
1138
1139
  ) as raw:
1139
1140
  checkout = Path(raw)
1140
1141
  commands = [
1141
- ["git", "init", "-q"],
1142
- ["git", "remote", "add", "origin", package.url],
1143
- [
1144
- "git",
1142
+ git_command("init", "-q"),
1143
+ git_command("remote", "add", "origin", package.url),
1144
+ git_command(
1145
1145
  "fetch",
1146
1146
  "--depth",
1147
1147
  "1",
1148
1148
  "--filter=blob:none",
1149
1149
  "origin",
1150
1150
  package.revision,
1151
- ],
1152
- ["git", "checkout", "--detach", "FETCH_HEAD"],
1151
+ ),
1152
+ git_command("checkout", "--detach", "FETCH_HEAD"),
1153
1153
  ]
1154
1154
  for command in commands:
1155
1155
  completed = subprocess.run(
@@ -1168,7 +1168,7 @@ class EnvironmentManager:
1168
1168
  output=completed.stdout + completed.stderr,
1169
1169
  )
1170
1170
  tree = subprocess.run(
1171
- ["git", "rev-parse", "HEAD^{tree}"],
1171
+ git_command("rev-parse", "HEAD^{tree}"),
1172
1172
  cwd=checkout,
1173
1173
  text=True,
1174
1174
  capture_output=True,
@@ -13,6 +13,7 @@ from dataclasses import dataclass
13
13
  from pathlib import Path
14
14
  from typing import TYPE_CHECKING, Any
15
15
 
16
+ from ._git import git_command
16
17
  from .errors import ProjectError
17
18
  from .models import ExecutionResult, ProjectProvenance
18
19
  from .policies import ExecutionPolicy
@@ -31,7 +32,7 @@ def _file_digest(path: Path) -> str | None:
31
32
 
32
33
  def _git(root: Path, *arguments: str) -> str | None:
33
34
  result = subprocess.run(
34
- ["git", "-C", str(root), *arguments],
35
+ git_command("-C", str(root), *arguments),
35
36
  text=True,
36
37
  capture_output=True,
37
38
  check=False,
@@ -17,6 +17,7 @@ if sys.version_info >= (3, 11):
17
17
  else: # pragma: no cover - exercised by the Python 3.10 CI job
18
18
  import tomli as tomllib
19
19
 
20
+ from ._git import git_command
20
21
  from .errors import ResolutionError, SpecificationError
21
22
  from .specs import GitPackage
22
23
  from .toolchains import ToolchainManager, normalize_toolchain
@@ -126,7 +127,7 @@ class DiscoveredPackage:
126
127
  def _run_git(arguments: list[str], *, cwd: Path | None = None, timeout: float = 120) -> str:
127
128
  try:
128
129
  process = subprocess.run(
129
- ["git", *arguments],
130
+ git_command(*arguments),
130
131
  cwd=cwd,
131
132
  text=True,
132
133
  capture_output=True,
@@ -137,7 +138,7 @@ def _run_git(arguments: list[str], *, cwd: Path | None = None, timeout: float =
137
138
  raise ResolutionError(
138
139
  "package-reference Git operation timed out",
139
140
  phase="package-discovery",
140
- command=("git", *arguments),
141
+ command=tuple(git_command(*arguments)),
141
142
  exit_code=124,
142
143
  output=str(exc.stdout or "") + str(exc.stderr or ""),
143
144
  ) from exc
@@ -145,7 +146,7 @@ def _run_git(arguments: list[str], *, cwd: Path | None = None, timeout: float =
145
146
  raise ResolutionError(
146
147
  "could not acquire package-reference metadata",
147
148
  phase="package-discovery",
148
- command=("git", *arguments),
149
+ command=tuple(git_command(*arguments)),
149
150
  exit_code=process.returncode,
150
151
  output=process.stdout + process.stderr,
151
152
  )
@@ -11,6 +11,7 @@ from dataclasses import replace
11
11
  from pathlib import Path
12
12
  from typing import Any
13
13
 
14
+ from ._git import git_command
14
15
  from .backends import Backend
15
16
  from .errors import ResolutionError
16
17
  from .events import EventEmitter
@@ -27,7 +28,7 @@ _COMMIT = re.compile(r"[0-9a-fA-F]{40}")
27
28
 
28
29
  def _git(path: Path, *arguments: str) -> str:
29
30
  process = subprocess.run(
30
- ["git", "-C", str(path), *arguments],
31
+ git_command("-C", str(path), *arguments),
31
32
  text=True,
32
33
  capture_output=True,
33
34
  check=False,
@@ -36,7 +37,7 @@ def _git(path: Path, *arguments: str) -> str:
36
37
  raise ResolutionError(
37
38
  f"could not inspect resolved Git package at {path}",
38
39
  phase="lock-validation",
39
- command=("git", "-C", str(path), *arguments),
40
+ command=tuple(git_command("-C", str(path), *arguments)),
40
41
  exit_code=process.returncode,
41
42
  output=process.stdout + process.stderr,
42
43
  )
@@ -144,7 +145,7 @@ class EnvironmentResolver:
144
145
  pinned.append(package)
145
146
  continue
146
147
  reference = f"refs/tags/{package.rev}"
147
- command = ["git", "ls-remote", package.url, reference, f"{reference}^{{}}"]
148
+ command = git_command("ls-remote", package.url, reference, f"{reference}^{{}}")
148
149
  process = self.backend.execute(
149
150
  command,
150
151
  cwd=self.store.home,
@@ -17,6 +17,7 @@ from dataclasses import dataclass
17
17
  from pathlib import Path
18
18
  from typing import Any
19
19
 
20
+ from ._git import git_command
20
21
  from .errors import EnvironmentError
21
22
  from .lockfiles import EnvironmentLock
22
23
  from .locking import FileLock
@@ -271,7 +272,7 @@ class EnvironmentStore:
271
272
  observed = []
272
273
  for arguments in commands:
273
274
  process = subprocess.run(
274
- ["git", "-C", str(source), *arguments],
275
+ git_command("-C", str(source), *arguments),
275
276
  text=True,
276
277
  capture_output=True,
277
278
  check=False,
@@ -298,8 +299,7 @@ class EnvironmentStore:
298
299
  parent.mkdir(parents=True, exist_ok=True)
299
300
  stage = parent / f".staging-{os.getpid()}-{uuid.uuid4().hex}"
300
301
  try:
301
- command = [
302
- "git",
302
+ command = git_command(
303
303
  "clone",
304
304
  "--quiet",
305
305
  "--no-local",
@@ -308,7 +308,7 @@ class EnvironmentStore:
308
308
  "--no-tags",
309
309
  checkout.resolve().as_uri(),
310
310
  str(stage),
311
- ]
311
+ )
312
312
  process = subprocess.run(
313
313
  command,
314
314
  text=True,
@@ -322,15 +322,14 @@ class EnvironmentStore:
322
322
  + process.stderr
323
323
  )
324
324
  remote = subprocess.run(
325
- [
326
- "git",
325
+ git_command(
327
326
  "-C",
328
327
  str(stage),
329
328
  "remote",
330
329
  "set-url",
331
330
  "origin",
332
331
  str(metadata["url"]),
333
- ],
332
+ ),
334
333
  text=True,
335
334
  capture_output=True,
336
335
  check=False,
@@ -346,7 +345,10 @@ class EnvironmentStore:
346
345
  stage.replace(destination)
347
346
  finally:
348
347
  if stage.exists():
349
- shutil.rmtree(stage)
348
+ # Failed Git checkouts can leave locked pack files on
349
+ # Windows. Cleanup must not mask the actionable Git error.
350
+ with suppress(OSError):
351
+ shutil.rmtree(stage)
350
352
  return destination
351
353
 
352
354
  def environment_path(self, environment_id: str) -> Path:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-runtime
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: Run Lean 4 proofs from Python or standalone files
5
5
  Author: Alejandro Radisic
6
6
  License-Expression: Apache-2.0
@@ -25,6 +25,7 @@ docs/v1-precision.md
25
25
  examples/mathlib.toml
26
26
  lean_runtime/__init__.py
27
27
  lean_runtime/__main__.py
28
+ lean_runtime/_git.py
28
29
  lean_runtime/backends.py
29
30
  lean_runtime/bundles.py
30
31
  lean_runtime/cli.py
@@ -86,6 +87,7 @@ tests/test_environment_integration.py
86
87
  tests/test_events_health.py
87
88
  tests/test_facade.py
88
89
  tests/test_frontmatter.py
90
+ tests/test_git.py
89
91
  tests/test_interactive.py
90
92
  tests/test_lockfiles.py
91
93
  tests/test_multifile.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lean-runtime"
7
- version = "2.0.0"
7
+ version = "2.0.1"
8
8
  description = "Run Lean 4 proofs from Python or standalone files"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,12 @@
1
+ from lean_runtime._git import git_command
2
+
3
+
4
+ def test_git_commands_enable_windows_long_paths_without_global_configuration() -> None:
5
+ assert git_command("clone", "source", "destination") == [
6
+ "git",
7
+ "-c",
8
+ "core.longpaths=true",
9
+ "clone",
10
+ "source",
11
+ "destination",
12
+ ]
@@ -197,3 +197,31 @@ def test_source_snapshot_is_shallow_and_detects_content_changes(tmp_path: Path)
197
197
  revision=revision,
198
198
  tree_hash=tree_hash,
199
199
  )
200
+
201
+
202
+ def test_source_snapshot_preserves_git_error_when_cleanup_also_fails(
203
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
204
+ ) -> None:
205
+ checkout = tmp_path / "checkout"
206
+ checkout.mkdir()
207
+ store = EnvironmentStore(tmp_path / "store")
208
+ source_id = "source_" + "2" * 64
209
+ metadata = {
210
+ "source_id": source_id,
211
+ "url": "https://example.test/package",
212
+ "revision": "a" * 40,
213
+ "tree_hash": "b" * 40,
214
+ }
215
+
216
+ def failed_clone(command: list[str], **_kwargs: object) -> subprocess.CompletedProcess[str]:
217
+ Path(command[-1]).mkdir()
218
+ return subprocess.CompletedProcess(command, 1, "", "Filename too long")
219
+
220
+ def failed_cleanup(_path: Path) -> None:
221
+ raise PermissionError("pack file is locked")
222
+
223
+ monkeypatch.setattr("lean_runtime.store.subprocess.run", failed_clone)
224
+ monkeypatch.setattr("lean_runtime.store.shutil.rmtree", failed_cleanup)
225
+
226
+ with pytest.raises(EnvironmentError, match="Filename too long"):
227
+ store.publish_source(checkout, source_id, metadata)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes