fix(parsers/python): guard extraction so one bad file can't abort the whole repo parse#136
Merged
Merged
Conversation
… whole repo parse FunctionExtractor.process_file guarded only ast.parse (except SyntaxError); the extraction body and both caller loops (extract_from_scan, extract_all) were unguarded, so a single pathological file raising a non-SyntaxError -- e.g. a RecursionError from a deeply-nested source, or any error in the tree walk -- propagated out of the file loop and aborted the entire parse, zeroing ALL units. - Add a per-file guard _process_file_guarded (try/except Exception -> log a WARNING to stderr + files_with_errors += 1) at both loops, mirroring the Zig/Go per-file guards (parsers/zig/function_extractor.py:57-77), the only currently-immune parsers. - Move files_processed += 1 to the end of process_file so a file that crashes mid-extraction is counted once as an error and never as processed (no double-count). - except Exception (not BaseException) so KeyboardInterrupt/SystemExit still propagate; the failure is logged, never silently swallowed. Verified against origin/master (98f5504): byte-identical unit-id set + stats on click/flask/httpie/rich via both extract_from_scan and extract_all (no change on valid code); recovers every real unit when one file raises at parse OR post-parse; python parser test suite unchanged vs base. Regression test (fails on master, passes here): $ python -m pytest tests/parsers/python/test_function_extractor_robustness.py -q 4 passed Does NOT change valid-file extraction output, the func_id scheme, or any other parser. The same latent pattern in the JS/C/Ruby/PHP extractors is a tracked follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gadievron
requested review from
dgeyshis,
shahar-davidson and
sounil
as code owners
July 9, 2026 11:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Add a per-file guard so a single pathological Python file cannot abort the whole repo's extraction (mirrors the existing Zig/Go parsers).
Root cause
FunctionExtractor.process_fileguarded onlyast.parse(except SyntaxError); the extraction body and both caller loops (extract_from_scan,extract_all) were unguarded. A single file raising a non-SyntaxError— aRecursionErrorfrom a deeply-nested source, or any error in the tree walk — propagated out of the file loop and aborted the entire parse, losing all units collected so far.How
_process_file_guarded(try/except Exception -> log a WARNING to stderr +files_with_errors += 1) and route all threeprocess_filecall sites (extract_from_scan+ bothextract_allbranches) through it. Mirrorsparsers/zig/function_extractor.py:57-77.files_processed += 1to the end ofprocess_file, so a file that crashes mid-extraction is counted once as an error and never as processed (no double-count).except Exception(notBaseException) soKeyboardInterrupt/SystemExitstill propagate; the failure is logged, never silently dropped.Regression test
tests/parsers/python/test_function_extractor_robustness.pydrives the real entry points (extract_from_scan= the production path used byparse_repository, andextract_all), not hand-built dicts. It covers a parse-time RecursionError, a post-parse extraction error (via monkeypatchedprocess_function), and stats correctness.RED on
origin/master(98f5504):GREEN on this branch:
Verification
Byte-identical unit-id set + statistics on click/flask/httpie/rich via both
extract_from_scanandextract_all(no change on valid code); recovers every real unit when one file raises at parse OR post-parse. Python parser test suite unchanged vs base.Compatibility / scope
function_extractor.py) land first. Master already carries the block-scoped extraction shape, so the change merges clean today.Author notes
_process_file_guarded+ the three re-routed call sites + thefiles_processedmove.ast.parse) returned zero units for the entire repo; it now skips that file and returns the rest.Exception(notBaseException), logs each failure to stderr with the file + exception type, and counts it infiles_with_errors, matching the Zig/Go guard and the file's existing stderr-print convention.🤖 Generated with Claude Code