11import ast
2- import itertools
32import multiprocessing as mp
43import os
54import shutil
@@ -508,7 +507,7 @@ def get_libdoc(self) -> VariablesDoc:
508507 return self ._lib_doc
509508
510509
511- @dataclass
510+ @dataclass ( slots = True )
512511class LibraryMetaData :
513512 name : Optional [str ]
514513 member_name : Optional [str ]
@@ -532,13 +531,45 @@ def cache_key(self) -> str:
532531 raise ValueError ("Cannot determine cache key." )
533532
534533
535- @dataclass
534+ def _collect_library_mtimes (
535+ origin : Optional [str ],
536+ submodule_search_locations : Optional [List [str ]],
537+ ) -> Optional [Dict [str , int ]]:
538+ """Collect mtimes from origin and submodule_search_locations."""
539+ mtimes : Dict [str , int ] = {}
540+
541+ if origin is not None :
542+ mtimes [origin ] = os .stat (origin , follow_symlinks = False ).st_mtime_ns
543+
544+ if submodule_search_locations :
545+ for loc in submodule_search_locations :
546+ for dirpath , _dirnames , filenames in os .walk (loc ):
547+ for filename in filenames :
548+ if filename .endswith (".py" ):
549+ filepath = os .path .join (dirpath , filename )
550+ mtimes [filepath ] = os .stat (filepath , follow_symlinks = False ).st_mtime_ns
551+
552+ return mtimes or None
553+
554+
555+ def _matches_any_pattern (
556+ patterns : List [Pattern ],
557+ name : Optional [str ],
558+ origin : Optional [str ],
559+ ) -> bool :
560+ return any (
561+ (p .matches (name ) if name is not None else False ) or (p .matches (origin ) if origin is not None else False )
562+ for p in patterns
563+ )
564+
565+
566+ @dataclass (slots = True )
536567class RobotFileMeta :
537568 source : str
538569 mtime_ns : int
539570
540571
541- @dataclass
572+ @dataclass ( slots = True )
542573class NamespaceMetaData :
543574 """Lightweight metadata for fast cache freshness checks.
544575
@@ -1214,7 +1245,14 @@ def get_library_meta(
12141245 module_spec : Optional [ModuleSpec ] = None
12151246 if is_library_by_path (import_name ):
12161247 if (p := Path (import_name )).exists ():
1217- result = LibraryMetaData (p .stem , None , import_name , None , True )
1248+ result = LibraryMetaData (
1249+ p .stem ,
1250+ None ,
1251+ import_name ,
1252+ None ,
1253+ True ,
1254+ mtimes = _collect_library_mtimes (import_name , None ),
1255+ )
12181256 else :
12191257 module_spec = self ._get_module_spec_cached (import_name )
12201258 if module_spec is not None and module_spec .origin is not None :
@@ -1224,22 +1262,15 @@ def get_library_meta(
12241262 module_spec .origin ,
12251263 module_spec .submodule_search_locations ,
12261264 False ,
1265+ mtimes = _collect_library_mtimes (module_spec .origin , module_spec .submodule_search_locations ),
12271266 )
12281267
12291268 if result is not None :
1230- # TODO: use IgnoreSpec instead of this
1231- ignore_arguments = any (
1232- (p .matches (result .name ) if result .name is not None else False )
1233- or (p .matches (result .origin ) if result .origin is not None else False )
1234- for p in self .ignore_arguments_for_library_patters
1269+ ignore_arguments = _matches_any_pattern (
1270+ self .ignore_arguments_for_library_patters , result .name , result .origin
12351271 )
12361272
1237- # TODO: use IgnoreSpec instead of this
1238- if any (
1239- (p .matches (result .name ) if result .name is not None else False )
1240- or (p .matches (result .origin ) if result .origin is not None else False )
1241- for p in self .ignored_libraries_patters
1242- ):
1273+ if _matches_any_pattern (self .ignored_libraries_patters , result .name , result .origin ):
12431274 self ._logger .debug (
12441275 lambda : (
12451276 f"Ignore library { result .name or '' if result is not None else '' } "
@@ -1249,21 +1280,6 @@ def get_library_meta(
12491280 )
12501281 return None , import_name , ignore_arguments
12511282
1252- if result .origin is not None :
1253- result .mtimes = {result .origin : os .stat (result .origin , follow_symlinks = False ).st_mtime_ns }
1254-
1255- if result .submodule_search_locations :
1256- if result .mtimes is None :
1257- result .mtimes = {}
1258- result .mtimes .update (
1259- {
1260- str (f ): os .stat (f , follow_symlinks = False ).st_mtime_ns
1261- for f in itertools .chain (
1262- * (Path (loc ).rglob ("**/*.py" ) for loc in result .submodule_search_locations )
1263- )
1264- }
1265- )
1266-
12671283 return result , import_name , ignore_arguments
12681284 except (SystemExit , KeyboardInterrupt ):
12691285 raise
@@ -1294,7 +1310,14 @@ def get_variables_meta(
12941310 module_spec : Optional [ModuleSpec ] = None
12951311 if is_variables_by_path (import_name ):
12961312 if (p := Path (import_name )).exists ():
1297- result = LibraryMetaData (p .stem , None , import_name , None , True )
1313+ result = LibraryMetaData (
1314+ p .stem ,
1315+ None ,
1316+ import_name ,
1317+ None ,
1318+ True ,
1319+ mtimes = _collect_library_mtimes (import_name , None ),
1320+ )
12981321 else :
12991322 module_spec = self ._get_module_spec_cached (import_name )
13001323 if module_spec is not None and module_spec .origin is not None :
@@ -1304,14 +1327,11 @@ def get_variables_meta(
13041327 module_spec .origin ,
13051328 module_spec .submodule_search_locations ,
13061329 False ,
1330+ mtimes = _collect_library_mtimes (module_spec .origin , module_spec .submodule_search_locations ),
13071331 )
13081332
13091333 if result is not None :
1310- if any (
1311- (p .matches (result .name ) if result .name is not None else False )
1312- or (p .matches (result .origin ) if result .origin is not None else False )
1313- for p in self .ignored_variables_patters
1314- ):
1334+ if _matches_any_pattern (self .ignored_variables_patters , result .name , result .origin ):
13151335 self ._logger .debug (
13161336 lambda : (
13171337 f"Ignore Variables { result .name or '' if result is not None else '' } "
@@ -1320,21 +1340,6 @@ def get_variables_meta(
13201340 )
13211341 return None , import_name
13221342
1323- if result .origin is not None :
1324- result .mtimes = {result .origin : os .stat (result .origin , follow_symlinks = False ).st_mtime_ns }
1325-
1326- if result .submodule_search_locations :
1327- if result .mtimes is None :
1328- result .mtimes = {}
1329- result .mtimes .update (
1330- {
1331- str (f ): os .stat (f , follow_symlinks = False ).st_mtime_ns
1332- for f in itertools .chain (
1333- * (Path (loc ).rglob ("**/*.py" ) for loc in result .submodule_search_locations )
1334- )
1335- }
1336- )
1337-
13381343 return result , import_name
13391344 except (SystemExit , KeyboardInterrupt ):
13401345 raise
0 commit comments