Transfer comments from template when re-saving project.yml files

This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-01-28 19:49:00 +01:00
1 parent 57423142fe
commit a58a1c2f16
2 files changed
+52 -6

No files matched your search

+15 -4
View File
@@ -29,7 +29,7 @@ from serena.constants import (
SERENA_MANAGED_DIR_NAME,
)
from serena.util.inspection import determine_programming_language_composition
from serena.util.yaml import load_yaml, save_yaml
from serena.util.yaml import YamlCommentNormalisation, load_yaml, save_yaml, transfer_missing_yaml_comments
from solidlsp.ls_config import Language
from ..analytics import RegisteredTokenCountEstimator
@@ -174,6 +174,11 @@ class ProjectConfig(ToolInclusionDefinition, ModeSelectionDefinition, ToStringMi
SERENA_DEFAULT_PROJECT_FILE = "project.yml"
FIELDS_WITHOUT_DEFAULTS = {"project_name", "languages"}
YAML_COMMENT_NORMALISATION = YamlCommentNormalisation.LEADING
"""
the comment normalisation strategy to use when loading/saving project configuration files.
The template file must match this configuration (i.e. it must use leading comments if this is set to LEADING).
"""
def _tostring_includes(self) -> list[str]:
return ["project_name"]
@@ -265,7 +270,9 @@ class ProjectConfig(ToolInclusionDefinition, ModeSelectionDefinition, ToStringMi
return os.path.join(SERENA_MANAGED_DIR_NAME, cls.SERENA_DEFAULT_PROJECT_FILE)
@classmethod
def _load_yaml(cls, yml_path: str) -> tuple[CommentedMap, bool]:
def _load_yaml(
cls, yml_path: str, comment_normalisation: YamlCommentNormalisation = YamlCommentNormalisation.NONE
) -> tuple[CommentedMap, bool]:
"""
Load the project configuration as a CommentedMap, preserving comments and ensuring
completeness of the configuration by applying default values for missing fields
@@ -276,7 +283,7 @@ class ProjectConfig(ToolInclusionDefinition, ModeSelectionDefinition, ToStringMi
full project configuration and `was_complete` indicates whether the loaded configuration
was complete (i.e., did not require any default values to be applied)
"""
data = load_yaml(yml_path)
data = load_yaml(yml_path, comment_normalisation=comment_normalisation)
# apply defaults
was_complete = True
@@ -379,9 +386,13 @@ class ProjectConfig(ToolInclusionDefinition, ModeSelectionDefinition, ToStringMi
log.info("Saving updated project configuration to %s", config_path)
# load original commented map and update it with current values
config_with_comments, _ = self._load_yaml(config_path)
config_with_comments, _ = self._load_yaml(config_path, self.YAML_COMMENT_NORMALISATION)
config_with_comments.update(self._to_yaml_dict())
# transfer missing comments from the template file
template_config, _ = self._load_yaml(PROJECT_TEMPLATE_FILE, self.YAML_COMMENT_NORMALISATION)
transfer_missing_yaml_comments(template_config, config_with_comments, self.YAML_COMMENT_NORMALISATION)
save_yaml(config_path, config_with_comments)
+37 -2
View File
@@ -31,8 +31,8 @@ DOC_COMMENT_INDEX_POST = 0
DOC_COMMENT_INDEX_PRE = 1
# item comment indices: (post key, pre key, post value, pre value)
ITEM_COMMENT_INDEX_BEFORE = 1 # Must be a list at this index
ITEM_COMMENT_INDEX_AFTER = 2 # Not a list at this index
ITEM_COMMENT_INDEX_BEFORE = 1 # (pre-key; must be a list at this index)
ITEM_COMMENT_INDEX_AFTER = 2 # (post-value; typically no list at this index)
def load_yaml(path: str, comment_normalisation: YamlCommentNormalisation = YamlCommentNormalisation.NONE) -> CommentedMap:
@@ -81,3 +81,38 @@ def save_yaml(path: str, data: dict | CommentedMap, preserve_comments: bool = Tr
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding=SERENA_FILE_ENCODING) as f:
yaml.dump(data, f)
def transfer_missing_yaml_comments_by_index(source: CommentedMap, target: CommentedMap, indices: list[int]) -> None:
"""
:param source: the source, from which to transfer missing comments
:param target: the target map, whose comments will be updated
:param indices: list of comment indices to transfer
"""
for key in target.keys():
if key in source:
source_comment = source.ca.items.get(key)
if source_comment is None:
continue
target_comment = target.ca.items.get(key, [None, None, None, None])
target.ca.items[key] = target_comment
for index in indices:
if target_comment[index] is None:
target_comment[index] = source_comment[index]
def transfer_missing_yaml_comments(source: CommentedMap, target: CommentedMap, comment_normalisation: YamlCommentNormalisation) -> None:
"""
Transfers missing comments from source to target YAML.
:param source: the source, from which to transfer missing comments
:param target: the target map, whose comments will be updated.
:param comment_normalisation: the comment normalisation to assume; if NONE, no comments are transferred
"""
match comment_normalisation:
case YamlCommentNormalisation.NONE:
pass
case YamlCommentNormalisation.LEADING:
transfer_missing_yaml_comments_by_index(source, target, [ITEM_COMMENT_INDEX_BEFORE])
case _:
raise ValueError(f"Unhandled comment normalisation: {comment_normalisation}")