1- /// Statically analyses some Python modules for import statements within their shared package.
2- use rayon:: prelude:: * ;
31use crate :: errors:: GrimpResult ;
42use crate :: filesystem:: { FileSystem , PyFakeBasicFileSystem , PyRealBasicFileSystem } ;
53use crate :: import_parsing;
@@ -8,6 +6,8 @@ use itertools::Itertools;
86use pyo3:: exceptions:: PyTypeError ;
97use pyo3:: prelude:: * ;
108use pyo3:: types:: { PyDict , PySet } ;
9+ /// Statically analyses some Python modules for import statements within their shared package.
10+ use rayon:: prelude:: * ;
1111use std:: collections:: { HashMap , HashSet } ;
1212use std:: io:: { self , ErrorKind } ;
1313
@@ -85,12 +85,20 @@ pub fn scan_for_imports_no_py(
8585) -> GrimpResult < HashMap < Module , HashSet < DirectImport > > > {
8686 let module_packages = get_modules_from_found_packages ( found_packages) ;
8787
88+ // Assemble a lookup table so we only need to do this once.
89+ let mut found_packages_by_module = HashMap :: new ( ) ;
90+ for found_package in found_packages {
91+ for module_file in & found_package. module_files {
92+ found_packages_by_module. insert ( & module_file. module , found_package) ;
93+ }
94+ }
8895 let results: GrimpResult < Vec < ( Module , HashSet < DirectImport > ) > > = modules
8996 . par_iter ( )
9097 . map ( |module| {
9198 let imports = scan_for_imports_no_py_single_module (
9299 module,
93100 file_system,
101+ & found_packages_by_module,
94102 found_packages,
95103 & module_packages,
96104 include_external_packages,
@@ -107,13 +115,14 @@ pub fn scan_for_imports_no_py(
107115fn scan_for_imports_no_py_single_module (
108116 module : & Module ,
109117 file_system : & Box < dyn FileSystem + Send + Sync > ,
118+ found_packages_by_module : & HashMap < & Module , & FoundPackage > ,
110119 found_packages : & HashSet < FoundPackage > ,
111120 all_modules : & HashSet < Module > ,
112121 include_external_packages : bool ,
113122 exclude_type_checking_imports : bool ,
114123) -> GrimpResult < HashSet < DirectImport > > {
115124 let mut imports: HashSet < DirectImport > = HashSet :: new ( ) ;
116- let found_package_for_module = _lookup_found_package_for_module ( module, found_packages ) ;
125+ let found_package_for_module = found_packages_by_module [ module] ;
117126 let module_filename =
118127 _determine_module_filename ( module, found_package_for_module, file_system) . unwrap ( ) ;
119128 let module_contents = file_system. read ( & module_filename) . unwrap ( ) ;
@@ -148,14 +157,14 @@ fn scan_for_imports_no_py_single_module(
148157 if include_external_packages
149158 && let Some ( imported_module) =
150159 _distill_external_module ( & imported_object_name, found_packages)
151- {
152- imports. insert ( DirectImport {
153- importer : module. name . to_string ( ) ,
154- imported : imported_module,
155- line_number : imported_object. line_number ,
156- line_contents : imported_object. line_contents ,
157- } ) ;
158- }
160+ {
161+ imports. insert ( DirectImport {
162+ importer : module. name . to_string ( ) ,
163+ imported : imported_module,
164+ line_number : imported_object. line_number ,
165+ line_contents : imported_object. line_contents ,
166+ } ) ;
167+ }
159168 }
160169 }
161170 }
@@ -192,21 +201,6 @@ pub fn to_py_direct_imports<'a>(
192201 pyset
193202}
194203
195- fn _lookup_found_package_for_module < ' b > (
196- module : & Module ,
197- found_packages : & ' b HashSet < FoundPackage > ,
198- ) -> & ' b FoundPackage {
199- // TODO: it's probably inefficient to do this every time we look up a module.
200- for found_package in found_packages {
201- for module_file in & found_package. module_files {
202- if module_file. module == * module {
203- return found_package;
204- }
205- }
206- }
207- panic ! ( "Could not lookup found package for module {module}" ) ;
208- }
209-
210204#[ allow( clippy:: borrowed_box) ]
211205fn _determine_module_filename (
212206 module : & Module ,
0 commit comments