init
This commit is contained in:
@@ -337,6 +337,69 @@ def _append_missing_methods(
|
||||
return runtime_block.rstrip() + "\n\n" + "".join(additions).rstrip() + "\n"
|
||||
|
||||
|
||||
def _sync_generated_method_docstrings(
|
||||
runtime_block: str, generated_block: str, method_names: set[str]
|
||||
) -> str:
|
||||
"""Use generated method docstrings while preserving runtime method bodies."""
|
||||
runtime_class = ast.parse(runtime_block).body[0]
|
||||
generated_class = ast.parse(generated_block).body[0]
|
||||
if not isinstance(runtime_class, ast.ClassDef) or not isinstance(generated_class, ast.ClassDef):
|
||||
return runtime_block
|
||||
|
||||
runtime_methods = {
|
||||
statement.name: statement
|
||||
for statement in runtime_class.body
|
||||
if isinstance(statement, (ast.FunctionDef, ast.AsyncFunctionDef))
|
||||
}
|
||||
generated_methods = {
|
||||
statement.name: statement
|
||||
for statement in generated_class.body
|
||||
if isinstance(statement, (ast.FunctionDef, ast.AsyncFunctionDef))
|
||||
}
|
||||
runtime_lines = runtime_block.splitlines(keepends=True)
|
||||
generated_lines = generated_block.splitlines(keepends=True)
|
||||
replacements: list[tuple[int, int, list[str]]] = []
|
||||
|
||||
def docstring_statement(method: ast.FunctionDef | ast.AsyncFunctionDef) -> ast.Expr | None:
|
||||
if not method.body:
|
||||
return None
|
||||
statement = method.body[0]
|
||||
if (
|
||||
isinstance(statement, ast.Expr)
|
||||
and isinstance(statement.value, ast.Constant)
|
||||
and isinstance(statement.value.value, str)
|
||||
):
|
||||
return statement
|
||||
return None
|
||||
|
||||
for name in method_names:
|
||||
runtime_method = runtime_methods.get(name)
|
||||
generated_method = generated_methods.get(name)
|
||||
if runtime_method is None or generated_method is None:
|
||||
continue
|
||||
generated_doc = docstring_statement(generated_method)
|
||||
if generated_doc is None:
|
||||
continue
|
||||
generated_source = generated_lines[
|
||||
generated_doc.lineno - 1:generated_doc.end_lineno
|
||||
]
|
||||
runtime_doc = docstring_statement(runtime_method)
|
||||
if runtime_doc is not None:
|
||||
replacements.append(
|
||||
(runtime_doc.lineno - 1, runtime_doc.end_lineno, generated_source)
|
||||
)
|
||||
else:
|
||||
# A method without a docstring starts directly with executable
|
||||
# code. Insert the generated VP description before that code.
|
||||
replacements.append(
|
||||
(runtime_method.body[0].lineno - 1, runtime_method.body[0].lineno - 1, generated_source)
|
||||
)
|
||||
|
||||
for start, end, replacement in sorted(replacements, reverse=True):
|
||||
runtime_lines[start:end] = replacement
|
||||
return "".join(runtime_lines)
|
||||
|
||||
|
||||
def _ensure_get_data_import(source: str) -> str:
|
||||
if not re.search(r"(?m)^\s*data\d+\s*=\s*get_data\(", source):
|
||||
return source
|
||||
@@ -433,6 +496,9 @@ def merge(generated_path: Path, character_path: Path) -> tuple[str, dict[str, in
|
||||
block = _set_generated_field(block, "position", generated_skill.position)
|
||||
block = _set_generated_field(block, "cellPos", generated_skill.cell_pos)
|
||||
block = _append_missing_methods(block, generated_block, {"vp_1", "vp_2"})
|
||||
block = _sync_generated_method_docstrings(
|
||||
block, generated_block, {"vp_1", "vp_2"}
|
||||
)
|
||||
chunks.append(block.rstrip() + "\n")
|
||||
matched += 1
|
||||
cursor = generated_skill.end
|
||||
|
||||
Reference in New Issue
Block a user