lean-interact 0.8.2__tar.gz → 0.8.3__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 (47) hide show
  1. {lean_interact-0.8.2 → lean_interact-0.8.3}/.gitignore +4 -0
  2. {lean_interact-0.8.2 → lean_interact-0.8.3}/PKG-INFO +2 -2
  3. {lean_interact-0.8.2 → lean_interact-0.8.3}/README.md +1 -1
  4. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/index.md +1 -1
  5. {lean_interact-0.8.2 → lean_interact-0.8.3}/pyproject.toml +1 -1
  6. {lean_interact-0.8.2 → lean_interact-0.8.3}/src/lean_interact/config.py +18 -7
  7. {lean_interact-0.8.2 → lean_interact-0.8.3}/src/lean_interact/server.py +25 -9
  8. {lean_interact-0.8.2 → lean_interact-0.8.3}/src/lean_interact/utils.py +16 -5
  9. {lean_interact-0.8.2 → lean_interact-0.8.3}/tests/test_server.py +4 -0
  10. lean_interact-0.8.2/uv.lock +0 -1825
  11. {lean_interact-0.8.2 → lean_interact-0.8.3}/.devcontainer/devcontainer.json +0 -0
  12. {lean_interact-0.8.2 → lean_interact-0.8.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  13. {lean_interact-0.8.2 → lean_interact-0.8.3}/.github/copilot-instructions.md +0 -0
  14. {lean_interact-0.8.2 → lean_interact-0.8.3}/.github/workflows/ci.yml +0 -0
  15. {lean_interact-0.8.2 → lean_interact-0.8.3}/.github/workflows/docs.yml +0 -0
  16. {lean_interact-0.8.2 → lean_interact-0.8.3}/.github/workflows/publish-to-pypi.yml +0 -0
  17. {lean_interact-0.8.2 → lean_interact-0.8.3}/LICENSE +0 -0
  18. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/.nojekyll +0 -0
  19. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/api/config.md +0 -0
  20. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/api/interface.md +0 -0
  21. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/api/project.md +0 -0
  22. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/api/server.md +0 -0
  23. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/api/sessioncache.md +0 -0
  24. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/api/utils.md +0 -0
  25. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/contributing.md +0 -0
  26. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/generate_changelog.py +0 -0
  27. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/theme/main.html +0 -0
  28. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/basic-usage.md +0 -0
  29. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/custom-lean-configuration.md +0 -0
  30. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/examples.md +0 -0
  31. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/getting-started.md +0 -0
  32. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/installation.md +0 -0
  33. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/multi-processing.md +0 -0
  34. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/tactic-mode.md +0 -0
  35. {lean_interact-0.8.2 → lean_interact-0.8.3}/docs/user-guide/troubleshooting.md +0 -0
  36. {lean_interact-0.8.2 → lean_interact-0.8.3}/examples/beq_plus.py +0 -0
  37. {lean_interact-0.8.2 → lean_interact-0.8.3}/examples/multi_processing.py +0 -0
  38. {lean_interact-0.8.2 → lean_interact-0.8.3}/examples/proof_generation_and_autoformalization.py +0 -0
  39. {lean_interact-0.8.2 → lean_interact-0.8.3}/examples/type_check.py +0 -0
  40. {lean_interact-0.8.2 → lean_interact-0.8.3}/mkdocs.yml +0 -0
  41. {lean_interact-0.8.2 → lean_interact-0.8.3}/src/lean_interact/__init__.py +0 -0
  42. {lean_interact-0.8.2 → lean_interact-0.8.3}/src/lean_interact/interface.py +0 -0
  43. {lean_interact-0.8.2 → lean_interact-0.8.3}/src/lean_interact/project.py +0 -0
  44. {lean_interact-0.8.2 → lean_interact-0.8.3}/src/lean_interact/sessioncache.py +0 -0
  45. {lean_interact-0.8.2 → lean_interact-0.8.3}/tests/test_concurrency.py +0 -0
  46. {lean_interact-0.8.2 → lean_interact-0.8.3}/tests/test_git_functionality.py +0 -0
  47. {lean_interact-0.8.2 → lean_interact-0.8.3}/tests/test_utils.py +0 -0
@@ -12,6 +12,10 @@ __pycache__
12
12
 
13
13
  sandbox*
14
14
  .vscode
15
+ *.lock
15
16
 
16
17
  # Doc build
17
18
  site
19
+
20
+ # MacOS
21
+ .DS_Store
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-interact
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Summary: LeanInteract is a Python package that allows you to interact with the Lean theorem prover.
5
5
  Author-email: Auguste Poiroux <auguste.poiroux@epfl.ch>
6
6
  License: MIT License
@@ -53,7 +53,7 @@ Check the [documentation](https://augustepoiroux.github.io/LeanInteract/) for de
53
53
  - **🔗 Interactivity**: Execute Lean code and files directly from Python.
54
54
  - **🚀 Ease of Use**: LeanInteract abstracts the complexities of Lean setup and interaction.
55
55
  - **💻 Cross-platform**: Works on Windows, macOS, and Linux operating systems.
56
- - **🔧 Compatibility**: Supports all Lean versions between `v4.7.0-rc1` and `v4.23.0-rc2`.
56
+ - **🔧 Compatibility**: Supports all Lean versions between `v4.7.0-rc1` and `v4.24.0-rc1`.
57
57
  - We backport the latest features of Lean REPL to older versions of Lean (see [fork](https://github.com/augustepoiroux/repl)).
58
58
  - **📦 Temporary Projects**: Easily instantiate temporary Lean environments.
59
59
  - Useful for experimenting with benchmarks depending on [Mathlib](https://github.com/leanprover-community/mathlib4) like [ProofNet#](https://huggingface.co/datasets/PAug/ProofNetSharp) and [MiniF2F](https://github.com/yangky11/miniF2F-lean4).
@@ -15,7 +15,7 @@ Check the [documentation](https://augustepoiroux.github.io/LeanInteract/) for de
15
15
  - **🔗 Interactivity**: Execute Lean code and files directly from Python.
16
16
  - **🚀 Ease of Use**: LeanInteract abstracts the complexities of Lean setup and interaction.
17
17
  - **💻 Cross-platform**: Works on Windows, macOS, and Linux operating systems.
18
- - **🔧 Compatibility**: Supports all Lean versions between `v4.7.0-rc1` and `v4.23.0-rc2`.
18
+ - **🔧 Compatibility**: Supports all Lean versions between `v4.7.0-rc1` and `v4.24.0-rc1`.
19
19
  - We backport the latest features of Lean REPL to older versions of Lean (see [fork](https://github.com/augustepoiroux/repl)).
20
20
  - **📦 Temporary Projects**: Easily instantiate temporary Lean environments.
21
21
  - Useful for experimenting with benchmarks depending on [Mathlib](https://github.com/leanprover-community/mathlib4) like [ProofNet#](https://huggingface.co/datasets/PAug/ProofNetSharp) and [MiniF2F](https://github.com/yangky11/miniF2F-lean4).
@@ -17,7 +17,7 @@ hide:
17
17
  - **🔗 Interactivity**: Execute Lean code and files directly from Python
18
18
  - **🚀 Ease of Use**: LeanInteract abstracts the complexities of Lean setup and interaction
19
19
  - **💻 Cross-platform**: Works on Windows, macOS, and Linux operating systems
20
- - **🔧 Compatibility**: Supports all Lean versions between `v4.7.0-rc1` and `v4.23.0-rc2`
20
+ - **🔧 Compatibility**: Supports all Lean versions between `v4.7.0-rc1` and `v4.24.0-rc1`
21
21
  - We backport the latest features of Lean REPL to older versions of Lean (see [fork](https://github.com/augustepoiroux/repl)).
22
22
  - **📦 Temporary Projects**: Easily instantiate temporary Lean environments
23
23
  - Useful for experimenting with benchmarks depending on [Mathlib](https://github.com/leanprover-community/mathlib4) like [ProofNet#](https://huggingface.co/datasets/PAug/ProofNetSharp) and [MiniF2F](https://github.com/yangky11/miniF2F-lean4)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lean-interact"
3
- version = "0.8.2"
3
+ version = "0.8.3"
4
4
  description = "LeanInteract is a Python package that allows you to interact with the Lean theorem prover."
5
5
  keywords = ["Lean", "theorem proving", "autoformalization", "REPL"]
6
6
  license = { file = "LICENSE" }
@@ -383,16 +383,27 @@ class LeanREPLConfig:
383
383
  check_lake(self.lake_path)
384
384
 
385
385
  try:
386
- subprocess.run(
386
+ # Capture build output so failures can be diagnosed
387
+ res = subprocess.run(
387
388
  [str(self.lake_path), "build"],
388
389
  cwd=self._cache_repl_dir,
389
- check=True,
390
- stdout=None if self.verbose else subprocess.DEVNULL,
391
- stderr=None if self.verbose else subprocess.DEVNULL,
390
+ stdout=None if self.verbose else subprocess.PIPE,
391
+ stderr=None if self.verbose else subprocess.PIPE,
392
+ text=True,
393
+ )
394
+ except FileNotFoundError as e:
395
+ raise RuntimeError(
396
+ f"Lean 4 build system executable not found at `{self.lake_path}`. "
397
+ "You can try to run `install-lean` or follow: https://leanprover-community.github.io/get_started.html"
398
+ ) from e
399
+
400
+ if res.returncode != 0:
401
+ out = res.stdout or ""
402
+ err = res.stderr or ""
403
+ raise RuntimeError(
404
+ f"Failed to build the REPL at {self._cache_repl_dir}"
405
+ f"\n{'-' * 50}\nstdout:\n{out}\n{'-' * 50}\nstderr:\n{err}\n{'-' * 50}"
392
406
  )
393
- except subprocess.CalledProcessError as e:
394
- logger.error("Failed to build the REPL at %s: %s", self._cache_repl_dir, e)
395
- raise
396
407
 
397
408
  def _get_available_lean_versions(self) -> list[tuple[str, str | None]]:
398
409
  """
@@ -88,6 +88,19 @@ class LeanServer:
88
88
  if platform.system() != "Linux"
89
89
  else lambda: _limit_memory(self.config.memory_hard_limit_mb),
90
90
  )
91
+ if not self.is_alive():
92
+ stdout, stderr = self.get_stdout_stderr()
93
+ raise ChildProcessError(f"The Lean server could not be started:\nstdout: {stdout}\nstderr: {stderr}")
94
+
95
+ def get_stdout_stderr(self) -> tuple[str, str]:
96
+ """Get the stdout and stderr output from the Lean REPL.
97
+
98
+ Returns:
99
+ A tuple containing the stdout and stderr output.
100
+ """
101
+ stdout = self._proc.stdout.read() if self._proc and self._proc.stdout else ""
102
+ stderr = self._proc.stderr.read() if self._proc and self._proc.stderr else ""
103
+ return stdout, stderr
91
104
 
92
105
  def _sendline(self, line: str) -> None:
93
106
  assert self._proc is not None and self._proc.stdin is not None
@@ -199,11 +212,9 @@ class LeanServer:
199
212
  if t.is_alive():
200
213
  self.kill()
201
214
  raise TimeoutError(f"The Lean server did not respond in time ({timeout=}) and is now killed.")
202
- if output:
215
+ if output.strip():
203
216
  return output
204
- if output.strip() == "":
205
- raise BrokenPipeError("The Lean server returned no output.")
206
- raise BrokenPipeError(f"The Lean server closed unexpectedly with the output:\n`{output}`")
217
+ raise BrokenPipeError("The Lean server returned no output.")
207
218
 
208
219
  def _parse_repl_output(self, raw_output: str, verbose: bool) -> dict:
209
220
  """Parse JSON response.
@@ -258,7 +269,10 @@ class LeanServer:
258
269
  JsonDecodeError: If the Lean server output is not valid JSON.
259
270
  """
260
271
  if not self.is_alive():
261
- raise ChildProcessError("The Lean server is not running.")
272
+ stdout, stderr = self.get_stdout_stderr()
273
+ raise ChildProcessError(
274
+ f"The Lean server is not running.\n{'-' * 50}\nstdout:\n{stdout}\n{'-' * 50}\nstderr:\n{stderr}\n{'-' * 50}"
275
+ )
262
276
 
263
277
  json_query = json.dumps(request, ensure_ascii=False)
264
278
  try:
@@ -267,13 +281,15 @@ class LeanServer:
267
281
  self.kill()
268
282
  raise TimeoutError(f"The Lean server did not respond in time ({timeout=}) and is now killed.") from e
269
283
  except BrokenPipeError as e:
284
+ stdout, stderr = self.get_stdout_stderr()
270
285
  self.kill()
271
286
  raise ConnectionAbortedError(
272
- "The Lean server closed unexpectedly. Possible reasons (not exhaustive):\n"
273
- "- An uncaught exception in the Lean REPL\n"
287
+ f"The Lean server closed unexpectedly."
288
+ f"\n{'-' * 50}\nstdout:\n{stdout}\n{'-' * 50}\nstderr:\n{stderr}\n{'-' * 50}"
289
+ f"If stdout and stderr are empty or obscure, here is a list of possible reasons (not exhaustive):\n"
274
290
  "- Not enough memory and/or compute available\n"
275
- "- The cached Lean REPL is corrupted. In this case, clear the cache"
276
- " using the `clear-lean-cache` command."
291
+ "- The cached Lean REPL is corrupted. In this case, clear the cache using the `clear-lean-cache` command.\n"
292
+ "- An uncaught exception in the Lean REPL"
277
293
  ) from e
278
294
 
279
295
  return self._parse_repl_output(raw_output, verbose)
@@ -22,7 +22,7 @@ logger.addHandler(handler)
22
22
  ROOT_DIR = Path(__file__).resolve().parent
23
23
  DEFAULT_CACHE_DIR = ROOT_DIR / "cache"
24
24
  DEFAULT_REPL_GIT_URL = "https://github.com/augustepoiroux/repl"
25
- DEFAULT_REPL_VERSION = "v1.0.15"
25
+ DEFAULT_REPL_VERSION = "v1.0.16"
26
26
 
27
27
  os.makedirs(DEFAULT_CACHE_DIR, exist_ok=True)
28
28
 
@@ -92,11 +92,22 @@ def check_lake(lake_path: str | PathLike) -> None:
92
92
  lake_path = Path(lake_path)
93
93
 
94
94
  try:
95
- subprocess.run([str(lake_path), "--version"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
96
- except subprocess.CalledProcessError:
95
+ result = subprocess.run(
96
+ [str(lake_path), "--version"],
97
+ stdout=subprocess.PIPE,
98
+ stderr=subprocess.PIPE,
99
+ text=True,
100
+ )
101
+ except FileNotFoundError as e:
102
+ raise RuntimeError(
103
+ f"Lean 4 build system executable not found at `{lake_path}`: {e}. "
104
+ "You can try to run `install-lean` or follow: https://leanprover-community.github.io/get_started.html"
105
+ ) from e
106
+
107
+ if result.returncode != 0:
97
108
  raise RuntimeError(
98
- f"Lean 4 build system (`{lake_path}`) is not installed or not found in PATH. "
99
- "You can try to run `install-lean` or find installation instructions here: https://leanprover-community.github.io/get_started.html"
109
+ f"Lean 4 build system (`{lake_path}`) failed with exit code {result.returncode}.\n"
110
+ f"stdout:\n{result.stdout}\n\nstderr:\n{result.stderr}"
100
111
  )
101
112
 
102
113
 
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import platform
3
3
  import shutil
4
+ import subprocess
4
5
  import tempfile
5
6
  import time
6
7
  import unittest
@@ -120,6 +121,9 @@ class TestLeanServer(unittest.TestCase):
120
121
  self.assertIsInstance(response, CommandResponse)
121
122
  # Re-use the existing build
122
123
  with unittest.mock.patch("subprocess.run") as run_mock:
124
+ run_mock.return_value = subprocess.CompletedProcess(
125
+ args=["lake", "--version"], returncode=0, stdout="", stderr=""
126
+ )
123
127
  new_config = LeanREPLConfig(
124
128
  project=LocalProject(directory=base_config.working_dir, auto_build=False), verbose=True
125
129
  )