Module: lean_interact.sessioncache
This module implements the session cache classes responsible for storing and retrieving Lean proof states and environments.
Session cache is used internally by the AutoLeanServer
class.
It enables efficient resumption of proofs and environments after server restarts, timeouts, and automated recover from crashes.
While by default AutoLeanServer
instantiates a fresh PickleSessionCache
instance, you can also use a custom one.
It can be useful to share a session cache between multiple AutoLeanServer
instances, or to use a custom session cache implementation.
Examples:
from lean_interact.sessioncache import PickleSessionCache
from lean_interact.server import AutoLeanServer
# Create a session cache
cache = PickleSessionCache(working_dir="./cache")
# Create a Lean server with the cache
server = AutoLeanServer(config=..., session_cache=cache)
PickleSessionCache
PickleSessionCache(working_dir: str | PathLike)
Bases: BaseSessionCache
A session cache based on the local file storage and the REPL pickle feature.
Source code in src/lean_interact/sessioncache.py
| def __init__(self, working_dir: str | PathLike):
self._cache: dict[int, PickleSessionState] = {}
self._state_counter = 0
self._working_dir = Path(working_dir)
|
add
add(
lean_server: LeanServer,
request: BaseREPLQuery,
response: BaseREPLResponse,
verbose: bool = False,
) -> int
Source code in src/lean_interact/sessioncache.py
| def add(
self, lean_server: "LeanServer", request: BaseREPLQuery, response: BaseREPLResponse, verbose: bool = False
) -> int:
self._state_counter -= 1
process_id = os.getpid() # use process id to avoid conflicts in multiprocessing
hash_key = f"request_{type(request).__name__}_{id(request)}"
pickle_file = (
self._working_dir / "session_cache" / f"{hashlib.sha256(hash_key.encode()).hexdigest()}_{process_id}.olean"
)
pickle_file.parent.mkdir(parents=True, exist_ok=True)
if isinstance(response, ProofStepResponse):
repl_id = response.proof_state
is_proof_state = True
request = PickleProofState(proof_state=response.proof_state, pickle_to=str(pickle_file))
elif isinstance(response, CommandResponse):
repl_id = response.env
is_proof_state = False
request = PickleEnvironment(env=response.env, pickle_to=str(pickle_file))
else:
raise NotImplementedError(
f"Cannot pickle the session state for unsupported request of type {type(request).__name__}."
)
# Use file lock when accessing the pickle file to prevent cache invalidation
# from concurrent access
with FileLock(f"{pickle_file}.lock", timeout=60):
response_pickle = lean_server.run(request, verbose=verbose)
if isinstance(response_pickle, LeanError):
raise ValueError(
f"Could not store the result in the session cache. The Lean server returned an error: {response_pickle.message}"
)
self._cache[self._state_counter] = PickleSessionState(
session_id=self._state_counter,
repl_id=repl_id,
pickle_file=str(pickle_file),
is_proof_state=is_proof_state,
)
return self._state_counter
|
remove
remove(
session_state_id: int, verbose: bool = False
) -> None
Source code in src/lean_interact/sessioncache.py
| def remove(self, session_state_id: int, verbose: bool = False) -> None:
if (state_cache := self._cache.pop(session_state_id, None)) is not None:
pickle_file = state_cache.pickle_file
with FileLock(f"{pickle_file}.lock", timeout=60):
if os.path.exists(pickle_file):
os.remove(pickle_file)
|
reload
reload(
lean_server: LeanServer,
timeout_per_state: int | float | None,
verbose: bool = False,
) -> None
Source code in src/lean_interact/sessioncache.py
| def reload(self, lean_server: "LeanServer", timeout_per_state: int | float | None, verbose: bool = False) -> None:
for state_data in self:
# Use file lock when accessing the pickle file to prevent cache invalidation
# from multiple concurrent processes
with FileLock(
f"{state_data.pickle_file}.lock", timeout=float(timeout_per_state) if timeout_per_state else -1
):
if state_data.is_proof_state:
cmd = UnpickleProofState(unpickle_proof_state_from=state_data.pickle_file, env=state_data.repl_id)
else:
cmd = UnpickleEnvironment(unpickle_env_from=state_data.pickle_file)
result = lean_server.run(
cmd,
verbose=verbose,
timeout=timeout_per_state,
)
if isinstance(result, LeanError):
raise ValueError(
f"Could not reload the session cache. The Lean server returned an error: {result.message}"
)
elif isinstance(result, CommandResponse):
state_data.repl_id = result.env
elif isinstance(result, ProofStepResponse):
state_data.repl_id = result.proof_state
else:
raise ValueError(
f"Could not reload the session cache. The Lean server returned an unexpected response: {result}"
)
|
is_empty
Source code in src/lean_interact/sessioncache.py
| def is_empty(self) -> bool:
return len(self._cache) == 0
|
clear
clear(verbose: bool = False) -> None
Source code in src/lean_interact/sessioncache.py
| def clear(self, verbose: bool = False) -> None:
for state_data in list(self):
self.remove(session_state_id=state_data.session_id, verbose=verbose)
assert not self._cache, f"Cache is not empty after clearing: {self._cache}"
|
keys
Source code in src/lean_interact/sessioncache.py
| def keys(self) -> list[int]:
return list(self._cache.keys())
|
SessionState
dataclass
SessionState(
session_id: int, repl_id: int, is_proof_state: bool
)
session_id
instance-attribute
repl_id
instance-attribute
is_proof_state
instance-attribute
PickleSessionState
dataclass
PickleSessionState(
session_id: int,
repl_id: int,
is_proof_state: bool,
pickle_file: str,
)
Bases: SessionState
pickle_file
instance-attribute
session_id
instance-attribute
repl_id
instance-attribute
is_proof_state
instance-attribute