Minor (docstrings, validation)

This commit is contained in:
Michael Panchenko committed 2025-06-14 00:27:25 +02:00
1 parent f3901dfec2
commit 4514d04c90
2 files changed
+76 -15

No files matched your search

+22 -11
View File
@@ -1760,12 +1760,15 @@ class SyncLanguageServer:
Raise a [textDocument/definition](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition) request to the Language Server
for the symbol at the given line and column in the given file. Wait for the response and return the result.
:param relative_file_path: The relative path of the file that has the symbol for which definition should be looked up
:param line: The line number of the symbol
:param column: The column number of the symbol
:param file_path: The path of the file relative to the repository root.
:param line: The line number (zero-indexed).
:param column: The column number (zero-indexed).
:return List[multilspy_types.Location]: A list of locations where the symbol is defined
:return: A list of Locations defining the symbol.
"""
if not self.is_running():
raise RuntimeError("Language server is not running. Cannot make requests to a stopped language server.")
result = asyncio.run_coroutine_threadsafe(
self.language_server.request_definition(file_path, line, column), self.loop
).result(timeout=self.timeout)
@@ -1773,15 +1776,18 @@ class SyncLanguageServer:
def request_references(self, file_path: str, line: int, column: int) -> List[multilspy_types.Location]:
"""
Raise a [textDocument/references](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references) request to the Language Server
to find references to the symbol at the given line and column in the given file. Wait for the response and return the result.
Raises a [textDocument/references](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references) request to the Language Server
for the symbol at the given line and column in the given file. Wait for the response and return the result.
:param relative_file_path: The relative path of the file that has the symbol for which references should be looked up
:param line: The line number of the symbol
:param column: The column number of the symbol
:param file_path: The path of the file relative to the repository root.
:param line: The line number (zero-indexed).
:param column: The column number (zero-indexed).
:return List[multilspy_types.Location]: A list of locations where the symbol is referenced
:return: A list of Locations referencing the symbol.
"""
if not self.is_running():
raise RuntimeError("Language server is not running. Cannot make requests to a stopped language server.")
try:
result = asyncio.run_coroutine_threadsafe(
self.language_server.request_references(file_path, line, column), self.loop
@@ -1867,6 +1873,9 @@ class SyncLanguageServer:
:return: A list of root symbols representing the top-level packages/modules in the project.
"""
if not self.is_running():
raise RuntimeError("Language server is not running. Cannot make requests to a stopped language server.")
result = asyncio.run_coroutine_threadsafe(
self.language_server.request_full_symbol_tree(within_relative_path, include_body), self.loop
).result(timeout=self.timeout)
@@ -1879,7 +1888,9 @@ class SyncLanguageServer:
Maps relative paths of all contained files to info about top-level symbols in the file
(name, kind, line, column).
"""
assert self.loop
if not self.is_running():
raise RuntimeError("Language server is not running. Cannot make requests to a stopped language server.")
result = asyncio.run_coroutine_threadsafe(
self.language_server.request_dir_overview(relative_dir_path), self.loop
).result(timeout=self.timeout)
+54 -4
View File
@@ -9,7 +9,6 @@ import platform
import re
import shutil
import sys
import threading
import traceback
import webbrowser
from abc import ABC, abstractmethod
@@ -21,7 +20,6 @@ from fnmatch import fnmatch
from functools import cached_property
from logging import Logger
from pathlib import Path
from time import time
from types import TracebackType
from typing import TYPE_CHECKING, Any, Literal, Self, TypeVar, Union, cast
@@ -306,6 +304,59 @@ class SerenaConfigBase(ABC):
else:
raise ValueError(f"Project '{project_name}' not found in Serena configuration; valid project names: {self.project_names}")
def to_dict(self) -> dict:
"""Convert configuration to dictionary for serialization."""
return {
"projects": [
{
"project_root": project.project_root,
"project_config": {
"project_name": project.project_config.project_name,
"language": project.project_config.language,
"ignored_paths": project.project_config.ignored_paths,
"ignore_all_files_in_gitignore": project.project_config.ignore_all_files_in_gitignore,
},
}
for project in self.projects
],
"gui_log_window_enabled": self.gui_log_window_enabled,
"log_level": self.log_level,
"trace_lsp_communication": self.trace_lsp_communication,
"web_dashboard": self.web_dashboard,
"tool_timeout": self.tool_timeout,
}
@classmethod
def from_dict(cls, data: dict) -> "SerenaConfigBase":
"""Create configuration from dictionary."""
projects = []
for project_data in data.get("projects", []):
project_config = ProjectConfig(
project_name=project_data["project_config"]["project_name"],
language=project_data["project_config"]["language"],
ignored_paths=project_data["project_config"]["ignored_paths"],
ignore_all_files_in_gitignore=project_data["project_config"]["ignore_all_files_in_gitignore"],
)
project = Project(project_root=project_data["project_root"], project_config=project_config)
projects.append(project)
# Create a basic config class that can be instantiated
from dataclasses import dataclass
@dataclass(kw_only=True)
class DeserializedConfig(SerenaConfigBase):
def _add_new_project(self, project: Project) -> None:
self.projects.append(project)
return DeserializedConfig(
projects=projects,
gui_log_window_enabled=data.get("gui_log_window_enabled", False),
log_level=data.get("log_level", logging.INFO),
trace_lsp_communication=data.get("trace_lsp_communication", False),
web_dashboard=data.get("web_dashboard", True),
tool_timeout=data.get("tool_timeout", DEFAULT_TOOL_TIMEOUT),
)
@dataclass(kw_only=True)
class SerenaConfig(SerenaConfigBase):
@@ -851,14 +902,13 @@ class SerenaAgent:
"""
Starts/resets the language server for the current project
"""
tool_timeout = self.serena_config.tool_timeout
if tool_timeout is None or tool_timeout < 0:
ls_timeout = None
else:
if tool_timeout < 10:
raise ValueError(f"Tool timeout must be at least 10 seconds, but is {tool_timeout} seconds")
ls_timeout = tool_timeout - 5 # the LS timeout is for a single call, it should be smaller than the tool timeout
ls_timeout = tool_timeout - 5 # the LS timeout is for a single call, it should be smaller than the tool timeout
# stop the language server if it is running
if self.is_language_server_running():