mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-14 00:16:57 +00:00
SerenaConfig: Unify handling of file-mapped configuration entries
Fixes 'fixed_tools' not being loaded
This commit is contained in:
1 parent
abef88c482
commit
0c43e60810
1 file changed
+35
-34
@@ -5,7 +5,7 @@ The Serena Model Context Protocol (MCP) Server
|
||||
import dataclasses
|
||||
import os
|
||||
import shutil
|
||||
from collections.abc import Sequence
|
||||
from collections.abc import Iterator, Sequence
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
@@ -448,6 +448,7 @@ class SerenaConfig(ToolInclusionDefinition, ToStringMixin):
|
||||
# *** static members ***
|
||||
|
||||
CONFIG_FILE = "serena_config.yml"
|
||||
CONFIG_FIELDS_WITH_TYPE_CONVERSION = {"projects", "language_backend"}
|
||||
|
||||
# *** methods ***
|
||||
|
||||
@@ -455,6 +456,15 @@ class SerenaConfig(ToolInclusionDefinition, ToStringMixin):
|
||||
def config_file_path(self) -> str | None:
|
||||
return self._config_file_path
|
||||
|
||||
def _iter_config_file_mapped_fields_without_type_conversion(self) -> Iterator[str]:
|
||||
for field_info in dataclasses.fields(self):
|
||||
field_name = field_info.name
|
||||
if field_name.startswith("_"):
|
||||
continue
|
||||
if field_name in self.CONFIG_FIELDS_WITH_TYPE_CONVERSION:
|
||||
continue
|
||||
yield field_name
|
||||
|
||||
def _tostring_includes(self) -> list[str]:
|
||||
return ["config_file_path"]
|
||||
|
||||
@@ -509,14 +519,23 @@ class SerenaConfig(ToolInclusionDefinition, ToStringMixin):
|
||||
|
||||
# create the configuration instance
|
||||
instance = cls(_loaded_commented_yaml=loaded_commented_yaml, _config_file_path=config_file_path)
|
||||
num_migrations = 0
|
||||
|
||||
def get_value_or_default(field_name: str) -> Any:
|
||||
nonlocal num_migrations
|
||||
if field_name not in loaded_commented_yaml:
|
||||
num_migrations += 1
|
||||
return loaded_commented_yaml.get(field_name, get_dataclass_default(SerenaConfig, field_name))
|
||||
|
||||
# transfer regular fields that do not require type conversion
|
||||
for field_name in instance._iter_config_file_mapped_fields_without_type_conversion():
|
||||
assert hasattr(instance, field_name)
|
||||
setattr(instance, field_name, get_value_or_default(field_name))
|
||||
|
||||
# read projects
|
||||
if "projects" not in loaded_commented_yaml:
|
||||
raise SerenaConfigError("`projects` key not found in Serena configuration. Please update your `serena_config.yml` file.")
|
||||
|
||||
# load list of known projects
|
||||
instance.projects = []
|
||||
num_migrations = 0
|
||||
for path in loaded_commented_yaml["projects"]:
|
||||
path = Path(path).resolve()
|
||||
if not path.exists() or (path.is_dir() and not (path / ProjectConfig.rel_path_to_project_yml()).exists()):
|
||||
@@ -534,12 +553,6 @@ class SerenaConfig(ToolInclusionDefinition, ToStringMixin):
|
||||
)
|
||||
instance.projects.append(project)
|
||||
|
||||
def get_value_or_default(field_name: str) -> Any:
|
||||
nonlocal num_migrations
|
||||
if field_name not in loaded_commented_yaml:
|
||||
num_migrations += 1
|
||||
return loaded_commented_yaml.get(field_name, get_dataclass_default(SerenaConfig, field_name))
|
||||
|
||||
# determine language backend
|
||||
language_backend = get_dataclass_default(SerenaConfig, "language_backend")
|
||||
if "language_backend" in loaded_commented_yaml:
|
||||
@@ -554,20 +567,12 @@ class SerenaConfig(ToolInclusionDefinition, ToStringMixin):
|
||||
del loaded_commented_yaml["jetbrains"]
|
||||
instance.language_backend = language_backend
|
||||
|
||||
# set other configuration parameters (primitive types)
|
||||
instance.gui_log_window = get_value_or_default("gui_log_window")
|
||||
instance.web_dashboard_listen_address = get_value_or_default("web_dashboard_listen_address")
|
||||
instance.log_level = loaded_commented_yaml.get("log_level", loaded_commented_yaml.get("gui_log_level", logging.INFO))
|
||||
instance.web_dashboard = get_value_or_default("web_dashboard")
|
||||
instance.web_dashboard_open_on_launch = get_value_or_default("web_dashboard_open_on_launch")
|
||||
instance.jetbrains_plugin_server_address = get_value_or_default("jetbrains_plugin_server_address")
|
||||
instance.tool_timeout = get_value_or_default("tool_timeout")
|
||||
instance.trace_lsp_communication = get_value_or_default("trace_lsp_communication")
|
||||
instance.excluded_tools = get_value_or_default("excluded_tools")
|
||||
instance.included_optional_tools = get_value_or_default("included_optional_tools")
|
||||
instance.token_count_estimator = get_value_or_default("token_count_estimator")
|
||||
instance.default_max_tool_answer_chars = get_value_or_default("default_max_tool_answer_chars")
|
||||
instance.ls_specific_settings = get_value_or_default("ls_specific_settings")
|
||||
# migrate deprecated "gui_log_level" field if necessary
|
||||
if "gui_log_level" in loaded_commented_yaml:
|
||||
num_migrations += 1
|
||||
if "log_level" not in loaded_commented_yaml:
|
||||
instance.log_level = loaded_commented_yaml["gui_log_level"]
|
||||
del loaded_commented_yaml["gui_log_level"]
|
||||
|
||||
# re-save the configuration file if any migrations were performed
|
||||
if num_migrations > 0:
|
||||
@@ -677,23 +682,19 @@ class SerenaConfig(ToolInclusionDefinition, ToStringMixin):
|
||||
|
||||
assert self._loaded_commented_yaml is not None, "Cannot save configuration without loaded YAML"
|
||||
|
||||
loaded_original_yaml = deepcopy(self._loaded_commented_yaml)
|
||||
commented_yaml = deepcopy(self._loaded_commented_yaml)
|
||||
|
||||
# update fields with current values
|
||||
# iterate over all dataclass fields
|
||||
for field_info in dataclasses.fields(self):
|
||||
field_name = field_info.name
|
||||
if field_name in ["projects", "language_backend"] or field_name.startswith("_"):
|
||||
continue
|
||||
loaded_original_yaml[field_name] = getattr(self, field_name)
|
||||
for field_name in self._iter_config_file_mapped_fields_without_type_conversion():
|
||||
commented_yaml[field_name] = getattr(self, field_name)
|
||||
|
||||
# convert project objects into list of paths
|
||||
loaded_original_yaml["projects"] = sorted({str(project.project_root) for project in self.projects})
|
||||
commented_yaml["projects"] = sorted({str(project.project_root) for project in self.projects})
|
||||
|
||||
# convert language backend to string
|
||||
loaded_original_yaml["language_backend"] = self.language_backend.value
|
||||
commented_yaml["language_backend"] = self.language_backend.value
|
||||
|
||||
save_yaml(self.config_file_path, loaded_original_yaml, preserve_comments=True)
|
||||
save_yaml(self.config_file_path, commented_yaml, preserve_comments=True)
|
||||
|
||||
def propagate_settings(self) -> None:
|
||||
"""
|
||||
|
||||
Reference in new issue
Block a user