Skip to content

Commit a0cb4c6

Browse files
committed
refactor(diagnostics): deduplicate and optimize metadata classes in imports_manager
- Extract _collect_library_mtimes() to unify duplicated mtime collection from get_library_meta and get_variables_meta, using os.walk instead of Path.rglob for better performance - Extract _matches_any_pattern() to unify triplicated pattern matching - Add slots=True to LibraryMetaData, RobotFileMeta, and NamespaceMetaData - Move mtime collection into dataclass constructors to avoid post-init mutation - Remove unused itertools import
1 parent 45d8f9f commit a0cb4c6

File tree

1 file changed

+57
-52
lines changed

1 file changed

+57
-52
lines changed

packages/robot/src/robotcode/robot/diagnostics/imports_manager.py

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import ast
2-
import itertools
32
import multiprocessing as mp
43
import os
54
import shutil
@@ -508,7 +507,7 @@ def get_libdoc(self) -> VariablesDoc:
508507
return self._lib_doc
509508

510509

511-
@dataclass
510+
@dataclass(slots=True)
512511
class 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)
536567
class RobotFileMeta:
537568
source: str
538569
mtime_ns: int
539570

540571

541-
@dataclass
572+
@dataclass(slots=True)
542573
class 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

Comments
 (0)