fix(auto-fixer): remove ddof from rolling() args, not only from std()/var()

The LLM generates x.rolling(window=N, ddof=1).std() where ddof is passed
to rolling() instead of std() — pandas raises TypeError on any ddof in rolling().
Fix both forms: rolling(..., ddof=N) and rolling(...).std(ddof=N).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
TPTBusiness
2026-04-26 08:53:40 +02:00
parent 27803e8b85
commit 7582e55bb3
@@ -153,16 +153,25 @@ class FactorAutoFixer:
def _fix_rolling_ddof(self, code: str) -> str:
"""
Fix: pandas rolling().std(ddof=N) is not supported — ddof is ignored or
raises TypeError depending on pandas version. Remove the ddof kwarg.
Fix: pandas rolling() does not accept a ddof kwarg — raises TypeError.
Remove ddof from both rolling(..., ddof=N) and rolling(...).std(ddof=N).
"""
fixed_code = code
pattern = r'(\.rolling\([^)]+\)\.\w+\([^)]*),\s*ddof\s*=\s*\d+([^)]*\))'
if re.search(pattern, fixed_code):
fixed_code = re.sub(pattern, r'\1\2', fixed_code)
self.fixes_applied.append("rolling_ddof: removed unsupported ddof kwarg")
# Also handle ddof as only arg: .std(ddof=1) → .std()
fixed_code = re.sub(r'\.(std|var)\(ddof\s*=\s*\d+\)', r'.\1()', fixed_code)
# Form 1: ddof inside rolling() — .rolling(window=N, min_periods=M, ddof=K)
def _strip_ddof_from_rolling(m):
inner = re.sub(r',?\s*ddof\s*=\s*\d+', '', m.group(1))
inner = inner.strip(', ')
self.fixes_applied.append("rolling_ddof: removed ddof from rolling()")
return f'.rolling({inner})'
fixed_code = re.sub(r'\.rolling\(([^)]*ddof\s*=\s*\d+[^)]*)\)', _strip_ddof_from_rolling, fixed_code)
# Form 2: ddof inside .std() / .var() — .std(ddof=N)
if re.search(r'\.(std|var)\([^)]*ddof\s*=\s*\d+', fixed_code):
fixed_code = re.sub(r'\.(std|var)\([^)]*ddof\s*=\s*\d+[^)]*\)', r'.\1()', fixed_code)
self.fixes_applied.append("rolling_ddof: removed ddof from std()/var()")
return fixed_code
def _fix_min_periods(self, code: str) -> str: