Build import graphs for files within test directory (recursive). Uses cross-process shelve cache based on CPython version. Args: test_dir: Path to Lib/test/ directory Returns: Tuple of: - Dict mapping relative path (without .py) -> set of test modules it import
(
test_dir: pathlib.Path,
)
| 1359 | |
| 1360 | |
| 1361 | def _build_test_import_graph( |
| 1362 | test_dir: pathlib.Path, |
| 1363 | ) -> tuple[dict[str, set[str]], dict[str, set[str]]]: |
| 1364 | """Build import graphs for files within test directory (recursive). |
| 1365 | |
| 1366 | Uses cross-process shelve cache based on CPython version. |
| 1367 | |
| 1368 | Args: |
| 1369 | test_dir: Path to Lib/test/ directory |
| 1370 | |
| 1371 | Returns: |
| 1372 | Tuple of: |
| 1373 | - Dict mapping relative path (without .py) -> set of test modules it imports |
| 1374 | - Dict mapping relative path (without .py) -> set of all lib imports |
| 1375 | """ |
| 1376 | # In-process cache |
| 1377 | cache_key = str(test_dir) |
| 1378 | if cache_key in _test_import_graph_cache: |
| 1379 | return _test_import_graph_cache[cache_key] |
| 1380 | |
| 1381 | # Cross-process cache (only for standard Lib/test directory) |
| 1382 | use_file_cache = _is_standard_lib_path(cache_key) |
| 1383 | if use_file_cache: |
| 1384 | version = _get_cpython_version("cpython") |
| 1385 | shelve_key = f"test_import_graph:{version}" |
| 1386 | try: |
| 1387 | with shelve.open(_get_cache_path()) as db: |
| 1388 | if shelve_key in db: |
| 1389 | import_graph, lib_imports_graph = db[shelve_key] |
| 1390 | _test_import_graph_cache[cache_key] = ( |
| 1391 | import_graph, |
| 1392 | lib_imports_graph, |
| 1393 | ) |
| 1394 | return import_graph, lib_imports_graph |
| 1395 | except Exception: |
| 1396 | pass |
| 1397 | |
| 1398 | # Build from scratch |
| 1399 | import_graph: dict[str, set[str]] = {} |
| 1400 | lib_imports_graph: dict[str, set[str]] = {} |
| 1401 | |
| 1402 | for py_file in test_dir.glob("**/*.py"): |
| 1403 | content = safe_read_text(py_file) |
| 1404 | if content is None: |
| 1405 | continue |
| 1406 | |
| 1407 | imports = set() |
| 1408 | imports.update(parse_test_imports(content)) |
| 1409 | all_imports = parse_lib_imports(content) |
| 1410 | |
| 1411 | for imp in all_imports: |
| 1412 | if (py_file.parent / f"{imp}.py").exists(): |
| 1413 | imports.add(imp) |
| 1414 | if (test_dir / f"{imp}.py").exists(): |
| 1415 | imports.add(imp) |
| 1416 | |
| 1417 | submodule_imports = _parse_test_submodule_imports(content) |
| 1418 | for submodule, imported_names in submodule_imports.items(): |
no test coverage detected