"""AST-level concurrency safety injection for Python.""" import ast from typing import Optional from app.dataset.rules.base import Mutation, MutationRule class ConcurrencyRule(MutationRule): """Remove a threading.Lock.acquire/release pair to introduce race condition. Uses `ast` to find a with-statement using a lock and replaces it with the bare body, removing synchronization. """ name = "concurrency" language = "python" defect_type = "concurrency_issue" def detect_and_mutate(self, source: str, filename: str = "") -> Optional[Mutation]: try: tree = ast.parse(source) except SyntaxError: return None for node in ast.walk(tree): if not isinstance(node, ast.With): continue first_item = node.items[0] ctx = first_item.context_expr if isinstance(ctx, ast.Call) and isinstance(ctx.func, ast.Attribute) and ctx.func.attr == "acquire": start = node.lineno end = getattr(node, "end_lineno", node.lineno) or node.lineno lines = source.splitlines(keepends=True) body = lines[start:end] dedented = [] for line in body[1:]: if line.startswith(" "): dedented.append(line[4:]) else: dedented.append(line) mutated = "".join(lines[: start - 1] + dedented + lines[end:]) return Mutation( defect_type=self.defect_type, language=self.language, line_start=start, line_end=end, mutated_source=mutated, reference_fix="Restore `with lock:` to protect the critical section.", description="Removed lock acquisition, exposing a race condition.", ) return None