Files
cleveragents-core/robot/indentation_library.py

82 lines
2.8 KiB
Python

"""Robot library providing helpers for inline Python scripts."""
from __future__ import annotations
def fix_python_indentation(script: str) -> str:
"""Reconstruct indentation lost when Robot strips leading spaces.
Args:
script: Source code with indentation removed from the start of each line.
Returns:
Script with indentation restored so Python can execute it.
"""
lines = script.split("\n")
result: list[str] = []
indent_level = 0
block_stack: list[str] = []
for line in lines:
stripped = line.strip()
if not stripped:
result.append("")
continue
is_dedenting = stripped.startswith(
("else:", "elif ", "except:", "except ", "finally:")
)
# Check if we should dedent from a class/function body back to module level
# This happens when we see import, class, or a top-level statement after a class
is_module_level_statement = False
if indent_level > 0 and block_stack:
# If we're inside a class and see an import, we need to dedent
if stripped.startswith(("import ", "from ")) or (
stripped.startswith("class ") and block_stack[-1] == "class"
):
is_module_level_statement = True
if is_dedenting and block_stack:
if stripped.startswith(("except:", "except ", "finally:")):
dedent_levels = 0
for block in reversed(block_stack):
dedent_levels += 1
if block == "try":
break
indent_level = max(0, indent_level - dedent_levels)
else:
indent_level = max(0, indent_level - 1)
elif is_module_level_statement:
# Dedent back to module level
indent_level = 0
block_stack.clear()
current_indent = indent_level
result.append(" " * current_indent + stripped)
if stripped.startswith("try:"):
block_stack.append("try")
indent_level += 1
elif stripped.startswith(("except:", "except ", "finally:")):
while block_stack and block_stack[-1] != "try":
block_stack.pop()
if (
stripped.startswith("finally:")
and block_stack
and block_stack[-1] == "try"
):
block_stack.pop()
indent_level += 1
elif stripped.endswith(":") and not is_dedenting:
if stripped.startswith("class "):
block_stack.append("class")
else:
block_stack.append("other")
indent_level += 1
elif is_dedenting and stripped.endswith(":"):
indent_level += 1
return "\n".join(result)