@@ -75,6 +75,26 @@ func (e *PythonExtractor) Extract(ctx context.Context, repoPath string, files []
7575 modules := make (map [string ]bool )
7676 isDjango := detectDjango (repoPath )
7777
78+ // Pass 1: build a global symbol index across all Python files.
79+ idx := & pySymbolIndex {classes : make (map [string ]* pyClassInfo )}
80+ for _ , relFile := range files {
81+ select {
82+ case <- ctx .Done ():
83+ return allFacts , ctx .Err ()
84+ default :
85+ }
86+ if ! isPythonFile (relFile ) {
87+ continue
88+ }
89+ src , err := os .ReadFile (filepath .Join (repoPath , relFile ))
90+ if err != nil {
91+ continue
92+ }
93+ buildFileIndex (src , relFile , idx )
94+ }
95+ finalizeImplMap (idx )
96+
97+ // Pass 2: extract facts using the populated symbol index.
7898 for _ , relFile := range files {
7999 select {
80100 case <- ctx .Done ():
@@ -95,13 +115,11 @@ func (e *PythonExtractor) Extract(ctx context.Context, repoPath string, files []
95115
96116 src , readErr := readAll (f )
97117 f .Close ()
98- var fileFacts []facts.Fact
99118 if readErr != nil {
100119 log .Printf ("[python-extractor] error reading %s: %v" , relFile , readErr )
101120 continue
102121 }
103- fileFacts = extractFileAST (src , relFile , isDjango )
104- allFacts = append (allFacts , fileFacts ... )
122+ allFacts = append (allFacts , extractFileAST (src , relFile , isDjango , idx )... )
105123
106124 dir := filepath .Dir (relFile )
107125 modules [dir ] = true
0 commit comments